*/
MDB_IDL mt_free_pgs;
/** The sorted list of dirty pages we temporarily wrote to disk
- * because the dirty list was full.
+ * because the dirty list was full. page numbers in here are
+ * shifted left by 1, deleted slots have the LSB set.
*/
MDB_IDL mt_spill_pgs;
union {
if (!txn->mt_spill_pgs)
return ENOMEM;
} else {
- /* strip any dups */
+ /* purge deleted slots */
MDB_IDL sl = txn->mt_spill_pgs;
unsigned int num = sl[0];
- j=1;
+ j=0;
for (i=1; i<=num; i++) {
- if (sl[j] != sl[i])
+ if (!(sl[i] & 1))
sl[++j] = sl[i];
}
sl[0] = j;
/* Save the page IDs of all the pages we're flushing */
/* flush from the tail forward, this saves a lot of shifting later on. */
for (i=dl[0].mid; i && need; i--) {
+ MDB_ID pn = dl[i].mid << 1;
dp = dl[i].mptr;
if (dp->mp_flags & P_KEEP)
continue;
MDB_txn *tx2;
for (tx2 = txn->mt_parent; tx2; tx2 = tx2->mt_parent) {
if (tx2->mt_spill_pgs) {
- j = mdb_midl_search(tx2->mt_spill_pgs, dl[i].mid);
- if (j <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[j] == dl[i].mid) {
+ j = mdb_midl_search(tx2->mt_spill_pgs, pn);
+ if (j <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[j] == pn) {
dp->mp_flags |= P_KEEP;
break;
}
if (tx2)
continue;
}
- if ((rc = mdb_midl_append(&txn->mt_spill_pgs, dl[i].mid)))
+ if ((rc = mdb_midl_append(&txn->mt_spill_pgs, pn)))
goto done;
need--;
}
MDB_env *env = tx0->mt_env;
MDB_txn *txn;
unsigned x;
- pgno_t pgno = mp->mp_pgno;
+ pgno_t pgno = mp->mp_pgno, pn = pgno << 1;
for (txn = tx0; txn; txn=txn->mt_parent) {
if (!txn->mt_spill_pgs)
continue;
- x = mdb_midl_search(txn->mt_spill_pgs, pgno);
- if (x <= txn->mt_spill_pgs[0] && txn->mt_spill_pgs[x] == pgno) {
+ x = mdb_midl_search(txn->mt_spill_pgs, pn);
+ if (x <= txn->mt_spill_pgs[0] && txn->mt_spill_pgs[x] == pn) {
MDB_page *np;
int num;
if (IS_OVERFLOW(mp))
if (txn == tx0) {
/* If in current txn, this page is no longer spilled.
* If it happens to be the last page, truncate the spill list.
- * Otherwise temporarily dup its neighbor over it. Dups will
- * be stripped out later by the next mdb_page_spill run.
+ * Otherwise mark it as deleted by setting the LSB.
*/
if (x == txn->mt_spill_pgs[0])
txn->mt_spill_pgs[0]--;
else
- txn->mt_spill_pgs[x] = txn->mt_spill_pgs[x+1];
+ txn->mt_spill_pgs[x] |= 1;
} /* otherwise, if belonging to a parent txn, the
* page remains spilled until child commits
*/
len = x;
/* zero out our dirty pages in parent spill list */
for (i=1; i<=src[0].mid; i++) {
- if (src[i].mid < parent->mt_spill_pgs[x])
+ MDB_ID pn = src[i].mid << 1;
+ if (pn < parent->mt_spill_pgs[x])
continue;
- if (src[i].mid > parent->mt_spill_pgs[x]) {
+ if (pn > parent->mt_spill_pgs[x]) {
if (x <= 1)
break;
x--;
* leave that unless page_touch happens again).
*/
if (tx2->mt_spill_pgs) {
- x = mdb_midl_search(tx2->mt_spill_pgs, pgno);
- if (x <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[x] == pgno) {
+ MDB_ID pn = pgno << 1;
+ x = mdb_midl_search(tx2->mt_spill_pgs, pn);
+ if (x <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[x] == pn) {
p = (MDB_page *)(env->me_map + env->me_psize * pgno);
goto done;
}
unsigned x = 0, ovpages = mp->mp_pages;
MDB_env *env = txn->mt_env;
MDB_IDL sl = txn->mt_spill_pgs;
+ MDB_ID pn = pg << 1;
int rc;
DPRINTF(("free ov page %"Z"u (%d)", pg, ovpages));
if (env->me_pghead &&
!txn->mt_parent &&
((mp->mp_flags & P_DIRTY) ||
- (sl && (x = mdb_midl_search(sl, pg)) <= sl[0] && sl[x] == pg)))
+ (sl && (x = mdb_midl_search(sl, pn)) <= sl[0] && sl[x] == pn)))
{
unsigned i, j;
pgno_t *mop;
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]--;
+ if (x == sl[0])
+ sl[0]--;
+ else
+ sl[x] |= 1;
goto release;
}
/* Remove from dirty list */