diff --git a/libraries/liblmdb/lmdb.h b/libraries/liblmdb/lmdb.h index 9e51b55..1f4736c 100644 --- a/libraries/liblmdb/lmdb.h +++ b/libraries/liblmdb/lmdb.h @@ -332,8 +332,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 meta page rather than the latest one */ -#define MDB_PREVMETA 0x2000000 + /** use the previous snapshot rather than the latest one */ +#define MDB_PREVSNAPSHOT 0x2000000 /** @} */ /** @defgroup mdb_dbi_open Database Flags @@ -648,10 +648,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(). - *
  • #MDB_PREVMETA - * Open the environment with the previous meta page rather than the latest + *
  • #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. + * 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. * * @param[in] mode The UNIX permissions to set on created files and semaphores. * This parameter is ignored on Windows. diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 433fe50..fb57a72 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -3793,6 +3793,8 @@ done: return MDB_SUCCESS; } +static int ESECT mdb_env_share_locks(MDB_env *env, int *excl); + int mdb_txn_commit(MDB_txn *txn) { @@ -4015,6 +4017,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); @@ -4296,7 +4307,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 @@ -4868,6 +4880,9 @@ mdb_env_open2(MDB_env *env, int prev) #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); @@ -4967,9 +4982,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 { @@ -5391,7 +5403,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_PREVMETA) + 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" @@ -5477,6 +5489,10 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode rc = mdb_env_setup_locks(env, &fname, mode, &excl); if (rc) goto leave; + if ((flags & MDB_PREVSNAPSHOT) && !excl) { + rc = EAGAIN; + goto leave; + } } rc = mdb_fopen(env, &fname, @@ -5491,7 +5507,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode goto leave; } - if ((rc = mdb_env_open2(env, flags & MDB_PREVMETA)) == MDB_SUCCESS) { + if ((rc = mdb_env_open2(env, flags & MDB_PREVSNAPSHOT)) == MDB_SUCCESS) { if (!(flags & (MDB_RDONLY|MDB_WRITEMAP))) { /* Synchronous fd for meta writes. Needed even with * MDB_NOSYNC/MDB_NOMETASYNC, in case these get reset. @@ -5501,7 +5517,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode goto leave; } 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; diff --git a/libraries/liblmdb/mdb_copy.c b/libraries/liblmdb/mdb_copy.c index 98df57a..23be815 100644 --- a/libraries/liblmdb/mdb_copy.c +++ b/libraries/liblmdb/mdb_copy.c @@ -39,7 +39,7 @@ int main(int argc,char * 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_PREVMETA; + 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') { diff --git a/libraries/liblmdb/mdb_dump.c b/libraries/liblmdb/mdb_dump.c index 8ba688d..b7737f1 100644 --- a/libraries/liblmdb/mdb_dump.c +++ b/libraries/liblmdb/mdb_dump.c @@ -175,7 +175,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 metapage + * -v: use previous snapshot * -V: print version and exit * (default) dump only the main DB */ @@ -204,7 +204,7 @@ int main(int argc, char *argv[]) envflags |= MDB_NOSUBDIR; break; case 'v': - envflags |= MDB_PREVMETA; + envflags |= MDB_PREVSNAPSHOT; break; case 'p': mode |= PRINT; diff --git a/libraries/liblmdb/mdb_stat.c b/libraries/liblmdb/mdb_stat.c index 1ec1042..08f30be 100644 --- a/libraries/liblmdb/mdb_stat.c +++ b/libraries/liblmdb/mdb_stat.c @@ -61,7 +61,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 metapage + * -v: use previous snapshot * -V: print version and exit * (default) print stat of only the main DB */ @@ -86,7 +86,7 @@ int main(int argc, char *argv[]) envflags |= MDB_NOSUBDIR; break; case 'v': - envflags |= MDB_PREVMETA; + envflags |= MDB_PREVSNAPSHOT; break; case 'r': rdrinfo++;