diff --git a/src/cogs.h b/src/cogs.h index 11d7fe1d..7e814e7b 100644 --- a/src/cogs.h +++ b/src/cogs.h @@ -200,6 +200,10 @@ static inline bool check_table_flags(unsigned flags) { } } +static inline int tbl_setup_ifneed(const MDBX_env *env, volatile kvx_t *const kvx, const tree_t *const db) { + return likely(kvx->clc.v.lmax) ? MDBX_SUCCESS : tbl_setup(env, kvx, db); +} + /*----------------------------------------------------------------------------*/ MDBX_NOTHROW_PURE_FUNCTION static inline size_t pgno2bytes(const MDBX_env *env, size_t pgno) { diff --git a/src/cursor.c b/src/cursor.c index ff2c67e8..01fc8a56 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -298,10 +298,7 @@ static __always_inline int couple_init(cursor_couple_t *couple, const MDBX_txn * if (unlikely(*dbi_state & DBI_STALE)) return tbl_fetch(couple->outer.txn, cursor_dbi(&couple->outer)); - if (unlikely(kvx->clc.k.lmax == 0)) - return tbl_setup(txn->env, kvx, tree); - - return MDBX_SUCCESS; + return tbl_setup_ifneed(txn->env, kvx, tree); } __cold int cursor_init4walk(cursor_couple_t *couple, const MDBX_txn *const txn, tree_t *const tree, kvx_t *const kvx) { @@ -387,6 +384,7 @@ int cursor_dupsort_setup(MDBX_cursor *mc, const node_t *node, const page_t *mp) } mc->tree->dupfix_size = mx->nested_tree.dupfix_size; mc->clc->v.lmin = mc->clc->v.lmax = mx->nested_tree.dupfix_size; + cASSERT(mc, mc->clc->v.lmax >= mc->clc->v.lmin); } DEBUG("Sub-db dbi -%zu root page %" PRIaPGNO, cursor_dbi(&mx->cursor), mx->nested_tree.root); diff --git a/src/proto.h b/src/proto.h index f0a6657f..92bbce6d 100644 --- a/src/proto.h +++ b/src/proto.h @@ -95,7 +95,7 @@ MDBX_INTERNAL void recalculate_subpage_thresholds(MDBX_env *env); /* table.c */ MDBX_INTERNAL int __must_check_result tbl_fetch(MDBX_txn *txn, size_t dbi); -MDBX_INTERNAL int __must_check_result tbl_setup(const MDBX_env *env, kvx_t *const kvx, const tree_t *const db); +MDBX_INTERNAL int __must_check_result tbl_setup(const MDBX_env *env, volatile kvx_t *const kvx, const tree_t *const db); /* coherency.c */ MDBX_INTERNAL bool coherency_check_meta(const MDBX_env *env, const volatile meta_t *meta, bool report); diff --git a/src/table.c b/src/table.c index faa44da1..5b3e441a 100644 --- a/src/table.c +++ b/src/table.c @@ -3,28 +3,37 @@ #include "internals.h" -int tbl_setup(const MDBX_env *env, kvx_t *const kvx, const tree_t *const db) { +int tbl_setup(const MDBX_env *env, volatile kvx_t *const kvx, const tree_t *const db) { + osal_memory_fence(mo_AcquireRelease, false); + if (unlikely(!check_table_flags(db->flags))) { ERROR("incompatible or invalid db.flags (0x%x) ", db->flags); return MDBX_INCOMPATIBLE; } - if (unlikely(!kvx->clc.k.cmp)) { - kvx->clc.k.cmp = builtin_keycmp(db->flags); - kvx->clc.v.cmp = builtin_datacmp(db->flags); + + size_t v_lmin = valsize_min(db->flags); + size_t v_lmax = env_valsize_max(env, db->flags); + if ((db->flags & (MDBX_DUPFIXED | MDBX_INTEGERDUP)) != 0 && db->dupfix_size) { + if (!MDBX_DISABLE_VALIDATION && unlikely(db->dupfix_size < v_lmin || db->dupfix_size > v_lmax)) { + ERROR("db.dupfix_size (%u) <> min/max value-length (%zu/%zu)", db->dupfix_size, v_lmin, v_lmax); + return MDBX_CORRUPTED; + } + v_lmin = v_lmax = db->dupfix_size; } kvx->clc.k.lmin = keysize_min(db->flags); kvx->clc.k.lmax = env_keysize_max(env, db->flags); - kvx->clc.v.lmin = valsize_min(db->flags); - kvx->clc.v.lmax = env_valsize_max(env, db->flags); - - if ((db->flags & (MDBX_DUPFIXED | MDBX_INTEGERDUP)) != 0 && db->dupfix_size) { - if (!MDBX_DISABLE_VALIDATION && unlikely(db->dupfix_size < kvx->clc.v.lmin || db->dupfix_size > kvx->clc.v.lmax)) { - ERROR("db.dupfix_size (%u) <> min/max value-length (%zu/%zu)", db->dupfix_size, kvx->clc.v.lmin, kvx->clc.v.lmax); - return MDBX_CORRUPTED; - } - kvx->clc.v.lmin = kvx->clc.v.lmax = db->dupfix_size; + if (unlikely(!kvx->clc.k.cmp)) { + kvx->clc.v.cmp = builtin_datacmp(db->flags); + kvx->clc.k.cmp = builtin_keycmp(db->flags); } + kvx->clc.v.lmin = v_lmin; + osal_memory_fence(mo_Relaxed, true); + kvx->clc.v.lmax = v_lmax; + osal_memory_fence(mo_AcquireRelease, true); + + eASSERT(env, kvx->clc.k.lmax >= kvx->clc.k.lmin); + eASSERT(env, kvx->clc.v.lmax >= kvx->clc.v.lmin); return MDBX_SUCCESS; } @@ -86,10 +95,13 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { return MDBX_CORRUPTED; } #endif /* !MDBX_DISABLE_VALIDATION */ - rc = tbl_setup(txn->env, kvx, db); + rc = tbl_setup_ifneed(txn->env, kvx, db); if (unlikely(rc != MDBX_SUCCESS)) return rc; + if (unlikely(dbi_changed(txn, dbi))) + return MDBX_BAD_DBI; + txn->dbi_state[dbi] &= ~DBI_STALE; return MDBX_SUCCESS; }