]> git.sur5r.net Git - openldap/commitdiff
ITS#8704 add MDB_PREVMETA flag to mdb_env_open
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>
Sun, 30 Jul 2017 23:04:28 +0000 (00:04 +0100)
committerHoward Chu <hyc@openldap.org>
Mon, 31 Jul 2017 17:48:30 +0000 (18:48 +0100)
used to open the previous meta page, in case the latest one
is corrupted

From https://github.com/LMDB/lmdb/pull/12

libraries/liblmdb/lmdb.h
libraries/liblmdb/mdb.c

index 039210dcde2e036a86a29176e7db97992c550417..0a10fc92cd7142e334fd7df922fb24a88200c6be 100644 (file)
@@ -332,6 +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
 /** @} */
 
 /**    @defgroup       mdb_dbi_open    Database Flags
@@ -646,6 +648,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.
index 148dc45722b3f38dd532ee2645e9bf849413c3d7..94081cafcf838ef27fa4288828877d1244278395 100644 (file)
@@ -1582,7 +1582,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 */
@@ -3985,11 +3985,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;
@@ -4040,7 +4041,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;
@@ -4670,7 +4671,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;
@@ -4733,7 +4734,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");
@@ -5332,7 +5333,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_PREVMETA)
 
 #if VALID_FLAGS & PERSISTENT_FLAGS & (CHANGEABLE|CHANGELESS)
 # error "Persistent DB flags & env flags overlap, but both go in mm_flags"
@@ -5432,7 +5433,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.