Fix mdb_ovpage_free() vs. spill.

Ensure me_pghead has room before removing from spill/dirty list.
Don't return pages to me_pghead in nested txns, use mt_free_pgs.
vmware
Hallvard Furuseth 11 years ago
parent c3547e81f3
commit 2bd5d8102e
  1. 33
      libraries/liblmdb/mdb.c

@ -4703,33 +4703,38 @@ mdb_ovpage_free(MDB_cursor *mc, MDB_page *mp)
{ {
MDB_txn *txn = mc->mc_txn; MDB_txn *txn = mc->mc_txn;
pgno_t pg = mp->mp_pgno; pgno_t pg = mp->mp_pgno;
unsigned i, ovpages = mp->mp_pages; unsigned x = 0, ovpages = mp->mp_pages;
MDB_env *env = txn->mt_env; MDB_env *env = txn->mt_env;
MDB_IDL sl = txn->mt_spill_pgs;
int rc; int rc;
DPRINTF("free ov page %"Z"u (%d)", pg, ovpages); DPRINTF("free ov page %"Z"u (%d)", pg, ovpages);
/* If the page is dirty or on the spill list we just acquired it, /* If the page is dirty or on the spill list we just acquired it,
* so we should give it back to our current free list, if any. * so we should give it back to our current free list, if any.
* Not currently supported in nested txns.
* Otherwise put it onto the list of pages we freed in this txn. * Otherwise put it onto the list of pages we freed in this txn.
*
* Won't create me_pghead: me_pglast must be inited along with it.
* Unsupported in nested txns: They would need to hide the page
* range in ancestor txns' dirty and spilled lists.
*/ */
if (!(mp->mp_flags & P_DIRTY) && txn->mt_spill_pgs) { if (env->me_pghead &&
unsigned x = mdb_midl_search(txn->mt_spill_pgs, pg); !txn->mt_parent &&
if (x <= txn->mt_spill_pgs[0] && txn->mt_spill_pgs[x] == pg) { ((mp->mp_flags & P_DIRTY) ||
/* This page is no longer spilled */ (sl && (x = mdb_midl_search(sl, pg)) <= sl[0] && sl[x] == pg)))
for (; x < txn->mt_spill_pgs[0]; x++) {
txn->mt_spill_pgs[x] = txn->mt_spill_pgs[x+1]; unsigned i, j;
txn->mt_spill_pgs[0]--;
goto release;
}
}
if ((mp->mp_flags & P_DIRTY) && !txn->mt_parent && env->me_pghead) {
unsigned j, x;
pgno_t *mop; pgno_t *mop;
MDB_ID2 *dl, ix, iy; MDB_ID2 *dl, ix, iy;
rc = mdb_midl_need(&env->me_pghead, ovpages); rc = mdb_midl_need(&env->me_pghead, ovpages);
if (rc) if (rc)
return rc; return rc;
if (!(mp->mp_flags & P_DIRTY)) {
/* This page is no longer spilled */
for (; x < sl[0]; x++)
sl[x] = sl[x+1];
sl[0]--;
goto release;
}
/* Remove from dirty list */ /* Remove from dirty list */
dl = txn->mt_u.dirty_list; dl = txn->mt_u.dirty_list;
x = dl[0].mid--; x = dl[0].mid--;

Loading…
Cancel
Save