From 6c036add8bc0eec3461e6a2c93df85c29c59daf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:44:20 +0300 Subject: [PATCH] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BA=D0=B8=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BD=D0=B0=20=D0=B2=D1=85=D0=BE=D0=B4=D0=B5=20API-?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9=20=D1=81=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20?= =?UTF-8?q?`cursor=5Fcheck()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cold.c | 2 +- src/api-cursor.c | 155 ++++++++++++--------------------------- src/api-range-estimate.c | 34 ++++----- src/api-txn-data.c | 57 ++++++-------- src/api-txn.c | 12 ++- src/cogs.h | 14 +--- src/cursor.c | 30 ++++++++ src/cursor.h | 15 ++++ src/txn.c | 5 +- 9 files changed, 149 insertions(+), 175 deletions(-) diff --git a/src/api-cold.c b/src/api-cold.c index 8a8c8588..57e1d667 100644 --- a/src/api-cold.c +++ b/src/api-cold.c @@ -141,7 +141,7 @@ __cold int mdbx_env_warmup(const MDBX_env *env, const MDBX_txn *txn, MDBX_warmup return LOG_IFERR(MDBX_EINVAL); if (txn) { - int err = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR); + int err = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_ERROR); if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); } diff --git a/src/api-cursor.c b/src/api-cursor.c index 24288fb5..18396299 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -27,18 +27,12 @@ int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) { } int mdbx_cursor_reset(MDBX_cursor *mc) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); + int rc = cursor_check(mc, MDBX_TXN_FINISHED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); - if (likely(mc->signature == cur_signature_live)) { - cursor_reset((cursor_couple_t *)mc); - return MDBX_SUCCESS; - } - - if (likely(mc->signature == cur_signature_ready4dispose)) - return MDBX_SUCCESS; - - return LOG_IFERR(MDBX_EBADSIGN); + cursor_reset((cursor_couple_t *)mc); + return MDBX_SUCCESS; } int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { @@ -50,17 +44,17 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { return LOG_IFERR(rc); } - int rc = check_txn(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - - rc = dbi_check(txn, dbi); + int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); if (unlikely(dbi == FREE_DBI && !(txn->flags & MDBX_TXN_RDONLY))) return LOG_IFERR(MDBX_EACCESS); + rc = dbi_check(txn, dbi); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + if (unlikely(mc->backup)) /* Cursor from parent transaction */ LOG_IFERR(MDBX_EINVAL); @@ -199,12 +193,11 @@ int mdbx_cursor_close2(MDBX_cursor *mc) { } int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest) { - if (unlikely(!src)) - return LOG_IFERR(MDBX_EINVAL); - if (unlikely(src->signature != cur_signature_live)) - return LOG_IFERR((src->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check(src, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); - int rc = mdbx_cursor_bind(src->txn, dest, cursor_dbi(src)); + rc = mdbx_cursor_bind(src->txn, dest, cursor_dbi(src)); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -277,15 +270,16 @@ int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *co int mdbx_cursor_compare(const MDBX_cursor *l, const MDBX_cursor *r, bool ignore_multival) { const int incomparable = INT16_MAX + 1; + if (unlikely(!l)) return r ? -incomparable * 9 : 0; else if (unlikely(!r)) return incomparable * 9; - if (unlikely(l->signature != cur_signature_live)) - return (r->signature == cur_signature_live) ? -incomparable * 8 : 0; - if (unlikely(r->signature != cur_signature_live)) - return (l->signature == cur_signature_live) ? incomparable * 8 : 0; + if (unlikely(cursor_check_pure(l) != MDBX_SUCCESS)) + return (cursor_check_pure(r) == MDBX_SUCCESS) ? -incomparable * 8 : 0; + if (unlikely(cursor_check_pure(r) != MDBX_SUCCESS)) + return (cursor_check_pure(l) == MDBX_SUCCESS) ? incomparable * 8 : 0; if (unlikely(l->clc != r->clc)) { if (l->txn->env != r->txn->env) @@ -351,13 +345,7 @@ int mdbx_cursor_compare(const MDBX_cursor *l, const MDBX_cursor *r, bool ignore_ } int mdbx_cursor_count_ex(const MDBX_cursor *mc, size_t *count, MDBX_stat *ns, size_t bytes) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -407,11 +395,9 @@ int mdbx_cursor_count(const MDBX_cursor *mc, size_t *count) { } int mdbx_cursor_on_first(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); for (intptr_t i = 0; i <= mc->top; ++i) { if (mc->ki[i]) @@ -422,11 +408,9 @@ int mdbx_cursor_on_first(const MDBX_cursor *mc) { } int mdbx_cursor_on_first_dup(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); if (is_filled(mc) && mc->subcur) { mc = &mc->subcur->cursor; @@ -440,11 +424,9 @@ int mdbx_cursor_on_first_dup(const MDBX_cursor *mc) { } int mdbx_cursor_on_last(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); for (intptr_t i = 0; i <= mc->top; ++i) { size_t nkeys = page_numkeys(mc->pg[i]); @@ -456,11 +438,9 @@ int mdbx_cursor_on_last(const MDBX_cursor *mc) { } int mdbx_cursor_on_last_dup(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); if (is_filled(mc) && mc->subcur) { mc = &mc->subcur->cursor; @@ -475,29 +455,18 @@ int mdbx_cursor_on_last_dup(const MDBX_cursor *mc) { } int mdbx_cursor_eof(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); return is_eof(mc) ? MDBX_RESULT_TRUE : MDBX_RESULT_FALSE; } int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, MDBX_cursor_op op) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - return LOG_IFERR(cursor_ops(mc, key, data, op)); } @@ -622,19 +591,13 @@ int mdbx_cursor_get_batch(MDBX_cursor *mc, size_t *count, MDBX_val *pairs, size_ return LOG_IFERR(MDBX_EINVAL); *count = 0; - if (unlikely(mc == nullptr || limit < 4 || limit > INTPTR_MAX - 2)) + if (unlikely(limit < 4 || limit > INTPTR_MAX - 2)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - if (unlikely(mc->subcur)) return LOG_IFERR(MDBX_INCOMPATIBLE) /* must be a non-dupsort table */; @@ -703,11 +666,9 @@ bailout: /*----------------------------------------------------------------------------*/ int mdbx_cursor_set_userctx(MDBX_cursor *mc, void *ctx) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) - return LOG_IFERR(MDBX_EBADSIGN); + int rc = cursor_check(mc, 0); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t *couple = container_of(mc, cursor_couple_t, outer); couple->userctx = ctx; @@ -745,21 +706,13 @@ MDBX_dbi mdbx_cursor_dbi(const MDBX_cursor *mc) { /*----------------------------------------------------------------------------*/ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, MDBX_put_flags_t flags) { - if (unlikely(mc == nullptr || key == nullptr || data == nullptr)) + if (unlikely(key == nullptr || data == nullptr)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn_rw(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_rw(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - - cASSERT(mc, cursor_is_tracked(mc)); - /* Check this first so counter will always be zero on any early failures. */ if (unlikely(flags & MDBX_MULTIPLE)) { if (unlikely(flags & MDBX_RESERVE)) @@ -784,35 +737,21 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, MDBX_p data->iov_base = nullptr; } - if (unlikely(mc->txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) - return LOG_IFERR((mc->txn->flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN); - return LOG_IFERR(cursor_put_checklen(mc, key, data, flags)); } int mdbx_cursor_del(MDBX_cursor *mc, MDBX_put_flags_t flags) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn_rw(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_rw(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - return LOG_IFERR(cursor_del(mc, flags)); } __cold int mdbx_cursor_ignord(MDBX_cursor *mc) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check(mc, 0); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); mc->checking |= z_ignord; if (mc->subcur) diff --git a/src/api-range-estimate.c b/src/api-range-estimate.c index 5356d4da..56564da0 100644 --- a/src/api-range-estimate.c +++ b/src/api-range-estimate.c @@ -16,12 +16,6 @@ __hot static int cursor_diff(const MDBX_cursor *const __restrict x, const MDBX_c r->level = 0; r->root_nkeys = 0; - if (unlikely(x->signature != cur_signature_live)) - return (x->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN; - - if (unlikely(y->signature != cur_signature_live)) - return (y->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN; - int rc = check_txn(x->txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -146,12 +140,20 @@ __hot static ptrdiff_t estimate(const tree_t *tree, diff_t *const __restrict dr) * Range-Estimation API */ __hot int mdbx_estimate_distance(const MDBX_cursor *first, const MDBX_cursor *last, ptrdiff_t *distance_items) { - if (unlikely(first == nullptr || last == nullptr || distance_items == nullptr)) + if (unlikely(!distance_items)) return LOG_IFERR(MDBX_EINVAL); + int rc = cursor_check_pure(first); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + + rc = cursor_check_pure(last); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + *distance_items = 0; diff_t dr; - int rc = cursor_diff(last, first, &dr); + rc = cursor_diff(last, first, &dr); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -172,14 +174,10 @@ __hot int mdbx_estimate_distance(const MDBX_cursor *first, const MDBX_cursor *la __hot int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data, MDBX_cursor_op move_op, ptrdiff_t *distance_items) { - if (unlikely(cursor == nullptr || distance_items == nullptr || move_op == MDBX_GET_CURRENT || - move_op == MDBX_GET_MULTIPLE)) + if (unlikely(!distance_items || move_op == MDBX_GET_CURRENT || move_op == MDBX_GET_MULTIPLE)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(cursor->signature != cur_signature_live)) - return LOG_IFERR((cursor->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(cursor->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(cursor); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -232,10 +230,6 @@ __hot int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val __hot int mdbx_estimate_range(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *begin_key, const MDBX_val *begin_data, const MDBX_val *end_key, const MDBX_val *end_data, ptrdiff_t *size_items) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!size_items)) return LOG_IFERR(MDBX_EINVAL); @@ -248,6 +242,10 @@ __hot int mdbx_estimate_range(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val if (unlikely(begin_key == MDBX_EPSILON && end_key == MDBX_EPSILON)) return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + cursor_couple_t begin; /* LY: first, initialize cursor to refresh a DB in case it have DB_STALE */ rc = cursor_init(&begin.outer, txn, dbi); diff --git a/src/api-txn-data.c b/src/api-txn-data.c index 76bdf32a..2be54df8 100644 --- a/src/api-txn-data.c +++ b/src/api-txn-data.c @@ -51,15 +51,15 @@ __cold int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi, uint32_ } int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(canary == nullptr)) + return LOG_IFERR(MDBX_EINVAL); + + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); if (unlikely(rc != MDBX_SUCCESS)) { memset(canary, 0, sizeof(*canary)); return LOG_IFERR(rc); } - if (unlikely(canary == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - *canary = txn->canary; return MDBX_SUCCESS; } @@ -68,13 +68,13 @@ int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *d DKBUF_DEBUG; DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key)); + if (unlikely(!key || !data)) + return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(!key || !data)) - return LOG_IFERR(MDBX_EINVAL); - cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) @@ -84,15 +84,12 @@ int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *d } int mdbx_get_equal_or_great(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key || !data)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(txn->flags & MDBX_TXN_BLOCKED)) - return LOG_IFERR(MDBX_BAD_TXN); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); @@ -106,13 +103,13 @@ int mdbx_get_ex(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data DKBUF_DEBUG; DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key)); + if (unlikely(!key || !data)) + return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(!key || !data)) - return LOG_IFERR(MDBX_EINVAL); - cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) @@ -179,7 +176,7 @@ int mdbx_canary_put(MDBX_txn *txn, const MDBX_canary *canary) { * расположен в той-же странице памяти, в том числе для многостраничных * P_LARGE страниц с длинными данными. */ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -215,18 +212,15 @@ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) { } int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *data) { - int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key)) return LOG_IFERR(MDBX_EINVAL); if (unlikely(dbi <= FREE_DBI)) return LOG_IFERR(MDBX_BAD_DBI); - if (unlikely(txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) - return LOG_IFERR((txn->flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN); + int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); @@ -254,10 +248,6 @@ int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *d } int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, MDBX_put_flags_t flags) { - int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key || !data)) return LOG_IFERR(MDBX_EINVAL); @@ -268,8 +258,9 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, M MDBX_APPENDDUP | MDBX_CURRENT | MDBX_MULTIPLE))) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) - return LOG_IFERR((txn->flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN); + int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); @@ -330,10 +321,6 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, M int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *new_data, MDBX_val *old_data, MDBX_put_flags_t flags, MDBX_preserve_func preserver, void *preserver_context) { - int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key || !old_data || old_data == new_data)) return LOG_IFERR(MDBX_EINVAL); @@ -350,6 +337,10 @@ int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val * MDBX_APPENDDUP | MDBX_CURRENT))) return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) diff --git a/src/api-txn.c b/src/api-txn.c index 786e1e42..474f32fd 100644 --- a/src/api-txn.c +++ b/src/api-txn.c @@ -9,7 +9,7 @@ __attribute__((__no_sanitize_thread__, __noinline__)) #endif int mdbx_txn_straggler(const MDBX_txn *txn, int *percent) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR((rc > 0) ? -rc : rc); @@ -200,9 +200,13 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, M MDBX_txn *txn = nullptr; if (parent) { /* Nested transactions: Max 1 child, write txns only, no writemap */ - rc = check_txn_rw(parent, MDBX_TXN_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) { - if (rc == MDBX_BAD_TXN && (parent->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)) == 0) { + rc = check_txn(parent, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + + if (unlikely(parent->flags & (MDBX_TXN_RDONLY | MDBX_WRITEMAP))) { + rc = MDBX_BAD_TXN; + if ((parent->flags & MDBX_TXN_RDONLY) == 0) { ERROR("%s mode is incompatible with nested transactions", "MDBX_WRITEMAP"); rc = MDBX_INCOMPATIBLE; } diff --git a/src/cogs.h b/src/cogs.h index 7e814e7b..498e92b7 100644 --- a/src/cogs.h +++ b/src/cogs.h @@ -416,10 +416,11 @@ static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) { return MDBX_EPERM; if (unlikely(txn->flags & bad_bits)) { + if ((bad_bits & MDBX_TXN_RDONLY) && unlikely(txn->flags & MDBX_TXN_RDONLY)) + return MDBX_EACCESS; if ((bad_bits & MDBX_TXN_PARKED) == 0) return MDBX_BAD_TXN; - else - return txn_check_badbits_parked(txn, bad_bits); + return txn_check_badbits_parked(txn, bad_bits); } } @@ -437,14 +438,7 @@ static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) { } static inline int check_txn_rw(const MDBX_txn *txn, int bad_bits) { - int err = check_txn(txn, bad_bits & ~MDBX_TXN_PARKED); - if (unlikely(err)) - return err; - - if (unlikely(txn->flags & MDBX_TXN_RDONLY)) - return MDBX_EACCESS; - - return MDBX_SUCCESS; + return check_txn(txn, (bad_bits | MDBX_TXN_RDONLY) & ~MDBX_TXN_PARKED); } /*----------------------------------------------------------------------------*/ diff --git a/src/cursor.c b/src/cursor.c index 01fc8a56..8a96387d 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -2329,3 +2329,33 @@ __hot int cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_ return MDBX_EINVAL; } } + +int cursor_check(const MDBX_cursor *mc, int txn_bad_bits) { + if (unlikely(mc == nullptr)) + return MDBX_EINVAL; + + if (unlikely(mc->signature != cur_signature_live)) { + if (mc->signature != cur_signature_ready4dispose) + return MDBX_EBADSIGN; + return (txn_bad_bits > MDBX_TXN_FINISHED) ? MDBX_EINVAL : MDBX_SUCCESS; + } + + /* проверяем что курсор в связном списке для отслеживания, исключение допускается только для read-only операций для + * служебных/временных курсоров на стеке. */ + MDBX_MAYBE_UNUSED char stack_top[sizeof(void *)]; + cASSERT(mc, cursor_is_tracked(mc) || (!(txn_bad_bits & MDBX_TXN_RDONLY) && stack_top < (char *)mc && + (char *)mc - stack_top < (ptrdiff_t)globals.sys_pagesize * 4)); + + if (txn_bad_bits) { + int rc = check_txn(mc->txn, txn_bad_bits); + if (unlikely(rc != MDBX_SUCCESS)) { + cASSERT(mc, rc != MDBX_RESULT_TRUE); + return rc; + } + + if (unlikely(cursor_dbi_changed(mc))) + return MDBX_BAD_DBI; + } + + return MDBX_SUCCESS; +} diff --git a/src/cursor.h b/src/cursor.h index 4fa0e585..7f109bcc 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -292,6 +292,21 @@ MDBX_NOTHROW_PURE_FUNCTION static inline bool check_leaf_type(const MDBX_cursor return (((page_type(mp) ^ mc->checking) & (z_branch | z_leaf | z_largepage | z_dupfix)) == 0); } +MDBX_INTERNAL int cursor_check(const MDBX_cursor *mc, int txn_bad_bits); + +/* без необходимости доступа к данным, без активации припаркованных транзакций. */ +static inline int cursor_check_pure(const MDBX_cursor *mc) { + return cursor_check(mc, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); +} + +/* для чтения данных, с активацией припаркованных транзакций. */ +static inline int cursor_check_ro(const MDBX_cursor *mc) { return cursor_check(mc, MDBX_TXN_BLOCKED); } + +/* для записи данных. */ +static inline int cursor_check_rw(const MDBX_cursor *mc) { + return cursor_check(mc, (MDBX_TXN_BLOCKED - MDBX_TXN_PARKED) | MDBX_TXN_RDONLY); +} + MDBX_INTERNAL MDBX_cursor *cursor_eot(MDBX_cursor *mc, MDBX_txn *txn, const bool merge); MDBX_INTERNAL int cursor_shadow(MDBX_cursor *mc, MDBX_txn *nested, const size_t dbi); diff --git a/src/txn.c b/src/txn.c index a83cd9c8..36ddaf64 100644 --- a/src/txn.c +++ b/src/txn.c @@ -995,7 +995,10 @@ int txn_check_badbits_parked(const MDBX_txn *txn, int bad_bits) { * - но при распарковке поломанные транзакции завершаются. * - получается что транзакцию можно припарковать, потом поломать вызвав * mdbx_txn_break(), но далее любое её использование приведет к завершению - * при распарковке. */ + * при распарковке. + * + * Поэтому для припаркованных транзакций возвращается ошибка если не-включена + * авто-распарковка, либо есть другие плохие биты. */ if ((txn->flags & (bad_bits | MDBX_TXN_AUTOUNPARK)) != (MDBX_TXN_PARKED | MDBX_TXN_AUTOUNPARK)) return LOG_IFERR(MDBX_BAD_TXN);