|
|
@ -354,8 +354,10 @@ struct MDB_cursor { |
|
|
|
MDB_ppage mc_stack[CURSOR_STACK]; /* stack of parent pages */ |
|
|
|
MDB_ppage mc_stack[CURSOR_STACK]; /* stack of parent pages */ |
|
|
|
unsigned int mc_snum; /* number of pushed pages */ |
|
|
|
unsigned int mc_snum; /* number of pushed pages */ |
|
|
|
MDB_dbi mc_dbi; |
|
|
|
MDB_dbi mc_dbi; |
|
|
|
short mc_initialized; /* 1 if initialized */ |
|
|
|
unsigned int mc_flags; |
|
|
|
short mc_eof; /* 1 if end is reached */ |
|
|
|
#define C_INITIALIZED 0x01 |
|
|
|
|
|
|
|
#define C_EOF 0x02 |
|
|
|
|
|
|
|
#define C_XDIRTY 0x04 |
|
|
|
struct MDB_xcursor *mc_xcursor; |
|
|
|
struct MDB_xcursor *mc_xcursor; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -519,7 +521,7 @@ static int mdb_cursor_last(MDB_cursor *cursor, |
|
|
|
static void mdb_xcursor_init0(MDB_cursor *mc); |
|
|
|
static void mdb_xcursor_init0(MDB_cursor *mc); |
|
|
|
static void mdb_xcursor_init1(MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx, |
|
|
|
static void mdb_xcursor_init1(MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx, |
|
|
|
MDB_page *mp, MDB_node *node); |
|
|
|
MDB_page *mp, MDB_node *node); |
|
|
|
static void mdb_xcursor_fini(MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx); |
|
|
|
static void mdb_xcursor_fini(MDB_cursor *mc); |
|
|
|
|
|
|
|
|
|
|
|
static size_t mdb_leaf_size(MDB_env *env, MDB_val *key, |
|
|
|
static size_t mdb_leaf_size(MDB_env *env, MDB_val *key, |
|
|
|
MDB_val *data); |
|
|
|
MDB_val *data); |
|
|
@ -659,13 +661,18 @@ mdb_alloc_page(MDB_txn *txn, MDB_dbi dbi, MDB_page *parent, unsigned int parent_ |
|
|
|
if (!txn->mt_env->me_pghead && dbi != FREE_DBI && |
|
|
|
if (!txn->mt_env->me_pghead && dbi != FREE_DBI && |
|
|
|
txn->mt_dbs[FREE_DBI].md_root != P_INVALID) { |
|
|
|
txn->mt_dbs[FREE_DBI].md_root != P_INVALID) { |
|
|
|
/* See if there's anything in the free DB */ |
|
|
|
/* See if there's anything in the free DB */ |
|
|
|
|
|
|
|
MDB_cursor mc; |
|
|
|
MDB_pageparent mpp; |
|
|
|
MDB_pageparent mpp; |
|
|
|
MDB_node *leaf; |
|
|
|
MDB_node *leaf; |
|
|
|
ULONG *kptr, oldest; |
|
|
|
ULONG *kptr, oldest; |
|
|
|
|
|
|
|
|
|
|
|
mpp.mp_parent = NULL; |
|
|
|
mpp.mp_parent = NULL; |
|
|
|
mpp.mp_pi = 0; |
|
|
|
mpp.mp_pi = 0; |
|
|
|
mdb_search_page(txn, FREE_DBI, NULL, NULL, 0, &mpp); |
|
|
|
mc.mc_txn = txn; |
|
|
|
|
|
|
|
mc.mc_dbi = dbi; |
|
|
|
|
|
|
|
mc.mc_snum = 0; |
|
|
|
|
|
|
|
mc.mc_flags = 0; |
|
|
|
|
|
|
|
mdb_search_page(txn, FREE_DBI, NULL, &mc, 0, &mpp); |
|
|
|
leaf = NODEPTR(mpp.mp_page, 0); |
|
|
|
leaf = NODEPTR(mpp.mp_page, 0); |
|
|
|
kptr = (ULONG *)NODEKEY(leaf); |
|
|
|
kptr = (ULONG *)NODEKEY(leaf); |
|
|
|
|
|
|
|
|
|
|
@ -683,6 +690,7 @@ mdb_alloc_page(MDB_txn *txn, MDB_dbi dbi, MDB_page *parent, unsigned int parent_ |
|
|
|
/* It's usable, grab it.
|
|
|
|
/* It's usable, grab it.
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
MDB_oldpages *mop; |
|
|
|
MDB_oldpages *mop; |
|
|
|
|
|
|
|
MDB_ppage *top; |
|
|
|
MDB_val data; |
|
|
|
MDB_val data; |
|
|
|
pgno_t *idl; |
|
|
|
pgno_t *idl; |
|
|
|
|
|
|
|
|
|
|
@ -705,11 +713,10 @@ mdb_alloc_page(MDB_txn *txn, MDB_dbi dbi, MDB_page *parent, unsigned int parent_ |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
/* drop this IDL from the DB */ |
|
|
|
/* drop this IDL from the DB */ |
|
|
|
mpp.mp_parent = NULL; |
|
|
|
top = CURSOR_TOP(&mc); |
|
|
|
mpp.mp_pi = 0; |
|
|
|
top->mp_ki = 0; |
|
|
|
mdb_search_page(txn, FREE_DBI, NULL, NULL, 1, &mpp); |
|
|
|
mc.mc_flags = C_INITIALIZED; |
|
|
|
leaf = NODEPTR(mpp.mp_page, 0); |
|
|
|
mdb_cursor_del(&mc, 0); |
|
|
|
mdb_del0(txn, FREE_DBI, 0, &mpp, leaf); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (txn->mt_env->me_pghead) { |
|
|
|
if (txn->mt_env->me_pghead) { |
|
|
@ -2268,7 +2275,7 @@ mdb_get(MDB_txn *txn, MDB_dbi dbi, |
|
|
|
|
|
|
|
|
|
|
|
mc.mc_txn = txn; |
|
|
|
mc.mc_txn = txn; |
|
|
|
mc.mc_dbi = dbi; |
|
|
|
mc.mc_dbi = dbi; |
|
|
|
mc.mc_initialized = 0; |
|
|
|
mc.mc_flags = 0; |
|
|
|
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { |
|
|
|
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { |
|
|
|
mc.mc_xcursor = &mx; |
|
|
|
mc.mc_xcursor = &mx; |
|
|
|
mdb_xcursor_init0(&mc); |
|
|
|
mdb_xcursor_init0(&mc); |
|
|
@ -2333,11 +2340,11 @@ mdb_cursor_next(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op o |
|
|
|
MDB_node *leaf; |
|
|
|
MDB_node *leaf; |
|
|
|
int rc; |
|
|
|
int rc; |
|
|
|
|
|
|
|
|
|
|
|
if (cursor->mc_eof) { |
|
|
|
if (cursor->mc_flags & C_EOF) { |
|
|
|
return MDB_NOTFOUND; |
|
|
|
return MDB_NOTFOUND; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
assert(cursor->mc_initialized); |
|
|
|
assert(cursor->mc_flags & C_INITIALIZED); |
|
|
|
|
|
|
|
|
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
mp = top->mp_page; |
|
|
|
mp = top->mp_page; |
|
|
@ -2351,7 +2358,7 @@ mdb_cursor_next(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op o |
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
cursor->mc_xcursor->mx_cursor.mc_initialized = 0; |
|
|
|
cursor->mc_xcursor->mx_cursor.mc_flags = 0; |
|
|
|
if (op == MDB_NEXT_DUP) |
|
|
|
if (op == MDB_NEXT_DUP) |
|
|
|
return MDB_NOTFOUND; |
|
|
|
return MDB_NOTFOUND; |
|
|
|
} |
|
|
|
} |
|
|
@ -2362,7 +2369,7 @@ mdb_cursor_next(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op o |
|
|
|
if (top->mp_ki + 1 >= NUMKEYS(mp)) { |
|
|
|
if (top->mp_ki + 1 >= NUMKEYS(mp)) { |
|
|
|
DPUTS("=====> move to next sibling page"); |
|
|
|
DPUTS("=====> move to next sibling page"); |
|
|
|
if (mdb_sibling(cursor, 1) != MDB_SUCCESS) { |
|
|
|
if (mdb_sibling(cursor, 1) != MDB_SUCCESS) { |
|
|
|
cursor->mc_eof = 1; |
|
|
|
cursor->mc_flags |= C_EOF; |
|
|
|
return MDB_NOTFOUND; |
|
|
|
return MDB_NOTFOUND; |
|
|
|
} |
|
|
|
} |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
@ -2409,7 +2416,7 @@ mdb_cursor_prev(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op o |
|
|
|
MDB_node *leaf; |
|
|
|
MDB_node *leaf; |
|
|
|
int rc; |
|
|
|
int rc; |
|
|
|
|
|
|
|
|
|
|
|
assert(cursor->mc_initialized); |
|
|
|
assert(cursor->mc_flags & C_INITIALIZED); |
|
|
|
|
|
|
|
|
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
mp = top->mp_page; |
|
|
|
mp = top->mp_page; |
|
|
@ -2422,7 +2429,7 @@ mdb_cursor_prev(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op o |
|
|
|
if (op != MDB_PREV || rc == MDB_SUCCESS) |
|
|
|
if (op != MDB_PREV || rc == MDB_SUCCESS) |
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
cursor->mc_xcursor->mx_cursor.mc_initialized = 0; |
|
|
|
cursor->mc_xcursor->mx_cursor.mc_flags = 0; |
|
|
|
if (op == MDB_PREV_DUP) |
|
|
|
if (op == MDB_PREV_DUP) |
|
|
|
return MDB_NOTFOUND; |
|
|
|
return MDB_NOTFOUND; |
|
|
|
} |
|
|
|
} |
|
|
@ -2434,7 +2441,7 @@ mdb_cursor_prev(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op o |
|
|
|
if (top->mp_ki == 0) { |
|
|
|
if (top->mp_ki == 0) { |
|
|
|
DPUTS("=====> move to prev sibling page"); |
|
|
|
DPUTS("=====> move to prev sibling page"); |
|
|
|
if (mdb_sibling(cursor, 0) != MDB_SUCCESS) { |
|
|
|
if (mdb_sibling(cursor, 0) != MDB_SUCCESS) { |
|
|
|
cursor->mc_initialized = 0; |
|
|
|
cursor->mc_flags &= ~C_INITIALIZED; |
|
|
|
return MDB_NOTFOUND; |
|
|
|
return MDB_NOTFOUND; |
|
|
|
} |
|
|
|
} |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
@ -2444,7 +2451,7 @@ mdb_cursor_prev(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op o |
|
|
|
} else |
|
|
|
} else |
|
|
|
top->mp_ki--; |
|
|
|
top->mp_ki--; |
|
|
|
|
|
|
|
|
|
|
|
cursor->mc_eof = 0; |
|
|
|
cursor->mc_flags &= ~C_EOF; |
|
|
|
|
|
|
|
|
|
|
|
DPRINTF("==> cursor points to page %lu with %u keys, key index %u", |
|
|
|
DPRINTF("==> cursor points to page %lu with %u keys, key index %u", |
|
|
|
mp->mp_pgno, NUMKEYS(mp), top->mp_ki); |
|
|
|
mp->mp_pgno, NUMKEYS(mp), top->mp_ki); |
|
|
@ -2491,7 +2498,7 @@ mdb_cursor_set(MDB_cursor *cursor, MDB_val *key, MDB_val *data, |
|
|
|
assert(key->mv_size > 0); |
|
|
|
assert(key->mv_size > 0); |
|
|
|
|
|
|
|
|
|
|
|
/* See if we're already on the right page */ |
|
|
|
/* See if we're already on the right page */ |
|
|
|
if (cursor->mc_initialized) { |
|
|
|
if (cursor->mc_flags & C_INITIALIZED) { |
|
|
|
MDB_val nodekey; |
|
|
|
MDB_val nodekey; |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
/* Don't try this for LEAF2 pages. Maybe support that later. */ |
|
|
|
/* Don't try this for LEAF2 pages. Maybe support that later. */ |
|
|
@ -2539,8 +2546,8 @@ set2: |
|
|
|
leaf = NODEPTR(mpp.mp_page, 0); |
|
|
|
leaf = NODEPTR(mpp.mp_page, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
cursor->mc_initialized = 1; |
|
|
|
cursor->mc_flags |= C_INITIALIZED; |
|
|
|
cursor->mc_eof = 0; |
|
|
|
cursor->mc_flags &= ~C_EOF; |
|
|
|
|
|
|
|
|
|
|
|
if (IS_LEAF2(mpp.mp_page)) { |
|
|
|
if (IS_LEAF2(mpp.mp_page)) { |
|
|
|
key->mv_size = cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_pad; |
|
|
|
key->mv_size = cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_pad; |
|
|
@ -2606,8 +2613,8 @@ mdb_cursor_first(MDB_cursor *cursor, MDB_val *key, MDB_val *data) |
|
|
|
assert(IS_LEAF(mpp.mp_page)); |
|
|
|
assert(IS_LEAF(mpp.mp_page)); |
|
|
|
|
|
|
|
|
|
|
|
leaf = NODEPTR(mpp.mp_page, 0); |
|
|
|
leaf = NODEPTR(mpp.mp_page, 0); |
|
|
|
cursor->mc_initialized = 1; |
|
|
|
cursor->mc_flags |= C_INITIALIZED; |
|
|
|
cursor->mc_eof = 0; |
|
|
|
cursor->mc_flags &= ~C_EOF; |
|
|
|
|
|
|
|
|
|
|
|
if (IS_LEAF2(mpp.mp_page)) { |
|
|
|
if (IS_LEAF2(mpp.mp_page)) { |
|
|
|
key->mv_size = cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_pad; |
|
|
|
key->mv_size = cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_pad; |
|
|
@ -2623,7 +2630,7 @@ mdb_cursor_first(MDB_cursor *cursor, MDB_val *key, MDB_val *data) |
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (cursor->mc_xcursor) |
|
|
|
if (cursor->mc_xcursor) |
|
|
|
cursor->mc_xcursor->mx_cursor.mc_initialized = 0; |
|
|
|
cursor->mc_xcursor->mx_cursor.mc_flags = 0; |
|
|
|
if ((rc = mdb_read_data(cursor->mc_txn, leaf, data)) != MDB_SUCCESS) |
|
|
|
if ((rc = mdb_read_data(cursor->mc_txn, leaf, data)) != MDB_SUCCESS) |
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
} |
|
|
|
} |
|
|
@ -2652,8 +2659,8 @@ mdb_cursor_last(MDB_cursor *cursor, MDB_val *key, MDB_val *data) |
|
|
|
assert(IS_LEAF(mpp.mp_page)); |
|
|
|
assert(IS_LEAF(mpp.mp_page)); |
|
|
|
|
|
|
|
|
|
|
|
leaf = NODEPTR(mpp.mp_page, NUMKEYS(mpp.mp_page)-1); |
|
|
|
leaf = NODEPTR(mpp.mp_page, NUMKEYS(mpp.mp_page)-1); |
|
|
|
cursor->mc_initialized = 1; |
|
|
|
cursor->mc_flags |= C_INITIALIZED; |
|
|
|
cursor->mc_eof = 0; |
|
|
|
cursor->mc_flags &= ~C_EOF; |
|
|
|
|
|
|
|
|
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
top->mp_ki = NUMKEYS(top->mp_page) - 1; |
|
|
|
top->mp_ki = NUMKEYS(top->mp_page) - 1; |
|
|
@ -2709,12 +2716,13 @@ mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data, |
|
|
|
case MDB_GET_MULTIPLE: |
|
|
|
case MDB_GET_MULTIPLE: |
|
|
|
if (data == NULL || |
|
|
|
if (data == NULL || |
|
|
|
!(cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_flags & MDB_DUPFIXED) || |
|
|
|
!(cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_flags & MDB_DUPFIXED) || |
|
|
|
!cursor->mc_initialized) { |
|
|
|
!(cursor->mc_flags & C_INITIALIZED)) { |
|
|
|
rc = EINVAL; |
|
|
|
rc = EINVAL; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
rc = MDB_SUCCESS; |
|
|
|
rc = MDB_SUCCESS; |
|
|
|
if (!cursor->mc_xcursor->mx_cursor.mc_initialized || cursor->mc_xcursor->mx_cursor.mc_eof) |
|
|
|
if (!(cursor->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) || |
|
|
|
|
|
|
|
(cursor->mc_xcursor->mx_cursor.mc_flags & C_EOF)) |
|
|
|
break; |
|
|
|
break; |
|
|
|
goto fetchm; |
|
|
|
goto fetchm; |
|
|
|
case MDB_NEXT_MULTIPLE: |
|
|
|
case MDB_NEXT_MULTIPLE: |
|
|
@ -2723,12 +2731,12 @@ mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data, |
|
|
|
rc = EINVAL; |
|
|
|
rc = EINVAL; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!cursor->mc_initialized) |
|
|
|
if (!(cursor->mc_flags & C_INITIALIZED)) |
|
|
|
rc = mdb_cursor_first(cursor, key, data); |
|
|
|
rc = mdb_cursor_first(cursor, key, data); |
|
|
|
else |
|
|
|
else |
|
|
|
rc = mdb_cursor_next(cursor, key, data, MDB_NEXT_DUP); |
|
|
|
rc = mdb_cursor_next(cursor, key, data, MDB_NEXT_DUP); |
|
|
|
if (rc == MDB_SUCCESS) { |
|
|
|
if (rc == MDB_SUCCESS) { |
|
|
|
if (cursor->mc_xcursor->mx_cursor.mc_initialized) { |
|
|
|
if (cursor->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { |
|
|
|
MDB_ppage *top; |
|
|
|
MDB_ppage *top; |
|
|
|
fetchm: |
|
|
|
fetchm: |
|
|
|
top = CURSOR_TOP(&cursor->mc_xcursor->mx_cursor); |
|
|
|
top = CURSOR_TOP(&cursor->mc_xcursor->mx_cursor); |
|
|
@ -2744,7 +2752,7 @@ fetchm: |
|
|
|
case MDB_NEXT: |
|
|
|
case MDB_NEXT: |
|
|
|
case MDB_NEXT_DUP: |
|
|
|
case MDB_NEXT_DUP: |
|
|
|
case MDB_NEXT_NODUP: |
|
|
|
case MDB_NEXT_NODUP: |
|
|
|
if (!cursor->mc_initialized) |
|
|
|
if (!(cursor->mc_flags & C_INITIALIZED)) |
|
|
|
rc = mdb_cursor_first(cursor, key, data); |
|
|
|
rc = mdb_cursor_first(cursor, key, data); |
|
|
|
else |
|
|
|
else |
|
|
|
rc = mdb_cursor_next(cursor, key, data, op); |
|
|
|
rc = mdb_cursor_next(cursor, key, data, op); |
|
|
@ -2752,7 +2760,7 @@ fetchm: |
|
|
|
case MDB_PREV: |
|
|
|
case MDB_PREV: |
|
|
|
case MDB_PREV_DUP: |
|
|
|
case MDB_PREV_DUP: |
|
|
|
case MDB_PREV_NODUP: |
|
|
|
case MDB_PREV_NODUP: |
|
|
|
if (!cursor->mc_initialized || cursor->mc_eof) |
|
|
|
if (!(cursor->mc_flags & C_INITIALIZED) || (cursor->mc_flags & C_EOF)) |
|
|
|
rc = mdb_cursor_last(cursor, key, data); |
|
|
|
rc = mdb_cursor_last(cursor, key, data); |
|
|
|
else |
|
|
|
else |
|
|
|
rc = mdb_cursor_prev(cursor, key, data, op); |
|
|
|
rc = mdb_cursor_prev(cursor, key, data, op); |
|
|
@ -2763,8 +2771,8 @@ fetchm: |
|
|
|
case MDB_FIRST_DUP: |
|
|
|
case MDB_FIRST_DUP: |
|
|
|
if (data == NULL || |
|
|
|
if (data == NULL || |
|
|
|
!(cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_flags & MDB_DUPSORT) || |
|
|
|
!(cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_flags & MDB_DUPSORT) || |
|
|
|
!cursor->mc_initialized || |
|
|
|
!(cursor->mc_flags & C_INITIALIZED) || |
|
|
|
!cursor->mc_xcursor->mx_cursor.mc_initialized) { |
|
|
|
!(cursor->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) { |
|
|
|
rc = EINVAL; |
|
|
|
rc = EINVAL; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -2776,8 +2784,8 @@ fetchm: |
|
|
|
case MDB_LAST_DUP: |
|
|
|
case MDB_LAST_DUP: |
|
|
|
if (data == NULL || |
|
|
|
if (data == NULL || |
|
|
|
!(cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_flags & MDB_DUPSORT) || |
|
|
|
!(cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_flags & MDB_DUPSORT) || |
|
|
|
!cursor->mc_initialized || |
|
|
|
!(cursor->mc_flags & C_INITIALIZED) || |
|
|
|
!cursor->mc_xcursor->mx_cursor.mc_initialized) { |
|
|
|
!(cursor->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) { |
|
|
|
rc = EINVAL; |
|
|
|
rc = EINVAL; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -2811,8 +2819,6 @@ mdb_cursor_touch(MDB_cursor *cursor) |
|
|
|
mpp.mp_parent = mpp.mp_page; |
|
|
|
mpp.mp_parent = mpp.mp_page; |
|
|
|
mpp.mp_pi = cursor->mc_stack[i].mp_ki; |
|
|
|
mpp.mp_pi = cursor->mc_stack[i].mp_ki; |
|
|
|
} |
|
|
|
} |
|
|
|
if (cursor->mc_xcursor) |
|
|
|
|
|
|
|
return mdb_cursor_touch(&cursor->mc_xcursor->mx_cursor); |
|
|
|
|
|
|
|
return MDB_SUCCESS; |
|
|
|
return MDB_SUCCESS; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -2824,6 +2830,9 @@ mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data, |
|
|
|
MDB_node *leaf; |
|
|
|
MDB_node *leaf; |
|
|
|
int rc, exact; |
|
|
|
int rc, exact; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (F_ISSET(cursor->mc_txn->mt_flags, MDB_TXN_RDONLY)) |
|
|
|
|
|
|
|
return EACCES; |
|
|
|
|
|
|
|
|
|
|
|
if (flags == MDB_NODUPDATA) { |
|
|
|
if (flags == MDB_NODUPDATA) { |
|
|
|
rc = mdb_cursor_set(cursor, key, data, MDB_GET_BOTH, &exact); |
|
|
|
rc = mdb_cursor_set(cursor, key, data, MDB_GET_BOTH, &exact); |
|
|
|
if (rc == 0) |
|
|
|
if (rc == 0) |
|
|
@ -2836,15 +2845,98 @@ mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data, |
|
|
|
return MDB_KEYEXIST; |
|
|
|
return MDB_KEYEXIST; |
|
|
|
if (rc != MDB_NOTFOUND) |
|
|
|
if (rc != MDB_NOTFOUND) |
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
} else if (!cursor->mc_initialized) { |
|
|
|
} else if (!(cursor->mc_flags & C_INITIALIZED)) { |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
} |
|
|
|
} |
|
|
|
/* Cursor is positioned, now make sure all pages are writable */ |
|
|
|
/* Cursor is positioned, now make sure all pages are writable */ |
|
|
|
rc = mdb_cursor_touch(cursor); |
|
|
|
rc = mdb_cursor_touch(cursor); |
|
|
|
if (rc) return rc; |
|
|
|
if (rc) return rc; |
|
|
|
|
|
|
|
if (cursor->mc_xcursor) { |
|
|
|
|
|
|
|
rc = mdb_cursor_touch(&cursor->mc_xcursor->mx_cursor); |
|
|
|
|
|
|
|
if (rc) return rc; |
|
|
|
|
|
|
|
cursor->mc_flags |= C_XDIRTY; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
top = CURSOR_TOP(cursor); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return rc; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
|
|
|
mdb_cursor_del(MDB_cursor *mc, unsigned int flags) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
MDB_pageparent mpp; |
|
|
|
|
|
|
|
MDB_ppage *top; |
|
|
|
|
|
|
|
MDB_node *leaf; |
|
|
|
|
|
|
|
int rc; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (F_ISSET(mc->mc_txn->mt_flags, MDB_TXN_RDONLY)) |
|
|
|
|
|
|
|
return EACCES; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!mc->mc_flags & C_INITIALIZED) |
|
|
|
|
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = mdb_cursor_touch(mc); |
|
|
|
|
|
|
|
if (rc) return rc; |
|
|
|
|
|
|
|
if (mc->mc_xcursor) { |
|
|
|
|
|
|
|
rc = mdb_cursor_touch(&mc->mc_xcursor->mx_cursor); |
|
|
|
|
|
|
|
if (rc) return rc; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
top = CURSOR_TOP(mc); |
|
|
|
|
|
|
|
leaf = NODEPTR(top->mp_page, top->mp_ki); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_LEAF2(top->mp_page) && F_ISSET(leaf->mn_flags, F_DUPDATA)) { |
|
|
|
|
|
|
|
MDB_pageparent mp2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (flags != MDB_NODUPDATA) { |
|
|
|
|
|
|
|
rc = mdb_cursor_del(&mc->mc_xcursor->mx_cursor, 0); |
|
|
|
|
|
|
|
mdb_xcursor_fini(mc); |
|
|
|
|
|
|
|
/* If sub-DB still has entries, we're done */ |
|
|
|
|
|
|
|
if (mc->mc_xcursor->mx_txn.mt_dbs[mc->mc_xcursor->mx_cursor.mc_dbi].md_root |
|
|
|
|
|
|
|
!= P_INVALID) { |
|
|
|
|
|
|
|
memcpy(NODEDATA(leaf), |
|
|
|
|
|
|
|
&mc->mc_xcursor->mx_txn.mt_dbs[mc->mc_xcursor->mx_cursor.mc_dbi], |
|
|
|
|
|
|
|
sizeof(MDB_db)); |
|
|
|
|
|
|
|
mc->mc_txn->mt_dbs[mc->mc_dbi].md_entries--; |
|
|
|
|
|
|
|
return rc; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* otherwise fall thru and delete the sub-DB */ |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
/* add all the child DB's pages to the free list */ |
|
|
|
|
|
|
|
rc = mdb_search_page(&mx.mx_txn, mx.mx_cursor.mc_dbi, |
|
|
|
|
|
|
|
NULL, &mx.mx_cursor, 0, &mp2); |
|
|
|
|
|
|
|
if (rc == MDB_SUCCESS) { |
|
|
|
|
|
|
|
MDB_ppage *top, *parent; |
|
|
|
|
|
|
|
MDB_node *ni; |
|
|
|
|
|
|
|
unsigned int i; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cursor_pop_page(&mx.mx_cursor); |
|
|
|
|
|
|
|
if (mx.mx_cursor.mc_snum) { |
|
|
|
|
|
|
|
top = CURSOR_TOP(&mx.mx_cursor); |
|
|
|
|
|
|
|
while (mx.mx_cursor.mc_snum > 1) { |
|
|
|
|
|
|
|
parent = CURSOR_PARENT(&mx.mx_cursor); |
|
|
|
|
|
|
|
for (i=0; i<NUMKEYS(top->mp_page); i++) { |
|
|
|
|
|
|
|
ni = NODEPTR(top->mp_page, i); |
|
|
|
|
|
|
|
mdb_midl_insert(txn->mt_free_pgs, NODEPGNO(ni)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
parent->mp_ki++; |
|
|
|
|
|
|
|
if (parent->mp_ki >= NUMKEYS(parent->mp_page)) { |
|
|
|
|
|
|
|
cursor_pop_page(&mx.mx_cursor); |
|
|
|
|
|
|
|
top = parent; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
ni = NODEPTR(parent->mp_page, parent->mp_ki); |
|
|
|
|
|
|
|
rc = mdb_get_page(&mx.mx_txn, NODEPGNO(ni), &top->mp_page); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mdb_midl_insert(txn->mt_free_pgs, mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi].md_root); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return mdb_del0(txn, dbi, ki, &mpp, leaf); |
|
|
|
|
|
|
|
return rc; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Allocate a page and initialize it
|
|
|
|
/* Allocate a page and initialize it
|
|
|
@ -3109,22 +3201,22 @@ mdb_xcursor_init1(MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx, MDB_page *mp, MDB_ |
|
|
|
mx->mx_dbxs[dbn].md_name.mv_size = node->mn_ksize; |
|
|
|
mx->mx_dbxs[dbn].md_name.mv_size = node->mn_ksize; |
|
|
|
mx->mx_txn.mt_next_pgno = txn->mt_next_pgno; |
|
|
|
mx->mx_txn.mt_next_pgno = txn->mt_next_pgno; |
|
|
|
mx->mx_txn.mt_u = txn->mt_u; |
|
|
|
mx->mx_txn.mt_u = txn->mt_u; |
|
|
|
mx->mx_cursor.mc_initialized = 0; |
|
|
|
mx->mx_cursor.mc_flags = 0; |
|
|
|
mx->mx_cursor.mc_eof = 0; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
static void |
|
|
|
mdb_xcursor_fini(MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx) |
|
|
|
mdb_xcursor_fini(MDB_cursor *mc) |
|
|
|
{ |
|
|
|
{ |
|
|
|
txn->mt_next_pgno = mx->mx_txn.mt_next_pgno; |
|
|
|
MDB_xcursor *mx = mc->mc_xcursor; |
|
|
|
txn->mt_u = mx->mx_txn.mt_u; |
|
|
|
mc->mc_txn->mt_next_pgno = mx->mx_txn.mt_next_pgno; |
|
|
|
txn->mt_dbs[0] = mx->mx_dbs[0]; |
|
|
|
mc->mc_txn->mt_u = mx->mx_txn.mt_u; |
|
|
|
txn->mt_dbs[1] = mx->mx_dbs[1]; |
|
|
|
mc->mc_txn->mt_dbs[0] = mx->mx_dbs[0]; |
|
|
|
txn->mt_dbxs[0].md_dirty = mx->mx_dbxs[0].md_dirty; |
|
|
|
mc->mc_txn->mt_dbs[1] = mx->mx_dbs[1]; |
|
|
|
txn->mt_dbxs[1].md_dirty = mx->mx_dbxs[1].md_dirty; |
|
|
|
mc->mc_txn->mt_dbxs[0].md_dirty = mx->mx_dbxs[0].md_dirty; |
|
|
|
if (dbi > 1) { |
|
|
|
mc->mc_txn->mt_dbxs[1].md_dirty = mx->mx_dbxs[1].md_dirty; |
|
|
|
txn->mt_dbs[dbi] = mx->mx_dbs[2]; |
|
|
|
if (mc->mc_dbi > 1) { |
|
|
|
txn->mt_dbxs[dbi].md_dirty = mx->mx_dbxs[2].md_dirty; |
|
|
|
mc->mc_txn->mt_dbs[mc->mc_dbi] = mx->mx_dbs[2]; |
|
|
|
|
|
|
|
mc->mc_txn->mt_dbxs[mc->mc_dbi].md_dirty = mx->mx_dbxs[2].md_dirty; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3175,7 +3267,7 @@ mdb_cursor_count(MDB_cursor *mc, unsigned long *countp) |
|
|
|
if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { |
|
|
|
if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { |
|
|
|
*countp = 1; |
|
|
|
*countp = 1; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (!mc->mc_xcursor->mx_cursor.mc_initialized) |
|
|
|
if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
*countp = mc->mc_xcursor->mx_txn.mt_dbs[mc->mc_xcursor->mx_cursor.mc_dbi].md_entries; |
|
|
|
*countp = mc->mc_xcursor->mx_txn.mt_dbs[mc->mc_xcursor->mx_cursor.mc_dbi].md_entries; |
|
|
@ -3563,13 +3655,13 @@ mdb_del(MDB_txn *txn, MDB_dbi dbi, |
|
|
|
|
|
|
|
|
|
|
|
mc.mc_txn = txn; |
|
|
|
mc.mc_txn = txn; |
|
|
|
mc.mc_dbi = dbi; |
|
|
|
mc.mc_dbi = dbi; |
|
|
|
mc.mc_initialized = 0; |
|
|
|
mc.mc_flags = 0; |
|
|
|
mc.mc_xcursor = &mx; |
|
|
|
mc.mc_xcursor = &mx; |
|
|
|
mdb_xcursor_init0(&mc); |
|
|
|
mdb_xcursor_init0(&mc); |
|
|
|
mdb_xcursor_init1(txn, dbi, &mx, mpp.mp_page, leaf); |
|
|
|
mdb_xcursor_init1(txn, dbi, &mx, mpp.mp_page, leaf); |
|
|
|
if (data) { |
|
|
|
if (data) { |
|
|
|
rc = mdb_del(&mx.mx_txn, mx.mx_cursor.mc_dbi, data, NULL); |
|
|
|
rc = mdb_del(&mx.mx_txn, mx.mx_cursor.mc_dbi, data, NULL); |
|
|
|
mdb_xcursor_fini(txn, dbi, &mx); |
|
|
|
mdb_xcursor_fini(&mc); |
|
|
|
/* If sub-DB still has entries, we're done */ |
|
|
|
/* If sub-DB still has entries, we're done */ |
|
|
|
if (mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi].md_root != P_INVALID) { |
|
|
|
if (mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi].md_root != P_INVALID) { |
|
|
|
memcpy(NODEDATA(leaf), &mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi], |
|
|
|
memcpy(NODEDATA(leaf), &mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi], |
|
|
@ -3993,7 +4085,7 @@ new_sub: |
|
|
|
put_sub: |
|
|
|
put_sub: |
|
|
|
mc.mc_txn = txn; |
|
|
|
mc.mc_txn = txn; |
|
|
|
mc.mc_dbi = dbi; |
|
|
|
mc.mc_dbi = dbi; |
|
|
|
mc.mc_initialized = 0; |
|
|
|
mc.mc_flags = 0; |
|
|
|
mc.mc_xcursor = &mx; |
|
|
|
mc.mc_xcursor = &mx; |
|
|
|
mdb_xcursor_init0(&mc); |
|
|
|
mdb_xcursor_init0(&mc); |
|
|
|
mdb_xcursor_init1(txn, dbi, &mx, mpp.mp_page, leaf); |
|
|
|
mdb_xcursor_init1(txn, dbi, &mx, mpp.mp_page, leaf); |
|
|
@ -4008,7 +4100,7 @@ put_sub: |
|
|
|
leaf->mn_flags |= F_DUPDATA; |
|
|
|
leaf->mn_flags |= F_DUPDATA; |
|
|
|
} |
|
|
|
} |
|
|
|
rc = mdb_put0(&mx.mx_txn, mx.mx_cursor.mc_dbi, data, &xdata, flags); |
|
|
|
rc = mdb_put0(&mx.mx_txn, mx.mx_cursor.mc_dbi, data, &xdata, flags); |
|
|
|
mdb_xcursor_fini(txn, dbi, &mx); |
|
|
|
mdb_xcursor_fini(&mc); |
|
|
|
memcpy(NODEDATA(leaf), &mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi], |
|
|
|
memcpy(NODEDATA(leaf), &mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi], |
|
|
|
sizeof(MDB_db)); |
|
|
|
sizeof(MDB_db)); |
|
|
|
} |
|
|
|
} |
|
|
@ -4047,8 +4139,7 @@ mdb_put(MDB_txn *txn, MDB_dbi dbi, |
|
|
|
mc.mc_txn = txn; |
|
|
|
mc.mc_txn = txn; |
|
|
|
mc.mc_dbi = dbi; |
|
|
|
mc.mc_dbi = dbi; |
|
|
|
mc.mc_snum = 0; |
|
|
|
mc.mc_snum = 0; |
|
|
|
mc.mc_initialized = 0; |
|
|
|
mc.mc_flags = 0; |
|
|
|
mc.mc_eof = 0; |
|
|
|
|
|
|
|
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { |
|
|
|
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { |
|
|
|
mc.mc_xcursor = &mx; |
|
|
|
mc.mc_xcursor = &mx; |
|
|
|
mdb_xcursor_init0(&mc); |
|
|
|
mdb_xcursor_init0(&mc); |
|
|
@ -4059,7 +4150,7 @@ mdb_put(MDB_txn *txn, MDB_dbi dbi, |
|
|
|
if (mc.mc_xcursor) { |
|
|
|
if (mc.mc_xcursor) { |
|
|
|
MDB_ppage *top; |
|
|
|
MDB_ppage *top; |
|
|
|
MDB_node *leaf; |
|
|
|
MDB_node *leaf; |
|
|
|
mdb_xcursor_fini(txn, dbi, &mx); |
|
|
|
mdb_xcursor_fini(&mc); |
|
|
|
top = CURSOR_TOP(&mc); |
|
|
|
top = CURSOR_TOP(&mc); |
|
|
|
leaf = NODEPTR(top->mp_page, top->mp_ki); |
|
|
|
leaf = NODEPTR(top->mp_page, top->mp_ki); |
|
|
|
memcpy(NODEDATA(leaf), &mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi], |
|
|
|
memcpy(NODEDATA(leaf), &mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi], |
|
|
|