diff --git a/libraries/liblmdb/lmdb.h b/libraries/liblmdb/lmdb.h index 3a6be03..f9f847f 100644 --- a/libraries/liblmdb/lmdb.h +++ b/libraries/liblmdb/lmdb.h @@ -354,8 +354,8 @@ typedef void (MDB_enc_func)(const MDB_val *src, MDB_val *dst, const MDB_val *key #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 /** don't use a single mmap, remap individual chunks (needs MDB_RPAGE_CACHE) */ #define MDB_REMAP_CHUNKS 0x4000000 /** @} */ @@ -672,10 +672,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 217e203..4b77458 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -4047,6 +4047,8 @@ done: return MDB_SUCCESS; } +static int ESECT mdb_env_share_locks(MDB_env *env, int *excl); + int mdb_txn_commit(MDB_txn *txn) { @@ -4274,6 +4276,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); @@ -4564,7 +4575,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 @@ -5139,6 +5151,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); @@ -5238,9 +5253,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 { @@ -5684,7 +5696,7 @@ mdb_env_envflags(MDB_env *env) /*f*/ MDB_FIXEDMAP, /*h*/ MDB_NORDAHEAD, /*i*/ MDB_NOMEMINIT, /*l*/ MDB_NOLOCK, /*m*/ MDB_NOMETASYNC, /*n*/ MDB_NOSUBDIR, /*r*/ MDB_RDONLY, /*s*/ MDB_NOSYNC, /*t*/ MDB_NOTLS, - /*v*/ MDB_PREVMETA, /*w*/ MDB_WRITEMAP, + /*v*/ MDB_PREVSNAPSHOT, /*w*/ MDB_WRITEMAP, }; unsigned flags = 0; const char *s, *opts = getenv("LMDB_FLAGS"); @@ -5724,7 +5736,7 @@ mdb_env_envflags(MDB_env *env) */ #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_REMAP_CHUNKS) + MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD|MDB_PREVSNAPSHOT|MDB_REMAP_CHUNKS) #define EXPOSED (CHANGEABLE|CHANGELESS | MDB_ENCRYPT) #if VALID_FLAGS & PERSISTENT_FLAGS & EXPOSED @@ -5823,6 +5835,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, @@ -5837,7 +5853,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. @@ -5847,7 +5863,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 f156a54..fd7268d 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 05402bc..77c2a5a 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 15145b8..c67ed60 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++;