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
mdb.master3
moneromooo-monero 7 years ago committed by Howard Chu
parent b4ddec0bb4
commit 0158f67c14
  1. 8
      libraries/liblmdb/lmdb.h
  2. 15
      libraries/liblmdb/mdb.c

@ -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().
* <li>#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.
* </ul>
* @param[in] mode The UNIX permissions to set on created files and semaphores.
* This parameter is ignored on Windows.

@ -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.

Loading…
Cancel
Save