mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-20 05:08:21 +08:00
mdbx: implement MDBX_TXN_CHECKOWNER option.
Change-Id: Ia283dc9c4d984de1e74915481118f7f4fb5ba5c8
This commit is contained in:
parent
8fa718c5f9
commit
2f2df1ee76
@ -3360,7 +3360,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
||||
0);
|
||||
|
||||
if (flags & MDBX_RDONLY) {
|
||||
txn->mt_flags = MDBX_RDONLY;
|
||||
txn->mt_flags = MDBX_RDONLY | (env->me_flags & MDBX_NOTLS);
|
||||
MDBX_reader *r = txn->mt_ro_reader;
|
||||
if (likely(env->me_flags & MDBX_ENV_TXKEY)) {
|
||||
mdbx_assert(env, !(env->me_flags & MDBX_NOTLS));
|
||||
@ -3583,6 +3583,46 @@ bailout:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_flags & bad_bits))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
#if MDBX_TXN_CHECKOWNER
|
||||
if ((txn->mt_flags & MDBX_NOTLS) == 0 &&
|
||||
unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return txn->mt_owner ? MDBX_THREAD_MISMATCH : MDBX_BAD_TXN;
|
||||
#endif /* MDBX_TXN_CHECKOWNER */
|
||||
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
static __always_inline int check_txn_rw(const MDBX_txn *txn, int bad_bits) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_flags & bad_bits))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
if (unlikely(F_ISSET(txn->mt_flags, MDBX_RDONLY)))
|
||||
return MDBX_EACCESS;
|
||||
|
||||
#if MDBX_TXN_CHECKOWNER
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return txn->mt_owner ? MDBX_THREAD_MISMATCH : MDBX_BAD_TXN;
|
||||
#endif /* MDBX_TXN_CHECKOWNER */
|
||||
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
int mdbx_txn_renew(MDBX_txn *txn) {
|
||||
int rc;
|
||||
|
||||
@ -3651,23 +3691,18 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
|
||||
flags |= env->me_flags & MDBX_WRITEMAP;
|
||||
|
||||
if (parent) {
|
||||
if (unlikely(parent->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(parent->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
/* Nested transactions: Max 1 child, write txns only, no writemap */
|
||||
rc = check_txn_rw(parent, MDBX_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (unlikely(!env->me_map))
|
||||
return MDBX_EPERM;
|
||||
#endif /* Windows */
|
||||
|
||||
/* Nested transactions: Max 1 child, write txns only, no writemap */
|
||||
flags |= parent->mt_flags;
|
||||
if (unlikely(flags & (MDBX_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED)))
|
||||
return (parent->mt_flags & MDBX_RDONLY) ? MDBX_EINVAL : MDBX_BAD_TXN;
|
||||
|
||||
/* Child txns save MDBX_pgstate and use own copy of cursors */
|
||||
flags |= parent->mt_flags;
|
||||
size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1);
|
||||
size += tsize = sizeof(MDBX_ntxn);
|
||||
} else if (flags & MDBX_RDONLY) {
|
||||
@ -3925,21 +3960,16 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) {
|
||||
}
|
||||
|
||||
int mdbx_txn_reset(MDBX_txn *txn) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(txn, 0);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
/* This call is only valid for read-only txns */
|
||||
if (unlikely(!(txn->mt_flags & MDBX_RDONLY)))
|
||||
if (unlikely((txn->mt_flags & MDBX_RDONLY) == 0))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
/* LY: don't close DBI-handles in MDBX mode */
|
||||
int rc = mdbx_txn_end(txn, MDBX_END_RESET | MDBX_END_UPDATE);
|
||||
rc = mdbx_txn_end(txn, MDBX_END_RESET | MDBX_END_UPDATE);
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
mdbx_tassert(txn, txn->mt_signature == MDBX_MT_SIGNATURE);
|
||||
mdbx_tassert(txn, txn->mt_owner == 0);
|
||||
@ -3948,14 +3978,9 @@ int mdbx_txn_reset(MDBX_txn *txn) {
|
||||
}
|
||||
|
||||
int mdbx_txn_abort(MDBX_txn *txn) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(txn, 0);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (F_ISSET(txn->mt_flags, MDBX_RDONLY))
|
||||
/* LY: don't close DBI-handles in MDBX mode */
|
||||
@ -4933,16 +4958,9 @@ static __inline bool TXN_DBI_EXIST(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
}
|
||||
|
||||
int mdbx_txn_commit(MDBX_txn *txn) {
|
||||
int rc;
|
||||
|
||||
if (unlikely(txn == NULL))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_HAS_CHILD);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
MDBX_env *env = txn->mt_env;
|
||||
#if MDBX_TXN_CHECKPID
|
||||
@ -4952,25 +4970,17 @@ int mdbx_txn_commit(MDBX_txn *txn) {
|
||||
}
|
||||
#endif /* MDBX_TXN_CHECKPID */
|
||||
|
||||
if (txn->mt_child) {
|
||||
rc = mdbx_txn_commit(txn->mt_child);
|
||||
txn->mt_child = NULL;
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* mdbx_txn_end() mode for a commit which writes nothing */
|
||||
unsigned end_mode =
|
||||
MDBX_END_EMPTY_COMMIT | MDBX_END_UPDATE | MDBX_END_SLOT | MDBX_END_FREE;
|
||||
if (unlikely(F_ISSET(txn->mt_flags, MDBX_RDONLY)))
|
||||
goto done;
|
||||
|
||||
if (unlikely(txn->mt_flags & (MDBX_TXN_FINISHED | MDBX_TXN_ERROR))) {
|
||||
mdbx_debug("error flag is set, can't commit");
|
||||
if (txn->mt_parent)
|
||||
txn->mt_parent->mt_flags |= MDBX_TXN_ERROR;
|
||||
rc = MDBX_BAD_TXN;
|
||||
goto fail;
|
||||
if (txn->mt_child) {
|
||||
rc = mdbx_txn_commit(txn->mt_child);
|
||||
txn->mt_child = NULL;
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (txn->mt_parent) {
|
||||
@ -7921,48 +7931,39 @@ 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 exact = 0;
|
||||
DKBUF;
|
||||
|
||||
mdbx_debug("===> get db %u key [%s]", dbi, DKEY(key));
|
||||
|
||||
if (unlikely(!key || !data || !txn))
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!key || !data))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
MDBX_cursor_couple cx;
|
||||
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
int exact = 0;
|
||||
return mdbx_cursor_set(&cx.outer, key, data, MDBX_SET, &exact);
|
||||
}
|
||||
|
||||
int mdbx_get2(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
|
||||
int exact = 0;
|
||||
DKBUF;
|
||||
|
||||
mdbx_debug("===> get db %u key [%s]", dbi, DKEY(key));
|
||||
|
||||
if (unlikely(!key || !data || !txn))
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!key || !data))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -7970,12 +7971,13 @@ int mdbx_get2(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
MDBX_cursor_couple cx;
|
||||
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
const int op =
|
||||
(txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT) ? MDBX_GET_BOTH : MDBX_SET_KEY;
|
||||
int exact = 0;
|
||||
rc = mdbx_cursor_set(&cx.outer, key, data, op, &exact);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
@ -7983,6 +7985,53 @@ int mdbx_get2(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
|
||||
return exact ? MDBX_SUCCESS : MDBX_RESULT_TRUE;
|
||||
}
|
||||
|
||||
int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||
size_t *values_count) {
|
||||
DKBUF;
|
||||
mdbx_debug("===> get db %u key [%s]", dbi, DKEY(key));
|
||||
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!key || !data))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
MDBX_cursor_couple cx;
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
int exact = 0;
|
||||
rc = mdbx_cursor_set(&cx.outer, key, data, MDBX_SET_KEY, &exact);
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
if (rc == MDBX_NOTFOUND && values_count)
|
||||
*values_count = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (values_count) {
|
||||
*values_count = 1;
|
||||
if (cx.outer.mc_xcursor != NULL) {
|
||||
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)) {
|
||||
mdbx_tassert(txn, cx.outer.mc_xcursor == &cx.inner &&
|
||||
(cx.inner.mx_cursor.mc_flags & C_INITIALIZED));
|
||||
*values_count =
|
||||
(sizeof(*values_count) >= sizeof(cx.inner.mx_db.md_entries) ||
|
||||
cx.inner.mx_db.md_entries <= PTRDIFF_MAX)
|
||||
? (size_t)cx.inner.mx_db.md_entries
|
||||
: PTRDIFF_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Find a sibling for a page.
|
||||
* Replaces the page at the top of the cursor's stack with the specified
|
||||
* sibling, if one exists.
|
||||
@ -8518,19 +8567,18 @@ static int mdbx_cursor_last(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data) {
|
||||
|
||||
int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
|
||||
MDBX_cursor_op op) {
|
||||
int rc;
|
||||
int exact = 0;
|
||||
int (*mfunc)(MDBX_cursor * mc, MDBX_val * key, MDBX_val * data);
|
||||
|
||||
if (unlikely(mc == NULL))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(mc->mc_txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
int rc = check_txn(mc->mc_txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
int exact = 0;
|
||||
int (*mfunc)(MDBX_cursor * mc, MDBX_val * key, MDBX_val * data);
|
||||
switch (op) {
|
||||
case MDBX_GET_CURRENT: {
|
||||
if (unlikely(!(mc->mc_flags & C_INITIALIZED)))
|
||||
@ -8726,7 +8774,7 @@ int mdbx_cursor_put(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
|
||||
MDBX_db dummy;
|
||||
unsigned mcount = 0, dcount = 0, nospill;
|
||||
size_t nsize;
|
||||
int rc = MDBX_SUCCESS, rc2;
|
||||
int rc2;
|
||||
unsigned nflags;
|
||||
DKBUF;
|
||||
|
||||
@ -8736,6 +8784,10 @@ int mdbx_cursor_put(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
|
||||
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
int rc = check_txn_rw(mc->mc_txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
env = mc->mc_txn->mt_env;
|
||||
|
||||
/* Check this first so counter will always be zero on any early failures. */
|
||||
@ -9346,7 +9398,6 @@ fail:
|
||||
int mdbx_cursor_del(MDBX_cursor *mc, unsigned flags) {
|
||||
MDBX_node *leaf;
|
||||
MDBX_page *mp;
|
||||
int rc;
|
||||
|
||||
if (unlikely(!mc))
|
||||
return MDBX_EINVAL;
|
||||
@ -9354,8 +9405,9 @@ int mdbx_cursor_del(MDBX_cursor *mc, unsigned flags) {
|
||||
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(mc->mc_txn->mt_flags & (MDBX_RDONLY | MDBX_TXN_BLOCKED)))
|
||||
return (mc->mc_txn->mt_flags & MDBX_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
||||
int rc = check_txn_rw(mc->mc_txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!(mc->mc_flags & C_INITIALIZED)))
|
||||
return MDBX_EINVAL;
|
||||
@ -10029,23 +10081,15 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
||||
return MDBX_EINVAL;
|
||||
*ret = NULL;
|
||||
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
if (unlikely(dbi == FREE_DBI && !F_ISSET(txn->mt_flags, MDBX_RDONLY)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_EACCESS;
|
||||
|
||||
const size_t size = (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT)
|
||||
? sizeof(MDBX_cursor_couple)
|
||||
@ -10053,7 +10097,7 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
||||
|
||||
MDBX_cursor *mc;
|
||||
if (likely((mc = mdbx_malloc(size)) != NULL)) {
|
||||
int rc = mdbx_cursor_init(mc, txn, dbi);
|
||||
rc = mdbx_cursor_init(mc, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
mdbx_free(mc);
|
||||
return rc;
|
||||
@ -10072,22 +10116,17 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
||||
}
|
||||
|
||||
int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) {
|
||||
if (unlikely(!mc || !txn))
|
||||
if (unlikely(!mc))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return txn->mt_owner ? MDBX_THREAD_MISMATCH : MDBX_BAD_TXN;
|
||||
|
||||
if (unlikely(txn->mt_flags & (MDBX_TXN_FINISHED | MDBX_TXN_ERROR)))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE &&
|
||||
mc->mc_signature != MDBX_MC_READY4CLOSE))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
int rc = check_txn(mc->mc_txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, mc->mc_dbi, DB_VALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -10111,19 +10150,17 @@ int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) {
|
||||
|
||||
/* Return the count of duplicate data items for the current key */
|
||||
int mdbx_cursor_count(MDBX_cursor *mc, size_t *countp) {
|
||||
if (unlikely(mc == NULL || countp == NULL))
|
||||
if (unlikely(mc == NULL))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(mc->mc_txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(mc->mc_txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(mc->mc_txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
if (unlikely(!(mc->mc_flags & C_INITIALIZED)))
|
||||
if (unlikely(countp == NULL || !(mc->mc_flags & C_INITIALIZED)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (!mc->mc_snum) {
|
||||
@ -11180,15 +11217,13 @@ static int mdbx_cursor_del0(MDBX_cursor *mc) {
|
||||
}
|
||||
|
||||
int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
|
||||
if (unlikely(!key || !txn))
|
||||
int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!key))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -11723,16 +11758,13 @@ done:
|
||||
|
||||
int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||
unsigned flags) {
|
||||
int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!key || !data || !txn))
|
||||
if (unlikely(!key || !data))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -11744,7 +11776,7 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||
return (txn->mt_flags & MDBX_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
||||
|
||||
MDBX_cursor_couple cx;
|
||||
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
cx.outer.mc_next = txn->mt_cursors[dbi];
|
||||
@ -12508,10 +12540,9 @@ int __cold mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (txn) {
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int err = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(err != MDBX_SUCCESS))
|
||||
return err;
|
||||
}
|
||||
if (env) {
|
||||
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
|
||||
@ -12549,10 +12580,9 @@ int __cold mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (txn) {
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int err = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(err != MDBX_SUCCESS))
|
||||
return err;
|
||||
}
|
||||
if (env) {
|
||||
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
|
||||
@ -12703,7 +12733,11 @@ static int mdbx_dbi_bind(MDBX_txn *txn, const MDBX_dbi dbi, unsigned user_flags,
|
||||
int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
MDBX_dbi *dbi, MDBX_cmp_func *keycmp,
|
||||
MDBX_cmp_func *datacmp) {
|
||||
if (unlikely(!txn || !dbi || (user_flags & ~VALID_FLAGS) != 0))
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!dbi || (user_flags & ~VALID_FLAGS) != 0))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
switch (user_flags &
|
||||
@ -12720,15 +12754,6 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
/* main table? */
|
||||
if (!table_name) {
|
||||
*dbi = MAIN_DBI;
|
||||
@ -12774,7 +12799,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
key.iov_len = len;
|
||||
key.iov_base = (void *)table_name;
|
||||
MDBX_cursor mc;
|
||||
int rc = mdbx_cursor_init(&mc, txn, MAIN_DBI);
|
||||
rc = mdbx_cursor_init(&mc, txn, MAIN_DBI);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
rc = mdbx_cursor_set(&mc, &key, &data, MDBX_SET, &exact);
|
||||
@ -12891,15 +12916,13 @@ int mdbx_dbi_open(MDBX_txn *txn, const char *table_name, unsigned table_flags,
|
||||
|
||||
int __cold mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *arg,
|
||||
size_t bytes) {
|
||||
if (unlikely(!arg || !txn))
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!arg))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -12912,7 +12935,7 @@ int __cold mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *arg,
|
||||
if (unlikely(txn->mt_dbflags[dbi] & DB_STALE)) {
|
||||
MDBX_cursor_couple cx;
|
||||
/* Stale, must read the DB's root. cursor_init does it for us. */
|
||||
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
}
|
||||
@ -12957,15 +12980,13 @@ int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
|
||||
|
||||
int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
|
||||
unsigned *state) {
|
||||
if (unlikely(!txn || !flags || !state))
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!flags || !state))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -13080,26 +13101,21 @@ static int mdbx_drop0(MDBX_cursor *mc, int subs) {
|
||||
}
|
||||
|
||||
int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del) {
|
||||
if (unlikely(1 < (unsigned)del || !txn))
|
||||
int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(1 < (unsigned)del))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(TXN_DBI_CHANGED(txn, dbi)))
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(F_ISSET(txn->mt_flags, MDBX_RDONLY)))
|
||||
return MDBX_EACCESS;
|
||||
|
||||
MDBX_cursor *mc;
|
||||
int rc = mdbx_cursor_open(txn, dbi, &mc);
|
||||
rc = mdbx_cursor_open(txn, dbi, &mc);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
@ -13156,14 +13172,9 @@ bailout:
|
||||
}
|
||||
|
||||
int mdbx_set_compare(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
@ -13173,14 +13184,9 @@ int mdbx_set_compare(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
|
||||
}
|
||||
|
||||
int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
@ -13568,14 +13574,9 @@ __attribute__((__no_sanitize_thread__, __noinline__))
|
||||
#endif
|
||||
int mdbx_txn_straggler(MDBX_txn *txn, int *percent)
|
||||
{
|
||||
if (unlikely(!txn))
|
||||
return (MDBX_EINVAL > 0) ? -MDBX_EINVAL : MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return (rc > 0) ? -rc : rc;
|
||||
|
||||
MDBX_env *env = txn->mt_env;
|
||||
if (unlikely((txn->mt_flags & MDBX_RDONLY) == 0)) {
|
||||
@ -13828,14 +13829,9 @@ static int __cold mdbx_env_walk(mdbx_walk_ctx_t *ctx, const char *dbi,
|
||||
|
||||
int __cold mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
|
||||
void *user) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
mdbx_walk_ctx_t ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
@ -13844,11 +13840,11 @@ int __cold mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
|
||||
ctx.mw_user = user;
|
||||
ctx.mw_visitor = visitor;
|
||||
|
||||
int rc = visitor(
|
||||
0, NUM_METAS, user, 0, MDBX_PGWALK_META,
|
||||
pgno2bytes(txn->mt_env, NUM_METAS), MDBX_page_meta, NUM_METAS,
|
||||
sizeof(MDBX_meta) * NUM_METAS, PAGEHDRSZ * NUM_METAS,
|
||||
(txn->mt_env->me_psize - sizeof(MDBX_meta) - PAGEHDRSZ) * NUM_METAS);
|
||||
rc = visitor(0, NUM_METAS, user, 0, MDBX_PGWALK_META,
|
||||
pgno2bytes(txn->mt_env, NUM_METAS), MDBX_page_meta, NUM_METAS,
|
||||
sizeof(MDBX_meta) * NUM_METAS, PAGEHDRSZ * NUM_METAS,
|
||||
(txn->mt_env->me_psize - sizeof(MDBX_meta) - PAGEHDRSZ) *
|
||||
NUM_METAS);
|
||||
if (!MDBX_IS_ERROR(rc))
|
||||
rc = mdbx_env_walk(&ctx, MDBX_PGWALK_GC, txn->mt_dbs[FREE_DBI].md_root, 0);
|
||||
if (!MDBX_IS_ERROR(rc))
|
||||
@ -13861,20 +13857,9 @@ int __cold mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
|
||||
}
|
||||
|
||||
int mdbx_canary_put(MDBX_txn *txn, const mdbx_canary *canary) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
if (unlikely(F_ISSET(txn->mt_flags, MDBX_RDONLY)))
|
||||
return MDBX_EACCESS;
|
||||
int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (likely(canary)) {
|
||||
if (txn->mt_canary.x == canary->x && txn->mt_canary.y == canary->y &&
|
||||
@ -13894,15 +13879,13 @@ int mdbx_canary_put(MDBX_txn *txn, const mdbx_canary *canary) {
|
||||
}
|
||||
|
||||
int mdbx_canary_get(MDBX_txn *txn, mdbx_canary *canary) {
|
||||
if (unlikely(txn == NULL || canary == NULL))
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(canary == NULL))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
*canary = txn->mt_canary;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
@ -13984,6 +13967,13 @@ __hot static int cursor_diff(const MDBX_cursor *const __restrict x,
|
||||
x->mc_signature != MDBX_MC_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
int rc = check_txn(x->mc_txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(x->mc_txn != y->mc_txn))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
if (unlikely(y->mc_dbi != x->mc_dbi))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -14144,6 +14134,10 @@ int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data,
|
||||
if (unlikely(cursor->mc_signature != MDBX_MC_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
int rc = check_txn(cursor->mc_txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (!(cursor->mc_flags & C_INITIALIZED))
|
||||
return MDBX_ENODATA;
|
||||
|
||||
@ -14152,7 +14146,7 @@ int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data,
|
||||
next.outer.mc_xcursor = NULL;
|
||||
if (cursor->mc_db->md_flags & MDBX_DUPSORT) {
|
||||
next.outer.mc_xcursor = &next.inner;
|
||||
int rc = mdbx_xcursor_init0(&next.outer);
|
||||
rc = mdbx_xcursor_init0(&next.outer);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
MDBX_xcursor *mx = &container_of(cursor, MDBX_cursor_couple, outer)->inner;
|
||||
@ -14177,7 +14171,7 @@ int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data,
|
||||
key = &stub;
|
||||
}
|
||||
|
||||
int rc = mdbx_cursor_get(&next.outer, key, data, move_op);
|
||||
rc = mdbx_cursor_get(&next.outer, key, data, move_op);
|
||||
if (unlikely(rc != MDBX_SUCCESS &&
|
||||
(rc != MDBX_NOTFOUND || !(next.outer.mc_flags & C_INITIALIZED))))
|
||||
return rc;
|
||||
@ -14193,8 +14187,11 @@ static int mdbx_is_samedata(const MDBX_val *a, const MDBX_val *b) {
|
||||
int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
||||
MDBX_val *begin_data, MDBX_val *end_key,
|
||||
MDBX_val *end_data, ptrdiff_t *size_items) {
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!txn || !size_items))
|
||||
if (unlikely(!size_items))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(begin_data && (begin_key == NULL || begin_key == MDBX_EPSILON)))
|
||||
@ -14206,21 +14203,12 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
||||
if (unlikely(begin_key == MDBX_EPSILON && end_key == MDBX_EPSILON))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
MDBX_cursor_couple begin;
|
||||
/* LY: first, initialize cursor to refresh a DB in case it have DB_STALE */
|
||||
int rc = mdbx_cursor_init(&begin.outer, txn, dbi);
|
||||
rc = mdbx_cursor_init(&begin.outer, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
@ -14374,15 +14362,13 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
||||
*/
|
||||
int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *new_data,
|
||||
MDBX_val *old_data, unsigned flags) {
|
||||
if (unlikely(!key || !old_data || !txn || old_data == new_data))
|
||||
int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!key || !old_data || old_data == new_data))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(old_data->iov_base == NULL && old_data->iov_len))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -14396,11 +14382,8 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *new_data,
|
||||
MDBX_APPEND | MDBX_APPENDDUP | MDBX_CURRENT)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_flags & (MDBX_RDONLY | MDBX_TXN_BLOCKED)))
|
||||
return (txn->mt_flags & MDBX_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
||||
|
||||
MDBX_cursor_couple cx;
|
||||
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
cx.outer.mc_next = txn->mt_cursors[dbi];
|
||||
@ -14506,58 +14489,6 @@ bailout:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||
size_t *values_count) {
|
||||
DKBUF;
|
||||
mdbx_debug("===> get db %u key [%s]", dbi, DKEY(key));
|
||||
|
||||
if (unlikely(!key || !data || !txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
MDBX_cursor_couple cx;
|
||||
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
int exact = 0;
|
||||
rc = mdbx_cursor_set(&cx.outer, key, data, MDBX_SET_KEY, &exact);
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
if (rc == MDBX_NOTFOUND && values_count)
|
||||
*values_count = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (values_count) {
|
||||
*values_count = 1;
|
||||
if (cx.outer.mc_xcursor != NULL) {
|
||||
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)) {
|
||||
mdbx_tassert(txn, cx.outer.mc_xcursor == &cx.inner &&
|
||||
(cx.inner.mx_cursor.mc_flags & C_INITIALIZED));
|
||||
*values_count =
|
||||
(sizeof(*values_count) >= sizeof(cx.inner.mx_db.md_entries) ||
|
||||
cx.inner.mx_db.md_entries <= PTRDIFF_MAX)
|
||||
? (size_t)cx.inner.mx_db.md_entries
|
||||
: PTRDIFF_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Функция сообщает находится ли указанный адрес в "грязной" странице у
|
||||
* заданной пишущей транзакции. В конечном счете это позволяет избавиться от
|
||||
* лишнего копирования данных из НЕ-грязных страниц.
|
||||
@ -14581,16 +14512,11 @@ int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||
* расположен в той-же странице памяти, в том числе для многостраничных
|
||||
* P_OVERFLOW страниц с длинными данными. */
|
||||
int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
|
||||
if (unlikely(txn->mt_flags & MDBX_RDONLY))
|
||||
if (txn->mt_flags & MDBX_RDONLY)
|
||||
return MDBX_RESULT_FALSE;
|
||||
|
||||
const MDBX_env *env = txn->mt_env;
|
||||
@ -14645,14 +14571,9 @@ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) {
|
||||
|
||||
int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
|
||||
uint64_t increment) {
|
||||
if (unlikely(!txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(txn->mt_owner != mdbx_thread_self()))
|
||||
return MDBX_THREAD_MISMATCH;
|
||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
@ -14663,7 +14584,7 @@ int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
|
||||
if (unlikely(txn->mt_dbflags[dbi] & DB_STALE)) {
|
||||
MDBX_cursor_couple cx;
|
||||
/* Stale, must read the DB's root. cursor_init does it for us. */
|
||||
int rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
}
|
||||
@ -14673,10 +14594,7 @@ int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
|
||||
*result = dbs->md_seq;
|
||||
|
||||
if (likely(increment > 0)) {
|
||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
|
||||
if (unlikely(F_ISSET(txn->mt_flags, MDBX_RDONLY)))
|
||||
if (unlikely(txn->mt_flags & MDBX_RDONLY))
|
||||
return MDBX_EACCESS;
|
||||
|
||||
uint64_t new = dbs->md_seq + increment;
|
||||
|
@ -200,6 +200,11 @@
|
||||
#define MDBX_TXN_CHECKPID_CONFIG MDBX_TXN_CHECKPID
|
||||
#endif /* MDBX_TXN_CHECKPID */
|
||||
|
||||
#ifndef MDBX_TXN_CHECKOWNER
|
||||
#define MDBX_TXN_CHECKOWNER_CONFIG AUTO
|
||||
#define MDBX_TXN_CHECKOWNER 1
|
||||
#endif /* MDBX_TXN_CHECKOWNER */
|
||||
|
||||
#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
|
||||
#if defined(MDBX_TOOLS)
|
||||
extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
|
||||
|
Loading…
x
Reference in New Issue
Block a user