feat(storage): bump mdbx to 0.12.8 (#5123)

This commit is contained in:
Alexey Shekhirin
2023-10-24 11:34:10 +01:00
committed by GitHub
parent 4890006220
commit 2a4c787591
19 changed files with 441 additions and 133 deletions

View File

@ -512,23 +512,25 @@ else()
mark_as_advanced(MDBX_USE_OFDLOCKS) mark_as_advanced(MDBX_USE_OFDLOCKS)
set(MDBX_AVOID_MSYNC_DEFAULT OFF) set(MDBX_AVOID_MSYNC_DEFAULT OFF)
endif() 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) 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) 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) 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) mark_as_advanced(MDBX_TRUST_RTC)
option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF) add_mdbx_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) 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)
option(MDBX_ENABLE_REFUND "Zerocost auto-compactification during write-transactions" ON) mark_as_advanced(MDBX_DISABLE_VALIDATION)
option(MDBX_ENABLE_MADVISE "Using POSIX' madvise() and/or similar hints" ON) 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) if (CMAKE_TARGET_BITNESS GREATER 32)
set(MDBX_BIGFOOT_DEFAULT ON) set(MDBX_BIGFOOT_DEFAULT ON)
else() else()
set(MDBX_BIGFOOT_DEFAULT OFF) set(MDBX_BIGFOOT_DEFAULT OFF)
endif() endif()
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_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) add_mdbx_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_PROFGC "Profiling of GC search and updates" OFF)
mark_as_advanced(MDBX_ENABLE_PROFGC)
if(NOT MDBX_AMALGAMATED_SOURCE) if(NOT MDBX_AMALGAMATED_SOURCE)
if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG") if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG")

View File

@ -1 +1 @@
0.12.6.0 0.12.8.0

View File

@ -1039,9 +1039,15 @@ macro(probe_libcxx_filesystem)
#endif #endif
int main(int argc, const char*argv[]) { 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()); 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 "") set(LIBCXX_FILESYSTEM "")

View File

@ -1,6 +1,6 @@
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>. .\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" 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 .SH NAME
mdbx_chk \- MDBX checking tool mdbx_chk \- MDBX checking tool
.SH SYNOPSIS .SH SYNOPSIS

View File

@ -2,7 +2,7 @@
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>. .\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" 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 .SH NAME
mdbx_copy \- MDBX environment copy tool mdbx_copy \- MDBX environment copy tool
.SH SYNOPSIS .SH SYNOPSIS

View File

@ -1,7 +1,7 @@
.\" Copyright 2021-2023 Leonid Yuriev <leo@yuriev.ru>. .\" Copyright 2021-2023 Leonid Yuriev <leo@yuriev.ru>.
.\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved. .\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" 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 .SH NAME
mdbx_drop \- MDBX database delete tool mdbx_drop \- MDBX database delete tool
.SH SYNOPSIS .SH SYNOPSIS

View File

@ -2,7 +2,7 @@
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>. .\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" 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 .SH NAME
mdbx_dump \- MDBX environment export tool mdbx_dump \- MDBX environment export tool
.SH SYNOPSIS .SH SYNOPSIS

View File

@ -2,7 +2,7 @@
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>. .\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" 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 .SH NAME
mdbx_load \- MDBX environment import tool mdbx_load \- MDBX environment import tool
.SH SYNOPSIS .SH SYNOPSIS

View File

@ -2,7 +2,7 @@
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>. .\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" 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 .SH NAME
mdbx_stat \- MDBX environment status tool mdbx_stat \- MDBX environment status tool
.SH SYNOPSIS .SH SYNOPSIS

View File

