ITS#7210 fix leak of overflow pages in freelist

vmware
Howard Chu 13 years ago
parent f53beeabee
commit 91bab157f6
  1. 53
      libraries/libmdb/mdb.c

@ -1924,6 +1924,7 @@ mdb_txn_commit(MDB_txn *txn)
} }
/* save to free list */ /* save to free list */
free2:
freecnt = txn->mt_free_pgs[0]; freecnt = txn->mt_free_pgs[0];
if (!MDB_IDL_IS_ZERO(txn->mt_free_pgs)) { if (!MDB_IDL_IS_ZERO(txn->mt_free_pgs)) {
MDB_val key, data; MDB_val key, data;
@ -1962,8 +1963,6 @@ mdb_txn_commit(MDB_txn *txn)
return rc; return rc;
} }
} while (freecnt != txn->mt_free_pgs[0]); } while (freecnt != txn->mt_free_pgs[0]);
if (mdb_midl_shrink(&txn->mt_free_pgs))
env->me_free_pgs = txn->mt_free_pgs;
} }
/* should only be one record now */ /* should only be one record now */
again: again:
@ -1980,6 +1979,9 @@ again:
data.mv_size = MDB_IDL_SIZEOF(mop->mo_pages); data.mv_size = MDB_IDL_SIZEOF(mop->mo_pages);
data.mv_data = mop->mo_pages; data.mv_data = mop->mo_pages;
orig = mop->mo_pages[0]; orig = mop->mo_pages[0];
/* These steps may grow the freelist again
* due to freed overflow pages...
*/
mdb_cursor_put(&mc, &key, &data, 0); mdb_cursor_put(&mc, &key, &data, 0);
if (mop == env->me_pghead) { if (mop == env->me_pghead) {
/* could have been used again here */ /* could have been used again here */
@ -2000,6 +2002,14 @@ again:
env->me_pgfirst = 0; env->me_pgfirst = 0;
env->me_pglast = 0; env->me_pglast = 0;
} }
/* Check for growth of freelist again */
if (freecnt != txn->mt_free_pgs[0])
goto free2;
if (!MDB_IDL_IS_ZERO(txn->mt_free_pgs)) {
if (mdb_midl_shrink(&txn->mt_free_pgs))
env->me_free_pgs = txn->mt_free_pgs;
}
/* Update DB root pointers. Their pages have already been /* Update DB root pointers. Their pages have already been
* touched so this is all in-place and cannot fail. * touched so this is all in-place and cannot fail.
@ -4314,9 +4324,42 @@ more:
goto put_sub; goto put_sub;
} }
current: current:
/* same size, just replace it */ /* overflow page overwrites need special handling */
if (!F_ISSET(leaf->mn_flags, F_BIGDATA) && if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
NODEDSZ(leaf) == data->mv_size) { MDB_page *omp;
pgno_t pg;
int ovpages, dpages;
ovpages = OVPAGES(NODEDSZ(leaf), mc->mc_txn->mt_env->me_psize);
dpages = OVPAGES(data->mv_size, mc->mc_txn->mt_env->me_psize);
memcpy(&pg, NODEDATA(leaf), sizeof(pg));
mdb_page_get(mc->mc_txn, pg, &omp);
/* Is the ov page writable and large enough? */
if ((omp->mp_flags & P_DIRTY) && ovpages >= dpages) {
/* yes, overwrite it. Note in this case we don't
* bother to try shrinking the node if the new data
* is smaller than the overflow threshold.
*/
if (F_ISSET(flags, MDB_RESERVE))
data->mv_data = METADATA(omp);
else
memcpy(METADATA(omp), data->mv_data, data->mv_size);
goto done;
} else {
/* no, free ovpages */
int i;
mc->mc_db->md_overflow_pages -= ovpages;
for (i=0; i<ovpages; i++) {
DPRINTF("freed ov page %zu", pg);
mdb_midl_append(&mc->mc_txn->mt_free_pgs, pg);
pg++;
}
}
} else if (NODEDSZ(leaf) == data->mv_size) {
/* same size, just replace it. Note that we could
* also reuse this node if the new data is smaller,
* but instead we opt to shrink the node in that case.
*/
if (F_ISSET(flags, MDB_RESERVE)) if (F_ISSET(flags, MDB_RESERVE))
data->mv_data = NODEDATA(leaf); data->mv_data = NODEDATA(leaf);
else else

Loading…
Cancel
Save