ITS#7515 Fix mt_dirty_room in nested txns.

Fix description & code: Also ignore dirty pages hidden by
spilled pages, as they won't merge into our dirty_list.
Update it in mdb_page_flush() instead of mdb_page_spill().
vmware
Hallvard Furuseth 11 years ago
parent cfe262dce9
commit bc48a40621
  1. 57
      libraries/liblmdb/mdb.c

@ -892,7 +892,11 @@ struct MDB_txn {
#define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */ #define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */
/** @} */ /** @} */
unsigned int mt_flags; /**< @ref mdb_txn */ unsigned int mt_flags; /**< @ref mdb_txn */
/** dirty_list maxsize - # of allocated pages allowed, including in parent txns */ /** dirty_list room: Array size - #dirty pages visible to this txn.
* Includes ancestor txns' dirty pages not hidden by other txns'
* dirty/spilled pages. Thus commit(nested txn) has room to merge
* dirty_list into mt_parent after freeing hidden mt_parent pages.
*/
unsigned int mt_dirty_room; unsigned int mt_dirty_room;
/** Tracks which of the two meta pages was used at the start /** Tracks which of the two meta pages was used at the start
* of this transaction. * of this transaction.
@ -1560,31 +1564,7 @@ mdb_page_spill(MDB_cursor *m0, MDB_val *key, MDB_val *data)
rc = mdb_pages_xkeep(m0, P_DIRTY|P_KEEP, i); rc = mdb_pages_xkeep(m0, P_DIRTY|P_KEEP, i);
done: done:
if (rc == 0) { txn->mt_flags |= rc ? MDB_TXN_ERROR : MDB_TXN_SPILLS;
if (txn->mt_parent) {
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++) {
pgno_t pgno = dl[i].mid;
MDB_txn *tx2;
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;
} else {
txn->mt_flags |= MDB_TXN_ERROR;
}
return rc; return rc;
} }
@ -1829,6 +1809,8 @@ mdb_page_unspill(MDB_txn *tx0, MDB_page *mp, MDB_page **ret)
if (x <= txn->mt_spill_pgs[0] && txn->mt_spill_pgs[x] == pn) { if (x <= txn->mt_spill_pgs[0] && txn->mt_spill_pgs[x] == pn) {
MDB_page *np; MDB_page *np;
int num; int num;
if (txn->mt_dirty_room == 0)
return MDB_TXN_FULL;
if (IS_OVERFLOW(mp)) if (IS_OVERFLOW(mp))
num = mp->mp_pages; num = mp->mp_pages;
else else
@ -1857,21 +1839,6 @@ mdb_page_unspill(MDB_txn *tx0, MDB_page *mp, MDB_page **ret)
* page remains spilled until child commits * 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) {
tx0->mt_dirty_room++;
break;
}
}
}
mdb_page_dirty(tx0, np); mdb_page_dirty(tx0, np);
np->mp_flags |= P_DIRTY; np->mp_flags |= P_DIRTY;
*ret = np; *ret = np;
@ -2674,8 +2641,7 @@ mdb_page_flush(MDB_txn *txn, int keep)
} }
dp->mp_flags &= ~P_DIRTY; dp->mp_flags &= ~P_DIRTY;
} }
dl[0].mid = j; goto done;
return MDB_SUCCESS;
} }
/* Write the pages */ /* Write the pages */
@ -2769,8 +2735,11 @@ mdb_page_flush(MDB_txn *txn, int keep)
} }
mdb_dpage_free(env, dp); mdb_dpage_free(env, dp);
} }
dl[0].mid = j;
done:
i--;
txn->mt_dirty_room += i - j;
dl[0].mid = j;
return MDB_SUCCESS; return MDB_SUCCESS;
} }

Loading…
Cancel
Save