mdbx: fix wrong cursor's state after a deletion.

This commit is contained in:
Leo Yuriev 2017-02-21 19:53:05 +03:00
parent 44b378b8ea
commit a034502657

24
mdbx.c
View File

@ -6060,9 +6060,8 @@ static int mdbx_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data,
return mdbx_cursor_first(mc, key, data); return mdbx_cursor_first(mc, key, data);
mp = mc->mc_pg[mc->mc_top]; mp = mc->mc_pg[mc->mc_top];
if (mc->mc_flags & C_EOF) { if (mc->mc_flags & C_EOF) {
if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mp) - 1) if (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mp))
return MDB_NOTFOUND; return MDB_NOTFOUND;
mc->mc_flags ^= C_EOF; mc->mc_flags ^= C_EOF;
} }
@ -6142,6 +6141,9 @@ static int mdbx_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data,
MDB_node *leaf; MDB_node *leaf;
int rc; int rc;
if ((mc->mc_flags & C_DEL) && op == MDB_PREV_DUP)
return MDB_NOTFOUND;
if (!(mc->mc_flags & C_INITIALIZED)) { if (!(mc->mc_flags & C_INITIALIZED)) {
rc = mdbx_cursor_last(mc, key, data); rc = mdbx_cursor_last(mc, key, data);
if (unlikely(rc)) if (unlikely(rc))
@ -6150,8 +6152,8 @@ static int mdbx_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data,
} }
mp = mc->mc_pg[mc->mc_top]; mp = mc->mc_pg[mc->mc_top];
if ((mc->mc_db->md_flags & MDB_DUPSORT) &&
if (mc->mc_db->md_flags & MDB_DUPSORT) { mc->mc_ki[mc->mc_top] < NUMKEYS(mp)) {
leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
if (op == MDB_PREV || op == MDB_PREV_DUP) { if (op == MDB_PREV || op == MDB_PREV_DUP) {
@ -6461,7 +6463,7 @@ static int mdbx_cursor_last(MDB_cursor *mc, MDB_val *key, MDB_val *data) {
if (mc->mc_xcursor) if (mc->mc_xcursor)
mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED | C_EOF); mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED | C_EOF);
if (likely(!(mc->mc_flags & C_EOF))) { if (likely((mc->mc_flags & (C_EOF | C_DEL)) != C_EOF)) {
if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) { if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) {
rc = mdbx_page_search(mc, NULL, MDB_PS_LAST); rc = mdbx_page_search(mc, NULL, MDB_PS_LAST);
if (unlikely(rc != MDB_SUCCESS)) if (unlikely(rc != MDB_SUCCESS))
@ -6517,11 +6519,12 @@ int mdbx_cursor_get(MDB_cursor *mc, MDB_val *key, MDB_val *data,
if (unlikely(!(mc->mc_flags & C_INITIALIZED))) if (unlikely(!(mc->mc_flags & C_INITIALIZED)))
return EINVAL; return EINVAL;
MDB_page *mp = mc->mc_pg[mc->mc_top]; MDB_page *mp = mc->mc_pg[mc->mc_top];
int nkeys = NUMKEYS(mp); unsigned nkeys = NUMKEYS(mp);
if (!nkeys || mc->mc_ki[mc->mc_top] >= nkeys) { if (mc->mc_ki[mc->mc_top] >= nkeys) {
mc->mc_ki[mc->mc_top] = nkeys; mc->mc_ki[mc->mc_top] = nkeys;
return MDB_NOTFOUND; return MDB_NOTFOUND;
} }
assert(nkeys > 0);
rc = MDB_SUCCESS; rc = MDB_SUCCESS;
if (IS_LEAF2(mp)) { if (IS_LEAF2(mp)) {
@ -8502,11 +8505,12 @@ static int mdbx_rebalance(MDB_cursor *mc) {
if (mc->mc_snum < 2) { if (mc->mc_snum < 2) {
MDB_page *mp = mc->mc_pg[0]; MDB_page *mp = mc->mc_pg[0];
unsigned nkeys = NUMKEYS(mp);
if (IS_SUBP(mp)) { if (IS_SUBP(mp)) {
mdbx_debug("Can't rebalance a subpage, ignoring"); mdbx_debug("Can't rebalance a subpage, ignoring");
return MDB_SUCCESS; return MDB_SUCCESS;
} }
if (NUMKEYS(mp) == 0) { if (nkeys == 0) {
mdbx_debug("tree is completely empty"); mdbx_debug("tree is completely empty");
mc->mc_db->md_root = P_INVALID; mc->mc_db->md_root = P_INVALID;
mc->mc_db->md_depth = 0; mc->mc_db->md_depth = 0;
@ -8700,8 +8704,10 @@ static int mdbx_cursor_del0(MDB_cursor *mc) {
* Other cursors adjustments were already done * Other cursors adjustments were already done
* by mdbx_rebalance and aren't needed here. * by mdbx_rebalance and aren't needed here.
*/ */
if (!mc->mc_snum) if (!mc->mc_snum) {
mc->mc_flags |= C_DEL | C_EOF;
return rc; return rc;
}
mp = mc->mc_pg[mc->mc_top]; mp = mc->mc_pg[mc->mc_top];
nkeys = NUMKEYS(mp); nkeys = NUMKEYS(mp);