From 2a4c78759178f66e30c8976ec5d243b53102fc9a Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Tue, 24 Oct 2023 11:34:10 +0100 Subject: [PATCH] feat(storage): bump mdbx to 0.12.8 (#5123) --- .../mdbx-sys/libmdbx/CMakeLists.txt | 18 +- .../libmdbx-rs/mdbx-sys/libmdbx/VERSION.txt | 2 +- .../mdbx-sys/libmdbx/cmake/compiler.cmake | 10 +- .../mdbx-sys/libmdbx/man1/mdbx_chk.1 | 2 +- .../mdbx-sys/libmdbx/man1/mdbx_copy.1 | 2 +- .../mdbx-sys/libmdbx/man1/mdbx_drop.1 | 2 +- .../mdbx-sys/libmdbx/man1/mdbx_dump.1 | 2 +- .../mdbx-sys/libmdbx/man1/mdbx_load.1 | 2 +- .../mdbx-sys/libmdbx/man1/mdbx_stat.1 | 2 +- .../libmdbx-rs/mdbx-sys/libmdbx/mdbx.c | 240 ++++++++++++------ .../libmdbx-rs/mdbx-sys/libmdbx/mdbx.c++ | 110 +++++++- .../libmdbx-rs/mdbx-sys/libmdbx/mdbx.h | 92 ++++--- .../libmdbx-rs/mdbx-sys/libmdbx/mdbx.h++ | 72 +++++- .../libmdbx-rs/mdbx-sys/libmdbx/mdbx_chk.c | 3 +- .../libmdbx-rs/mdbx-sys/libmdbx/mdbx_copy.c | 3 +- .../libmdbx-rs/mdbx-sys/libmdbx/mdbx_drop.c | 3 +- .../libmdbx-rs/mdbx-sys/libmdbx/mdbx_dump.c | 3 +- .../libmdbx-rs/mdbx-sys/libmdbx/mdbx_load.c | 3 +- .../libmdbx-rs/mdbx-sys/libmdbx/mdbx_stat.c | 3 +- 19 files changed, 441 insertions(+), 133 deletions(-) diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/CMakeLists.txt b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/CMakeLists.txt index 777a3f302..33e6233d0 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/CMakeLists.txt +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/CMakeLists.txt @@ -512,23 +512,25 @@ else() mark_as_advanced(MDBX_USE_OFDLOCKS) set(MDBX_AVOID_MSYNC_DEFAULT OFF) endif() -option(MDBX_AVOID_MSYNC "Controls dirty pages tracking, spilling and persisting in MDBX_WRITEMAP mode" ${MDBX_AVOID_MSYNC_DEFAULT}) +add_mdbx_option(MDBX_AVOID_MSYNC "Controls dirty pages tracking, spilling and persisting in MDBX_WRITEMAP mode" ${MDBX_AVOID_MSYNC_DEFAULT}) add_mdbx_option(MDBX_LOCKING "Locking method (Windows=-1, SysV=5, POSIX=1988, POSIX=2001, POSIX=2008, Futexes=1995)" AUTO) mark_as_advanced(MDBX_LOCKING) add_mdbx_option(MDBX_TRUST_RTC "Does a system have battery-backed Real-Time Clock or just a fake" AUTO) mark_as_advanced(MDBX_TRUST_RTC) -option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF) -option(MDBX_DISABLE_VALIDATION "Disable some checks to reduce an overhead and detection probability of database corruption to a values closer to the LMDB" OFF) -option(MDBX_ENABLE_REFUND "Zerocost auto-compactification during write-transactions" ON) -option(MDBX_ENABLE_MADVISE "Using POSIX' madvise() and/or similar hints" ON) +add_mdbx_option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF) +add_mdbx_option(MDBX_DISABLE_VALIDATION "Disable some checks to reduce an overhead and detection probability of database corruption to a values closer to the LMDB" OFF) +mark_as_advanced(MDBX_DISABLE_VALIDATION) +add_mdbx_option(MDBX_ENABLE_REFUND "Zerocost auto-compactification during write-transactions" ON) +add_mdbx_option(MDBX_ENABLE_MADVISE "Using POSIX' madvise() and/or similar hints" ON) if (CMAKE_TARGET_BITNESS GREATER 32) set(MDBX_BIGFOOT_DEFAULT ON) else() set(MDBX_BIGFOOT_DEFAULT OFF) endif() -option(MDBX_ENABLE_BIGFOOT "Chunking long list of retired pages during huge transactions commit to avoid use sequences of pages" ${MDBX_BIGFOOT_DEFAULT}) -option(MDBX_ENABLE_PGOP_STAT "Gathering statistics for page operations" ON) -option(MDBX_ENABLE_PROFGC "Profiling of GC search and updates" OFF) +add_mdbx_option(MDBX_ENABLE_BIGFOOT "Chunking long list of retired pages during huge transactions commit to avoid use sequences of pages" ${MDBX_BIGFOOT_DEFAULT}) +add_mdbx_option(MDBX_ENABLE_PGOP_STAT "Gathering statistics for page operations" ON) +add_mdbx_option(MDBX_ENABLE_PROFGC "Profiling of GC search and updates" OFF) +mark_as_advanced(MDBX_ENABLE_PROFGC) if(NOT MDBX_AMALGAMATED_SOURCE) if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG") diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/VERSION.txt b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/VERSION.txt index cbc73cc52..d6afffa6d 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/VERSION.txt +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/VERSION.txt @@ -1 +1 @@ -0.12.6.0 +0.12.8.0 diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/cmake/compiler.cmake b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/cmake/compiler.cmake index 1d805ea04..762ea1bc9 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/cmake/compiler.cmake +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/cmake/compiler.cmake @@ -1039,9 +1039,15 @@ macro(probe_libcxx_filesystem) #endif int main(int argc, const char*argv[]) { - fs::path probe(argv[0]); + std::string str(argv[0]); + fs::path probe(str); if (argc != 1) throw fs::filesystem_error(std::string("fake"), std::error_code()); - return fs::is_directory(probe.relative_path()); + int r = fs::is_directory(probe.relative_path()); + for (auto const& i : fs::directory_iterator(probe)) { + ++r; + (void)i; + } + return r; } ]]) set(LIBCXX_FILESYSTEM "") diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_chk.1 b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_chk.1 index 7c3b688b4..aa4e9868d 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_chk.1 +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_chk.1 @@ -1,6 +1,6 @@ .\" Copyright 2015-2023 Leonid Yuriev . .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_CHK 1 "2023-04-29" "MDBX 0.12.6" +.TH MDBX_CHK 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_chk \- MDBX checking tool .SH SYNOPSIS diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_copy.1 b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_copy.1 index c8dce2988..4e67a5b8d 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_copy.1 +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_copy.1 @@ -2,7 +2,7 @@ .\" Copyright 2015,2016 Peter-Service R&D LLC . .\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_COPY 1 "2023-04-29" "MDBX 0.12.6" +.TH MDBX_COPY 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_copy \- MDBX environment copy tool .SH SYNOPSIS diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_drop.1 b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_drop.1 index 14924a76d..425eecd2a 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_drop.1 +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_drop.1 @@ -1,7 +1,7 @@ .\" Copyright 2021-2023 Leonid Yuriev . .\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_DROP 1 "2023-04-29" "MDBX 0.12.6" +.TH MDBX_DROP 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_drop \- MDBX database delete tool .SH SYNOPSIS diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_dump.1 b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_dump.1 index 50c799e55..d236b93c1 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_dump.1 +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_dump.1 @@ -2,7 +2,7 @@ .\" Copyright 2015,2016 Peter-Service R&D LLC . .\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_DUMP 1 "2023-04-29" "MDBX 0.12.6" +.TH MDBX_DUMP 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_dump \- MDBX environment export tool .SH SYNOPSIS diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_load.1 b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_load.1 index 668fdbdb9..ae8e75965 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_load.1 +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_load.1 @@ -2,7 +2,7 @@ .\" Copyright 2015,2016 Peter-Service R&D LLC . .\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_LOAD 1 "2023-04-29" "MDBX 0.12.6" +.TH MDBX_LOAD 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_load \- MDBX environment import tool .SH SYNOPSIS diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_stat.1 b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_stat.1 index d3f19f793..c330d2e64 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_stat.1 +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/man1/mdbx_stat.1 @@ -2,7 +2,7 @@ .\" Copyright 2015,2016 Peter-Service R&D LLC . .\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_STAT 1 "2023-04-29" "MDBX 0.12.6" +.TH MDBX_STAT 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_stat \- MDBX environment status tool .SH SYNOPSIS diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.c b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.c index e97392598..35a758014 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.c +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.c @@ -12,7 +12,7 @@ * . */ #define xMDBX_ALLOY 1 -#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a +#define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -3734,6 +3734,7 @@ struct MDBX_env { int me_valgrind_handle; #endif #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + MDBX_atomic_uint32_t me_ignore_EDEADLK; pgno_t me_poison_edge; #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ @@ -4875,6 +4876,9 @@ atomic_store64(MDBX_atomic_uint64_t *p, const uint64_t value, enum MDBX_memory_order order) { STATIC_ASSERT(sizeof(MDBX_atomic_uint64_t) == 8); #if MDBX_64BIT_ATOMIC +#if __GNUC_PREREQ(11, 0) + STATIC_ASSERT(__alignof__(MDBX_atomic_uint64_t) >= sizeof(uint64_t)); +#endif /* GNU C >= 11 */ #ifdef MDBX_HAVE_C11ATOMICS assert(atomic_is_lock_free(MDBX_c11a_rw(uint64_t, p))); atomic_store_explicit(MDBX_c11a_rw(uint64_t, p), value, mo_c11_store(order)); @@ -7667,18 +7671,15 @@ const char *mdbx_dump_val(const MDBX_val *key, char *const buf, char *const detent = buf + bufsize - 2; char *ptr = buf; *ptr++ = '<'; - for (size_t i = 0; i < key->iov_len; i++) { - const ptrdiff_t left = detent - ptr; - assert(left > 0); - int len = snprintf(ptr, left, "%02x", data[i]); - if (len < 0 || len >= left) - break; - ptr += len; - } - if (ptr < detent) { - ptr[0] = '>'; - ptr[1] = '\0'; + for (size_t i = 0; i < key->iov_len && ptr < detent; i++) { + const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + *ptr++ = hex[data[i] >> 4]; + *ptr++ = hex[data[i] & 15]; } + if (ptr < detent) + *ptr++ = '>'; + *ptr = '\0'; } return buf; } @@ -10505,27 +10506,47 @@ MDBX_MAYBE_UNUSED static __always_inline size_t __builtin_clzl(size_t value) { #define MDBX_ATTRIBUTE_TARGET(target) __attribute__((__target__(target))) #endif /* MDBX_ATTRIBUTE_TARGET */ -#if defined(__SSE2__) +#ifndef MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND +/* Workaround for GCC's bug with `-m32 -march=i686 -Ofast` + * gcc/i686-buildroot-linux-gnu/12.2.0/include/xmmintrin.h:814:1: + * error: inlining failed in call to 'always_inline' '_mm_movemask_ps': + * target specific option mismatch */ +#if !defined(__FAST_MATH__) || !__FAST_MATH__ || !defined(__GNUC__) || \ + defined(__e2k__) || defined(__clang__) || defined(__amd64__) || \ + defined(__SSE2__) +#define MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND 0 +#else +#define MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND 1 +#endif +#endif /* MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND */ + +#if defined(__SSE2__) && defined(__SSE__) #define MDBX_ATTRIBUTE_TARGET_SSE2 /* nope */ #elif (defined(_M_IX86_FP) && _M_IX86_FP >= 2) || defined(__amd64__) #define __SSE2__ #define MDBX_ATTRIBUTE_TARGET_SSE2 /* nope */ -#elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) -#define MDBX_ATTRIBUTE_TARGET_SSE2 MDBX_ATTRIBUTE_TARGET("sse2") +#elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) && \ + !MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND +#define MDBX_ATTRIBUTE_TARGET_SSE2 MDBX_ATTRIBUTE_TARGET("sse,sse2") #endif /* __SSE2__ */ #if defined(__AVX2__) #define MDBX_ATTRIBUTE_TARGET_AVX2 /* nope */ -#elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) -#define MDBX_ATTRIBUTE_TARGET_AVX2 MDBX_ATTRIBUTE_TARGET("avx2") +#elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) && \ + !MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND +#define MDBX_ATTRIBUTE_TARGET_AVX2 MDBX_ATTRIBUTE_TARGET("sse,sse2,avx,avx2") #endif /* __AVX2__ */ +#if defined(MDBX_ATTRIBUTE_TARGET_AVX2) #if defined(__AVX512BW__) #define MDBX_ATTRIBUTE_TARGET_AVX512BW /* nope */ #elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) && \ + !MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND && \ (__GNUC_PREREQ(6, 0) || __CLANG_PREREQ(5, 0)) -#define MDBX_ATTRIBUTE_TARGET_AVX512BW MDBX_ATTRIBUTE_TARGET("avx512bw") +#define MDBX_ATTRIBUTE_TARGET_AVX512BW \ + MDBX_ATTRIBUTE_TARGET("sse,sse2,avx,avx2,avx512bw") #endif /* __AVX512BW__ */ +#endif /* MDBX_ATTRIBUTE_TARGET_AVX2 for MDBX_ATTRIBUTE_TARGET_AVX512BW */ #ifdef MDBX_ATTRIBUTE_TARGET_SSE2 MDBX_ATTRIBUTE_TARGET_SSE2 static __always_inline unsigned @@ -10599,6 +10620,15 @@ diffcmp2mask_avx2(const pgno_t *const ptr, const ptrdiff_t offset, return _mm256_movemask_ps(*(const __m256 *)&cmp); } +MDBX_ATTRIBUTE_TARGET_AVX2 static __always_inline unsigned +diffcmp2mask_sse2avx(const pgno_t *const ptr, const ptrdiff_t offset, + const __m128i pattern) { + const __m128i f = _mm_loadu_si128((const __m128i *)ptr); + const __m128i l = _mm_loadu_si128((const __m128i *)(ptr + offset)); + const __m128i cmp = _mm_cmpeq_epi32(_mm_sub_epi32(f, l), pattern); + return _mm_movemask_ps(*(const __m128 *)&cmp); +} + MDBX_MAYBE_UNUSED __hot MDBX_ATTRIBUTE_TARGET_AVX2 static pgno_t * scan4seq_avx2(pgno_t *range, const size_t len, const size_t seq) { assert(seq > 0 && len > seq); @@ -10644,7 +10674,7 @@ scan4seq_avx2(pgno_t *range, const size_t len, const size_t seq) { } #endif /* __SANITIZE_ADDRESS__ */ if (range - 3 > detent) { - mask = diffcmp2mask_sse2(range - 3, offset, *(const __m128i *)&pattern); + mask = diffcmp2mask_sse2avx(range - 3, offset, *(const __m128i *)&pattern); if (mask) return range + 28 - __builtin_clz(mask); range -= 4; @@ -10718,7 +10748,7 @@ scan4seq_avx512bw(pgno_t *range, const size_t len, const size_t seq) { range -= 8; } if (range - 3 > detent) { - mask = diffcmp2mask_sse2(range - 3, offset, *(const __m128i *)&pattern); + mask = diffcmp2mask_sse2avx(range - 3, offset, *(const __m128i *)&pattern); if (mask) return range + 28 - __builtin_clz(mask); range -= 4; @@ -11248,7 +11278,7 @@ bailout: #if MDBX_ENABLE_PROFGC size_t majflt_after; prof->xtime_cpu += osal_cputime(&majflt_after) - cputime_before; - prof->majflt += majflt_after - majflt_before; + prof->majflt += (uint32_t)(majflt_after - majflt_before); #endif /* MDBX_ENABLE_PROFGC */ return ret; } @@ -12122,13 +12152,9 @@ retry:; } const bool inside_txn = (env->me_txn0->mt_owner == osal_thread_self()); - meta_ptr_t head; - if (inside_txn | locked) - head = meta_recent(env, &env->me_txn0->tw.troika); - else { - const meta_troika_t troika = meta_tap(env); - head = meta_recent(env, &troika); - } + const meta_troika_t troika = + (inside_txn | locked) ? env->me_txn0->tw.troika : meta_tap(env); + const meta_ptr_t head = meta_recent(env, &troika); const uint64_t unsynced_pages = atomic_load64(&env->me_lck->mti_unsynced_pages, mo_Relaxed); if (unsynced_pages == 0) { @@ -12141,10 +12167,19 @@ retry:; if (!inside_txn && locked && (env->me_flags & MDBX_WRITEMAP) && unlikely(head.ptr_c->mm_geo.next > bytes2pgno(env, env->me_dxb_mmap.current))) { - rc = dxb_resize(env, head.ptr_c->mm_geo.next, head.ptr_c->mm_geo.now, - head.ptr_c->mm_geo.upper, implicit_grow); - if (unlikely(rc != MDBX_SUCCESS)) - goto bailout; + + if (unlikely(env->me_stuck_meta >= 0) && + troika.recent != (uint8_t)env->me_stuck_meta) { + NOTICE("skip %s since wagering meta-page (%u) is mispatch the recent " + "meta-page (%u)", + "sync datafile", env->me_stuck_meta, troika.recent); + rc = MDBX_RESULT_TRUE; + } else { + rc = dxb_resize(env, head.ptr_c->mm_geo.next, head.ptr_c->mm_geo.now, + head.ptr_c->mm_geo.upper, implicit_grow); + if (unlikely(rc != MDBX_SUCCESS)) + goto bailout; + } } const size_t autosync_threshold = @@ -12223,6 +12258,14 @@ retry:; eASSERT(env, inside_txn || locked); eASSERT(env, !inside_txn || (flags & MDBX_SHRINK_ALLOWED) == 0); + if (!head.is_steady && unlikely(env->me_stuck_meta >= 0) && + troika.recent != (uint8_t)env->me_stuck_meta) { + NOTICE("skip %s since wagering meta-page (%u) is mispatch the recent " + "meta-page (%u)", + "sync datafile", env->me_stuck_meta, troika.recent); + rc = MDBX_RESULT_TRUE; + goto bailout; + } if (!head.is_steady || ((flags & MDBX_SAFE_NOSYNC) == 0 && unsynced_pages)) { DEBUG("meta-head %" PRIaPGNO ", %s, sync_pending %" PRIu64, data_page(head.ptr_c)->mp_pgno, durable_caption(head.ptr_c), @@ -13122,7 +13165,7 @@ static int txn_renew(MDBX_txn *txn, const unsigned flags) { } #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) txn_valgrind(env, txn); -#endif +#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ txn->mt_owner = tid; return MDBX_SUCCESS; } @@ -13190,7 +13233,7 @@ int mdbx_txn_renew(MDBX_txn *txn) { rc = txn_renew(txn, MDBX_TXN_RDONLY); if (rc == MDBX_SUCCESS) { - txn->mt_owner = osal_thread_self(); + tASSERT(txn, txn->mt_owner == osal_thread_self()); DEBUG("renew txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, txn->mt_txnid, (txn->mt_flags & MDBX_TXN_RDONLY) ? 'r' : 'w', @@ -13804,8 +13847,10 @@ static int txn_end(MDBX_txn *txn, const unsigned mode) { txn->mt_txnid == slot->mr_txnid.weak && slot->mr_txnid.weak >= env->me_lck->mti_oldest_reader.weak); #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + atomic_add32(&env->me_ignore_EDEADLK, 1); txn_valgrind(env, nullptr); -#endif + atomic_sub32(&env->me_ignore_EDEADLK, 1); +#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ atomic_store32(&slot->mr_snapshot_pages_used, 0, mo_Relaxed); safe64_reset(&slot->mr_txnid, false); atomic_store32(&env->me_lck->mti_readers_refresh_flag, true, @@ -13834,7 +13879,7 @@ static int txn_end(MDBX_txn *txn, const unsigned mode) { #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) if (txn == env->me_txn0) txn_valgrind(env, nullptr); -#endif +#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ txn->mt_flags = MDBX_TXN_FINISHED; txn->mt_owner = 0; @@ -14249,6 +14294,14 @@ static int gcu_prepare_backlog(MDBX_txn *txn, gcu_context_t *ctx) { } static __inline void gcu_clean_reserved(MDBX_env *env, MDBX_val pnl) { +#if MDBX_DEBUG && (defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)) + /* Для предотвращения предупреждения Valgrind из mdbx_dump_val() + * вызванное через макрос DVAL_DEBUG() на выходе + * из cursor_set(MDBX_SET_KEY), которая вызывается ниже внутри update_gc() в + * цикле очистки и цикле заполнения зарезервированных элементов. */ + memset(pnl.iov_base, 0xBB, pnl.iov_len); +#endif /* MDBX_DEBUG && (MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__) */ + /* PNL is initially empty, zero out at least the length */ memset(pnl.iov_base, 0, sizeof(pgno_t)); if ((env->me_flags & (MDBX_WRITEMAP | MDBX_NOMEMINIT)) == 0) @@ -14564,6 +14617,15 @@ retry: if (unlikely(rc != MDBX_SUCCESS)) goto bailout; +#if MDBX_DEBUG && (defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)) + /* Для предотвращения предупреждения Valgrind из mdbx_dump_val() + * вызванное через макрос DVAL_DEBUG() на выходе + * из cursor_set(MDBX_SET_KEY), которая вызывается как выше в цикле + * очистки, так и ниже в цикле заполнения зарезервированных элементов. + */ + memset(data.iov_base, 0xBB, data.iov_len); +#endif /* MDBX_DEBUG && (MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__) */ + if (retired_pages_before == MDBX_PNL_GETSIZE(txn->tw.retired_pages)) { const size_t at = (ctx->lifo == MDBX_PNL_ASCENDING) ? left - chunk @@ -14601,6 +14663,16 @@ retry: rc = cursor_put_nochecklen(&ctx->cursor, &key, &data, MDBX_RESERVE); if (unlikely(rc != MDBX_SUCCESS)) goto bailout; + +#if MDBX_DEBUG && (defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)) + /* Для предотвращения предупреждения Valgrind из mdbx_dump_val() + * вызванное через макрос DVAL_DEBUG() на выходе + * из cursor_set(MDBX_SET_KEY), которая вызывается как выше в цикле + * очистки, так и ниже в цикле заполнения зарезервированных элементов. + */ + memset(data.iov_base, 0xBB, data.iov_len); +#endif /* MDBX_DEBUG && (MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__) */ + /* Retry if tw.retired_pages[] grew during the Put() */ } while (data.iov_len < MDBX_PNL_SIZEOF(txn->tw.retired_pages)); @@ -15085,7 +15157,7 @@ bailout: MDBX_PNL_SETSIZE(txn->tw.relist, 0); #if MDBX_ENABLE_PROFGC - env->me_lck->mti_pgop_stat.gc_prof.wloops += ctx->loop; + env->me_lck->mti_pgop_stat.gc_prof.wloops += (uint32_t)ctx->loop; #endif /* MDBX_ENABLE_PROFGC */ TRACE("<<< %zu loops, rc = %d", ctx->loop, rc); return rc; @@ -15920,6 +15992,7 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) { (size_t)(commit_txnid - txn->mt_txnid)); } #endif + meta.unsafe_sign = MDBX_DATASIGN_NONE; meta_set_txnid(env, &meta, commit_txnid); rc = sync_locked(env, env->me_flags | txn->mt_flags | MDBX_SHRINK_ALLOWED, @@ -17768,8 +17841,9 @@ __cold static int setup_dxb(MDBX_env *env, const int lck_rc, mdbx_is_readahead_reasonable(used_bytes, 0) == MDBX_RESULT_TRUE; #endif /* MDBX_ENABLE_MADVISE */ - err = osal_mmap(env->me_flags, &env->me_dxb_mmap, env->me_dbgeo.now, - env->me_dbgeo.upper, lck_rc ? MMAP_OPTION_TRUNCATE : 0); + err = osal_mmap( + env->me_flags, &env->me_dxb_mmap, env->me_dbgeo.now, env->me_dbgeo.upper, + (lck_rc && env->me_stuck_meta < 0) ? MMAP_OPTION_TRUNCATE : 0); if (unlikely(err != MDBX_SUCCESS)) return err; @@ -17969,7 +18043,12 @@ __cold static int setup_dxb(MDBX_env *env, const int lck_rc, } const meta_ptr_t recent = meta_recent(env, &troika); - if (memcmp(&header.mm_geo, &recent.ptr_c->mm_geo, sizeof(header.mm_geo))) { + if (/* не учитываем различия в geo.next */ + header.mm_geo.grow_pv != recent.ptr_c->mm_geo.grow_pv || + header.mm_geo.shrink_pv != recent.ptr_c->mm_geo.shrink_pv || + header.mm_geo.lower != recent.ptr_c->mm_geo.lower || + header.mm_geo.upper != recent.ptr_c->mm_geo.upper || + header.mm_geo.now != recent.ptr_c->mm_geo.now) { if ((env->me_flags & MDBX_RDONLY) != 0 || /* recovery mode */ env->me_stuck_meta >= 0) { WARNING("skipped update meta.geo in %s mode: from l%" PRIaPGNO @@ -18419,8 +18498,12 @@ __cold static int __must_check_result override_meta(MDBX_env *env, if (unlikely(MDBX_IS_ERROR(rc))) return MDBX_PROBLEM; - if (shape && memcmp(model, shape, sizeof(MDBX_meta)) == 0) + if (shape && memcmp(model, shape, sizeof(MDBX_meta)) == 0) { + NOTICE("skip overriding meta-%zu since no changes " + "for txnid #%" PRIaTXN, + target, txnid); return MDBX_SUCCESS; + } if (env->me_flags & MDBX_WRITEMAP) { #if MDBX_ENABLE_PGOP_STAT @@ -18474,14 +18557,16 @@ __cold int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target) { MDBX_EXCLUSIVE)) return MDBX_EPERM; - const MDBX_meta *target_meta = METAPAGE(env, target); - txnid_t new_txnid = safe64_txnid_next(constmeta_txnid(target_meta)); - for (size_t n = 0; n < NUM_METAS; ++n) { + const MDBX_meta *const target_meta = METAPAGE(env, target); + txnid_t new_txnid = constmeta_txnid(target_meta); + if (new_txnid < MIN_TXNID) + new_txnid = MIN_TXNID; + for (unsigned n = 0; n < NUM_METAS; ++n) { if (n == target) continue; - MDBX_meta meta = *METAPAGE(env, target); - if (validate_meta(env, &meta, pgno2page(env, n), (pgno_t)n, nullptr) != - MDBX_SUCCESS) { + MDBX_page *const page = pgno2page(env, n); + MDBX_meta meta = *page_meta(page); + if (validate_meta(env, &meta, page, n, nullptr) != MDBX_SUCCESS) { int err = override_meta(env, n, 0, nullptr); if (unlikely(err != MDBX_SUCCESS)) return err; @@ -19270,7 +19355,7 @@ bailout: } else { #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) txn_valgrind(env, nullptr); -#endif +#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ } osal_free(env_pathname.buffer_for_free); return rc; @@ -20831,11 +20916,13 @@ static __hot int cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, } break; case MDBX_GET_MULTIPLE: - if (unlikely(data == NULL || !(mc->mc_flags & C_INITIALIZED))) + if (unlikely(!data)) return MDBX_EINVAL; - if (unlikely(!(mc->mc_db->md_flags & MDBX_DUPFIXED))) + if (unlikely((mc->mc_db->md_flags & MDBX_DUPFIXED) == 0)) return MDBX_INCOMPATIBLE; - rc = MDBX_SUCCESS; + rc = (mc->mc_flags & C_INITIALIZED) + ? MDBX_SUCCESS + : cursor_set(mc, key, data, MDBX_SET).err; if ((mc->mc_xcursor->mx_cursor.mc_flags & (C_INITIALIZED | C_EOF)) != C_INITIALIZED) break; @@ -21194,9 +21281,6 @@ static __hot int cursor_touch(MDBX_cursor *const mc, const MDBX_val *key, static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags) { - MDBX_page *sub_root = nullptr; - MDBX_val xdata, *rdata, dkey, olddata; - MDBX_db nested_dupdb; int err; DKBUF_DEBUG; MDBX_env *const env = mc->mc_txn->mt_env; @@ -21204,7 +21288,6 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key, DDBI(mc), DKEY_DEBUG(key), key->iov_len, DVAL_DEBUG((flags & MDBX_RESERVE) ? nullptr : data), data->iov_len); - int dupdata_flag = 0; if ((flags & MDBX_CURRENT) != 0 && (mc->mc_flags & C_SUB) == 0) { if (unlikely(flags & (MDBX_APPEND | MDBX_NOOVERWRITE))) return MDBX_EINVAL; @@ -21263,10 +21346,11 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key, rc = MDBX_NO_ROOT; } else if ((flags & MDBX_CURRENT) == 0) { bool exact = false; + MDBX_val lastkey, olddata; if ((flags & MDBX_APPEND) && mc->mc_db->md_entries > 0) { - rc = cursor_last(mc, &dkey, &olddata); + rc = cursor_last(mc, &lastkey, &olddata); if (likely(rc == MDBX_SUCCESS)) { - const int cmp = mc->mc_dbx->md_cmp(key, &dkey); + const int cmp = mc->mc_dbx->md_cmp(key, &lastkey); if (likely(cmp > 0)) { mc->mc_ki[mc->mc_top]++; /* step forward for appending */ rc = MDBX_NOTFOUND; @@ -21331,7 +21415,7 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key, } mc->mc_flags &= ~C_DEL; - rdata = data; + MDBX_val xdata, *rdata = data; size_t mcount = 0, dcount = 0; if (unlikely(flags & MDBX_MULTIPLE)) { dcount = data[1].iov_len; @@ -21376,11 +21460,15 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key, mc->mc_flags |= C_INITIALIZED; } - bool insert_key, insert_data, do_sub = false; - insert_key = insert_data = (rc != MDBX_SUCCESS); + MDBX_val dkey, olddata; + MDBX_db nested_dupdb; + MDBX_page *sub_root = nullptr; + bool insert_key, insert_data; uint16_t fp_flags = P_LEAF; MDBX_page *fp = env->me_pbuf; fp->mp_txnid = mc->mc_txn->mt_front; + insert_key = insert_data = (rc != MDBX_SUCCESS); + dkey.iov_base = nullptr; if (insert_key) { /* The key does not exist */ DEBUG("inserting key at index %i", mc->mc_ki[mc->mc_top]); @@ -21555,7 +21643,6 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key, /* Back up original data item */ memcpy(dkey.iov_base = fp + 1, olddata.iov_base, dkey.iov_len = olddata.iov_len); - dupdata_flag = 1; /* Make sub-page header for the dup items, with dummy body */ fp->mp_flags = P_LEAF | P_SUBP; @@ -21659,11 +21746,10 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key, } } - rdata = &xdata; - flags |= F_DUPDATA; - do_sub = true; if (!insert_key) node_del(mc, 0); + rdata = &xdata; + flags |= F_DUPDATA; goto new_sub; } @@ -21748,8 +21834,8 @@ new_sub:; * storing the user data in the keys field, so there are strict * size limits on dupdata. The actual data fields of the child * DB are all zero size. */ - if (do_sub) { - int xflags; + if (flags & F_DUPDATA) { + unsigned xflags; size_t ecount; put_sub: xdata.iov_len = 0; @@ -21770,13 +21856,11 @@ new_sub:; if (sub_root) mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root; /* converted, write the original data first */ - if (dupdata_flag) { + if (dkey.iov_base) { rc = cursor_put_nochecklen(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags); if (unlikely(rc)) goto bad_sub; - /* we've done our job */ - dkey.iov_len = 0; } if (!(node_flags(node) & F_SUBDATA) || sub_root) { /* Adjust other cursors pointing to mp */ @@ -21793,7 +21877,7 @@ new_sub:; continue; if (m2->mc_pg[i] == mp) { if (m2->mc_ki[i] == mc->mc_ki[i]) { - err = cursor_xinit2(m2, mx, dupdata_flag); + err = cursor_xinit2(m2, mx, dkey.iov_base != nullptr); if (unlikely(err != MDBX_SUCCESS)) return err; } else if (!insert_key && m2->mc_ki[i] < nkeys) { @@ -21837,6 +21921,7 @@ new_sub:; if (mcount < dcount) { data[0].iov_base = ptr_disp(data[0].iov_base, data[0].iov_len); insert_key = insert_data = false; + dkey.iov_base = nullptr; goto more; } } @@ -25091,6 +25176,10 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, tASSERT(txn, XCURSOR_INITED(&cx.outer) && cx.outer.mc_xcursor->mx_db.md_entries > 1); rc = MDBX_EMULTIVAL; + if ((flags & MDBX_NOOVERWRITE) == 0) { + flags -= MDBX_CURRENT; + rc = cursor_del(&cx.outer, MDBX_ALLDUPS); + } } } } @@ -33276,10 +33365,10 @@ __dll_export const struct MDBX_version_info mdbx_version = { 0, 12, - 6, + 8, 0, - {"2023-04-29T21:30:35+03:00", "44de01dd81ac366a7d37111eaf72726edebe5528", "c019631a8c88a98a11d814e4111a2a9ae8cb4099", - "v0.12.6-0-gc019631a"}, + {"2023-10-17T18:16:29+03:00", "24f7245ccd42c9bf34a93d07de56c598302e5e46", "02c7cf2a9c1004b3d3dae73cb006c9d7ed008665", + "v0.12.8-0-g02c7cf2a"}, sourcery}; __dll_export @@ -35027,6 +35116,11 @@ __cold static int mdbx_ipclock_failed(MDBX_env *env, osal_ipclock_t *ipc, #error "FIXME" #endif /* MDBX_LOCKING */ +#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + if (rc == EDEADLK && atomic_load32(&env->me_ignore_EDEADLK, mo_Relaxed) > 0) + return rc; +#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ + ERROR("mutex (un)lock failed, %s", mdbx_strerror(err)); if (rc != EDEADLK) env->me_flags |= MDBX_FATAL_ERROR; diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.c++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.c++ index 45817290a..8a08d54c5 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.c++ +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.c++ @@ -12,7 +12,7 @@ * . */ #define xMDBX_ALLOY 1 -#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a +#define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -3734,6 +3734,7 @@ struct MDBX_env { int me_valgrind_handle; #endif #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + MDBX_atomic_uint32_t me_ignore_EDEADLK; pgno_t me_poison_edge; #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ @@ -4272,6 +4273,10 @@ namespace mdbx { "into an incompatible memory allocation scheme."); } +[[noreturn]] __cold void throw_bad_value_size() { + throw bad_value_size(MDBX_BAD_VALSIZE); +} + __cold exception::exception(const ::mdbx::error &error) noexcept : base(error.what()), error_(error) {} @@ -4522,6 +4527,109 @@ bool slice::is_printable(bool disable_utf8) const noexcept { return true; } +#ifdef MDBX_U128_TYPE +MDBX_U128_TYPE slice::as_uint128() const { + static_assert(sizeof(MDBX_U128_TYPE) == 16, "WTF?"); + if (size() == 16) { + MDBX_U128_TYPE r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_uint64(); +} +#endif /* MDBX_U128_TYPE */ + +uint64_t slice::as_uint64() const { + static_assert(sizeof(uint64_t) == 8, "WTF?"); + if (size() == 8) { + uint64_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_uint32(); +} + +uint32_t slice::as_uint32() const { + static_assert(sizeof(uint32_t) == 4, "WTF?"); + if (size() == 4) { + uint32_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_uint16(); +} + +uint16_t slice::as_uint16() const { + static_assert(sizeof(uint16_t) == 2, "WTF?"); + if (size() == 2) { + uint16_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_uint8(); +} + +uint8_t slice::as_uint8() const { + static_assert(sizeof(uint8_t) == 1, "WTF?"); + if (size() == 1) + return *static_cast(data()); + else if (size() == 0) + return 0; + else + MDBX_CXX20_UNLIKELY throw_bad_value_size(); +} + +#ifdef MDBX_I128_TYPE +MDBX_I128_TYPE slice::as_int128() const { + static_assert(sizeof(MDBX_I128_TYPE) == 16, "WTF?"); + if (size() == 16) { + MDBX_I128_TYPE r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_int64(); +} +#endif /* MDBX_I128_TYPE */ + +int64_t slice::as_int64() const { + static_assert(sizeof(int64_t) == 8, "WTF?"); + if (size() == 8) { + uint64_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_int32(); +} + +int32_t slice::as_int32() const { + static_assert(sizeof(int32_t) == 4, "WTF?"); + if (size() == 4) { + int32_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_int16(); +} + +int16_t slice::as_int16() const { + static_assert(sizeof(int16_t) == 2, "WTF?"); + if (size() == 2) { + int16_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_int8(); +} + +int8_t slice::as_int8() const { + if (size() == 1) + return *static_cast(data()); + else if (size() == 0) + return 0; + else + MDBX_CXX20_UNLIKELY throw_bad_value_size(); +} + //------------------------------------------------------------------------------ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const { diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.h b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.h index cc4229813..f702fc46b 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.h +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.h @@ -1876,7 +1876,8 @@ enum MDBX_error_t { MDBX_BAD_RSLOT = -30783, /** Transaction is not valid for requested operation, - * e.g. had errored and be must aborted, has a child, or is invalid */ + * e.g. had errored and be must aborted, has a child/nested transaction, + * or is invalid */ MDBX_BAD_TXN = -30782, /** Invalid size or alignment of key or data for target database, @@ -2699,11 +2700,12 @@ MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_info, * success. The \ref MDBX_RESULT_TRUE means no data pending for flush * to disk, and 0 otherwise. Some possible errors are: * - * \retval MDBX_EACCES the environment is read-only. - * \retval MDBX_BUSY the environment is used by other thread + * \retval MDBX_EACCES The environment is read-only. + * \retval MDBX_BUSY The environment is used by other thread * and `nonblock=true`. - * \retval MDBX_EINVAL an invalid parameter was specified. - * \retval MDBX_EIO an error occurred during synchronization. */ + * \retval MDBX_EINVAL An invalid parameter was specified. + * \retval MDBX_EIO An error occurred during the flushing/writing data + * to a storage medium/disk. */ LIBMDBX_API int mdbx_env_sync_ex(MDBX_env *env, bool force, bool nonblock); /** \brief The shortcut to calling \ref mdbx_env_sync_ex() with @@ -2846,9 +2848,9 @@ LIBMDBX_INLINE_API(int, mdbx_env_get_syncperiod, * * Only a single thread may call this function. All transactions, databases, * and cursors must already be closed before calling this function. Attempts - * to use any such handles after calling this function will cause a `SIGSEGV`. - * The environment handle will be freed and must not be used again after this - * call. + * to use any such handles after calling this function is UB and would cause + * a `SIGSEGV`. The environment handle will be freed and must not be used again + * after this call. * * \param [in] env An environment handle returned by * \ref mdbx_env_create(). @@ -2878,7 +2880,8 @@ LIBMDBX_INLINE_API(int, mdbx_env_get_syncperiod, * is expected, i.e. \ref MDBX_env instance was freed in * proper manner. * - * \retval MDBX_EIO An error occurred during synchronization. */ + * \retval MDBX_EIO An error occurred during the flushing/writing data + * to a storage medium/disk. */ LIBMDBX_API int mdbx_env_close_ex(MDBX_env *env, bool dont_sync); /** \brief The shortcut to calling \ref mdbx_env_close_ex() with @@ -3918,7 +3921,8 @@ LIBMDBX_API int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency); * by current thread. * \retval MDBX_EINVAL Transaction handle is NULL. * \retval MDBX_ENOSPC No more disk space. - * \retval MDBX_EIO A system-level I/O error occurred. + * \retval MDBX_EIO An error occurred during the flushing/writing + * data to a storage medium/disk. * \retval MDBX_ENOMEM Out of memory. */ LIBMDBX_INLINE_API(int, mdbx_txn_commit, (MDBX_txn * txn)) { return mdbx_txn_commit_ex(txn, NULL); @@ -4031,7 +4035,7 @@ LIBMDBX_API int mdbx_txn_renew(MDBX_txn *txn); /** \brief The fours integers markers (aka "canary") associated with the * environment. * \ingroup c_crud - * \see mdbx_canary_set() + * \see mdbx_canary_put() * \see mdbx_canary_get() * * The `x`, `y` and `z` values could be set by \ref mdbx_canary_put(), while the @@ -4069,10 +4073,10 @@ LIBMDBX_API int mdbx_canary_put(MDBX_txn *txn, const MDBX_canary *canary); /** \brief Returns fours integers markers (aka "canary") associated with the * environment. * \ingroup c_crud - * \see mdbx_canary_set() + * \see mdbx_canary_put() * * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). - * \param [in] canary The address of an MDBX_canary structure where the + * \param [in] canary The address of an \ref MDBX_canary structure where the * information will be copied. * * \returns A non-zero error value on failure and 0 on success. */ @@ -4084,9 +4088,9 @@ LIBMDBX_API int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary); * \see mdbx_get_datacmp \see mdbx_dcmp() * * \anchor avoid_custom_comparators - * It is recommend not using custom comparison functions, but instead - * converting the keys to one of the forms that are suitable for built-in - * comparators (for instance take look to the \ref value2key). + * \deprecated It is recommend not using custom comparison functions, but + * instead converting the keys to one of the forms that are suitable for + * built-in comparators (for instance take look to the \ref value2key). * The reasons to not using custom comparators are: * - The order of records could not be validated without your code. * So `mdbx_chk` utility will reports "wrong order" errors @@ -4316,7 +4320,7 @@ LIBMDBX_API int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi, enum MDBX_dbi_state_t { /** DB was written in this txn */ MDBX_DBI_DIRTY = 0x01, - /** Named-DB record is older than txnID */ + /** Cached Named-DB record is older than txnID */ MDBX_DBI_STALE = 0x02, /** Named-DB handle opened in this txn */ MDBX_DBI_FRESH = 0x04, @@ -4398,9 +4402,14 @@ LIBMDBX_API int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del); * items requires the use of \ref mdbx_cursor_get(). * * \note The memory pointed to by the returned values is owned by the - * database. The caller need not dispose of the memory, and may not - * modify it in any way. For values returned in a read-only transaction - * any modification attempts will cause a `SIGSEGV`. + * database. The caller MUST not dispose of the memory, and MUST not modify it + * in any way regardless in a read-only nor read-write transactions! + * For case a database opened without the \ref MDBX_WRITEMAP modification + * attempts likely will cause a `SIGSEGV`. However, when a database opened with + * the \ref MDBX_WRITEMAP or in case values returned inside read-write + * transaction are located on a "dirty" (modified and pending to commit) pages, + * such modification will silently accepted and likely will lead to DB and/or + * data corruption. * * \note Values returned from the database are valid only until a * subsequent update operation, or the end of the transaction. @@ -4650,7 +4659,7 @@ LIBMDBX_API int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *data); -/** \brief Create a cursor handle but not bind it to transaction nor DBI handle. +/** \brief Create a cursor handle but not bind it to transaction nor DBI-handle. * \ingroup c_cursors * * A cursor cannot be used when its database handle is closed. Nor when its @@ -4674,7 +4683,7 @@ LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, * \returns Created cursor handle or NULL in case out of memory. */ LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void *context); -/** \brief Set application information associated with the \ref MDBX_cursor. +/** \brief Set application information associated with the cursor. * \ingroup c_cursors * \see mdbx_cursor_get_userctx() * @@ -4697,11 +4706,11 @@ LIBMDBX_API int mdbx_cursor_set_userctx(MDBX_cursor *cursor, void *ctx); MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void * mdbx_cursor_get_userctx(const MDBX_cursor *cursor); -/** \brief Bind cursor to specified transaction and DBI handle. +/** \brief Bind cursor to specified transaction and DBI-handle. * \ingroup c_cursors * * Using of the `mdbx_cursor_bind()` is equivalent to calling - * \ref mdbx_cursor_renew() but with specifying an arbitrary dbi handle. + * \ref mdbx_cursor_renew() but with specifying an arbitrary DBI-handle. * * A cursor may be associated with a new transaction, and referencing a new or * the same database handle as it was created with. This may be done whether the @@ -4715,7 +4724,7 @@ mdbx_cursor_get_userctx(const MDBX_cursor *cursor); * * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). * \param [in] dbi A database handle returned by \ref mdbx_dbi_open(). - * \param [out] cursor A cursor handle returned by \ref mdbx_cursor_create(). + * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_create(). * * \returns A non-zero error value on failure and 0 on success, * some possible errors are: @@ -4774,15 +4783,14 @@ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, * or \ref mdbx_cursor_create(). */ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); -/** \brief Renew a cursor handle. +/** \brief Renew a cursor handle for use within the given transaction. * \ingroup c_cursors * - * The cursor may be associated with a new transaction, and referencing a new or - * the same database handle as it was created with. This may be done whether the - * previous transaction is live or dead. + * A cursor may be associated with a new transaction whether the previous + * transaction is running or finished. * * Using of the `mdbx_cursor_renew()` is equivalent to calling - * \ref mdbx_cursor_bind() with the DBI handle that previously + * \ref mdbx_cursor_bind() with the DBI-handle that previously * the cursor was used with. * * \note In contrast to LMDB, the MDBX allow any cursor to be re-used by using @@ -4796,7 +4804,9 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_EINVAL An invalid parameter was specified. */ + * \retval MDBX_EINVAL An invalid parameter was specified. + * \retval MDBX_BAD_DBI The cursor was not bound to a DBI-handle + * or such a handle became invalid. */ LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor); /** \brief Return the cursor's transaction handle. @@ -4834,6 +4844,16 @@ LIBMDBX_API int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest); * to which data refers. * \see mdbx_get() * + * \note The memory pointed to by the returned values is owned by the + * database. The caller MUST not dispose of the memory, and MUST not modify it + * in any way regardless in a read-only nor read-write transactions! + * For case a database opened without the \ref MDBX_WRITEMAP modification + * attempts likely will cause a `SIGSEGV`. However, when a database opened with + * the \ref MDBX_WRITEMAP or in case values returned inside read-write + * transaction are located on a "dirty" (modified and pending to commit) pages, + * such modification will silently accepted and likely will lead to DB and/or + * data corruption. + * * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open(). * \param [in,out] key The key for a retrieved item. * \param [in,out] data The data of a retrieved item. @@ -4860,6 +4880,16 @@ LIBMDBX_API int mdbx_cursor_get(MDBX_cursor *cursor, MDBX_val *key, * array to which `pairs` refers. * \see mdbx_cursor_get() * + * \note The memory pointed to by the returned values is owned by the + * database. The caller MUST not dispose of the memory, and MUST not modify it + * in any way regardless in a read-only nor read-write transactions! + * For case a database opened without the \ref MDBX_WRITEMAP modification + * attempts likely will cause a `SIGSEGV`. However, when a database opened with + * the \ref MDBX_WRITEMAP or in case values returned inside read-write + * transaction are located on a "dirty" (modified and pending to commit) pages, + * such modification will silently accepted and likely will lead to DB and/or + * data corruption. + * * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open(). * \param [out] count The number of key and value item returned, on success * it always be the even because the key-value diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.h++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.h++ index ac956790e..385bf9a23 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.h++ +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx.h++ @@ -80,7 +80,8 @@ #if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L #include -#elif __has_include() +#elif defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L && \ + __has_include() #include #endif @@ -368,6 +369,7 @@ using string = ::std::basic_string, ALLOCATOR>; using filehandle = ::mdbx_filehandle_t; #if defined(DOXYGEN) || \ (defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \ + defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L && \ (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || \ __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && \ (!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || \ @@ -394,6 +396,16 @@ using path = ::std::wstring; using path = ::std::string; #endif /* mdbx::path */ +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) +#ifndef MDBX_U128_TYPE +#define MDBX_U128_TYPE __uint128_t +#endif /* MDBX_U128_TYPE */ +#ifndef MDBX_I128_TYPE +#define MDBX_I128_TYPE __int128_t +#endif /* MDBX_I128_TYPE */ +#endif /* __SIZEOF_INT128__ || _INTEGRAL_MAX_BITS >= 128 */ + #if __cplusplus >= 201103L || defined(DOXYGEN) /// \brief Duration in 1/65536 units of second. using duration = ::std::chrono::duration>; @@ -552,6 +564,7 @@ MDBX_DECLARE_EXCEPTION(transaction_overlapping); [[noreturn]] LIBMDBX_API void throw_max_length_exceeded(); [[noreturn]] LIBMDBX_API void throw_out_range(); [[noreturn]] LIBMDBX_API void throw_allocators_mismatch(); +[[noreturn]] LIBMDBX_API void throw_bad_value_size(); static MDBX_CXX14_CONSTEXPR size_t check_length(size_t bytes); static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom, size_t payload); @@ -1029,6 +1042,35 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val { return slice(size_t(-1)); } + template MDBX_CXX14_CONSTEXPR POD as_pod() const { + static_assert(::std::is_standard_layout::value && + !::std::is_pointer::value, + "Must be a standard layout type!"); + if (MDBX_LIKELY(size() == sizeof(POD))) + MDBX_CXX20_LIKELY { + POD r; + memcpy(&r, data(), sizeof(r)); + return r; + } + throw_bad_value_size(); + } + +#ifdef MDBX_U128_TYPE + MDBX_U128_TYPE as_uint128() const; +#endif /* MDBX_U128_TYPE */ + uint64_t as_uint64() const; + uint32_t as_uint32() const; + uint16_t as_uint16() const; + uint8_t as_uint8() const; + +#ifdef MDBX_I128_TYPE + MDBX_I128_TYPE as_int128() const; +#endif /* MDBX_I128_TYPE */ + int64_t as_int64() const; + int32_t as_int32() const; + int16_t as_int16() const; + int8_t as_int8() const; + protected: MDBX_CXX11_CONSTEXPR slice(size_t invalid_length) noexcept : ::MDBX_val({nullptr, invalid_length}) {} @@ -2292,6 +2334,10 @@ public: return buffer(::mdbx::slice::wrap(pod), make_reference, allocator); } + template MDBX_CXX14_CONSTEXPR POD as_pod() const { + return slice_.as_pod(); + } + /// \brief Reserves storage space. void reserve(size_t wanna_headroom, size_t wanna_tailroom) { wanna_headroom = ::std::min(::std::max(headroom(), wanna_headroom), @@ -3000,7 +3046,11 @@ public: //---------------------------------------------------------------------------- - /// Database geometry for size management. + /// \brief Database geometry for size management. + /// \see env_managed::create_parameters + /// \see env_managed::env_managed(const ::std::string &pathname, const + /// create_parameters &, const operate_parameters &, bool accede) + struct LIBMDBX_API_TYPE geometry { enum : int64_t { default_value = -1, ///< Means "keep current or use default" @@ -3659,6 +3709,8 @@ public: bool accede = true); /// \brief Additional parameters for creating a new database. + /// \see env_managed(const ::std::string &pathname, const create_parameters &, + /// const operate_parameters &, bool accede) struct create_parameters { env::geometry geometry; mdbx_mode_t file_mode_bits{0640}; @@ -3969,10 +4021,20 @@ public: size_t values_count, put_mode mode, bool allow_partial = false); template + size_t put_multiple(map_handle map, const slice &key, + const VALUE *values_array, size_t values_count, + put_mode mode, bool allow_partial = false) { + static_assert(::std::is_standard_layout::value && + !::std::is_pointer::value && + !::std::is_array::value, + "Must be a standard layout type!"); + return put_multiple(map, key, sizeof(VALUE), values_array, values_count, + mode, allow_partial); + } + template void put_multiple(map_handle map, const slice &key, const ::std::vector &vector, put_mode mode) { - put_multiple(map, key, sizeof(VALUE), vector.data(), vector.size(), mode, - false); + put_multiple(map, key, vector.data(), vector.size(), mode); } inline ptrdiff_t estimate(map_handle map, pair from, pair to) const; @@ -5134,7 +5196,7 @@ inline filehandle env::get_filehandle() const { } inline MDBX_env_flags_t env::get_flags() const { - unsigned bits; + unsigned bits = 0; error::success_or_throw(::mdbx_env_get_flags(handle_, &bits)); return MDBX_env_flags_t(bits); } diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_chk.c b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_chk.c index 74bde38a3..4f7347402 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_chk.c +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_chk.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a +#define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -3756,6 +3756,7 @@ struct MDBX_env { int me_valgrind_handle; #endif #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + MDBX_atomic_uint32_t me_ignore_EDEADLK; pgno_t me_poison_edge; #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_copy.c b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_copy.c index b9bf2d934..4df13c02c 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_copy.c +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_copy.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a +#define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -3756,6 +3756,7 @@ struct MDBX_env { int me_valgrind_handle; #endif #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + MDBX_atomic_uint32_t me_ignore_EDEADLK; pgno_t me_poison_edge; #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_drop.c b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_drop.c index 3f232625f..a68da9f98 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_drop.c +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_drop.c @@ -36,7 +36,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a +#define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -3758,6 +3758,7 @@ struct MDBX_env { int me_valgrind_handle; #endif #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + MDBX_atomic_uint32_t me_ignore_EDEADLK; pgno_t me_poison_edge; #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_dump.c b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_dump.c index 5cc90c8dc..f6831ef31 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_dump.c +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_dump.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a +#define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -3756,6 +3756,7 @@ struct MDBX_env { int me_valgrind_handle; #endif #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + MDBX_atomic_uint32_t me_ignore_EDEADLK; pgno_t me_poison_edge; #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_load.c b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_load.c index 0cca77155..b6c5b993a 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_load.c +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_load.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a +#define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -3756,6 +3756,7 @@ struct MDBX_env { int me_valgrind_handle; #endif #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + MDBX_atomic_uint32_t me_ignore_EDEADLK; pgno_t me_poison_edge; #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ diff --git a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_stat.c b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_stat.c index 0aabb5766..7bc92a33e 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_stat.c +++ b/crates/storage/libmdbx-rs/mdbx-sys/libmdbx/mdbx_stat.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a +#define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -3756,6 +3756,7 @@ struct MDBX_env { int me_valgrind_handle; #endif #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + MDBX_atomic_uint32_t me_ignore_EDEADLK; pgno_t me_poison_edge; #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */