ITS#7515 Fix mdb_txn_commit(nested txn with spills).

Catch malloc error.
Fix hunt for dirty vs spilled pages: Don't leave x at a deleted pageno.
Cleanup: Factor out variables, squash pages already marked for deletion.
vmware
Hallvard Furuseth 11 years ago
parent bc48a40621
commit a3b3482854
  1. 54
      libraries/liblmdb/mdb.c

@ -2779,14 +2779,18 @@ mdb_txn_commit(MDB_txn *txn)
if (txn->mt_parent) { if (txn->mt_parent) {
MDB_txn *parent = txn->mt_parent; MDB_txn *parent = txn->mt_parent;
unsigned x, y, len;
MDB_ID2L dst, src; MDB_ID2L dst, src;
MDB_IDL pspill;
unsigned x, y, len, ps_len;
/* Append our free list to parent's */ /* Append our free list to parent's */
rc = mdb_midl_append_list(&parent->mt_free_pgs, txn->mt_free_pgs); rc = mdb_midl_append_list(&parent->mt_free_pgs, txn->mt_free_pgs);
if (rc) if (rc)
goto fail; goto fail;
mdb_midl_free(txn->mt_free_pgs); mdb_midl_free(txn->mt_free_pgs);
/* Failures after this must either undo the changes
* to the parent or set MDB_TXN_ERROR in the parent.
*/
parent->mt_next_pgno = txn->mt_next_pgno; parent->mt_next_pgno = txn->mt_next_pgno;
parent->mt_flags = txn->mt_flags; parent->mt_flags = txn->mt_flags;
@ -2808,37 +2812,26 @@ mdb_txn_commit(MDB_txn *txn)
dst = parent->mt_u.dirty_list; dst = parent->mt_u.dirty_list;
src = txn->mt_u.dirty_list; src = txn->mt_u.dirty_list;
/* Remove anything in our dirty list from parent's spill list */ /* Remove anything in our dirty list from parent's spill list */
if (parent->mt_spill_pgs) { if ((pspill = parent->mt_spill_pgs) && (ps_len = pspill[0])) {
x = parent->mt_spill_pgs[0]; x = y = ps_len;
len = x; pspill[0] = (pgno_t)-1;
/* zero out our dirty pages in parent spill list */ /* Mark our dirty pages as deleted in parent spill list */
for (i=1; i<=src[0].mid; i++) { for (i=0, len=src[0].mid; ++i <= len; ) {
MDB_ID pn = src[i].mid << 1; MDB_ID pn = src[i].mid << 1;
if (pn < parent->mt_spill_pgs[x]) while (pn > pspill[x])
continue;
if (pn > parent->mt_spill_pgs[x]) {
if (x <= 1)
break;
x--; x--;
continue; if (pn == pspill[x]) {
} pspill[x] = 1;
parent->mt_spill_pgs[x] = 0; y = --x;
len--;
} }
/* OK, we had a few hits, squash zeros from the spill list */
if (len < parent->mt_spill_pgs[0]) {
x=1;
for (y=1; y<=parent->mt_spill_pgs[0]; y++) {
if (parent->mt_spill_pgs[y]) {
if (y != x) {
parent->mt_spill_pgs[x] = parent->mt_spill_pgs[y];
}
x++;
}
}
parent->mt_spill_pgs[0] = len;
} }
/* Squash deleted pagenums if we deleted any */
for (x=y; ++x <= ps_len; )
if (!(pspill[x] & 1))
pspill[++y] = pspill[x];
pspill[0] = y;
} }
/* Find len = length of merging our dirty list with parent's */ /* Find len = length of merging our dirty list with parent's */
x = dst[0].mid; x = dst[0].mid;
dst[0].mid = 0; /* simplify loops */ dst[0].mid = 0; /* simplify loops */
@ -2872,7 +2865,10 @@ mdb_txn_commit(MDB_txn *txn)
parent->mt_dirty_room = txn->mt_dirty_room; parent->mt_dirty_room = txn->mt_dirty_room;
if (txn->mt_spill_pgs) { if (txn->mt_spill_pgs) {
if (parent->mt_spill_pgs) { if (parent->mt_spill_pgs) {
mdb_midl_append_list(&parent->mt_spill_pgs, txn->mt_spill_pgs); /* TODO: Prevent failure here, so parent does not fail */
rc = mdb_midl_append_list(&parent->mt_spill_pgs, txn->mt_spill_pgs);
if (rc)
parent->mt_flags |= MDB_TXN_ERROR;
mdb_midl_free(txn->mt_spill_pgs); mdb_midl_free(txn->mt_spill_pgs);
mdb_midl_sort(parent->mt_spill_pgs); mdb_midl_sort(parent->mt_spill_pgs);
} else { } else {
@ -2883,7 +2879,7 @@ mdb_txn_commit(MDB_txn *txn)
parent->mt_child = NULL; parent->mt_child = NULL;
mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead); mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead);
free(txn); free(txn);
return MDB_SUCCESS; return rc;
} }
if (txn != env->me_txn) { if (txn != env->me_txn) {

Loading…
Cancel
Save