From 501eac2fc48899aa7f3971666eaef1eb9e2f387c Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sun, 14 Jul 2013 16:53:04 -0700 Subject: [PATCH] Fix child txn dirty_room counts in spill/unspill Don't count pages twice if they're already accounted in an ancestor txn. --- libraries/liblmdb/mdb.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 102bd77..2f99773 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1478,7 +1478,26 @@ mdb_page_spill(MDB_cursor *m0, MDB_val *key, MDB_val *data) mdb_cursorpages_mark(m0, P_DIRTY|P_KEEP); if (rc == 0) { - txn->mt_dirty_room = MDB_IDL_UM_MAX - dl[0].mid; + if (txn->mt_parent) { + MDB_txn *tx2; + pgno_t pgno = dl[i].mid; + txn->mt_dirty_room = txn->mt_parent->mt_dirty_room - dl[0].mid; + /* dirty pages that are dirty in an ancestor don't + * count against this txn's dirty_room. + */ + for (i=1; i<=dl[0].mid; i++) { + for (tx2 = txn->mt_parent; tx2; tx2 = tx2->mt_parent) { + j = mdb_mid2l_search(tx2->mt_u.dirty_list, pgno); + if (j <= tx2->mt_u.dirty_list[0].mid && + tx2->mt_u.dirty_list[j].mid == pgno) { + txn->mt_dirty_room++; + break; + } + } + } + } else { + txn->mt_dirty_room = MDB_IDL_UM_MAX - dl[0].mid; + } txn->mt_flags |= MDB_TXN_SPILLS; } return rc; @@ -1743,6 +1762,22 @@ mdb_page_unspill(MDB_txn *tx0, MDB_page *mp, MDB_page **ret) } /* otherwise, if belonging to a parent txn, the * page remains spilled until child commits */ + + if (txn->mt_parent) { + MDB_txn *tx2; + /* If this page is also in a parent's dirty list, then + * it's already accounted in dirty_room, and we need to + * cancel out the decrement that mdb_page_dirty does. + */ + for (tx2 = txn->mt_parent; tx2; tx2 = tx2->mt_parent) { + x = mdb_mid2l_search(tx2->mt_u.dirty_list, pgno); + if (x <= tx2->mt_u.dirty_list[0].mid && + tx2->mt_u.dirty_list[x].mid == pgno) { + txn->mt_dirty_room++; + break; + } + } + } mdb_page_dirty(tx0, np); np->mp_flags |= P_DIRTY; *ret = np; -- 2.7.4