diff options
-rw-r--r-- | plugins/Dbx_mdb/src/mdbx/bits.h | 6 | ||||
-rw-r--r-- | plugins/Dbx_mdb/src/mdbx/defs.h | 58 | ||||
-rw-r--r-- | plugins/Dbx_mdb/src/mdbx/lck-windows.c | 9 | ||||
-rw-r--r-- | plugins/Dbx_mdb/src/mdbx/mdbx.c | 152 | ||||
-rw-r--r-- | plugins/Dbx_mdb/src/mdbx/mdbx.h | 14 | ||||
-rw-r--r-- | plugins/Dbx_mdb/src/mdbx/osal.h | 2 |
6 files changed, 177 insertions, 64 deletions
diff --git a/plugins/Dbx_mdb/src/mdbx/bits.h b/plugins/Dbx_mdb/src/mdbx/bits.h index 74b30c628a..4d3a50cc0b 100644 --- a/plugins/Dbx_mdb/src/mdbx/bits.h +++ b/plugins/Dbx_mdb/src/mdbx/bits.h @@ -48,6 +48,7 @@ #pragma warning(disable : 4710) /* 'xyz': function not inlined */ #pragma warning(disable : 4711) /* function 'xyz' selected for automatic inline expansion */ #pragma warning(disable : 4201) /* nonstandard extension used : nameless struct / union */ +#pragma warning(disable : 4702) /* unreachable code */ #pragma warning(disable : 4706) /* assignment within conditional expression */ #pragma warning(disable : 4127) /* conditional expression is constant */ #pragma warning(disable : 4324) /* 'xyz': structure was padded due to alignment specifier */ @@ -405,7 +406,7 @@ typedef struct MDBX_lockinfo { }; union { - volatile uint32_t mti_reader_finished_flag; + volatile uint32_t mti_readers_refresh_flag; uint64_t align_reader_finished_flag; }; @@ -553,7 +554,8 @@ struct MDBX_txn { /* Transaction Flags */ /* mdbx_txn_begin() flags */ -#define MDBX_TXN_BEGIN_FLAGS (MDBX_NOMETASYNC | MDBX_NOSYNC | MDBX_RDONLY) +#define MDBX_TXN_BEGIN_FLAGS \ + (MDBX_NOMETASYNC | MDBX_NOSYNC | MDBX_RDONLY | MDBX_TRYTXN) #define MDBX_TXN_NOMETASYNC \ MDBX_NOMETASYNC /* don't sync meta for this txn on commit */ #define MDBX_TXN_NOSYNC MDBX_NOSYNC /* don't sync this txn on commit */ diff --git a/plugins/Dbx_mdb/src/mdbx/defs.h b/plugins/Dbx_mdb/src/mdbx/defs.h index ed1a87e8a4..800553bb17 100644 --- a/plugins/Dbx_mdb/src/mdbx/defs.h +++ b/plugins/Dbx_mdb/src/mdbx/defs.h @@ -139,13 +139,50 @@ # endif #endif /* __deprecated */ -#ifndef __packed -# if defined(__GNUC__) || __has_attribute(packed) -# define __packed __attribute__((packed)) -# else -# define __packed -# endif -#endif /* __packed */ +#if !defined(__noop) && !defined(_MSC_VER) +# ifdef __cplusplus + static inline void __noop_consume_args() {} + template <typename First, typename... Rest> + static inline void + __noop_consume_args(const First &first, const Rest &... rest) { + (void) first; __noop_consume_args(rest...); + } +# define __noop(...) __noop_consume_args(__VA_ARGS__) +# elif defined(__GNUC__) && (!defined(__STRICT_ANSI__) || !__STRICT_ANSI__) + static __inline void __noop_consume_args(void* anchor, ...) { + (void) anchor; + } +# define __noop(...) __noop_consume_args(0, ##__VA_ARGS__) +# else +# define __noop(...) do {} while(0) +# endif +#endif /* __noop */ + +#ifndef __fallthrough +# if __GNUC_PREREQ(7, 0) || __has_attribute(fallthrough) +# define __fallthrough __attribute__((fallthrough)) +# else +# define __fallthrough __noop() +# endif +#endif /* __fallthrough */ + +#ifndef __unreachable +# if __GNUC_PREREQ(4,5) +# define __unreachable() __builtin_unreachable() +# elif defined(_MSC_VER) +# define __unreachable() __assume(0) +# else +# define __unreachable() __noop() +# endif +#endif /* __unreachable */ + +#ifndef __prefetch +# if defined(__GNUC__) || defined(__clang__) +# define __prefetch(ptr) __builtin_prefetch(ptr) +# else +# define __prefetch(ptr) __noop(ptr) +# endif +#endif /* __prefetch */ #ifndef __aligned # if defined(__GNUC__) || __has_attribute(aligned) @@ -283,13 +320,6 @@ # endif #endif /* unlikely */ -#if !defined(__noop) && !defined(_MSC_VER) - static __inline int __do_noop(void* crutch, ...) { - (void) crutch; return 0; - } -# define __noop(...) __do_noop(0, __VA_ARGS__) -#endif /* __noop */ - /* Wrapper around __func__, which is a C99 feature */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L # define mdbx_func_ __func__ diff --git a/plugins/Dbx_mdb/src/mdbx/lck-windows.c b/plugins/Dbx_mdb/src/mdbx/lck-windows.c index 66591db912..0582b28d78 100644 --- a/plugins/Dbx_mdb/src/mdbx/lck-windows.c +++ b/plugins/Dbx_mdb/src/mdbx/lck-windows.c @@ -126,10 +126,13 @@ static __inline BOOL funlock(mdbx_filehandle_t fd, uint64_t offset, #define LCK_BODY LCK_BODY_OFFSET, LCK_BODY_LEN #define LCK_WHOLE 0, LCK_MAXLEN -int mdbx_txn_lock(MDBX_env *env) { - if (flock(env->me_fd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_BODY)) +int mdbx_txn_lock(MDBX_env *env, bool dontwait) { + if (flock(env->me_fd, dontwait ? (LCK_EXCLUSIVE | LCK_DONTWAIT) + : (LCK_EXCLUSIVE | LCK_WAITFOR), + LCK_BODY)) return MDBX_SUCCESS; - return GetLastError(); + int rc = GetLastError(); + return (!dontwait || rc != ERROR_LOCK_VIOLATION) ? rc : MDBX_BUSY; } void mdbx_txn_unlock(MDBX_env *env) { diff --git a/plugins/Dbx_mdb/src/mdbx/mdbx.c b/plugins/Dbx_mdb/src/mdbx/mdbx.c index 897051a12b..7ecb59008b 100644 --- a/plugins/Dbx_mdb/src/mdbx/mdbx.c +++ b/plugins/Dbx_mdb/src/mdbx/mdbx.c @@ -203,7 +203,8 @@ static bool mdbx_pnl_check(MDBX_PNL pl) { if (pl) { for (const pgno_t *ptr = pl + pl[0]; --ptr > pl;) { assert(MDBX_PNL_ORDERED(ptr[0], ptr[1])); - if (unlikely(MDBX_PNL_DISORDERED(ptr[0], ptr[1]))) + assert(ptr[0] >= NUM_METAS); + if (unlikely(MDBX_PNL_DISORDERED(ptr[0], ptr[1]) || ptr[0] < NUM_METAS)) return false; } } @@ -499,6 +500,13 @@ static unsigned __hot mdbx_mid2l_search(MDBX_ID2L pnl, pgno_t id) { int val = 0; unsigned n = (unsigned)pnl[0].mid; +#if MDBX_DEBUG + for (const MDBX_ID2 *ptr = pnl + pnl[0].mid; --ptr > pnl;) { + assert(ptr[0].mid < ptr[1].mid); + assert(ptr[0].mid >= NUM_METAS); + } +#endif + while (n > 0) { unsigned pivot = n >> 1; cursor = base + pivot + 1; @@ -548,6 +556,14 @@ static int mdbx_mid2l_insert(MDBX_ID2L pnl, MDBX_ID2 *id) { * [in] id The ID2 to append. * Returns 0 on success, -2 if the ID2L is too big. */ static int mdbx_mid2l_append(MDBX_ID2L pnl, MDBX_ID2 *id) { +#if MDBX_DEBUG + for (unsigned i = pnl[0].mid; i > 0; --i) { + assert(pnl[i].mid != id->mid); + if (unlikely(pnl[i].mid == id->mid)) + return -1; + } +#endif + /* Too big? */ if (unlikely(pnl[0].mid >= MDBX_PNL_UM_MAX)) return -2; @@ -692,6 +708,7 @@ static const char *__mdbx_strerr(int errnum) { "DUPFIXED size", "MDBX_BAD_DBI: The specified DBI handle was closed/changed unexpectedly", "MDBX_PROBLEM: Unexpected problem - txn should abort", + "MDBX_BUSY: Another write transation is started", }; if (errnum >= MDBX_KEYEXIST && errnum <= MDBX_LAST_ERRCODE) { @@ -1035,6 +1052,9 @@ static MDBX_page *mdbx_page_malloc(MDBX_txn *txn, unsigned num) { skip += pgno2bytes(env, num - 1); memset((char *)np + skip, 0, size - skip); } +#if MDBX_DEBUG + np->mp_pgno = 0; +#endif VALGRIND_MAKE_MEM_UNDEFINED(np, size); np->mp_flags = 0; np->mp_pages = num; @@ -1045,6 +1065,9 @@ static MDBX_page *mdbx_page_malloc(MDBX_txn *txn, unsigned num) { * Saves single pages to a list, for future reuse. * (This is not used for multi-page overflow pages.) */ static __inline void mdbx_page_free(MDBX_env *env, MDBX_page *mp) { +#if MDBX_DEBUG + mp->mp_pgno = MAX_PAGENO; +#endif mp->mp_next = env->me_dpages; VALGRIND_MEMPOOL_FREE(env, mp); env->me_dpages = mp; @@ -1067,9 +1090,9 @@ static void mdbx_dlist_free(MDBX_txn *txn) { MDBX_ID2L dl = txn->mt_rw_dirtylist; size_t i, n = dl[0].mid; - for (i = 1; i <= n; i++) { + for (i = 1; i <= n; i++) mdbx_dpage_free(env, dl[i].mptr); - } + dl[0].mid = 0; } @@ -1111,6 +1134,7 @@ static int mdbx_page_loose(MDBX_cursor *mc, MDBX_page *mp) { if ((mp->mp_flags & P_DIRTY) && mc->mc_dbi != FREE_DBI) { if (txn->mt_parent) { + mdbx_cassert(mc, (txn->mt_env->me_flags & MDBX_WRITEMAP) == 0); MDBX_ID2 *dl = txn->mt_rw_dirtylist; /* If txn has a parent, * make sure the page is in our dirty list. */ @@ -1423,24 +1447,28 @@ static __inline bool mdbx_meta_ot(const enum meta_choise_mode mode, mdbx_jitter4testing(true); txnid_t txnid_a = mdbx_meta_txnid_fluid(env, a); txnid_t txnid_b = mdbx_meta_txnid_fluid(env, b); - if (txnid_a == txnid_b) - return META_IS_STEADY(b) || (META_IS_WEAK(a) && !META_IS_WEAK(a)); mdbx_jitter4testing(true); switch (mode) { default: assert(false); - /* fall through */ + __unreachable(); + /* fall through */ + __fallthrough; case prefer_steady: if (META_IS_STEADY(a) != META_IS_STEADY(b)) return META_IS_STEADY(b); - /* fall through */ + /* fall through */ + __fallthrough; case prefer_noweak: if (META_IS_WEAK(a) != META_IS_WEAK(b)) return !META_IS_WEAK(b); - /* fall through */ + /* fall through */ + __fallthrough; case prefer_last: mdbx_jitter4testing(true); + if (txnid_a == txnid_b) + return META_IS_STEADY(b) || (META_IS_WEAK(a) && !META_IS_WEAK(b)); return txnid_a < txnid_b; } } @@ -1532,16 +1560,23 @@ static txnid_t mdbx_find_oldest(MDBX_txn *txn) { const MDBX_env *env = txn->mt_env; MDBX_lockinfo *const lck = env->me_lck; - txnid_t oldest = mdbx_reclaiming_detent(env); - mdbx_tassert(txn, oldest <= txn->mt_txnid - 1); + const txnid_t edge = mdbx_reclaiming_detent(env); + mdbx_tassert(txn, edge <= txn->mt_txnid - 1); const txnid_t last_oldest = lck->mti_oldest; - mdbx_tassert(txn, oldest >= last_oldest); - if (last_oldest == oldest || - lck->mti_reader_finished_flag == MDBX_STRING_TETRAD("None")) + mdbx_tassert(txn, edge >= last_oldest); + if (last_oldest == edge) + return edge; + + const uint32_t nothing_changed = MDBX_STRING_TETRAD("None"); + const uint32_t snap_readers_refresh_flag = lck->mti_readers_refresh_flag; + mdbx_jitter4testing(false); + if (snap_readers_refresh_flag == nothing_changed) return last_oldest; + txnid_t oldest = edge; + lck->mti_readers_refresh_flag = nothing_changed; + mdbx_coherent_barrier(); const unsigned snap_nreaders = lck->mti_numreaders; - lck->mti_reader_finished_flag = MDBX_STRING_TETRAD("None"); for (unsigned i = 0; i < snap_nreaders; ++i) { if (lck->mti_readers[i].mr_pid) { /* mdbx_jitter4testing(true); */ @@ -1549,7 +1584,7 @@ static txnid_t mdbx_find_oldest(MDBX_txn *txn) { if (oldest > snap && last_oldest <= /* ignore pending updates */ snap) { oldest = snap; if (oldest == last_oldest) - break; + return oldest; } } } @@ -2177,6 +2212,7 @@ static int mdbx_page_touch(MDBX_cursor *mc) { mc->mc_db->md_root = pgno; } } else if (txn->mt_parent && !IS_SUBP(mp)) { + mdbx_tassert(txn, (txn->mt_env->me_flags & MDBX_WRITEMAP) == 0); MDBX_ID2 mid, *dl = txn->mt_rw_dirtylist; pgno = mp->mp_pgno; /* If txn has a parent, make sure the page is in our dirty list. */ @@ -2263,7 +2299,7 @@ int mdbx_env_sync(MDBX_env *env, int force) { (!env->me_txn0 || env->me_txn0->mt_owner != mdbx_thread_self()); if (outside_txn) { - int rc = mdbx_txn_lock(env); + int rc = mdbx_txn_lock(env, false); if (unlikely(rc != MDBX_SUCCESS)) return rc; } @@ -2292,7 +2328,7 @@ int mdbx_env_sync(MDBX_env *env, int force) { if (unlikely(rc != MDBX_SUCCESS)) return rc; - rc = mdbx_txn_lock(env); + rc = mdbx_txn_lock(env, false); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -2504,6 +2540,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) { mdbx_assert(env, r->mr_tid == mdbx_thread_self()); mdbx_assert(env, r->mr_txnid == snap); mdbx_coherent_barrier(); + env->me_lck->mti_readers_refresh_flag = true; } mdbx_jitter4testing(true); @@ -2519,12 +2556,10 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) { mdbx_compiler_barrier(); if (likely(meta == mdbx_meta_head(env) && snap == mdbx_meta_txnid_fluid(env, meta) && - snap >= env->me_oldest[0])) { + snap >= *env->me_oldest)) { mdbx_jitter4testing(false); break; } - if (env->me_lck) - env->me_lck->mti_reader_finished_flag = true; } if (unlikely(txn->mt_txnid == 0)) { @@ -2538,7 +2573,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) { } else { /* Not yet touching txn == env->me_txn0, it may be active */ mdbx_jitter4testing(false); - rc = mdbx_txn_lock(env); + rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TRYTXN)); if (unlikely(rc)) return rc; @@ -2602,6 +2637,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) { if (rc != MDBX_SUCCESS) goto bailout; } + txn->mt_owner = mdbx_thread_self(); return MDBX_SUCCESS; } bailout: @@ -2619,14 +2655,15 @@ int mdbx_txn_renew(MDBX_txn *txn) { 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(!F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY | MDBX_TXN_FINISHED))) return MDBX_EINVAL; + if (unlikely(txn->mt_owner != 0)) + return MDBX_THREAD_MISMATCH; + rc = mdbx_txn_renew0(txn, MDBX_TXN_RDONLY); if (rc == MDBX_SUCCESS) { + txn->mt_owner = mdbx_thread_self(); mdbx_debug("renew txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, txn->mt_txnid, (txn->mt_flags & MDBX_TXN_RDONLY) ? 'r' : 'w', @@ -2749,7 +2786,6 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, if (txn != env->me_txn0) free(txn); } else { - txn->mt_owner = mdbx_thread_self(); txn->mt_signature = MDBX_MT_SIGNATURE; *ret = txn; mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO @@ -2828,7 +2864,7 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) { if (F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)) { if (txn->mt_ro_reader) { txn->mt_ro_reader->mr_txnid = ~(txnid_t)0; - env->me_lck->mti_reader_finished_flag = true; + env->me_lck->mti_readers_refresh_flag = true; if (mode & MDBX_END_SLOT) { if ((env->me_flags & MDBX_ENV_TXKEY) == 0) txn->mt_ro_reader->mr_pid = 0; @@ -2909,7 +2945,12 @@ int mdbx_txn_reset(MDBX_txn *txn) { return MDBX_EINVAL; /* LY: don't close DBI-handles in MDBX mode */ - return mdbx_txn_end(txn, MDBX_END_RESET | MDBX_END_UPDATE); + int rc = mdbx_txn_end(txn, MDBX_END_RESET | MDBX_END_UPDATE); + if (rc == MDBX_SUCCESS) { + assert(txn->mt_signature == MDBX_MT_SIGNATURE); + assert(txn->mt_owner == 0); + } + return rc; } int mdbx_txn_abort(MDBX_txn *txn) { @@ -2919,7 +2960,8 @@ int mdbx_txn_abort(MDBX_txn *txn) { if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE)) return MDBX_EBADSIGN; - if (unlikely(txn->mt_owner != mdbx_thread_self())) + if (unlikely(txn->mt_owner != + ((txn->mt_flags & MDBX_TXN_FINISHED) ? 0 : mdbx_thread_self()))) return MDBX_THREAD_MISMATCH; if (F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)) @@ -3047,11 +3089,10 @@ again_on_freelist_change: !(lifo && env->me_last_reclaimed > 1)) { /* Put loose page numbers in mt_free_pages, * since unable to return them to me_reclaimed_pglist. */ - MDBX_page *mp = txn->mt_loose_pages; if (unlikely((rc = mdbx_pnl_need(&txn->mt_befree_pages, txn->mt_loose_count)) != 0)) return rc; - for (; mp; mp = NEXT_LOOSE_PAGE(mp)) + for (MDBX_page *mp = txn->mt_loose_pages; mp; mp = NEXT_LOOSE_PAGE(mp)) mdbx_pnl_xappend(txn->mt_befree_pages, mp->mp_pgno); } else { /* Room for loose pages + temp PNL with same */ @@ -3069,6 +3110,25 @@ again_on_freelist_change: mdbx_pnl_xmerge(env->me_reclaimed_pglist, loose); } + MDBX_ID2L dl = txn->mt_rw_dirtylist; + for (MDBX_page *mp = txn->mt_loose_pages; mp;) { + mdbx_tassert(txn, mp->mp_pgno < txn->mt_next_pgno); + mdbx_ensure(env, mp->mp_pgno >= NUM_METAS); + + unsigned s, d; + for (s = d = 0; ++s <= dl[0].mid;) + if (dl[s].mid != mp->mp_pgno) + dl[++d] = dl[s]; + + dl[0].mid -= 1; + mdbx_tassert(txn, dl[0].mid == d); + + MDBX_page *dp = mp; + mp = NEXT_LOOSE_PAGE(mp); + if ((env->me_flags & MDBX_WRITEMAP) == 0) + mdbx_dpage_free(env, dp); + } + txn->mt_loose_pages = NULL; txn->mt_loose_count = 0; } @@ -3295,6 +3355,7 @@ again_on_freelist_change: mc.mc_flags |= C_RECLAIMING; rc = mdbx_cursor_put(&mc, &key, &data, MDBX_CURRENT); mc.mc_flags ^= C_RECLAIMING; + mdbx_tassert(txn, mdbx_pnl_check(rpl_end)); mdbx_tassert( txn, cleanup_reclaimed_pos == (txn->mt_lifo_reclaimed ? txn->mt_lifo_reclaimed[0] : 0)); @@ -3694,6 +3755,7 @@ int mdbx_txn_commit(MDBX_txn *txn) { } if (unlikely(rc != MDBX_SUCCESS)) goto fail; + env->me_lck->mti_readers_refresh_flag = false; end_mode = MDBX_END_COMMITTED | MDBX_END_UPDATE | MDBX_END_EOTDONE; done: @@ -3767,7 +3829,8 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) { } if (page.mp_meta.mm_magic_and_version != MDBX_DATA_MAGIC) { - mdbx_error("meta[%u] has invalid magic/version", meta_number); + mdbx_error("meta[%u] has invalid magic/version MDBX_DEVEL=%d", + meta_number, MDBX_DEVEL); return ((page.mp_meta.mm_magic_and_version >> 8) != MDBX_MAGIC) ? MDBX_INVALID : MDBX_VERSION_MISMATCH; @@ -3921,7 +3984,7 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) { continue; } - if (mdbx_meta_ot(prefer_steady, env, meta, &page.mp_meta)) { + if (mdbx_meta_ot(prefer_noweak, env, meta, &page.mp_meta)) { *meta = page.mp_meta; if (META_IS_WEAK(meta)) loop_limit += 1; /* LY: should re-read to hush race with update */ @@ -4398,7 +4461,7 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, return MDBX_EACCESS; if (outside_txn) { - int err = mdbx_txn_lock(env); + int err = mdbx_txn_lock(env, false); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -4473,7 +4536,8 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, if ((size_t)size_now >= MAX_MAPSIZE / 2) size_upper = MAX_MAPSIZE; else if (MAX_MAPSIZE != MAX_MAPSIZE32 && - (size_t)size_now >= MAX_MAPSIZE32 / 2) + (size_t)size_now >= MAX_MAPSIZE32 / 2 && + (size_t)size_now <= MAX_MAPSIZE32 / 4 * 3) size_upper = MAX_MAPSIZE32; else { size_upper = size_now + size_now; @@ -4703,9 +4767,11 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) { || lck_rc != MDBX_RESULT_TRUE /* not exclusive */) { /* use present params from db */ err = mdbx_env_set_geometry( - env, meta.mm_geo.lower * meta.mm_psize, meta.mm_geo.now * meta.mm_psize, - meta.mm_geo.upper * meta.mm_psize, meta.mm_geo.grow * meta.mm_psize, - meta.mm_geo.shrink * meta.mm_psize, meta.mm_psize); + env, meta.mm_geo.lower * (uint64_t)meta.mm_psize, + meta.mm_geo.now * (uint64_t)meta.mm_psize, + meta.mm_geo.upper * (uint64_t)meta.mm_psize, + meta.mm_geo.grow * (uint64_t)meta.mm_psize, + meta.mm_geo.shrink * (uint64_t)meta.mm_psize, meta.mm_psize); if (unlikely(err != MDBX_SUCCESS)) { mdbx_error("could not use present dbsize-params from db"); return MDBX_INCOMPATIBLE; @@ -7005,7 +7071,8 @@ int mdbx_cursor_put(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, offset *= 4; /* space for 4 more */ break; } - /* FALLTHRU: Big enough MDBX_DUPFIXED sub-page */ + /* FALLTHRU: Big enough MDBX_DUPFIXaED sub-page */ + __fallthrough; case MDBX_CURRENT | MDBX_NODUPDATA: case MDBX_CURRENT: fp->mp_flags |= P_DIRTY; @@ -9723,7 +9790,7 @@ static int __cold mdbx_env_copy_asis(MDBX_env *env, mdbx_filehandle_t fd) { goto bailout; /* FIXME: or just return? */ /* Temporarily block writers until we snapshot the meta pages */ - rc = mdbx_txn_lock(env); + rc = mdbx_txn_lock(env, false); if (unlikely(rc != MDBX_SUCCESS)) goto bailout; @@ -9808,7 +9875,7 @@ int __cold mdbx_env_set_flags(MDBX_env *env, unsigned flags, int onoff) { if (unlikely(flags & ~CHANGEABLE)) return MDBX_EINVAL; - int rc = mdbx_txn_lock(env); + int rc = mdbx_txn_lock(env, false); if (unlikely(rc)) return rc; @@ -10596,7 +10663,7 @@ int __cold mdbx_reader_check0(MDBX_env *env, int rdt_locked, int *dead) { mdbx_debug("clear stale reader pid %" PRIuPTR " txn %" PRIaTXN "", (size_t)pid, lck->mti_readers[j].mr_txnid); lck->mti_readers[j].mr_pid = 0; - lck->mti_reader_finished_flag = true; + lck->mti_readers_refresh_flag = true; count++; } } @@ -10705,7 +10772,7 @@ static txnid_t __cold mdbx_oomkick(MDBX_env *env, const txnid_t laggard) { if (rc) { asleep->mr_txnid = ~(txnid_t)0; - env->me_lck->mti_reader_finished_flag = true; + env->me_lck->mti_readers_refresh_flag = true; if (rc > 1) { asleep->mr_tid = 0; asleep->mr_pid = 0; @@ -10844,6 +10911,7 @@ static int __cold mdbx_env_walk(mdbx_walk_ctx_t *ctx, const char *dbi, break; case P_META: case P_OVERFLOW: + __fallthrough; default: return MDBX_CORRUPTED; } diff --git a/plugins/Dbx_mdb/src/mdbx/mdbx.h b/plugins/Dbx_mdb/src/mdbx/mdbx.h index 4d95ae252a..421d833b70 100644 --- a/plugins/Dbx_mdb/src/mdbx/mdbx.h +++ b/plugins/Dbx_mdb/src/mdbx/mdbx.h @@ -327,6 +327,10 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b); /* Store multiple data items in one call. Only for MDBX_DUPFIXED. */ #define MDBX_MULTIPLE 0x80000u +/* Transaction Flags */ +/* Do not block when starting a write transaction */ +#define MDBX_TRYTXN 0x10000000u + /* Copy Flags */ /* Compacting copy: Omit free space from copy, and renumber all * pages sequentially. */ @@ -420,8 +424,10 @@ typedef enum MDBX_cursor_op { #define MDBX_BAD_DBI (-30780) /* Unexpected problem - txn should abort */ #define MDBX_PROBLEM (-30779) +/* Unexpected problem - txn should abort */ +#define MDBX_BUSY (-30778) /* The last defined error code */ -#define MDBX_LAST_ERRCODE MDBX_PROBLEM +#define MDBX_LAST_ERRCODE MDBX_BUSY /* The mdbx_put() or mdbx_replace() was called for key, that has more that one associated value. */ @@ -953,6 +959,9 @@ LIBMDBX_API int mdbx_env_set_assert(MDBX_env *env, MDBX_assert_func *func); * - MDBX_RDONLY * This transaction will not perform any write operations. * + * - MDBX_TRYTXN + * Do not block when starting a write transaction + * * [out] txn Address where the new MDBX_txn handle will be stored * * Returns A non-zero error value on failure and 0 on success, some @@ -964,7 +973,8 @@ LIBMDBX_API int mdbx_env_set_assert(MDBX_env *env, MDBX_assert_func *func); * as well. See mdbx_env_set_mapsize(). * - MDBX_READERS_FULL - a read-only transaction was requested and the reader * lock table is full. See mdbx_env_set_maxreaders(). - * - MDBX_ENOMEM - out of memory. */ + * - MDBX_ENOMEM - out of memory. + * - MDBX_BUSY - a write transaction is already started. */ LIBMDBX_API int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, MDBX_txn **txn); diff --git a/plugins/Dbx_mdb/src/mdbx/osal.h b/plugins/Dbx_mdb/src/mdbx/osal.h index 4216a5346a..871e52b0dc 100644 --- a/plugins/Dbx_mdb/src/mdbx/osal.h +++ b/plugins/Dbx_mdb/src/mdbx/osal.h @@ -505,7 +505,7 @@ void mdbx_lck_destroy(MDBX_env *env); int mdbx_rdt_lock(MDBX_env *env); void mdbx_rdt_unlock(MDBX_env *env); -int mdbx_txn_lock(MDBX_env *env); +int mdbx_txn_lock(MDBX_env *env, bool dontwait); void mdbx_txn_unlock(MDBX_env *env); int mdbx_rpid_set(MDBX_env *env); |