ITS#7229 more mdb_page_split fixes

vmware
Howard Chu 13 years ago
parent 84acc0e803
commit 7ba25c488a
  1. 33
      libraries/libmdb/mdb.c

@ -5638,7 +5638,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
unsigned int nflags) unsigned int nflags)
{ {
unsigned int flags; unsigned int flags;
int rc = MDB_SUCCESS, ins_new = 0, new_root = 0; int rc = MDB_SUCCESS, ins_new = 0, new_root = 0, newpos = 1;
indx_t newindx; indx_t newindx;
pgno_t pgno = 0; pgno_t pgno = 0;
unsigned int i, j, split_indx, nkeys, pmax; unsigned int i, j, split_indx, nkeys, pmax;
@ -5751,15 +5751,22 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
} }
/* For leaf pages, check the split point based on what /* For leaf pages, check the split point based on what
* fits where, since otherwise add_node can fail. * fits where, since otherwise mdb_node_add can fail.
*
* This check is only needed when the data items are
* relatively large, such that being off by one will
* make the difference between success or failure.
* When the size of the data items is much smaller than
* one-half of a page, this check is irrelevant.
*/ */
if (IS_LEAF(mp)) { if (IS_LEAF(mp) && nkeys < 4) {
unsigned int psize, nsize; unsigned int psize, nsize;
/* Maximum free space in an empty page */ /* Maximum free space in an empty page */
pmax = mc->mc_txn->mt_env->me_psize - PAGEHDRSZ; pmax = mc->mc_txn->mt_env->me_psize - PAGEHDRSZ;
nsize = mdb_leaf_size(mc->mc_txn->mt_env, newkey, newdata); nsize = mdb_leaf_size(mc->mc_txn->mt_env, newkey, newdata);
if (newindx < split_indx) { if (newindx <= split_indx) {
psize = nsize; psize = nsize;
newpos = 0;
for (i=0; i<split_indx; i++) { for (i=0; i<split_indx; i++) {
node = NODEPTR(mp, i); node = NODEPTR(mp, i);
psize += NODESIZE + NODEKSZ(node) + sizeof(indx_t); psize += NODESIZE + NODEKSZ(node) + sizeof(indx_t);
@ -5769,6 +5776,9 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
psize += NODEDSZ(node); psize += NODEDSZ(node);
psize += psize & 1; psize += psize & 1;
if (psize > pmax) { if (psize > pmax) {
if (i == split_indx - 1 && newindx == split_indx)
newpos = 1;
else
split_indx = i; split_indx = i;
break; break;
} }
@ -5792,8 +5802,11 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
} }
/* First find the separating key between the split pages. /* First find the separating key between the split pages.
* The case where newindx == split_indx is ambiguous; the
* new item could go to the new page or stay on the original
* page. If newpos == 1 it goes to the new page.
*/ */
if (newindx == split_indx) { if (newindx == split_indx && newpos) {
sepkey.mv_size = newkey->mv_size; sepkey.mv_size = newkey->mv_size;
sepkey.mv_data = newkey->mv_data; sepkey.mv_data = newkey->mv_data;
} else { } else {
@ -5856,9 +5869,11 @@ newsep:
if (i == split_indx) { if (i == split_indx) {
/* Insert in right sibling. */ /* Insert in right sibling. */
/* Reset insert index for right sibling. */ /* Reset insert index for right sibling. */
j = (i == newindx && ins_new); if (i != newindx || (newpos ^ ins_new)) {
j = 0;
mc->mc_pg[mc->mc_top] = rp; mc->mc_pg[mc->mc_top] = rp;
} }
}
if (i == newindx && !ins_new) { if (i == newindx && !ins_new) {
/* Insert the original entry that caused the split. */ /* Insert the original entry that caused the split. */
@ -5872,9 +5887,7 @@ newsep:
ins_new = 1; ins_new = 1;
/* Update page and index for the new key. */ /* Update index for the new key. */
if (!newindx)
mc->mc_pg[mc->mc_top] = copy;
mc->mc_ki[mc->mc_top] = j; mc->mc_ki[mc->mc_top] = j;
} else if (i == nkeys) { } else if (i == nkeys) {
break; break;
@ -5910,7 +5923,7 @@ newsep:
mc->mc_txn->mt_env->me_psize - copy->mp_upper); mc->mc_txn->mt_env->me_psize - copy->mp_upper);
/* reset back to original page */ /* reset back to original page */
if (!newindx || (newindx < split_indx)) { if (newindx < split_indx || (!newpos && newindx == split_indx)) {
mc->mc_pg[mc->mc_top] = mp; mc->mc_pg[mc->mc_top] = mp;
if (nflags & MDB_RESERVE) { if (nflags & MDB_RESERVE) {
node = NODEPTR(mp, mc->mc_ki[mc->mc_top]); node = NODEPTR(mp, mc->mc_ki[mc->mc_top]);

Loading…
Cancel
Save