From: moneromooo-monero Date: Sun, 30 Jul 2017 23:04:28 +0000 (+0100) Subject: ITS#8704 add MDB_PREVMETA flag to mdb_env_open X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0158f67c14e4be93fe8ad5e6ff22f020de65f7b8;p=thirdparty%2Fopenldap.git ITS#8704 add MDB_PREVMETA flag to mdb_env_open used to open the previous meta page, in case the latest one is corrupted From https://github.com/LMDB/lmdb/pull/12 --- diff --git a/libraries/liblmdb/lmdb.h b/libraries/liblmdb/lmdb.h index d691264657..3a6be034a4 100644 --- a/libraries/liblmdb/lmdb.h +++ b/libraries/liblmdb/lmdb.h @@ -354,8 +354,10 @@ 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 /** don't use a single mmap, remap individual chunks (needs MDB_RPAGE_CACHE) */ -#define MDB_REMAP_CHUNKS 0x2000000 +#define MDB_REMAP_CHUNKS 0x4000000 /** @} */ /** @defgroup mdb_dbi_open Database Flags @@ -670,6 +672,10 @@ 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 + * one. This loses the latest transaction, but may help work around some + * types of corruption. * * @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 0911bbb6d6..e14b8656af 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1697,7 +1697,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 */ @@ -4270,11 +4270,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; @@ -4325,7 +4326,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; @@ -4965,7 +4966,7 @@ mdb_fopen(const MDB_env *env, MDB_name *fname, /** 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; @@ -5028,7 +5029,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"); @@ -5706,7 +5707,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_REMAP_CHUNKS) + MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD|MDB_PREVMETA|MDB_REMAP_CHUNKS) #define EXPOSED (CHANGEABLE|CHANGELESS | MDB_ENCRYPT) #if VALID_FLAGS & PERSISTENT_FLAGS & EXPOSED @@ -5819,7 +5820,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)) == MDB_SUCCESS) { + if ((rc = mdb_env_open2(env, flags & MDB_PREVMETA)) == 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.