mdbx: simplify & fix mdbx_txn_keep() and mdbx_cursor_keep().

1 of 2 fixes for https://github.com/erthink/libmdbx/issues/195
This commit is contained in:
Leonid Yuriev 2021-05-20 12:29:59 +03:00
parent 84b699a47c
commit bc6a690733

View File

@ -4976,58 +4976,33 @@ static int spill_page(MDBX_txn *txn, struct mdbx_iov_ctx *ctx, MDBX_page *dp,
* Returns the number of pages marked as unspillable. */
static unsigned mdbx_cursor_keep(MDBX_txn *txn, MDBX_cursor *mc) {
unsigned keep = 0;
if (!(mc->mc_flags & C_INITIALIZED))
return keep;
loop:;
const MDBX_page *mp = NULL;
for (unsigned i = 0; i < mc->mc_snum; i++) {
mp = mc->mc_pg[i];
if (IS_MODIFIABLE(txn, mp)) {
unsigned const n = mdbx_dpl_search(txn, mp->mp_pgno);
if (txn->tw.dirtylist->items[n].pgno == mp->mp_pgno &&
txn->tw.dirtylist->items[n].lru != txn->tw.dirtylru) {
txn->tw.dirtylist->items[n].lru = txn->tw.dirtylru;
keep++;
while (mc->mc_flags & C_INITIALIZED) {
for (unsigned i = 0; i < mc->mc_snum; i++) {
const MDBX_page *mp = mc->mc_pg[i];
if (IS_MODIFIABLE(txn, mp) && !IS_SUBP(mp)) {
unsigned const n = mdbx_dpl_search(txn, mp->mp_pgno);
if (txn->tw.dirtylist->items[n].pgno == mp->mp_pgno &&
txn->tw.dirtylist->items[n].lru != txn->tw.dirtylru) {
txn->tw.dirtylist->items[n].lru = txn->tw.dirtylru;
keep++;
}
}
}
}
if (!(mp && IS_LEAF(mp)))
return keep;
/* Proceed to mx if it is at a sub-database */
MDBX_xcursor *mx = mc->mc_xcursor;
if (!(mx && (mx->mx_cursor.mc_flags & C_INITIALIZED)))
return keep;
const unsigned nkeys = page_numkeys(mp);
unsigned ki = mc->mc_ki[mc->mc_top];
mdbx_cassert(mc, nkeys > 0 &&
(ki < nkeys ||
(ki == nkeys && (mx->mx_cursor.mc_flags & C_EOF))));
ki -= ki >= nkeys;
if ((node_flags(page_node(mp, ki)) & F_SUBDATA)) {
mc = &mx->mx_cursor;
goto loop;
if (!mc->mc_xcursor)
break;
mc = &mc->mc_xcursor->mx_cursor;
}
return keep;
}
static unsigned mdbx_txn_keep(MDBX_txn *txn, MDBX_cursor *m0) {
unsigned keep = m0 ? mdbx_cursor_keep(txn, m0) : 0;
for (unsigned i = FREE_DBI; i < txn->mt_numdbs; ++i) {
const pgno_t pgno = txn->mt_dbs[i].md_root;
if ((txn->mt_dbistate[i] & DBI_DIRTY) && pgno != P_INVALID) {
unsigned const n = mdbx_dpl_search(txn, pgno);
if (likely(txn->tw.dirtylist->items[n].pgno == pgno)) {
txn->tw.dirtylist->items[n].lru = txn->tw.dirtylru;
for (MDBX_cursor *mc = txn->tw.cursors[i]; mc; mc = mc->mc_next)
if (mc != m0)
keep += mdbx_cursor_keep(txn, mc);
}
}
}
for (unsigned i = FREE_DBI; i < txn->mt_numdbs; ++i)
if (F_ISSET(txn->mt_dbistate[i], DBI_DIRTY | DBI_VALID) &&
txn->mt_dbs[i].md_root != P_INVALID)
for (MDBX_cursor *mc = txn->tw.cursors[i]; mc; mc = mc->mc_next)
if (mc != m0)
keep += mdbx_cursor_keep(txn, mc);
return keep;
}