]> 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>
Sat, 25 Jun 2016 05:57:04 +0000 (07:57 +0200)
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 a794c9f7d84b3ab009d29ebd436c3cc4139a80b4..85dc50d580c81ca2d44a3a075b736bfa64acbb6b 100644 (file)
@@ -688,6 +688,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 77b05b1edcfa4a34a68591b55eec402c69eeb46e..4ea4204fd72fa7afe131e9bdf708e11d7da97518 100644 (file)
@@ -9906,6 +9906,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
@@ -9963,10 +9964,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;
@@ -9979,19 +9982,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.