ITS#8209 MDB_CP_COMPACT: Handle empty or broken DB

Preserve DB flags (use metapage#1) when main DB is empty.
Fail if metapage root != actual root in output file.
ntdll
Hallvard Furuseth 8 years ago
parent eb7bbed967
commit 5ea12b0be8
  1. 1
      libraries/liblmdb/lmdb.h
  2. 36
      libraries/liblmdb/mdb.c
  3. 1
      libraries/liblmdb/mdb_copy.1

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

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

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

Loading…
Cancel
Save