]> git.ipfire.org Git - thirdparty/openldap.git/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>
Sat, 10 Oct 2020 12:03:36 +0000 (13:03 +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 d691264657a97a4cb0583a6e20c7f33d6eb35943..3a6be034a4a0f1b15957476868fd80a7e297e4d9 100644 (file)
@@ -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.
index 0911bbb6d630852ddf8d26c67a34add930af675c..e14b8656afde9e23eb8171cb80079c542497e39d 100644 (file)
@@ -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.