diff options
Diffstat (limited to 'libs/libmdbx/src/mdbx.c++')
-rw-r--r-- | libs/libmdbx/src/mdbx.c++ | 249 |
1 files changed, 187 insertions, 62 deletions
diff --git a/libs/libmdbx/src/mdbx.c++ b/libs/libmdbx/src/mdbx.c++ index ef4cb789fb..e3c3552b39 100644 --- a/libs/libmdbx/src/mdbx.c++ +++ b/libs/libmdbx/src/mdbx.c++ @@ -12,11 +12,16 @@ * <http://www.OpenLDAP.org/license.html>. */ #define MDBX_ALLOY 1 -#define MDBX_BUILD_SOURCERY 3b5677a6062b714f1e138b0066c5590ee3c9ebf3bf8cfa3bb9503515ea0d1f02_v0_9_1_18_g1d31ebdc1c +#define MDBX_BUILD_SOURCERY 47492323531afee427a3de6ddaeae26eed45bfd1b52d92fd121a5a13a9747dbb_v0_9_2_0_g092ab09 #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif +#define LIBMDBX_INTERNALS +#ifdef MDBX_TOOLS +#define MDBX_DEPRECATED +#endif /* MDBX_TOOLS */ + /* *INDENT-OFF* */ /* clang-format off */ @@ -97,11 +102,6 @@ #pragma warning(disable : 4505) /* unreferenced local function has been removed */ #endif /* _MSC_VER (warnings) */ -#if defined(MDBX_TOOLS) -#undef MDBX_DEPRECATED -#define MDBX_DEPRECATED -#endif /* MDBX_TOOLS */ - #include "mdbx.h++" /* * Copyright 2015-2020 Leonid Yuriev <leo@yuriev.ru> @@ -817,7 +817,7 @@ typedef pthread_mutex_t mdbx_fastmutex_t; defined(__amd64__) || defined(__amd64) || defined(_M_X64) || \ defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__) #ifndef __ia32__ -/* LY: define neutral __ia32__ for x86 and x86-64 archs */ +/* LY: define neutral __ia32__ for x86 and x86-64 */ #define __ia32__ 1 #endif /* __ia32__ */ #if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) || \ @@ -993,6 +993,35 @@ typedef union MDBX_srwlock { #ifdef __cplusplus extern void mdbx_osal_jitter(bool tiny); #else + +/*----------------------------------------------------------------------------*/ +/* Atomics */ + +#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && __has_include(<cstdatomic>) +#include <cstdatomic> +#elif !defined(__cplusplus) && (__STDC_VERSION__ >= 201112L) && \ + !defined(__STDC_NO_ATOMICS__) && \ + (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) || \ + !(defined(__GNUC__) || defined(__clang__))) +#include <stdatomic.h> +#elif defined(__GNUC__) || defined(__clang__) +/* LY: nothing required */ +#elif defined(_MSC_VER) +#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */ +#pragma warning(disable : 4133) /* 'function': incompatible types - from \ + 'size_t' to 'LONGLONG' */ +#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to \ + 'std::size_t', possible loss of data */ +#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to \ + 'long', possible loss of data */ +#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64) +#elif defined(__APPLE__) +#include <libkern/OSAtomic.h> +#else +#error FIXME atomic-ops +#endif + /*----------------------------------------------------------------------------*/ /* Memory/Compiler barriers, cache coherence */ @@ -1034,8 +1063,8 @@ static __maybe_unused __inline void mdbx_compiler_barrier(void) { } static __maybe_unused __inline void mdbx_memory_barrier(void) { -#if __has_extension(c_atomic) || __has_extension(cxx_atomic) - __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); +#if __has_extension(c_atomic) && !defined(__STDC_NO_ATOMICS__) + atomic_thread_fence(__ATOMIC_SEQ_CST); #elif defined(__ATOMIC_SEQ_CST) __atomic_thread_fence(__ATOMIC_SEQ_CST); #elif defined(__clang__) || defined(__GNUC__) @@ -1088,8 +1117,7 @@ MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap); #if defined(__linux__) || defined(__gnu_linux__) MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version; -MDBX_INTERNAL_VAR bool - mdbx_RunningOnWSL /* Windows Subsystem for Linux is mad and trouble-full */; +MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */; #endif /* Linux */ #ifndef mdbx_strdup @@ -1160,7 +1188,8 @@ enum mdbx_openfile_purpose { MDBX_OPEN_DXB_LAZY = 1, MDBX_OPEN_DXB_DSYNC = 2, MDBX_OPEN_LCK = 3, - MDBX_OPEN_COPY = 4 + MDBX_OPEN_COPY = 4, + MDBX_OPEN_DELETE = 5 }; MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, @@ -1169,7 +1198,9 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, mdbx_mode_t unix_mode_bits); MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd); MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname); +MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname); MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd); +MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait); #define MMAP_OPTION_TRUNCATE 1 #define MMAP_OPTION_SEMAPHORE 2 @@ -1429,32 +1460,6 @@ MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA; #endif /* Windows */ -/*----------------------------------------------------------------------------*/ -/* Atomics */ - -#if !defined(__cplusplus) && (__STDC_VERSION__ >= 201112L) && \ - !defined(__STDC_NO_ATOMICS__) && \ - (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) || \ - !(defined(__GNUC__) || defined(__clang__))) -#include <stdatomic.h> -#elif defined(__GNUC__) || defined(__clang__) -/* LY: nothing required */ -#elif defined(_MSC_VER) -#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */ -#pragma warning(disable : 4133) /* 'function': incompatible types - from \ - 'size_t' to 'LONGLONG' */ -#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to \ - 'std::size_t', possible loss of data */ -#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to \ - 'long', possible loss of data */ -#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange) -#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64) -#elif defined(__APPLE__) -#include <libkern/OSAtomic.h> -#else -#error FIXME atomic-ops -#endif - #endif /* !__cplusplus */ /*----------------------------------------------------------------------------*/ @@ -1890,7 +1895,7 @@ typedef struct MDBX_db { pgno_t md_overflow_pages; /* number of overflow pages */ uint64_t md_seq; /* table sequence counter */ uint64_t md_entries; /* number of data items */ - uint64_t md_mod_txnid; /* txnid of last commited modification */ + uint64_t md_mod_txnid; /* txnid of last committed modification */ } MDBX_db; /* database size-related parameters */ @@ -1974,7 +1979,7 @@ typedef struct MDBX_meta { typedef struct MDBX_page { union { struct MDBX_page *mp_next; /* for in-memory list of freed pages */ - uint64_t mp_txnid; /* txnid during which the page has been COW-ed */ + uint64_t mp_txnid; /* txnid that committed this page */ }; uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */ #define P_BRANCH 0x01 /* branch page */ @@ -2222,7 +2227,7 @@ typedef struct MDBX_lockinfo { #if defined(_WIN32) || defined(_WIN64) #define MAX_MAPSIZE32 UINT32_C(0x38000000) #else -#define MAX_MAPSIZE32 UINT32_C(0x7ff80000) +#define MAX_MAPSIZE32 UINT32_C(0x7f000000) #endif #define MAX_MAPSIZE64 (MAX_PAGENO * (uint64_t)MAX_PAGESIZE) @@ -2381,8 +2386,6 @@ struct MDBX_txn { MDBX_db *mt_dbs; /* Array of sequence numbers for each DB handle */ unsigned *mt_dbiseqs; - /* In write txns, array of cursors for each DB */ - MDBX_cursor **mt_cursors; /* Transaction DBI Flags */ #define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */ @@ -2409,6 +2412,8 @@ struct MDBX_txn { MDBX_reader *reader; } to; struct { + /* In write txns, array of cursors for each DB */ + MDBX_cursor **cursors; pgno_t *reclaimed_pglist; /* Reclaimed GC pages */ txnid_t last_reclaimed; /* ID of last used record */ pgno_t loose_refund_wl /* FIXME: describe */; @@ -2546,7 +2551,7 @@ struct MDBX_env { #define me_lfd me_lck_mmap.fd #define me_lck me_lck_mmap.lck - unsigned me_psize; /* DB page size, inited from me_os_psize */ + unsigned me_psize; /* DB page size, initialized from me_os_psize */ uint8_t me_psize2log; /* log2 of DB page size */ int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */ unsigned me_os_psize; /* OS page size, from mdbx_syspagesize() */ @@ -2556,7 +2561,7 @@ struct MDBX_env { MDBX_dbi me_maxdbs; /* size of the DB table */ uint32_t me_pid; /* process ID of this env */ mdbx_thread_key_t me_txkey; /* thread-key for readers */ - char *me_path; /* path to the DB files */ + char *me_pathname; /* path to the DB files */ void *me_pbuf; /* scratch area for DUPSORT put() */ MDBX_txn *me_txn; /* current write transaction */ MDBX_txn *me_txn0; /* prealloc'd write transaction */ @@ -2832,7 +2837,7 @@ static __maybe_unused __inline void mdbx_jitter4testing(bool tiny) { ((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE) /* Internal error codes, not exposed outside libmdbx */ -#define MDBX_NO_ROOT (MDBX_LAST_LMDB_ERRCODE + 10) +#define MDBX_NO_ROOT (MDBX_LAST_ADDED_ERRCODE + 10) /* Debugging output value of a cursor DBI: Negative in a sub-cursor. */ #define DDBI(mc) \ @@ -3441,15 +3446,15 @@ __cold void error::throw_exception() const { bool slice::is_printable(bool disable_utf8) const noexcept { enum : byte { - LS = 5, // shift for UTF8 sequence length - P_ = 1 << (LS - 1), // printable ASCII flag + LS = 4, // shift for UTF8 sequence length + P_ = 1 << LS, // printable ASCII flag N_ = 0, // non-printable ASCII second_range_mask = P_ - 1, // mask for range flag - r80_BF = P_ | 0, // flag for UTF8 2nd byte range - rA0_BF = P_ | 1, // flag for UTF8 2nd byte range - r80_9F = P_ | 2, // flag for UTF8 2nd byte range - r90_BF = P_ | 3, // flag for UTF8 2nd byte range - r80_8F = P_ | 4, // flag for UTF8 2nd byte range + r80_BF = 0, // flag for UTF8 2nd byte range + rA0_BF = 1, // flag for UTF8 2nd byte range + r80_9F = 2, // flag for UTF8 2nd byte range + r90_BF = 3, // flag for UTF8 2nd byte range + r80_8F = 4, // flag for UTF8 2nd byte range // valid utf-8 byte sequences // http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf - page 94 @@ -4117,9 +4122,35 @@ bool env::is_pristine() const { bool env::is_empty() const { return get_stat().ms_branch_pages == 0; } -env &env::copy(const path &destination, bool compactify, +#ifdef MDBX_STD_FILESYSTEM_PATH +env &env::copy(const ::std::filesystem::path &destination, bool compactify, + bool force_dynamic_size) { + const path_to_pchar<::std::filesystem::path> utf8(destination); + error::success_or_throw( + ::mdbx_env_copy(handle_, utf8, + (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | + (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE + : MDBX_CP_DEFAULTS))); + return *this; +} +#endif /* MDBX_STD_FILESYSTEM_PATH */ + +#if defined(_WIN32) || defined(_WIN64) +env &env::copy(const ::std::wstring &destination, bool compactify, + bool force_dynamic_size) { + const path_to_pchar<::std::wstring> utf8(destination); + error::success_or_throw( + ::mdbx_env_copy(handle_, utf8, + (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | + (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE + : MDBX_CP_DEFAULTS))); + return *this; +} +#endif /* Windows */ + +env &env::copy(const ::std::string &destination, bool compactify, bool force_dynamic_size) { - const path_to_pchar<path> utf8(destination); + const path_to_pchar<::std::string> utf8(destination); error::success_or_throw( ::mdbx_env_copy(handle_, utf8, (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | @@ -4143,6 +4174,29 @@ path env::get_path() const { return pchar_to_path<path>(c_str); } +#ifdef MDBX_STD_FILESYSTEM_PATH +bool env::remove(const ::std::filesystem::path &pathname, + const remove_mode mode) { + const path_to_pchar<::std::filesystem::path> utf8(pathname); + return error::boolean_or_throw( + ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode))); +} +#endif /* MDBX_STD_FILESYSTEM_PATH */ + +#if defined(_WIN32) || defined(_WIN64) +bool env::remove(const ::std::wstring &pathname, const remove_mode mode) { + const path_to_pchar<::std::wstring> utf8(pathname); + return error::boolean_or_throw( + ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode))); +} +#endif /* Windows */ + +bool env::remove(const ::std::string &pathname, const remove_mode mode) { + const path_to_pchar<::std::string> utf8(pathname); + return error::boolean_or_throw( + ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode))); +} + //------------------------------------------------------------------------------ static inline MDBX_env *create_env() { @@ -4179,11 +4233,43 @@ __cold void env_managed::setup(unsigned max_maps, unsigned max_readers) { error::success_or_throw(::mdbx_env_set_maxdbs(handle_, max_maps)); } -__cold env_managed::env_managed(const path &pathname, +#ifdef MDBX_STD_FILESYSTEM_PATH +__cold env_managed::env_managed(const ::std::filesystem::path &pathname, + const operate_parameters &op, bool accede) + : env_managed(create_env()) { + setup(op.max_maps, op.max_readers); + const path_to_pchar<::std::filesystem::path> utf8(pathname); + error::success_or_throw( + ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0)); + + if (op.options.nested_write_transactions && + !get_options().nested_write_transactions) + error::throw_exception(MDBX_INCOMPATIBLE); +} + +__cold env_managed::env_managed(const ::std::filesystem::path &pathname, + const env_managed::create_parameters &cp, + const env::operate_parameters &op, bool accede) + : env_managed(create_env()) { + setup(op.max_maps, op.max_readers); + const path_to_pchar<::std::filesystem::path> utf8(pathname); + set_geometry(cp.geometry); + error::success_or_throw( + ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory), + cp.file_mode_bits)); + + if (op.options.nested_write_transactions && + !get_options().nested_write_transactions) + error::throw_exception(MDBX_INCOMPATIBLE); +} +#endif /* MDBX_STD_FILESYSTEM_PATH */ + +#if defined(_WIN32) || defined(_WIN64) +__cold env_managed::env_managed(const ::std::wstring &pathname, const operate_parameters &op, bool accede) : env_managed(create_env()) { setup(op.max_maps, op.max_readers); - const path_to_pchar<path> utf8(pathname); + const path_to_pchar<::std::wstring> utf8(pathname); error::success_or_throw( ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0)); @@ -4192,12 +4278,42 @@ __cold env_managed::env_managed(const path &pathname, error::throw_exception(MDBX_INCOMPATIBLE); } -__cold env_managed::env_managed(const path &pathname, +__cold env_managed::env_managed(const ::std::wstring &pathname, const env_managed::create_parameters &cp, const env::operate_parameters &op, bool accede) : env_managed(create_env()) { setup(op.max_maps, op.max_readers); - const path_to_pchar<path> utf8(pathname); + const path_to_pchar<::std::wstring> utf8(pathname); + set_geometry(cp.geometry); + error::success_or_throw( + ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory), + cp.file_mode_bits)); + + if (op.options.nested_write_transactions && + !get_options().nested_write_transactions) + error::throw_exception(MDBX_INCOMPATIBLE); +} +#endif /* Windows */ + +__cold env_managed::env_managed(const ::std::string &pathname, + const operate_parameters &op, bool accede) + : env_managed(create_env()) { + setup(op.max_maps, op.max_readers); + const path_to_pchar<::std::string> utf8(pathname); + error::success_or_throw( + ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0)); + + if (op.options.nested_write_transactions && + !get_options().nested_write_transactions) + error::throw_exception(MDBX_INCOMPATIBLE); +} + +__cold env_managed::env_managed(const ::std::string &pathname, + const env_managed::create_parameters &cp, + const env::operate_parameters &op, bool accede) + : env_managed(create_env()) { + setup(op.max_maps, op.max_readers); + const path_to_pchar<::std::string> utf8(pathname); set_geometry(cp.geometry); error::success_or_throw( ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory), @@ -4300,9 +4416,13 @@ __cold ::std::ostream &operator<<(::std::ostream &out, const slice &it) { out << "EMPTY->" << it.data(); else { const slice root(it.head(std::min(it.length(), size_t(64)))); - out << it.length() << "->" - << (root.is_printable() ? root.string() : root.base58_encode()) - << ((root == it) ? "" : "..."); + out << it.length() << "."; + if (root.is_printable()) + (out << "\"").write(root.char_ptr(), root.length()) << "\""; + else + out << root.base58_encode(); + if (root.length() < it.length()) + out << "..."; } return out << "}"; } @@ -4311,6 +4431,11 @@ __cold ::std::ostream &operator<<(::std::ostream &out, const pair &it) { return out << "{" << it.key << " => " << it.value << "}"; } +__cold ::std::ostream &operator<<(::std::ostream &out, const pair_result &it) { + return out << "{" << (it.done ? "done: " : "non-done: ") << it.key << " => " + << it.value << "}"; +} + __cold ::std::ostream &operator<<(::std::ostream &out, const ::mdbx::env::geometry::size &it) { switch (it.bytes) { |