mirror of
https://github.com/isar/libmdbx.git
synced 2025-02-05 06:02:06 +08:00
mdbx: rework cursor's couple (required for further fixing).
Change-Id: Ic89c59eaea36d14a26e29d2012c693d92474a748
This commit is contained in:
parent
e25b30b5ce
commit
02f3230e0c
@ -691,6 +691,11 @@ typedef struct MDBX_xcursor {
|
|||||||
uint8_t mx_dbflag;
|
uint8_t mx_dbflag;
|
||||||
} MDBX_xcursor;
|
} MDBX_xcursor;
|
||||||
|
|
||||||
|
typedef struct MDBX_cursor_couple {
|
||||||
|
MDBX_cursor outer;
|
||||||
|
MDBX_xcursor inner;
|
||||||
|
} MDBX_cursor_couple;
|
||||||
|
|
||||||
/* Check if there is an inited xcursor, so XCURSOR_REFRESH() is proper */
|
/* Check if there is an inited xcursor, so XCURSOR_REFRESH() is proper */
|
||||||
#define XCURSOR_INITED(mc) \
|
#define XCURSOR_INITED(mc) \
|
||||||
((mc)->mc_xcursor && ((mc)->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED))
|
((mc)->mc_xcursor && ((mc)->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED))
|
||||||
|
181
src/mdbx.c
181
src/mdbx.c
@ -1074,7 +1074,7 @@ static int __must_check_result mdbx_cursor_last(MDBX_cursor *mc, MDBX_val *key,
|
|||||||
MDBX_val *data);
|
MDBX_val *data);
|
||||||
|
|
||||||
static int __must_check_result mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn,
|
static int __must_check_result mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn,
|
||||||
MDBX_dbi dbi, MDBX_xcursor *mx);
|
MDBX_dbi dbi);
|
||||||
static int __must_check_result mdbx_xcursor_init0(MDBX_cursor *mc);
|
static int __must_check_result mdbx_xcursor_init0(MDBX_cursor *mc);
|
||||||
static int __must_check_result mdbx_xcursor_init1(MDBX_cursor *mc,
|
static int __must_check_result mdbx_xcursor_init1(MDBX_cursor *mc,
|
||||||
MDBX_node *node);
|
MDBX_node *node);
|
||||||
@ -2233,7 +2233,7 @@ static int mdbx_page_alloc(MDBX_cursor *mc, unsigned num, MDBX_page **mp,
|
|||||||
/* Prepare to fetch more and coalesce */
|
/* Prepare to fetch more and coalesce */
|
||||||
oldest = (flags & MDBX_LIFORECLAIM) ? mdbx_find_oldest(txn)
|
oldest = (flags & MDBX_LIFORECLAIM) ? mdbx_find_oldest(txn)
|
||||||
: env->me_oldest[0];
|
: env->me_oldest[0];
|
||||||
rc = mdbx_cursor_init(&recur, txn, FREE_DBI, NULL);
|
rc = mdbx_cursor_init(&recur, txn, FREE_DBI);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (flags & MDBX_LIFORECLAIM) {
|
if (flags & MDBX_LIFORECLAIM) {
|
||||||
@ -3517,7 +3517,6 @@ static int mdbx_prep_backlog(MDBX_txn *txn, MDBX_cursor *mc) {
|
|||||||
* it matches the actual number of pages being used.
|
* it matches the actual number of pages being used.
|
||||||
* All named DBs must be open for a correct count. */
|
* All named DBs must be open for a correct count. */
|
||||||
static int mdbx_audit(MDBX_txn *txn, unsigned befree_stored) {
|
static int mdbx_audit(MDBX_txn *txn, unsigned befree_stored) {
|
||||||
MDBX_cursor mc;
|
|
||||||
MDBX_val key, data;
|
MDBX_val key, data;
|
||||||
|
|
||||||
const pgno_t pending =
|
const pgno_t pending =
|
||||||
@ -3529,21 +3528,22 @@ static int mdbx_audit(MDBX_txn *txn, unsigned befree_stored) {
|
|||||||
: 0) +
|
: 0) +
|
||||||
(txn->mt_befree_pages ? txn->mt_befree_pages[0] - befree_stored
|
(txn->mt_befree_pages ? txn->mt_befree_pages[0] - befree_stored
|
||||||
: 0);
|
: 0);
|
||||||
int rc = mdbx_cursor_init(&mc, txn, FREE_DBI, NULL);
|
|
||||||
|
MDBX_cursor_couple cx;
|
||||||
|
int rc = mdbx_cursor_init(&cx.outer, txn, FREE_DBI);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
pgno_t freecount = 0;
|
pgno_t freecount = 0;
|
||||||
while ((rc = mdbx_cursor_get(&mc, &key, &data, MDBX_NEXT)) == 0)
|
while ((rc = mdbx_cursor_get(&cx.outer, &key, &data, MDBX_NEXT)) == 0)
|
||||||
freecount += *(pgno_t *)data.iov_base;
|
freecount += *(pgno_t *)data.iov_base;
|
||||||
mdbx_tassert(txn, rc == MDBX_NOTFOUND);
|
mdbx_tassert(txn, rc == MDBX_NOTFOUND);
|
||||||
|
|
||||||
pgno_t count = 0;
|
pgno_t count = 0;
|
||||||
for (MDBX_dbi i = FREE_DBI; i <= MAIN_DBI; i++) {
|
for (MDBX_dbi i = FREE_DBI; i <= MAIN_DBI; i++) {
|
||||||
MDBX_xcursor mx;
|
|
||||||
if (!(txn->mt_dbflags[i] & DB_VALID))
|
if (!(txn->mt_dbflags[i] & DB_VALID))
|
||||||
continue;
|
continue;
|
||||||
rc = mdbx_cursor_init(&mc, txn, i, &mx);
|
rc = mdbx_cursor_init(&cx.outer, txn, i);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
if (txn->mt_dbs[i].md_root == P_INVALID)
|
if (txn->mt_dbs[i].md_root == P_INVALID)
|
||||||
@ -3551,9 +3551,9 @@ static int mdbx_audit(MDBX_txn *txn, unsigned befree_stored) {
|
|||||||
count += txn->mt_dbs[i].md_branch_pages + txn->mt_dbs[i].md_leaf_pages +
|
count += txn->mt_dbs[i].md_branch_pages + txn->mt_dbs[i].md_leaf_pages +
|
||||||
txn->mt_dbs[i].md_overflow_pages;
|
txn->mt_dbs[i].md_overflow_pages;
|
||||||
|
|
||||||
rc = mdbx_page_search(&mc, NULL, MDBX_PS_FIRST);
|
rc = mdbx_page_search(&cx.outer, NULL, MDBX_PS_FIRST);
|
||||||
while (rc == MDBX_SUCCESS) {
|
while (rc == MDBX_SUCCESS) {
|
||||||
MDBX_page *mp = mc.mc_pg[mc.mc_top];
|
MDBX_page *mp = cx.outer.mc_pg[cx.outer.mc_top];
|
||||||
for (unsigned j = 0; j < NUMKEYS(mp); j++) {
|
for (unsigned j = 0; j < NUMKEYS(mp); j++) {
|
||||||
MDBX_node *leaf = NODEPTR(mp, j);
|
MDBX_node *leaf = NODEPTR(mp, j);
|
||||||
if ((leaf->mn_flags & (F_DUPDATA | F_SUBDATA)) == F_SUBDATA) {
|
if ((leaf->mn_flags & (F_DUPDATA | F_SUBDATA)) == F_SUBDATA) {
|
||||||
@ -3575,7 +3575,7 @@ static int mdbx_audit(MDBX_txn *txn, unsigned befree_stored) {
|
|||||||
db->md_branch_pages + db->md_leaf_pages + db->md_overflow_pages;
|
db->md_branch_pages + db->md_leaf_pages + db->md_overflow_pages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc = mdbx_cursor_sibling(&mc, 1);
|
rc = mdbx_cursor_sibling(&cx.outer, 1);
|
||||||
}
|
}
|
||||||
mdbx_tassert(txn, rc == MDBX_NOTFOUND);
|
mdbx_tassert(txn, rc == MDBX_NOTFOUND);
|
||||||
}
|
}
|
||||||
@ -3610,7 +3610,7 @@ static int mdbx_update_gc(MDBX_txn *txn) {
|
|||||||
const bool lifo = (env->me_flags & MDBX_LIFORECLAIM) != 0;
|
const bool lifo = (env->me_flags & MDBX_LIFORECLAIM) != 0;
|
||||||
|
|
||||||
MDBX_cursor mc;
|
MDBX_cursor mc;
|
||||||
int rc = mdbx_cursor_init(&mc, txn, FREE_DBI, NULL);
|
int rc = mdbx_cursor_init(&mc, txn, FREE_DBI);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -4465,7 +4465,7 @@ int mdbx_txn_commit(MDBX_txn *txn) {
|
|||||||
MDBX_val data;
|
MDBX_val data;
|
||||||
data.iov_len = sizeof(MDBX_db);
|
data.iov_len = sizeof(MDBX_db);
|
||||||
|
|
||||||
rc = mdbx_cursor_init(&mc, txn, MAIN_DBI, NULL);
|
rc = mdbx_cursor_init(&mc, txn, MAIN_DBI);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
goto fail;
|
goto fail;
|
||||||
for (i = CORE_DBS; i < txn->mt_numdbs; i++) {
|
for (i = CORE_DBS; i < txn->mt_numdbs; i++) {
|
||||||
@ -6743,7 +6743,7 @@ static int mdbx_page_search(MDBX_cursor *mc, MDBX_val *key, int flags) {
|
|||||||
MDBX_cursor mc2;
|
MDBX_cursor mc2;
|
||||||
if (unlikely(TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi)))
|
if (unlikely(TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi)))
|
||||||
return MDBX_BAD_DBI;
|
return MDBX_BAD_DBI;
|
||||||
rc = mdbx_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, NULL);
|
rc = mdbx_cursor_init(&mc2, mc->mc_txn, MAIN_DBI);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
rc = mdbx_page_search(&mc2, &mc->mc_dbx->md_name, 0);
|
rc = mdbx_page_search(&mc2, &mc->mc_dbx->md_name, 0);
|
||||||
@ -6911,8 +6911,6 @@ static __inline int mdbx_node_read(MDBX_cursor *mc, MDBX_node *leaf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
|
int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
|
||||||
MDBX_cursor mc;
|
|
||||||
MDBX_xcursor mx;
|
|
||||||
int exact = 0;
|
int exact = 0;
|
||||||
DKBUF;
|
DKBUF;
|
||||||
|
|
||||||
@ -6933,10 +6931,11 @@ int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
|
|||||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||||
return MDBX_BAD_TXN;
|
return MDBX_BAD_TXN;
|
||||||
|
|
||||||
int rc = mdbx_cursor_init(&mc, txn, dbi, &mx);
|
MDBX_cursor_couple cx;
|
||||||
|
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
return mdbx_cursor_set(&mc, key, data, MDBX_SET, &exact);
|
return mdbx_cursor_set(&cx.outer, key, data, MDBX_SET, &exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find a sibling for a page.
|
/* Find a sibling for a page.
|
||||||
@ -7651,14 +7650,13 @@ static int mdbx_cursor_touch(MDBX_cursor *mc) {
|
|||||||
(*mc->mc_dbflag & (DB_DIRTY | DB_DUPDATA)) == 0) {
|
(*mc->mc_dbflag & (DB_DIRTY | DB_DUPDATA)) == 0) {
|
||||||
mdbx_cassert(mc, (mc->mc_flags & C_RECLAIMING) == 0);
|
mdbx_cassert(mc, (mc->mc_flags & C_RECLAIMING) == 0);
|
||||||
/* Touch DB record of named DB */
|
/* Touch DB record of named DB */
|
||||||
MDBX_cursor mc2;
|
MDBX_cursor_couple cx;
|
||||||
MDBX_xcursor mcx;
|
|
||||||
if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi))
|
if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi))
|
||||||
return MDBX_BAD_DBI;
|
return MDBX_BAD_DBI;
|
||||||
rc = mdbx_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, &mcx);
|
rc = mdbx_cursor_init(&cx.outer, mc->mc_txn, MAIN_DBI);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
rc = mdbx_page_search(&mc2, &mc->mc_dbx->md_name, MDBX_PS_MODIFY);
|
rc = mdbx_page_search(&cx.outer, &mc->mc_dbx->md_name, MDBX_PS_MODIFY);
|
||||||
if (unlikely(rc))
|
if (unlikely(rc))
|
||||||
return rc;
|
return rc;
|
||||||
*mc->mc_dbflag |= DB_DIRTY;
|
*mc->mc_dbflag |= DB_DIRTY;
|
||||||
@ -8851,8 +8849,7 @@ static int mdbx_xcursor_init2(MDBX_cursor *mc, MDBX_xcursor *src_mx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize a cursor for a given transaction and database. */
|
/* Initialize a cursor for a given transaction and database. */
|
||||||
static int mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn, MDBX_dbi dbi,
|
static int mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn, MDBX_dbi dbi) {
|
||||||
MDBX_xcursor *mx) {
|
|
||||||
mc->mc_signature = MDBX_MC_SIGNATURE;
|
mc->mc_signature = MDBX_MC_SIGNATURE;
|
||||||
mc->mc_next = NULL;
|
mc->mc_next = NULL;
|
||||||
mc->mc_backup = NULL;
|
mc->mc_backup = NULL;
|
||||||
@ -8869,6 +8866,8 @@ static int mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn, MDBX_dbi dbi,
|
|||||||
mc->mc_xcursor = NULL;
|
mc->mc_xcursor = NULL;
|
||||||
|
|
||||||
if (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT) {
|
if (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT) {
|
||||||
|
STATIC_ASSERT(offsetof(MDBX_cursor_couple, outer) == 0);
|
||||||
|
MDBX_xcursor *mx = &container_of(mc, MDBX_cursor_couple, outer)->inner;
|
||||||
mdbx_tassert(txn, mx != NULL);
|
mdbx_tassert(txn, mx != NULL);
|
||||||
mx->mx_cursor.mc_signature = MDBX_MC_SIGNATURE;
|
mx->mx_cursor.mc_signature = MDBX_MC_SIGNATURE;
|
||||||
mc->mc_xcursor = mx;
|
mc->mc_xcursor = mx;
|
||||||
@ -8887,9 +8886,6 @@ static int mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn, MDBX_dbi dbi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
||||||
MDBX_cursor *mc;
|
|
||||||
size_t size = sizeof(MDBX_cursor);
|
|
||||||
|
|
||||||
if (unlikely(!ret || !txn))
|
if (unlikely(!ret || !txn))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
|
|
||||||
@ -8908,11 +8904,13 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
|||||||
if (unlikely(dbi == FREE_DBI && !F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)))
|
if (unlikely(dbi == FREE_DBI && !F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
|
|
||||||
if (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT)
|
const size_t size = (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT)
|
||||||
size += sizeof(MDBX_xcursor);
|
? sizeof(MDBX_cursor_couple)
|
||||||
|
: sizeof(MDBX_cursor);
|
||||||
|
|
||||||
|
MDBX_cursor *mc;
|
||||||
if (likely((mc = malloc(size)) != NULL)) {
|
if (likely((mc = malloc(size)) != NULL)) {
|
||||||
int rc = mdbx_cursor_init(mc, txn, dbi, (MDBX_xcursor *)(mc + 1));
|
int rc = mdbx_cursor_init(mc, txn, dbi);
|
||||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
free(mc);
|
free(mc);
|
||||||
return rc;
|
return rc;
|
||||||
@ -8965,7 +8963,7 @@ int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) {
|
|||||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||||
return MDBX_BAD_TXN;
|
return MDBX_BAD_TXN;
|
||||||
|
|
||||||
return mdbx_cursor_init(mc, txn, mc->mc_dbi, mc->mc_xcursor);
|
return mdbx_cursor_init(mc, txn, mc->mc_dbi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the count of duplicate data items for the current key */
|
/* Return the count of duplicate data items for the current key */
|
||||||
@ -9840,8 +9838,7 @@ int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
|
|||||||
|
|
||||||
static int mdbx_del0(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
static int mdbx_del0(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||||
unsigned flags) {
|
unsigned flags) {
|
||||||
MDBX_cursor mc;
|
MDBX_cursor_couple cx;
|
||||||
MDBX_xcursor mx;
|
|
||||||
MDBX_cursor_op op;
|
MDBX_cursor_op op;
|
||||||
MDBX_val rdata;
|
MDBX_val rdata;
|
||||||
int rc, exact = 0;
|
int rc, exact = 0;
|
||||||
@ -9850,7 +9847,7 @@ static int mdbx_del0(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
|||||||
mdbx_debug("====> delete db %u key [%s], data [%s]", dbi, DKEY(key),
|
mdbx_debug("====> delete db %u key [%s], data [%s]", dbi, DKEY(key),
|
||||||
DVAL(data));
|
DVAL(data));
|
||||||
|
|
||||||
rc = mdbx_cursor_init(&mc, txn, dbi, &mx);
|
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -9862,7 +9859,7 @@ static int mdbx_del0(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
|||||||
op = MDBX_SET;
|
op = MDBX_SET;
|
||||||
flags |= MDBX_NODUPDATA;
|
flags |= MDBX_NODUPDATA;
|
||||||
}
|
}
|
||||||
rc = mdbx_cursor_set(&mc, key, data, op, &exact);
|
rc = mdbx_cursor_set(&cx.outer, key, data, op, &exact);
|
||||||
if (likely(rc == MDBX_SUCCESS)) {
|
if (likely(rc == MDBX_SUCCESS)) {
|
||||||
/* let mdbx_page_split know about this cursor if needed:
|
/* let mdbx_page_split know about this cursor if needed:
|
||||||
* delete will trigger a rebalance; if it needs to move
|
* delete will trigger a rebalance; if it needs to move
|
||||||
@ -9871,10 +9868,10 @@ static int mdbx_del0(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
|||||||
* is larger than the current one, the parent page may
|
* is larger than the current one, the parent page may
|
||||||
* run out of space, triggering a split. We need this
|
* run out of space, triggering a split. We need this
|
||||||
* cursor to be consistent until the end of the rebalance. */
|
* cursor to be consistent until the end of the rebalance. */
|
||||||
mc.mc_next = txn->mt_cursors[dbi];
|
cx.outer.mc_next = txn->mt_cursors[dbi];
|
||||||
txn->mt_cursors[dbi] = &mc;
|
txn->mt_cursors[dbi] = &cx.outer;
|
||||||
rc = mdbx_cursor_del(&mc, flags);
|
rc = mdbx_cursor_del(&cx.outer, flags);
|
||||||
txn->mt_cursors[dbi] = mc.mc_next;
|
txn->mt_cursors[dbi] = cx.outer.mc_next;
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -10318,8 +10315,6 @@ done:
|
|||||||
|
|
||||||
int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||||
unsigned flags) {
|
unsigned flags) {
|
||||||
MDBX_cursor mc;
|
|
||||||
MDBX_xcursor mx;
|
|
||||||
|
|
||||||
if (unlikely(!key || !data || !txn))
|
if (unlikely(!key || !data || !txn))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
@ -10340,30 +10335,32 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
|||||||
if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
|
if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
|
||||||
return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
||||||
|
|
||||||
int rc = mdbx_cursor_init(&mc, txn, dbi, &mx);
|
MDBX_cursor_couple cx;
|
||||||
|
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
mc.mc_next = txn->mt_cursors[dbi];
|
cx.outer.mc_next = txn->mt_cursors[dbi];
|
||||||
txn->mt_cursors[dbi] = &mc;
|
txn->mt_cursors[dbi] = &cx.outer;
|
||||||
|
|
||||||
/* LY: support for update (explicit overwrite) */
|
/* LY: support for update (explicit overwrite) */
|
||||||
if (flags & MDBX_CURRENT) {
|
if (flags & MDBX_CURRENT) {
|
||||||
rc = mdbx_cursor_get(&mc, key, NULL, MDBX_SET);
|
rc = mdbx_cursor_get(&cx.outer, key, NULL, MDBX_SET);
|
||||||
if (likely(rc == MDBX_SUCCESS) &&
|
if (likely(rc == MDBX_SUCCESS) &&
|
||||||
(txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT)) {
|
(txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT)) {
|
||||||
/* LY: allows update (explicit overwrite) only for unique keys */
|
/* LY: allows update (explicit overwrite) only for unique keys */
|
||||||
MDBX_node *leaf = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
|
MDBX_node *leaf = NODEPTR(cx.outer.mc_pg[cx.outer.mc_top],
|
||||||
|
cx.outer.mc_ki[cx.outer.mc_top]);
|
||||||
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
|
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
|
||||||
mdbx_tassert(txn, XCURSOR_INITED(&mc) &&
|
mdbx_tassert(txn, XCURSOR_INITED(&cx.outer) &&
|
||||||
mc.mc_xcursor->mx_db.md_entries > 1);
|
cx.outer.mc_xcursor->mx_db.md_entries > 1);
|
||||||
rc = MDBX_EMULTIVAL;
|
rc = MDBX_EMULTIVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(rc == MDBX_SUCCESS))
|
if (likely(rc == MDBX_SUCCESS))
|
||||||
rc = mdbx_cursor_put(&mc, key, data, flags);
|
rc = mdbx_cursor_put(&cx.outer, key, data, flags);
|
||||||
txn->mt_cursors[dbi] = mc.mc_next;
|
txn->mt_cursors[dbi] = cx.outer.mc_next;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -10673,7 +10670,7 @@ static int __cold mdbx_env_compact(MDBX_env *env, mdbx_filehandle_t fd) {
|
|||||||
MDBX_cursor mc;
|
MDBX_cursor mc;
|
||||||
MDBX_val key, data;
|
MDBX_val key, data;
|
||||||
|
|
||||||
rc = mdbx_cursor_init(&mc, txn, FREE_DBI, NULL);
|
rc = mdbx_cursor_init(&mc, txn, FREE_DBI);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
while ((rc = mdbx_cursor_get(&mc, &key, &data, MDBX_NEXT)) == 0)
|
while ((rc = mdbx_cursor_get(&mc, &key, &data, MDBX_NEXT)) == 0)
|
||||||
@ -11111,7 +11108,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
|||||||
key.iov_len = len;
|
key.iov_len = len;
|
||||||
key.iov_base = (void *)table_name;
|
key.iov_base = (void *)table_name;
|
||||||
MDBX_cursor mc;
|
MDBX_cursor mc;
|
||||||
int rc = mdbx_cursor_init(&mc, txn, MAIN_DBI, NULL);
|
int rc = mdbx_cursor_init(&mc, txn, MAIN_DBI);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
rc = mdbx_cursor_set(&mc, &key, &data, MDBX_SET, &exact);
|
rc = mdbx_cursor_set(&mc, &key, &data, MDBX_SET, &exact);
|
||||||
@ -11247,10 +11244,9 @@ int __cold mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *arg,
|
|||||||
return MDBX_BAD_TXN;
|
return MDBX_BAD_TXN;
|
||||||
|
|
||||||
if (unlikely(txn->mt_dbflags[dbi] & DB_STALE)) {
|
if (unlikely(txn->mt_dbflags[dbi] & DB_STALE)) {
|
||||||
MDBX_cursor mc;
|
MDBX_cursor_couple cx;
|
||||||
MDBX_xcursor mx;
|
|
||||||
/* Stale, must read the DB's root. cursor_init does it for us. */
|
/* Stale, must read the DB's root. cursor_init does it for us. */
|
||||||
int rc = mdbx_cursor_init(&mc, txn, dbi, &mx);
|
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -12254,13 +12250,12 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *new_data,
|
|||||||
if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
|
if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
|
||||||
return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
||||||
|
|
||||||
MDBX_cursor mc;
|
MDBX_cursor_couple cx;
|
||||||
MDBX_xcursor mx;
|
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||||
int rc = mdbx_cursor_init(&mc, txn, dbi, &mx);
|
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
mc.mc_next = txn->mt_cursors[dbi];
|
cx.outer.mc_next = txn->mt_cursors[dbi];
|
||||||
txn->mt_cursors[dbi] = &mc;
|
txn->mt_cursors[dbi] = &cx.outer;
|
||||||
|
|
||||||
MDBX_val present_key = *key;
|
MDBX_val present_key = *key;
|
||||||
if (F_ISSET(flags, MDBX_CURRENT | MDBX_NOOVERWRITE)) {
|
if (F_ISSET(flags, MDBX_CURRENT | MDBX_NOOVERWRITE)) {
|
||||||
@ -12273,7 +12268,7 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *new_data,
|
|||||||
/* убираем лишний бит, он был признаком запрошенного режима */
|
/* убираем лишний бит, он был признаком запрошенного режима */
|
||||||
flags -= MDBX_NOOVERWRITE;
|
flags -= MDBX_NOOVERWRITE;
|
||||||
|
|
||||||
rc = mdbx_cursor_get(&mc, &present_key, old_data, MDBX_GET_BOTH);
|
rc = mdbx_cursor_get(&cx.outer, &present_key, old_data, MDBX_GET_BOTH);
|
||||||
if (rc != MDBX_SUCCESS)
|
if (rc != MDBX_SUCCESS)
|
||||||
goto bailout;
|
goto bailout;
|
||||||
|
|
||||||
@ -12288,7 +12283,7 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *new_data,
|
|||||||
if (unlikely(new_data && old_data->iov_base == new_data->iov_base))
|
if (unlikely(new_data && old_data->iov_base == new_data->iov_base))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
MDBX_val present_data;
|
MDBX_val present_data;
|
||||||
rc = mdbx_cursor_get(&mc, &present_key, &present_data, MDBX_SET_KEY);
|
rc = mdbx_cursor_get(&cx.outer, &present_key, &present_data, MDBX_SET_KEY);
|
||||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
old_data->iov_base = NULL;
|
old_data->iov_base = NULL;
|
||||||
old_data->iov_len = rc;
|
old_data->iov_len = rc;
|
||||||
@ -12299,16 +12294,16 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *new_data,
|
|||||||
*old_data = present_data;
|
*old_data = present_data;
|
||||||
goto bailout;
|
goto bailout;
|
||||||
} else {
|
} else {
|
||||||
MDBX_page *page = mc.mc_pg[mc.mc_top];
|
MDBX_page *page = cx.outer.mc_pg[cx.outer.mc_top];
|
||||||
if (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT) {
|
if (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT) {
|
||||||
if (flags & MDBX_CURRENT) {
|
if (flags & MDBX_CURRENT) {
|
||||||
/* для не-уникальных ключей позволяем update/delete только если ключ
|
/* для не-уникальных ключей позволяем update/delete только если ключ
|
||||||
* один */
|
* один */
|
||||||
MDBX_node *leaf = NODEPTR(page, mc.mc_ki[mc.mc_top]);
|
MDBX_node *leaf = NODEPTR(page, cx.outer.mc_ki[cx.outer.mc_top]);
|
||||||
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
|
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
|
||||||
mdbx_tassert(txn, XCURSOR_INITED(&mc) &&
|
mdbx_tassert(txn, XCURSOR_INITED(&cx.outer) &&
|
||||||
mc.mc_xcursor->mx_db.md_entries > 1);
|
cx.outer.mc_xcursor->mx_db.md_entries > 1);
|
||||||
if (mc.mc_xcursor->mx_db.md_entries > 1) {
|
if (cx.outer.mc_xcursor->mx_db.md_entries > 1) {
|
||||||
rc = MDBX_EMULTIVAL;
|
rc = MDBX_EMULTIVAL;
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
@ -12353,12 +12348,12 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *new_data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (likely(new_data))
|
if (likely(new_data))
|
||||||
rc = mdbx_cursor_put(&mc, key, new_data, flags);
|
rc = mdbx_cursor_put(&cx.outer, key, new_data, flags);
|
||||||
else
|
else
|
||||||
rc = mdbx_cursor_del(&mc, 0);
|
rc = mdbx_cursor_del(&cx.outer, 0);
|
||||||
|
|
||||||
bailout:
|
bailout:
|
||||||
txn->mt_cursors[dbi] = mc.mc_next;
|
txn->mt_cursors[dbi] = cx.outer.mc_next;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12382,14 +12377,13 @@ int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
|||||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||||
return MDBX_BAD_TXN;
|
return MDBX_BAD_TXN;
|
||||||
|
|
||||||
MDBX_cursor mc;
|
MDBX_cursor_couple cx;
|
||||||
MDBX_xcursor mx;
|
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||||
int rc = mdbx_cursor_init(&mc, txn, dbi, &mx);
|
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
int exact = 0;
|
int exact = 0;
|
||||||
rc = mdbx_cursor_set(&mc, key, data, MDBX_SET_KEY, &exact);
|
rc = mdbx_cursor_set(&cx.outer, key, data, MDBX_SET_KEY, &exact);
|
||||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
if (rc == MDBX_NOTFOUND && values_count)
|
if (rc == MDBX_NOTFOUND && values_count)
|
||||||
*values_count = 0;
|
*values_count = 0;
|
||||||
@ -12398,15 +12392,17 @@ int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
|||||||
|
|
||||||
if (values_count) {
|
if (values_count) {
|
||||||
*values_count = 1;
|
*values_count = 1;
|
||||||
if (mc.mc_xcursor != NULL) {
|
if (cx.outer.mc_xcursor != NULL) {
|
||||||
MDBX_node *leaf = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
|
MDBX_node *leaf = NODEPTR(cx.outer.mc_pg[cx.outer.mc_top],
|
||||||
|
cx.outer.mc_ki[cx.outer.mc_top]);
|
||||||
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
|
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
|
||||||
mdbx_tassert(txn, mc.mc_xcursor == &mx &&
|
mdbx_tassert(txn, cx.outer.mc_xcursor == &cx.inner &&
|
||||||
(mx.mx_cursor.mc_flags & C_INITIALIZED));
|
(cx.inner.mx_cursor.mc_flags & C_INITIALIZED));
|
||||||
*values_count = (sizeof(*values_count) >= sizeof(mx.mx_db.md_entries) ||
|
*values_count =
|
||||||
mx.mx_db.md_entries <= SIZE_MAX)
|
(sizeof(*values_count) >= sizeof(cx.inner.mx_db.md_entries) ||
|
||||||
? (size_t)mx.mx_db.md_entries
|
cx.inner.mx_db.md_entries <= SIZE_MAX)
|
||||||
: SIZE_MAX;
|
? (size_t)cx.inner.mx_db.md_entries
|
||||||
|
: SIZE_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12682,19 +12678,18 @@ int mdbx_set_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
|||||||
if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
|
if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
|
||||||
return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
||||||
|
|
||||||
MDBX_cursor mc;
|
MDBX_cursor_couple cx;
|
||||||
MDBX_xcursor mx;
|
|
||||||
MDBX_val old_data;
|
MDBX_val old_data;
|
||||||
int rc = mdbx_cursor_init(&mc, txn, dbi, &mx);
|
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
rc = mdbx_cursor_set(&mc, key, &old_data, MDBX_SET, NULL);
|
rc = mdbx_cursor_set(&cx.outer, key, &old_data, MDBX_SET, NULL);
|
||||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
if (rc == MDBX_NOTFOUND && data) {
|
if (rc == MDBX_NOTFOUND && data) {
|
||||||
mc.mc_next = txn->mt_cursors[dbi];
|
cx.outer.mc_next = txn->mt_cursors[dbi];
|
||||||
txn->mt_cursors[dbi] = &mc;
|
txn->mt_cursors[dbi] = &cx.outer;
|
||||||
rc = mdbx_cursor_put_attr(&mc, key, data, attr, 0);
|
rc = mdbx_cursor_put_attr(&cx.outer, key, data, attr, 0);
|
||||||
txn->mt_cursors[dbi] = mc.mc_next;
|
txn->mt_cursors[dbi] = cx.outer.mc_next;
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -12709,11 +12704,11 @@ int mdbx_set_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
|||||||
old_data.iov_len) == 0)))
|
old_data.iov_len) == 0)))
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
|
|
||||||
mc.mc_next = txn->mt_cursors[dbi];
|
cx.outer.mc_next = txn->mt_cursors[dbi];
|
||||||
txn->mt_cursors[dbi] = &mc;
|
txn->mt_cursors[dbi] = &cx.outer;
|
||||||
rc = mdbx_cursor_put_attr(&mc, key, data ? data : &old_data, attr,
|
rc = mdbx_cursor_put_attr(&cx.outer, key, data ? data : &old_data, attr,
|
||||||
MDBX_CURRENT);
|
MDBX_CURRENT);
|
||||||
txn->mt_cursors[dbi] = mc.mc_next;
|
txn->mt_cursors[dbi] = cx.outer.mc_next;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user