@ -12,7 +12,7 @@
* <http://www.OpenLDAP.org/license.html>. */ * <http://www.OpenLDAP.org/license.html>. */
#define xMDBX_ALLOY 1 #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 #ifdef MDBX_CONFIG_H
#include MDBX_CONFIG_H #include MDBX_CONFIG_H
#endif #endif
@ -3734,6 +3734,7 @@ struct MDBX_env {
int me_valgrind_handle; int me_valgrind_handle;
#endif #endif
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
MDBX_atomic_uint32_t me_ignore_EDEADLK;
pgno_t me_poison_edge; pgno_t me_poison_edge;
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ #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) { enum MDBX_memory_order order) {
STATIC_ASSERT(sizeof(MDBX_atomic_uint64_t) == 8); STATIC_ASSERT(sizeof(MDBX_atomic_uint64_t) == 8);
#if MDBX_64BIT_ATOMIC #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 #ifdef MDBX_HAVE_C11ATOMICS
assert(atomic_is_lock_free(MDBX_c11a_rw(uint64_t, p))); 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)); 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 *const detent = buf + bufsize - 2;
char *ptr = buf; char *ptr = buf;
*ptr++ = '<'; *ptr++ = '<';
for (size_t i = 0; i < key->iov_len; i++) { for (size_t i = 0; i < key->iov_len && ptr < detent; i++) {
const ptrdiff_t left = detent - ptr; const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
assert(left > 0); '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
int len = snprintf(ptr, left, "%02x", data[i]); *ptr++ = hex[data[i] >> 4];
if (len < 0 || len >= left) *ptr++ = hex[data[i] & 15];
break;
ptr += len;
}
if (ptr < detent) {
ptr[0] = '>';
ptr[1] = '\0';
} }
if (ptr < detent)
*ptr++ = '>';
*ptr = '\0';
} }
return buf; 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))) #define MDBX_ATTRIBUTE_TARGET(target) __attribute__((__target__(target)))
#endif /* MDBX_ATTRIBUTE_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 */ #define MDBX_ATTRIBUTE_TARGET_SSE2 /* nope */
#elif (defined(_M_IX86_FP) && _M_IX86_FP >= 2) || defined(__amd64__) #elif (defined(_M_IX86_FP) && _M_IX86_FP >= 2) || defined(__amd64__)
#define __SSE2__ #define __SSE2__
#define MDBX_ATTRIBUTE_TARGET_SSE2 /* nope */ #define MDBX_ATTRIBUTE_TARGET_SSE2 /* nope */
#elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) #elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) && \
#define MDBX_ATTRIBUTE_TARGET_SSE2 MDBX_ATTRIBUTE_TARGET("sse2") !MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND
#define MDBX_ATTRIBUTE_TARGET_SSE2 MDBX_ATTRIBUTE_TARGET("sse,sse2")
#endif /* __SSE2__ */ #endif /* __SSE2__ */
#if defined(__AVX2__) #if defined(__AVX2__)
#define MDBX_ATTRIBUTE_TARGET_AVX2 /* nope */ #define MDBX_ATTRIBUTE_TARGET_AVX2 /* nope */
#elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) #elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) && \
#define MDBX_ATTRIBUTE_TARGET_AVX2 MDBX_ATTRIBUTE_TARGET("avx2") !MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND
#define MDBX_ATTRIBUTE_TARGET_AVX2 MDBX_ATTRIBUTE_TARGET("sse,sse2,avx,avx2")
#endif /* __AVX2__ */ #endif /* __AVX2__ */
#if defined(MDBX_ATTRIBUTE_TARGET_AVX2)
#if defined(__AVX512BW__) #if defined(__AVX512BW__)
#define MDBX_ATTRIBUTE_TARGET_AVX512BW /* nope */ #define MDBX_ATTRIBUTE_TARGET_AVX512BW /* nope */
#elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) && \ #elif defined(MDBX_ATTRIBUTE_TARGET) && defined(__ia32__) && \
!MDBX_GCC_FASTMATH_i686_SIMD_WORKAROUND && \
(__GNUC_PREREQ(6, 0) || __CLANG_PREREQ(5, 0)) (__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 /* __AVX512BW__ */
#endif /* MDBX_ATTRIBUTE_TARGET_AVX2 for MDBX_ATTRIBUTE_TARGET_AVX512BW */
#ifdef MDBX_ATTRIBUTE_TARGET_SSE2 #ifdef MDBX_ATTRIBUTE_TARGET_SSE2
MDBX_ATTRIBUTE_TARGET_SSE2 static __always_inline unsigned 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); 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 * MDBX_MAYBE_UNUSED __hot MDBX_ATTRIBUTE_TARGET_AVX2 static pgno_t *
scan4seq_avx2(pgno_t *range, const size_t len, const size_t seq) { scan4seq_avx2(pgno_t *range, const size_t len, const size_t seq) {
assert(seq > 0 && len > 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__ */ #endif /* __SANITIZE_ADDRESS__ */
if (range - 3 > detent) { if (range - 3 > detent) {
mask = diffcmp2mask_sse2(range - 3, offset, *(const __m128i *)&pattern); mask = diffcmp2mask_sse2avx(range - 3, offset, *(const __m128i *)&pattern);
if (mask) if (mask)
return range + 28 - __builtin_clz(mask); return range + 28 - __builtin_clz(mask);
range -= 4; range -= 4;
@ -10718,7 +10748,7 @@ scan4seq_avx512bw(pgno_t *range, const size_t len, const size_t seq) {
range -= 8; range -= 8;
} }
if (range - 3 > detent) { if (range - 3 > detent) {
mask = diffcmp2mask_sse2(range - 3, offset, *(const __m128i *)&pattern); mask = diffcmp2mask_sse2avx(range - 3, offset, *(const __m128i *)&pattern);
if (mask) if (mask)
return range + 28 - __builtin_clz(mask); return range + 28 - __builtin_clz(mask);
range -= 4; range -= 4;
@ -11248,7 +11278,7 @@ bailout:
#if MDBX_ENABLE_PROFGC #if MDBX_ENABLE_PROFGC
size_t majflt_after; size_t majflt_after;
prof->xtime_cpu += osal_cputime(&majflt_after) - cputime_before; 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 */ #endif /* MDBX_ENABLE_PROFGC */
return ret; return ret;
} }
@ -12122,13 +12152,9 @@ retry:;
} }
const bool inside_txn = (env->me_txn0->mt_owner == osal_thread_self()); const bool inside_txn = (env->me_txn0->mt_owner == osal_thread_self());
meta_ptr_t head; const meta_troika_t troika =
if (inside_txn | locked) (inside_txn | locked) ? env->me_txn0->tw.troika : meta_tap(env);
head = meta_recent(env, &env->me_txn0->tw.troika); const meta_ptr_t head = meta_recent(env, &troika);
else {
const meta_troika_t troika = meta_tap(env);
head = meta_recent(env, &troika);
}
const uint64_t unsynced_pages = const uint64_t unsynced_pages =
atomic_load64(&env->me_lck->mti_unsynced_pages, mo_Relaxed); atomic_load64(&env->me_lck->mti_unsynced_pages, mo_Relaxed);
if (unsynced_pages == 0) { if (unsynced_pages == 0) {
@ -12141,11 +12167,20 @@ retry:;
if (!inside_txn && locked && (env->me_flags & MDBX_WRITEMAP) && if (!inside_txn && locked && (env->me_flags & MDBX_WRITEMAP) &&
unlikely(head.ptr_c->mm_geo.next > unlikely(head.ptr_c->mm_geo.next >
bytes2pgno(env, env->me_dxb_mmap.current))) { bytes2pgno(env, env->me_dxb_mmap.current))) {
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, rc = dxb_resize(env, head.ptr_c->mm_geo.next, head.ptr_c->mm_geo.now,
head.ptr_c->mm_geo.upper, implicit_grow); head.ptr_c->mm_geo.upper, implicit_grow);
if (unlikely(rc != MDBX_SUCCESS)) if (unlikely(rc != MDBX_SUCCESS))
goto bailout; goto bailout;
} }
}
const size_t autosync_threshold = const size_t autosync_threshold =
atomic_load32(&env->me_lck->mti_autosync_threshold, mo_Relaxed); atomic_load32(&env->me_lck->mti_autosync_threshold, mo_Relaxed);
@ -12223,6 +12258,14 @@ retry:;
eASSERT(env, inside_txn || locked); eASSERT(env, inside_txn || locked);
eASSERT(env, !inside_txn || (flags & MDBX_SHRINK_ALLOWED) == 0); 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)) { if (!head.is_steady || ((flags & MDBX_SAFE_NOSYNC) == 0 && unsynced_pages)) {
DEBUG("meta-head %" PRIaPGNO ", %s, sync_pending %" PRIu64, DEBUG("meta-head %" PRIaPGNO ", %s, sync_pending %" PRIu64,
data_page(head.ptr_c)->mp_pgno, durable_caption(head.ptr_c), 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__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
txn_valgrind(env, txn); txn_valgrind(env, txn);
#endif #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
txn->mt_owner = tid; txn->mt_owner = tid;
return MDBX_SUCCESS; return MDBX_SUCCESS;
} }
@ -13190,7 +13233,7 @@ int mdbx_txn_renew(MDBX_txn *txn) {
rc = txn_renew(txn, MDBX_TXN_RDONLY); rc = txn_renew(txn, MDBX_TXN_RDONLY);
if (rc == MDBX_SUCCESS) { 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 DEBUG("renew txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO
"/%" PRIaPGNO, "/%" PRIaPGNO,
txn->mt_txnid, (txn->mt_flags & MDBX_TXN_RDONLY) ? 'r' : 'w', 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 && txn->mt_txnid == slot->mr_txnid.weak &&
slot->mr_txnid.weak >= env->me_lck->mti_oldest_reader.weak); slot->mr_txnid.weak >= env->me_lck->mti_oldest_reader.weak);
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
atomic_add32(&env->me_ignore_EDEADLK, 1);
txn_valgrind(env, nullptr); 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); atomic_store32(&slot->mr_snapshot_pages_used, 0, mo_Relaxed);
safe64_reset(&slot->mr_txnid, false); safe64_reset(&slot->mr_txnid, false);
atomic_store32(&env->me_lck->mti_readers_refresh_flag, true, 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 defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
if (txn == env->me_txn0) if (txn == env->me_txn0)
txn_valgrind(env, nullptr); txn_valgrind(env, nullptr);
#endif #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
txn->mt_flags = MDBX_TXN_FINISHED; txn->mt_flags = MDBX_TXN_FINISHED;
txn->mt_owner = 0; 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) { 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 */ /* PNL is initially empty, zero out at least the length */
memset(pnl.iov_base, 0, sizeof(pgno_t)); memset(pnl.iov_base, 0, sizeof(pgno_t));
if ((env->me_flags & (MDBX_WRITEMAP | MDBX_NOMEMINIT)) == 0) if ((env->me_flags & (MDBX_WRITEMAP | MDBX_NOMEMINIT)) == 0)
@ -14564,6 +14617,15 @@ retry:
if (unlikely(rc != MDBX_SUCCESS)) if (unlikely(rc != MDBX_SUCCESS))
goto bailout; 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)) { if (retired_pages_before == MDBX_PNL_GETSIZE(txn->tw.retired_pages)) {
const size_t at = (ctx->lifo == MDBX_PNL_ASCENDING) const size_t at = (ctx->lifo == MDBX_PNL_ASCENDING)
? left - chunk ? left - chunk
@ -14601,6 +14663,16 @@ retry:
rc = cursor_put_nochecklen(&ctx->cursor, &key, &data, MDBX_RESERVE); rc = cursor_put_nochecklen(&ctx->cursor, &key, &data, MDBX_RESERVE);
if (unlikely(rc != MDBX_SUCCESS)) if (unlikely(rc != MDBX_SUCCESS))
goto bailout; 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() */ /* Retry if tw.retired_pages[] grew during the Put() */
} while (data.iov_len < MDBX_PNL_SIZEOF(txn->tw.retired_pages)); } while (data.iov_len < MDBX_PNL_SIZEOF(txn->tw.retired_pages));
@ -15085,7 +15157,7 @@ bailout:
MDBX_PNL_SETSIZE(txn->tw.relist, 0); MDBX_PNL_SETSIZE(txn->tw.relist, 0);
#if MDBX_ENABLE_PROFGC #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 */ #endif /* MDBX_ENABLE_PROFGC */
TRACE("<<< %zu loops, rc = %d", ctx->loop, rc); TRACE("<<< %zu loops, rc = %d", ctx->loop, rc);
return 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)); (size_t)(commit_txnid - txn->mt_txnid));
} }
#endif #endif
meta.unsafe_sign = MDBX_DATASIGN_NONE;
meta_set_txnid(env, &meta, commit_txnid); meta_set_txnid(env, &meta, commit_txnid);
rc = sync_locked(env, env->me_flags | txn->mt_flags | MDBX_SHRINK_ALLOWED, 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; mdbx_is_readahead_reasonable(used_bytes, 0) == MDBX_RESULT_TRUE;
#endif /* MDBX_ENABLE_MADVISE */ #endif /* MDBX_ENABLE_MADVISE */
err = osal_mmap(env->me_flags, &env->me_dxb_mmap, env->me_dbgeo.now, err = osal_mmap(
env->me_dbgeo.upper, lck_rc ? MMAP_OPTION_TRUNCATE : 0); 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)) if (unlikely(err != MDBX_SUCCESS))
return err; 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); 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 || if ((env->me_flags & MDBX_RDONLY) != 0 ||
/* recovery mode */ env->me_stuck_meta >= 0) { /* recovery mode */ env->me_stuck_meta >= 0) {
WARNING("skipped update meta.geo in %s mode: from l%" PRIaPGNO 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))) if (unlikely(MDBX_IS_ERROR(rc)))
return MDBX_PROBLEM; 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; return MDBX_SUCCESS;
}
if (env->me_flags & MDBX_WRITEMAP) { if (env->me_flags & MDBX_WRITEMAP) {
#if MDBX_ENABLE_PGOP_STAT #if MDBX_ENABLE_PGOP_STAT
@ -18474,14 +18557,16 @@ __cold int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target) {
MDBX_EXCLUSIVE)) MDBX_EXCLUSIVE))
return MDBX_EPERM; return MDBX_EPERM;
const MDBX_meta *target_meta = METAPAGE(env, target); const MDBX_meta *const target_meta = METAPAGE(env, target);
txnid_t new_txnid = safe64_txnid_next(constmeta_txnid(target_meta)); txnid_t new_txnid = constmeta_txnid(target_meta);
for (size_t n = 0; n < NUM_METAS; ++n) { if (new_txnid < MIN_TXNID)
new_txnid = MIN_TXNID;
for (unsigned n = 0; n < NUM_METAS; ++n) {
if (n == target) if (n == target)
continue; continue;
MDBX_meta meta = *METAPAGE(env, target); MDBX_page *const page = pgno2page(env, n);
if (validate_meta(env, &meta, pgno2page(env, n), (pgno_t)n, nullptr) != MDBX_meta meta = *page_meta(page);
MDBX_SUCCESS) { if (validate_meta(env, &meta, page, n, nullptr) != MDBX_SUCCESS) {
int err = override_meta(env, n, 0, nullptr); int err = override_meta(env, n, 0, nullptr);
if (unlikely(err != MDBX_SUCCESS)) if (unlikely(err != MDBX_SUCCESS))
return err; return err;
@ -19270,7 +19355,7 @@ bailout:
} else { } else {
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
txn_valgrind(env, nullptr); txn_valgrind(env, nullptr);
#endif #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
} }
osal_free(env_pathname.buffer_for_free); osal_free(env_pathname.buffer_for_free);
return rc; return rc;
@ -20831,11 +20916,13 @@ static __hot int cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
} }
break; break;
case MDBX_GET_MULTIPLE: case MDBX_GET_MULTIPLE:
if (unlikely(data == NULL || !(mc->mc_flags & C_INITIALIZED))) if (unlikely(!data))
return MDBX_EINVAL; 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; 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)) != if ((mc->mc_xcursor->mx_cursor.mc_flags & (C_INITIALIZED | C_EOF)) !=
C_INITIALIZED) C_INITIALIZED)
break; 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, static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
MDBX_val *data, unsigned flags) { MDBX_val *data, unsigned flags) {
MDBX_page *sub_root = nullptr;
MDBX_val xdata, *rdata, dkey, olddata;
MDBX_db nested_dupdb;
int err; int err;
DKBUF_DEBUG; DKBUF_DEBUG;
MDBX_env *const env = mc->mc_txn->mt_env; 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, DDBI(mc), DKEY_DEBUG(key), key->iov_len,
DVAL_DEBUG((flags & MDBX_RESERVE) ? nullptr : data), data->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 ((flags & MDBX_CURRENT) != 0 && (mc->mc_flags & C_SUB) == 0) {
if (unlikely(flags & (MDBX_APPEND | MDBX_NOOVERWRITE))) if (unlikely(flags & (MDBX_APPEND | MDBX_NOOVERWRITE)))
return MDBX_EINVAL; return MDBX_EINVAL;
@ -21263,10 +21346,11 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
rc = MDBX_NO_ROOT; rc = MDBX_NO_ROOT;
} else if ((flags & MDBX_CURRENT) == 0) { } else if ((flags & MDBX_CURRENT) == 0) {
bool exact = false; bool exact = false;
MDBX_val lastkey, olddata;
if ((flags & MDBX_APPEND) && mc->mc_db->md_entries > 0) { 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)) { 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)) { if (likely(cmp > 0)) {
mc->mc_ki[mc->mc_top]++; /* step forward for appending */ mc->mc_ki[mc->mc_top]++; /* step forward for appending */
rc = MDBX_NOTFOUND; 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; mc->mc_flags &= ~C_DEL;
rdata = data; MDBX_val xdata, *rdata = data;
size_t mcount = 0, dcount = 0; size_t mcount = 0, dcount = 0;
if (unlikely(flags & MDBX_MULTIPLE)) { if (unlikely(flags & MDBX_MULTIPLE)) {
dcount = data[1].iov_len; 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; mc->mc_flags |= C_INITIALIZED;
} }
bool insert_key, insert_data, do_sub = false; MDBX_val dkey, olddata;
insert_key = insert_data = (rc != MDBX_SUCCESS); MDBX_db nested_dupdb;
MDBX_page *sub_root = nullptr;
bool insert_key, insert_data;
uint16_t fp_flags = P_LEAF; uint16_t fp_flags = P_LEAF;
MDBX_page *fp = env->me_pbuf; MDBX_page *fp = env->me_pbuf;
fp->mp_txnid = mc->mc_txn->mt_front; fp->mp_txnid = mc->mc_txn->mt_front;
insert_key = insert_data = (rc != MDBX_SUCCESS);
dkey.iov_base = nullptr;
if (insert_key) { if (insert_key) {
/* The key does not exist */ /* The key does not exist */
DEBUG("inserting key at index %i", mc->mc_ki[mc->mc_top]); 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 */ /* Back up original data item */
memcpy(dkey.iov_base = fp + 1, olddata.iov_base, memcpy(dkey.iov_base = fp + 1, olddata.iov_base,
dkey.iov_len = olddata.iov_len); dkey.iov_len = olddata.iov_len);
dupdata_flag = 1;
/* Make sub-page header for the dup items, with dummy body */ /* Make sub-page header for the dup items, with dummy body */
fp->mp_flags = P_LEAF | P_SUBP; 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) if (!insert_key)
node_del(mc, 0); node_del(mc, 0);
rdata = &xdata;
flags |= F_DUPDATA;
goto new_sub; goto new_sub;
} }
@ -21748,8 +21834,8 @@ new_sub:;
* storing the user data in the keys field, so there are strict * storing the user data in the keys field, so there are strict
* size limits on dupdata. The actual data fields of the child * size limits on dupdata. The actual data fields of the child
* DB are all zero size. */ * DB are all zero size. */
if (do_sub) { if (flags & F_DUPDATA) {
int xflags; unsigned xflags;
size_t ecount; size_t ecount;
put_sub: put_sub:
xdata.iov_len = 0; xdata.iov_len = 0;
@ -21770,13 +21856,11 @@ new_sub:;
if (sub_root) if (sub_root)
mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root; mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root;
/* converted, write the original data first */ /* converted, write the original data first */
if (dupdata_flag) { if (dkey.iov_base) {
rc = cursor_put_nochecklen(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, rc = cursor_put_nochecklen(&mc->mc_xcursor->mx_cursor, &dkey, &xdata,
xflags); xflags);
if (unlikely(rc)) if (unlikely(rc))
goto bad_sub; goto bad_sub;
/* we've done our job */
dkey.iov_len = 0;
} }
if (!(node_flags(node) & F_SUBDATA) || sub_root) { if (!(node_flags(node) & F_SUBDATA) || sub_root) {
/* Adjust other cursors pointing to mp */ /* Adjust other cursors pointing to mp */
@ -21793,7 +21877,7 @@ new_sub:;
continue; continue;
if (m2->mc_pg[i] == mp) { if (m2->mc_pg[i] == mp) {
if (m2->mc_ki[i] == mc->mc_ki[i]) { 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)) if (unlikely(err != MDBX_SUCCESS))
return err; return err;
} else if (!insert_key && m2->mc_ki[i] < nkeys) { } else if (!insert_key && m2->mc_ki[i] < nkeys) {
@ -21837,6 +21921,7 @@ new_sub:;
if (mcount < dcount) { if (mcount < dcount) {
data[0].iov_base = ptr_disp(data[0].iov_base, data[0].iov_len); data[0].iov_base = ptr_disp(data[0].iov_base, data[0].iov_len);
insert_key = insert_data = false; insert_key = insert_data = false;
dkey.iov_base = nullptr;
goto more; 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) && tASSERT(txn, XCURSOR_INITED(&cx.outer) &&
cx.outer.mc_xcursor->mx_db.md_entries > 1); cx.outer.mc_xcursor->mx_db.md_entries > 1);
rc = MDBX_EMULTIVAL; 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 = { const struct MDBX_version_info mdbx_version = {
0, 0,
12, 12,
6, 8,
0, 0,
{"2023-04-29T21:30:35+03:00", "44de01dd81ac366a7d37111eaf72726edebe5528", "c019631a8c88a98a11d814e4111a2a9ae8cb4099", {"2023-10-17T18:16:29+03:00", "24f7245ccd42c9bf34a93d07de56c598302e5e46", "02c7cf2a9c1004b3d3dae73cb006c9d7ed008665",
"v0.12.6-0-gc019631a"}, "v0.12.8-0-g02c7cf2a"},
sourcery}; sourcery};
__dll_export __dll_export
@ -35027,6 +35116,11 @@ __cold static int mdbx_ipclock_failed(MDBX_env *env, osal_ipclock_t *ipc,
#error "FIXME" #error "FIXME"
#endif /* MDBX_LOCKING */ #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)); ERROR("mutex (un)lock failed, %s", mdbx_strerror(err));
if (rc != EDEADLK) if (rc != EDEADLK)
env->me_flags |= MDBX_FATAL_ERROR; env->me_flags |= MDBX_FATAL_ERROR;

View File

@ -12,7 +12,7 @@
* <http://www.OpenLDAP.org/license.html>. */ * <http://www.OpenLDAP.org/license.html>. */
#define xMDBX_ALLOY 1 #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 #ifdef MDBX_CONFIG_H
#include MDBX_CONFIG_H #include MDBX_CONFIG_H
#endif #endif
@ -3734,6 +3734,7 @@ struct MDBX_env {
int me_valgrind_handle; int me_valgrind_handle;
#endif #endif
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
MDBX_atomic_uint32_t me_ignore_EDEADLK;
pgno_t me_poison_edge; pgno_t me_poison_edge;
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
@ -4272,6 +4273,10 @@ namespace mdbx {
"into an incompatible memory allocation scheme."); "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 __cold exception::exception(const ::mdbx::error &error) noexcept
: base(error.what()), error_(error) {} : base(error.what()), error_(error) {}
@ -4522,6 +4527,109 @@ bool slice::is_printable(bool disable_utf8) const noexcept {
return true; 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<const uint8_t *>(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<const int8_t *>(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 { char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {

View File

@ -1876,7 +1876,8 @@ enum MDBX_error_t {
MDBX_BAD_RSLOT = -30783, MDBX_BAD_RSLOT = -30783,
/** Transaction is not valid for requested operation, /** 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, MDBX_BAD_TXN = -30782,
/** Invalid size or alignment of key or data for target database, /** 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 * success. The \ref MDBX_RESULT_TRUE means no data pending for flush
* to disk, and 0 otherwise. Some possible errors are: * to disk, and 0 otherwise. Some possible errors are:
* *
* \retval MDBX_EACCES the environment is read-only. * \retval MDBX_EACCES The environment is read-only.
* \retval MDBX_BUSY the environment is used by other thread * \retval MDBX_BUSY The environment is used by other thread
* and `nonblock=true`. * and `nonblock=true`.
* \retval MDBX_EINVAL an invalid parameter was specified. * \retval MDBX_EINVAL An invalid parameter was specified.
* \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_sync_ex(MDBX_env *env, bool force, bool nonblock); 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 /** \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, * Only a single thread may call this function. All transactions, databases,
* and cursors must already be closed before calling this function. Attempts * and cursors must already be closed before calling this function. Attempts
* to use any such handles after calling this function will cause a `SIGSEGV`. * to use any such handles after calling this function is UB and would cause
* The environment handle will be freed and must not be used again after this * a `SIGSEGV`. The environment handle will be freed and must not be used again
* call. * after this call.
* *
* \param [in] env An environment handle returned by * \param [in] env An environment handle returned by
* \ref mdbx_env_create(). * \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 * is expected, i.e. \ref MDBX_env instance was freed in
* proper manner. * 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); LIBMDBX_API int mdbx_env_close_ex(MDBX_env *env, bool dont_sync);
/** \brief The shortcut to calling \ref mdbx_env_close_ex() with /** \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. * by current thread.
* \retval MDBX_EINVAL Transaction handle is NULL. * \retval MDBX_EINVAL Transaction handle is NULL.
* \retval MDBX_ENOSPC No more disk space. * \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. */ * \retval MDBX_ENOMEM Out of memory. */
LIBMDBX_INLINE_API(int, mdbx_txn_commit, (MDBX_txn * txn)) { LIBMDBX_INLINE_API(int, mdbx_txn_commit, (MDBX_txn * txn)) {
return mdbx_txn_commit_ex(txn, NULL); 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 /** \brief The fours integers markers (aka "canary") associated with the
* environment. * environment.
* \ingroup c_crud * \ingroup c_crud
* \see mdbx_canary_set() * \see mdbx_canary_put()
* \see mdbx_canary_get() * \see mdbx_canary_get()
* *
* The `x`, `y` and `z` values could be set by \ref mdbx_canary_put(), while the * 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 /** \brief Returns fours integers markers (aka "canary") associated with the
* environment. * environment.
* \ingroup c_crud * \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] 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. * information will be copied.
* *
* \returns A non-zero error value on failure and 0 on success. */ * \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() * \see mdbx_get_datacmp \see mdbx_dcmp()
* *
* \anchor avoid_custom_comparators * \anchor avoid_custom_comparators
* It is recommend not using custom comparison functions, but instead * \deprecated It is recommend not using custom comparison functions, but
* converting the keys to one of the forms that are suitable for built-in * instead converting the keys to one of the forms that are suitable for
* comparators (for instance take look to the \ref value2key). * built-in comparators (for instance take look to the \ref value2key).
* The reasons to not using custom comparators are: * The reasons to not using custom comparators are:
* - The order of records could not be validated without your code. * - The order of records could not be validated without your code.
* So `mdbx_chk` utility will reports "wrong order" errors * 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 { enum MDBX_dbi_state_t {
/** DB was written in this txn */ /** DB was written in this txn */
MDBX_DBI_DIRTY = 0x01, MDBX_DBI_DIRTY = 0x01,
/** Named-DB record is older than txnID */ /** Cached Named-DB record is older than txnID */
MDBX_DBI_STALE = 0x02, MDBX_DBI_STALE = 0x02,
/** Named-DB handle opened in this txn */ /** Named-DB handle opened in this txn */
MDBX_DBI_FRESH = 0x04, 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(). * items requires the use of \ref mdbx_cursor_get().
* *
* \note The memory pointed to by the returned values is owned by the * \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 * database. The caller MUST not dispose of the memory, and MUST not modify it
* modify it in any way. For values returned in a read-only transaction * in any way regardless in a read-only nor read-write transactions!
* any modification attempts will cause a `SIGSEGV`. * 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 * \note Values returned from the database are valid only until a
* subsequent update operation, or the end of the transaction. * 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, LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
const MDBX_val *data); 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 * \ingroup c_cursors
* *
* A cursor cannot be used when its database handle is closed. Nor when its * 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. */ * \returns Created cursor handle or NULL in case out of memory. */
LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void *context); 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 * \ingroup c_cursors
* \see mdbx_cursor_get_userctx() * \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_NOTHROW_PURE_FUNCTION LIBMDBX_API void *
mdbx_cursor_get_userctx(const MDBX_cursor *cursor); 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 * \ingroup c_cursors
* *
* Using of the `mdbx_cursor_bind()` is equivalent to calling * 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 * 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 * 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] txn A transaction handle returned by \ref mdbx_txn_begin().
* \param [in] dbi A database handle returned by \ref mdbx_dbi_open(). * \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, * \returns A non-zero error value on failure and 0 on success,
* some possible errors are: * 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(). */ * or \ref mdbx_cursor_create(). */
LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); 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 * \ingroup c_cursors
* *
* The cursor may be associated with a new transaction, and referencing a new or * A cursor may be associated with a new transaction whether the previous
* the same database handle as it was created with. This may be done whether the * transaction is running or finished.
* previous transaction is live or dead.
* *
* Using of the `mdbx_cursor_renew()` is equivalent to calling * 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. * the cursor was used with.
* *
* \note In contrast to LMDB, the MDBX allow any cursor to be re-used by using * \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: * some possible errors are:
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned * \retval MDBX_THREAD_MISMATCH Given transaction is not owned
* by current thread. * 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); LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor);
/** \brief Return the cursor's transaction handle. /** \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. * to which data refers.
* \see mdbx_get() * \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] cursor A cursor handle returned by \ref mdbx_cursor_open().
* \param [in,out] key The key for a retrieved item. * \param [in,out] key The key for a retrieved item.
* \param [in,out] data The data of 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. * array to which `pairs` refers.
* \see mdbx_cursor_get() * \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 [in] cursor A cursor handle returned by \ref mdbx_cursor_open().
* \param [out] count The number of key and value item returned, on success * \param [out] count The number of key and value item returned, on success
* it always be the even because the key-value * it always be the even because the key-value

View File

@ -80,7 +80,8 @@
#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L #if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
#include <filesystem> #include <filesystem>
#elif __has_include(<experimental/filesystem>) #elif defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L && \
__has_include(<experimental/filesystem>)
#include <experimental/filesystem> #include <experimental/filesystem>
#endif #endif
@ -368,6 +369,7 @@ using string = ::std::basic_string<char, ::std::char_traits<char>, ALLOCATOR>;
using filehandle = ::mdbx_filehandle_t; using filehandle = ::mdbx_filehandle_t;
#if defined(DOXYGEN) || \ #if defined(DOXYGEN) || \
(defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \ (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) || \ (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || \
__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && \ __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && \
(!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || \ (!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || \
@ -394,6 +396,16 @@ using path = ::std::wstring;
using path = ::std::string; using path = ::std::string;
#endif /* mdbx::path */ #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) #if __cplusplus >= 201103L || defined(DOXYGEN)
/// \brief Duration in 1/65536 units of second. /// \brief Duration in 1/65536 units of second.
using duration = ::std::chrono::duration<unsigned, ::std::ratio<1, 65536>>; using duration = ::std::chrono::duration<unsigned, ::std::ratio<1, 65536>>;
@ -552,6 +564,7 @@ MDBX_DECLARE_EXCEPTION(transaction_overlapping);
[[noreturn]] LIBMDBX_API void throw_max_length_exceeded(); [[noreturn]] LIBMDBX_API void throw_max_length_exceeded();
[[noreturn]] LIBMDBX_API void throw_out_range(); [[noreturn]] LIBMDBX_API void throw_out_range();
[[noreturn]] LIBMDBX_API void throw_allocators_mismatch(); [[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 bytes);
static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom, static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom,
size_t payload); size_t payload);
@ -1029,6 +1042,35 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val {
return slice(size_t(-1)); return slice(size_t(-1));
} }
template <typename POD> MDBX_CXX14_CONSTEXPR POD as_pod() const {
static_assert(::std::is_standard_layout<POD>::value &&
!::std::is_pointer<POD>::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: protected:
MDBX_CXX11_CONSTEXPR slice(size_t invalid_length) noexcept MDBX_CXX11_CONSTEXPR slice(size_t invalid_length) noexcept
: ::MDBX_val({nullptr, invalid_length}) {} : ::MDBX_val({nullptr, invalid_length}) {}
@ -2292,6 +2334,10 @@ public:
return buffer(::mdbx::slice::wrap(pod), make_reference, allocator); return buffer(::mdbx::slice::wrap(pod), make_reference, allocator);
} }
template <typename POD> MDBX_CXX14_CONSTEXPR POD as_pod() const {
return slice_.as_pod<POD>();
}
/// \brief Reserves storage space. /// \brief Reserves storage space.
void reserve(size_t wanna_headroom, size_t wanna_tailroom) { void reserve(size_t wanna_headroom, size_t wanna_tailroom) {
wanna_headroom = ::std::min(::std::max(headroom(), wanna_headroom), 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 { struct LIBMDBX_API_TYPE geometry {
enum : int64_t { enum : int64_t {
default_value = -1, ///< Means "keep current or use default" default_value = -1, ///< Means "keep current or use default"
@ -3659,6 +3709,8 @@ public:
bool accede = true); bool accede = true);
/// \brief Additional parameters for creating a new database. /// \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 { struct create_parameters {
env::geometry geometry; env::geometry geometry;
mdbx_mode_t file_mode_bits{0640}; mdbx_mode_t file_mode_bits{0640};
@ -3969,10 +4021,20 @@ public:
size_t values_count, put_mode mode, size_t values_count, put_mode mode,
bool allow_partial = false); bool allow_partial = false);
template <typename VALUE> template <typename VALUE>
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>::value &&
!::std::is_pointer<VALUE>::value &&
!::std::is_array<VALUE>::value,
"Must be a standard layout type!");
return put_multiple(map, key, sizeof(VALUE), values_array, values_count,
mode, allow_partial);
}
template <typename VALUE>
void put_multiple(map_handle map, const slice &key, void put_multiple(map_handle map, const slice &key,
const ::std::vector<VALUE> &vector, put_mode mode) { const ::std::vector<VALUE> &vector, put_mode mode) {
put_multiple(map, key, sizeof(VALUE), vector.data(), vector.size(), mode, put_multiple(map, key, vector.data(), vector.size(), mode);
false);
} }
inline ptrdiff_t estimate(map_handle map, pair from, pair to) const; 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 { inline MDBX_env_flags_t env::get_flags() const {
unsigned bits; unsigned bits = 0;
error::success_or_throw(::mdbx_env_get_flags(handle_, &bits)); error::success_or_throw(::mdbx_env_get_flags(handle_, &bits));
return MDBX_env_flags_t(bits); return MDBX_env_flags_t(bits);
} }

View File

@ -34,7 +34,7 @@
* top-level directory of the distribution or, alternatively, at * top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>. */ * <http://www.OpenLDAP.org/license.html>. */
#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a #define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a
#ifdef MDBX_CONFIG_H #ifdef MDBX_CONFIG_H
#include MDBX_CONFIG_H #include MDBX_CONFIG_H
#endif #endif
@ -3756,6 +3756,7 @@ struct MDBX_env {
int me_valgrind_handle; int me_valgrind_handle;
#endif #endif
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
MDBX_atomic_uint32_t me_ignore_EDEADLK;
pgno_t me_poison_edge; pgno_t me_poison_edge;
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */

View File

@ -34,7 +34,7 @@
* top-level directory of the distribution or, alternatively, at * top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>. */ * <http://www.OpenLDAP.org/license.html>. */
#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a #define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a
#ifdef MDBX_CONFIG_H #ifdef MDBX_CONFIG_H
#include MDBX_CONFIG_H #include MDBX_CONFIG_H
#endif #endif
@ -3756,6 +3756,7 @@ struct MDBX_env {
int me_valgrind_handle; int me_valgrind_handle;
#endif #endif
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
MDBX_atomic_uint32_t me_ignore_EDEADLK;
pgno_t me_poison_edge; pgno_t me_poison_edge;
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */

View File

@ -36,7 +36,7 @@
* top-level directory of the distribution or, alternatively, at * top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>. */ * <http://www.OpenLDAP.org/license.html>. */
#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a #define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a
#ifdef MDBX_CONFIG_H #ifdef MDBX_CONFIG_H
#include MDBX_CONFIG_H #include MDBX_CONFIG_H
#endif #endif
@ -3758,6 +3758,7 @@ struct MDBX_env {
int me_valgrind_handle; int me_valgrind_handle;
#endif #endif
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
MDBX_atomic_uint32_t me_ignore_EDEADLK;
pgno_t me_poison_edge; pgno_t me_poison_edge;
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */

View File

@ -34,7 +34,7 @@
* top-level directory of the distribution or, alternatively, at * top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>. */ * <http://www.OpenLDAP.org/license.html>. */
#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a #define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a
#ifdef MDBX_CONFIG_H #ifdef MDBX_CONFIG_H
#include MDBX_CONFIG_H #include MDBX_CONFIG_H
#endif #endif
@ -3756,6 +3756,7 @@ struct MDBX_env {
int me_valgrind_handle; int me_valgrind_handle;
#endif #endif
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
MDBX_atomic_uint32_t me_ignore_EDEADLK;
pgno_t me_poison_edge; pgno_t me_poison_edge;
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */

View File

@ -34,7 +34,7 @@
* top-level directory of the distribution or, alternatively, at * top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>. */ * <http://www.OpenLDAP.org/license.html>. */
#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a #define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a
#ifdef MDBX_CONFIG_H #ifdef MDBX_CONFIG_H
#include MDBX_CONFIG_H #include MDBX_CONFIG_H
#endif #endif
@ -3756,6 +3756,7 @@ struct MDBX_env {
int me_valgrind_handle; int me_valgrind_handle;
#endif #endif
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
MDBX_atomic_uint32_t me_ignore_EDEADLK;
pgno_t me_poison_edge; pgno_t me_poison_edge;
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */

View File

@ -34,7 +34,7 @@
* top-level directory of the distribution or, alternatively, at * top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>. */ * <http://www.OpenLDAP.org/license.html>. */
#define MDBX_BUILD_SOURCERY a0e7c54f688eecaf45ddd7493b737f88a97e4e8b0fdaa55c9d3b00d69e0c8548_v0_12_6_0_gc019631a #define MDBX_BUILD_SOURCERY 30c8f70db1f021dc2bfb201ba04efdcc34fc7495127f517f9624f18c0100b8ab_v0_12_8_0_g02c7cf2a
#ifdef MDBX_CONFIG_H #ifdef MDBX_CONFIG_H
#include MDBX_CONFIG_H #include MDBX_CONFIG_H
#endif #endif
@ -3756,6 +3756,7 @@ struct MDBX_env {
int me_valgrind_handle; int me_valgrind_handle;
#endif #endif
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
MDBX_atomic_uint32_t me_ignore_EDEADLK;
pgno_t me_poison_edge; pgno_t me_poison_edge;
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */