]> git.sur5r.net Git - openldap/commitdiff
ITS#8209 MDB_CP_COMPACT: Handle empty or broken DB
authorHallvard Furuseth <hallvard@openldap.org>
Sat, 25 Jun 2016 05:57:04 +0000 (07:57 +0200)
committerHallvard Furuseth <hallvard@openldap.org>
Thu, 15 Dec 2016 21:27:32 +0000 (22:27 +0100)
Preserve DB flags (use metapage#1) when main DB is empty.
Fail if metapage root != actual root in output file.

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

index bc3a29484c3f287139c5ec81b0c869a230f736b3..a3565385957c3be6b61d65d388b9906dd9b1ac31 100644 (file)
@@ -679,6 +679,7 @@ int  mdb_env_copyfd(MDB_env *env, mdb_filehandle_t fd);
         *      <li>#MDB_CP_COMPACT - Perform compaction while copying: omit free
         *              pages and sequentially renumber all pages in output. This option
         *              consumes more CPU and runs more slowly than the default.
+        *              Currently it fails if the environment has suffered a page leak.
         * </ul>
         * @return A non-zero error value on failure and 0 on success.
         */
index 255e2167248a8c8a5ca6f20f70ea29d0d8507128..28ccb73e667057a96cde2f67aef21e57739206fe 100644 (file)
@@ -9093,6 +9093,7 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd)
        mdb_copy my = {0};
        MDB_txn *txn = NULL;
        pthread_t thr;
+       pgno_t root, new_root;
        int rc = MDB_SUCCESS;
 
 #ifdef _WIN32
@@ -9154,10 +9155,12 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd)
        *(MDB_meta *)METADATA(mp) = *mm;
        mm = (MDB_meta *)METADATA(mp);
 
-       /* Count the number of free pages, subtract from lastpg to find
-        * number of active pages
-        */
-       {
+       /* Set metapage 1 with current main DB */
+       root = new_root = txn->mt_dbs[MAIN_DBI].md_root;
+       if (root != P_INVALID) {
+               /* Count free pages + freeDB pages.  Subtract from last_pg
+                * to find the new last_pg, which also becomes the new root.
+                */
                MDB_ID freecount = 0;
                MDB_cursor mc;
                MDB_val key, data;
@@ -9170,19 +9173,26 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd)
                        txn->mt_dbs[FREE_DBI].md_leaf_pages +
                        txn->mt_dbs[FREE_DBI].md_overflow_pages;
 
-               /* Set metapage 1 */
-               mm->mm_last_pg = txn->mt_next_pgno - freecount - 1;
+               new_root = txn->mt_next_pgno - 1 - freecount;
+               mm->mm_last_pg = new_root;
                mm->mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI];
-               if (mm->mm_last_pg > NUM_METAS-1) {
-                       mm->mm_dbs[MAIN_DBI].md_root = mm->mm_last_pg;
-                       mm->mm_txnid = 1;
-               } else {
-                       mm->mm_dbs[MAIN_DBI].md_root = P_INVALID;
-               }
+               mm->mm_dbs[MAIN_DBI].md_root = new_root;
+       } else {
+               /* When the DB is empty, handle it specially to
+                * fix any breakage like page leaks from ITS#8174.
+                */
+               mm->mm_dbs[MAIN_DBI].md_flags = txn->mt_dbs[MAIN_DBI].md_flags;
+       }
+       if (root != P_INVALID || mm->mm_dbs[MAIN_DBI].md_flags) {
+               mm->mm_txnid = 1;               /* use metapage 1 */
        }
+
        my.mc_wlen[0] = env->me_psize * NUM_METAS;
        my.mc_txn = txn;
-       rc = mdb_env_cwalk(&my, &txn->mt_dbs[MAIN_DBI].md_root, 0);
+       rc = mdb_env_cwalk(&my, &root, 0);
+       if (rc == MDB_SUCCESS && root != new_root) {
+               rc = MDB_INCOMPATIBLE;  /* page leak or corrupt DB */
+       }
 
 finish:
        if (rc)
index 258affbfb404bd1c27e0774e78467d5b760928bc..4387ac3a1446e3c4e07f48dc5161d3bfccfd42c5 100644 (file)
@@ -36,6 +36,7 @@ Write the library version number to the standard output, and exit.
 Compact while copying. Only current data pages will be copied; freed
 or unused pages will be omitted from the copy. This option will
 slow down the backup process as it is more CPU-intensive.
+Currently it fails if the environment has suffered a page leak.
 .TP
 .BR \-n
 Open LDMB environment(s) which do not use subdirectories.