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;
} /* 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;