ITS#8704 add MDB_PREVSNAPSHOT flag to mdb_env_open
used to open the previous snapshot, in case the latest one is corrupted
This commit is contained in:
parent
86226754a9
commit
9c6eb75c65
|
@ -311,6 +311,8 @@ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *rel
|
|||
#define MDB_NORDAHEAD 0x800000
|
||||
/** don't initialize malloc'd memory before writing to datafile */
|
||||
#define MDB_NOMEMINIT 0x1000000
|
||||
/** use the previous snapshot rather than the latest one */
|
||||
#define MDB_PREVSNAPSHOT 0x2000000
|
||||
/** @} */
|
||||
|
||||
/** @defgroup mdb_dbi_open Database Flags
|
||||
|
@ -622,6 +624,12 @@ int mdb_env_create(MDB_env **env);
|
|||
* caller is expected to overwrite all of the memory that was
|
||||
* reserved in that case.
|
||||
* This flag may be changed at any time using #mdb_env_set_flags().
|
||||
* <li>#MDB_PREVSNAPSHOT
|
||||
* Open the environment with the previous snapshot rather than the latest
|
||||
* one. This loses the latest transaction, but may help work around some
|
||||
* types of corruption. If opened with write access, this must be the
|
||||
* only process using the environment. This flag is automatically reset
|
||||
* after a write transaction is successfully committed.
|
||||
* </ul>
|
||||
* @param[in] mode The UNIX permissions to set on created files and semaphores.
|
||||
* This parameter is ignored on Windows.
|
||||
|
|
|
@ -1468,7 +1468,7 @@ static int mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst);
|
|||
static int mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata,
|
||||
pgno_t newpgno, unsigned int nflags);
|
||||
|
||||
static int mdb_env_read_header(MDB_env *env, MDB_meta *meta);
|
||||
static int mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta);
|
||||
static MDB_meta *mdb_env_pick_meta(const MDB_env *env);
|
||||
static int mdb_env_write_meta(MDB_txn *txn);
|
||||
#ifdef MDB_USE_POSIX_MUTEX /* Drop unused excl arg */
|
||||
|
@ -3632,6 +3632,8 @@ done:
|
|||
return MDB_SUCCESS;
|
||||
}
|
||||
|
||||
static int ESECT mdb_env_share_locks(MDB_env *env, int *excl);
|
||||
|
||||
int
|
||||
mdb_txn_commit(MDB_txn *txn)
|
||||
{
|
||||
|
@ -3854,6 +3856,15 @@ mdb_txn_commit(MDB_txn *txn)
|
|||
if ((rc = mdb_env_write_meta(txn)))
|
||||
goto fail;
|
||||
end_mode = MDB_END_COMMITTED|MDB_END_UPDATE;
|
||||
if (env->me_flags & MDB_PREVSNAPSHOT) {
|
||||
if (!(env->me_flags & MDB_NOLOCK)) {
|
||||
int excl;
|
||||
rc = mdb_env_share_locks(env, &excl);
|
||||
if (rc)
|
||||
goto fail;
|
||||
}
|
||||
env->me_flags ^= MDB_PREVSNAPSHOT;
|
||||
}
|
||||
|
||||
done:
|
||||
mdb_txn_end(txn, end_mode);
|
||||
|
@ -3867,11 +3878,12 @@ fail:
|
|||
/** Read the environment parameters of a DB environment before
|
||||
* mapping it into memory.
|
||||
* @param[in] env the environment handle
|
||||
* @param[in] prev whether to read the backup meta page
|
||||
* @param[out] meta address of where to store the meta information
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
static int ESECT
|
||||
mdb_env_read_header(MDB_env *env, MDB_meta *meta)
|
||||
mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta)
|
||||
{
|
||||
MDB_metabuf pbuf;
|
||||
MDB_page *p;
|
||||
|
@ -3922,7 +3934,7 @@ mdb_env_read_header(MDB_env *env, MDB_meta *meta)
|
|||
return MDB_VERSION_MISMATCH;
|
||||
}
|
||||
|
||||
if (off == 0 || m->mm_txnid > meta->mm_txnid)
|
||||
if (off == 0 || (prev ? m->mm_txnid < meta->mm_txnid : m->mm_txnid > meta->mm_txnid))
|
||||
*meta = *m;
|
||||
}
|
||||
return 0;
|
||||
|
@ -4131,7 +4143,8 @@ static MDB_meta *
|
|||
mdb_env_pick_meta(const MDB_env *env)
|
||||
{
|
||||
MDB_meta *const *metas = env->me_metas;
|
||||
return metas[ metas[0]->mm_txnid < metas[1]->mm_txnid ];
|
||||
return metas[ (metas[0]->mm_txnid < metas[1]->mm_txnid) ^
|
||||
((env->me_flags & MDB_PREVSNAPSHOT) != 0) ];
|
||||
}
|
||||
|
||||
int ESECT
|
||||
|
@ -4366,7 +4379,7 @@ mdb_fsize(HANDLE fd, mdb_size_t *size)
|
|||
/** Further setup required for opening an LMDB environment
|
||||
*/
|
||||
static int ESECT
|
||||
mdb_env_open2(MDB_env *env)
|
||||
mdb_env_open2(MDB_env *env, int prev)
|
||||
{
|
||||
unsigned int flags = env->me_flags;
|
||||
int i, newenv = 0, rc;
|
||||
|
@ -4429,7 +4442,7 @@ mdb_env_open2(MDB_env *env)
|
|||
}
|
||||
#endif
|
||||
|
||||
if ((i = mdb_env_read_header(env, &meta)) != 0) {
|
||||
if ((i = mdb_env_read_header(env, prev, &meta)) != 0) {
|
||||
if (i != ENOENT)
|
||||
return i;
|
||||
DPUTS("new mdbenv");
|
||||
|
@ -4505,6 +4518,9 @@ mdb_env_open2(MDB_env *env)
|
|||
#endif
|
||||
env->me_maxpg = env->me_mapsize / env->me_psize;
|
||||
|
||||
if (env->me_txns)
|
||||
env->me_txns->mti_txnid = meta.mm_txnid;
|
||||
|
||||
#if MDB_DEBUG
|
||||
{
|
||||
MDB_meta *meta = mdb_env_pick_meta(env);
|
||||
|
@ -4600,9 +4616,6 @@ static int ESECT
|
|||
mdb_env_share_locks(MDB_env *env, int *excl)
|
||||
{
|
||||
int rc = 0;
|
||||
MDB_meta *meta = mdb_env_pick_meta(env);
|
||||
|
||||
env->me_txns->mti_txnid = meta->mm_txnid;
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
|
@ -5056,7 +5069,7 @@ fail:
|
|||
*/
|
||||
#define CHANGEABLE (MDB_NOSYNC|MDB_NOMETASYNC|MDB_MAPASYNC|MDB_NOMEMINIT)
|
||||
#define CHANGELESS (MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY| \
|
||||
MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD)
|
||||
MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD|MDB_PREVSNAPSHOT)
|
||||
|
||||
#if VALID_FLAGS & PERSISTENT_FLAGS & (CHANGEABLE|CHANGELESS)
|
||||
# error "Persistent DB flags & env flags overlap, but both go in mm_flags"
|
||||
|
@ -5178,9 +5191,13 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
|
|||
rc = mdb_env_setup_locks(env, lpath, mode, &excl);
|
||||
if (rc)
|
||||
goto leave;
|
||||
if ((flags & MDB_PREVSNAPSHOT) && !excl) {
|
||||
rc = EAGAIN;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rc = mdb_env_open2(env)) == MDB_SUCCESS) {
|
||||
if ((rc = mdb_env_open2(env, flags & MDB_PREVSNAPSHOT)) == MDB_SUCCESS) {
|
||||
if (flags & (MDB_RDONLY|MDB_WRITEMAP)) {
|
||||
env->me_mfd = env->me_fd;
|
||||
} else {
|
||||
|
@ -5206,7 +5223,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
|
|||
}
|
||||
}
|
||||
DPRINTF(("opened dbenv %p", (void *) env));
|
||||
if (excl > 0) {
|
||||
if (excl > 0 && !(flags & MDB_PREVSNAPSHOT)) {
|
||||
rc = mdb_env_share_locks(env, &excl);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
|
|
@ -11,6 +11,8 @@ mdb_copy \- LMDB environment copy tool
|
|||
.BR \-c ]
|
||||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BR \-v ]
|
||||
.B srcpath
|
||||
[\c
|
||||
.BR dstpath ]
|
||||
|
@ -39,6 +41,10 @@ slow down the backup process as it is more CPU-intensive.
|
|||
.TP
|
||||
.BR \-n
|
||||
Open LDMB environment(s) which do not use subdirectories.
|
||||
.TP
|
||||
.BR \-v
|
||||
Use the previous environment state instead of the latest state.
|
||||
This may be useful if the latest state has been corrupted.
|
||||
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is zero if no errors occur.
|
||||
|
|
|
@ -38,6 +38,8 @@ int main(int argc,char * argv[])
|
|||
for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
|
||||
if (argv[1][1] == 'n' && argv[1][2] == '\0')
|
||||
flags |= MDB_NOSUBDIR;
|
||||
else if (argv[1][1] == 'v' && argv[1][2] == '\0')
|
||||
flags |= MDB_PREVSNAPSHOT;
|
||||
else if (argv[1][1] == 'c' && argv[1][2] == '\0')
|
||||
cpflags |= MDB_CP_COMPACT;
|
||||
else if (argv[1][1] == 'V' && argv[1][2] == '\0') {
|
||||
|
@ -48,7 +50,7 @@ int main(int argc,char * argv[])
|
|||
}
|
||||
|
||||
if (argc<2 || argc>3) {
|
||||
fprintf(stderr, "usage: %s [-V] [-c] [-n] srcpath [dstpath]\n", progname);
|
||||
fprintf(stderr, "usage: %s [-V] [-c] [-n] [-v] srcpath [dstpath]\n", progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ mdb_dump \- LMDB environment export tool
|
|||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BR \-v ]
|
||||
[\c
|
||||
.BR \-p ]
|
||||
[\c
|
||||
.BR \-a \ |
|
||||
|
@ -42,6 +44,10 @@ names will be listed, no data will be output.
|
|||
.BR \-n
|
||||
Dump an LMDB database which does not use subdirectories.
|
||||
.TP
|
||||
.BR \-v
|
||||
Use the previous environment state instead of the latest state.
|
||||
This may be useful if the latest state has been corrupted.
|
||||
.TP
|
||||
.BR \-p
|
||||
If characters in either the key or data items are printing characters (as
|
||||
defined by isprint(3)), output them directly. This option permits users to
|
||||
|
|
|
@ -164,7 +164,7 @@ static int dumpit(MDB_txn *txn, MDB_dbi dbi, char *name)
|
|||
|
||||
static void usage(char *prog)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-a|-s subdb] dbpath\n", prog);
|
||||
fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-v] [-a|-s subdb] dbpath\n", prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -188,6 +188,7 @@ int main(int argc, char *argv[])
|
|||
* -n: use NOSUBDIR flag on env_open
|
||||
* -p: use printable characters
|
||||
* -f: write to file instead of stdout
|
||||
* -v: use previous snapshot
|
||||
* -V: print version and exit
|
||||
* (default) dump only the main DB
|
||||
*/
|
||||
|
@ -215,6 +216,9 @@ int main(int argc, char *argv[])
|
|||
case 'n':
|
||||
envflags |= MDB_NOSUBDIR;
|
||||
break;
|
||||
case 'v':
|
||||
envflags |= MDB_PREVSNAPSHOT;
|
||||
break;
|
||||
case 'p':
|
||||
mode |= PRINT;
|
||||
break;
|
||||
|
|
|
@ -14,6 +14,8 @@ mdb_stat \- LMDB environment status tool
|
|||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BR \-v ]
|
||||
[\c
|
||||
.BR \-r [ r ]]
|
||||
[\c
|
||||
.BR \-a \ |
|
||||
|
@ -39,6 +41,10 @@ If \fB\-fff\fP is given, display the full list of page IDs in the freelist.
|
|||
.BR \-n
|
||||
Display the status of an LMDB database which does not use subdirectories.
|
||||
.TP
|
||||
.BR \-v
|
||||
Use the previous environment state instead of the latest state.
|
||||
This may be useful if the latest state has been corrupted.
|
||||
.TP
|
||||
.BR \-r
|
||||
Display information about the environment reader table.
|
||||
Shows the process ID, thread ID, and transaction ID for each active
|
||||
|
|
|
@ -46,7 +46,7 @@ static void prstat(MDB_stat *ms)
|
|||
|
||||
static void usage(char *prog)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-a|-s subdb] dbpath\n", prog);
|
||||
fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-v] [-a|-s subdb] dbpath\n", prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,7 @@ int main(int argc, char *argv[])
|
|||
* -f: print freelist info
|
||||
* -r: print reader info
|
||||
* -n: use NOSUBDIR flag on env_open
|
||||
* -v: use previous snapshot
|
||||
* -V: print version and exit
|
||||
* (default) print stat of only the main DB
|
||||
*/
|
||||
|
@ -96,6 +97,9 @@ int main(int argc, char *argv[])
|
|||
case 'n':
|
||||
envflags |= MDB_NOSUBDIR;
|
||||
break;
|
||||
case 'v':
|
||||
envflags |= MDB_PREVSNAPSHOT;
|
||||
break;
|
||||
case 'r':
|
||||
rdrinfo++;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue