From 05b3b4e51e8aab47dfec356b6cfd1e9b70f63234 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Thu, 8 Oct 2020 12:41:56 +0300 Subject: [PATCH 01/20] mdbx-packages: add patch for buildroot. Based on v0.9.1.0 Change-Id: If61d1f47e3ad71479ccfb1d25dbfd4a5c9e750cc --- .github/actions/spelling/excludes.txt | 1 + ChangeLog.md | 3 + packages/buildroot/v4-0000-cover-letter.patch | 255 +++++++++ ...libmdbx-new-package-library-database.patch | 490 ++++++++++++++++++ 4 files changed, 749 insertions(+) create mode 100644 packages/buildroot/v4-0000-cover-letter.patch create mode 100644 packages/buildroot/v4-0001-package-libmdbx-new-package-library-database.patch diff --git a/.github/actions/spelling/excludes.txt b/.github/actions/spelling/excludes.txt index 0bd6cbf6..21414cf1 100644 --- a/.github/actions/spelling/excludes.txt +++ b/.github/actions/spelling/excludes.txt @@ -1,3 +1,4 @@ ^\.github/actions/spelling/ ^\.travis\.yml$ \.def$ +^packages/buildroot/ diff --git a/ChangeLog.md b/ChangeLog.md index 34be056b..c7f4e94a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -9,6 +9,9 @@ TODO: - Finalize C++ API (few typos and trivia bugs are likely for now). - Packages for ROSA Linux, ALT Linux, Fedora/RHEL, Debian/Ubuntu. +Added features: + - Provided package for [buildroot](https://buildroot.org/). + Fixes: - Fixed missing installation of `mdbx.h++`. diff --git a/packages/buildroot/v4-0000-cover-letter.patch b/packages/buildroot/v4-0000-cover-letter.patch new file mode 100644 index 00000000..5f014be0 --- /dev/null +++ b/packages/buildroot/v4-0000-cover-letter.patch @@ -0,0 +1,255 @@ +From 0bf9d06e8b090e2d9783d03074f3752ed708f6cf Mon Sep 17 00:00:00 2001 +In-Reply-To: +References: +From: Leonid Yuriev +Date: Tue, 6 Oct 2020 22:19:56 +0300 +Cc: Heiko Thiery +Subject: [PATCH v4 0/1] package/libmdbx: new package (library/database) + +This patch adds libmdbx v0.9.1 and below is a brief overview of libmdbx. + +Changes v1 -> v2: + - libmdbx version v0.8.2 -> v0.9.1 (released 2020-09-30) + +Changes v2 -> v3: + - removed outcommented stuff (suggested by Heiko Thiery). + - cleaned up and simplified the makefile (suggested by Heiko Thiery). + - added patch for C++ header installation. + - added patch with fix minor copy&paste typo. + - added patch with pthread workaround for buggy toolchain/cmake/buildroot. + - added patch for `pthread_yield()`. + - passed `utils/check-package package/libmdbx/*` (suggested by Heiko Thiery). + - passed `utils/test-pkg -a -p libmdbx` (suggested by Heiko Thiery). + +Changes v3 -> v4: + - fix passing BR2_PACKAGE_LIBMDBX_TOOLS option to cmake. + - fix using `depend on` instead of `select`, + and add `comment` for C++ toolchain (suggested by Heiko Thiery). + - fix minor help typo. + +Please merge. + +Regards, +Leonid. + +-- + +libmdbx is an extremely fast, compact, powerful, embedded, transactional +key-value database, with permissive license. libmdbx has a specific set +of properties and capabilities, focused on creating unique lightweight +solutions. + +Historically, libmdbx (MDBX) is a deeply revised and extended descendant +of the legendary LMDB (Lightning Memory-Mapped Database). libmdbx +inherits all benefits from LMDB, but resolves some issues and adds a set +of improvements. + +According to developers, for now libmdbx surpasses the LMDB in terms of +reliability, features and performance. + + +The most important differences MDBX from LMDB: +============================================== + +1. More attention is paid to the quality of the code, to an +"unbreakability" of the API, to testing and automatic checks (i.e. +sanitizers, etc). So there: + - more control during operation; + - more checking parameters, internal audit of database structures; + - no warnings from compiler; + - no issues from ASAN, UBSAN, Valgrind, Coverity; + - etc. + +2. Keys could be more than 2 times longer than LMDB. + +3. Up to 20% faster than LMDB in CRUD benchmarks. + +4. Automatic on-the-fly database size adjustment, +both increment and reduction. + +5. Automatic continuous zero-overhead database compactification. + +6. The same database format for 32- and 64-bit builds. + +7. LIFO policy for Garbage Collection recycling (this can significantly +increase write performance due write-back disk cache up to several times +in a best case scenario). + +8. Range query estimation. + +9. Utility for checking the integrity of the database structure with +some recovery capabilities. + +For more info please refer: + - https://github.com/erthink/libmdbx for source code and README. + - https://erthink.github.io/libmdbx for API description. + +-- + +MDBX is a Btree-based database management library modeled loosely on the +BerkeleyDB API, but much simplified. The entire database (aka +"environment") is exposed in a memory map, and all data fetches return +data directly from the mapped memory, so no malloc's or memcpy's occur +during data fetches. As such, the library is extremely simple because it +requires no page caching layer of its own, and it is extremely high +performance and memory-efficient. It is also fully transactional with +full ACID semantics, and when the memory map is read-only, the database +integrity cannot be corrupted by stray pointer writes from application +code. + +The library is fully thread-aware and supports concurrent read/write +access from multiple processes and threads. Data pages use a +copy-on-write strategy so no active data pages are ever overwritten, +which also provides resistance to corruption and eliminates the need of +any special recovery procedures after a system crash. Writes are fully +serialized; only one write transaction may be active at a time, which +guarantees that writers can never deadlock. The database structure is +multi-versioned so readers run with no locks; writers cannot block +readers, and readers don't block writers. + +Unlike other well-known database mechanisms which use either write-ahead +transaction logs or append-only data writes, MDBX requires no +maintenance during operation. Both write-ahead loggers and append-only +databases require periodic checkpointing and/or compaction of their log +or database files otherwise they grow without bound. MDBX tracks +retired/freed pages within the database and re-uses them for new write +operations, so the database size does not grow without bound in normal +use. + +The memory map can be used as a read-only or read-write map. It is +read-only by default as this provides total immunity to corruption. +Using read-write mode offers much higher write performance, but adds the +possibility for stray application writes thru pointers to silently +corrupt the database. + + +Features +======== + +- Key-value data model, keys are always sorted. + +- Fully ACID-compliant, through to MVCC and CoW. + +- Multiple key-value sub-databases within a single datafile. + +- Range lookups, including range query estimation. + +- Efficient support for short fixed length keys, including native + 32/64-bit integers. + +- Ultra-efficient support for multimaps. Multi-values sorted, searchable + and iterable. Keys stored without duplication. + +- Data is memory-mapped and accessible directly/zero-copy. Traversal of + database records is extremely-fast. + +- Transactions for readers and writers, ones do not block others. + +- Writes are strongly serialized. No transaction conflicts nor + deadlocks. + +- Readers are non-blocking, notwithstanding snapshot isolation. + +- Nested write transactions. + +- Reads scale linearly across CPUs. + +- Continuous zero-overhead database compactification. + +- Automatic on-the-fly database size adjustment. + +- Customizable database page size. + +- Olog(N) cost of lookup, insert, update, and delete operations by + virtue of B+ tree characteristics. + +- Online hot backup. + +- Append operation for efficient bulk insertion of pre-sorted data. + +- No WAL nor any transaction journal. No crash recovery needed. No + maintenance is required. + +- No internal cache and/or memory management, all done by basic OS + services. + + +Limitations +=========== + +- Page size: a power of 2, maximum 65536 bytes, default 4096 bytes. + +- Key size: minimum 0, maximum ≈¼ pagesize (1300 bytes for default 4K + pagesize, 21780 bytes for 64K pagesize). + +- Value size: minimum 0, maximum 2146435072 (0x7FF00000) bytes for maps, + ≈¼ pagesize for multimaps (1348 bytes default 4K pagesize, 21828 bytes + for 64K pagesize). + +- Write transaction size: up to 4194301 (0x3FFFFD) pages (16 GiB for + default 4K pagesize, 256 GiB for 64K pagesize). + +- Database size: up to 2147483648 pages (8 TiB for default 4K pagesize, + 128 TiB for 64K pagesize). + +- Maximum sub-databases: 32765. + + +Gotchas +======= + +- There cannot be more than one writer at a time, i.e. no more than one + write transaction at a time. + +- libmdbx is based on B+ tree, so access to database pages is mostly + random. Thus SSDs provide a significant performance boost over + spinning disks for large databases. + +- libmdbx uses shadow paging instead of WAL. Thus syncing data to disk + might be a bottleneck for write intensive workload. + +- libmdbx uses copy-on-write for snapshot isolation during updates, but + read transactions prevents recycling an old retired/freed pages, since + it read ones. Thus altering of data during a parallel long-lived read + operation will increase the process work set, may exhaust entire free + database space, the database can grow quickly, and result in + performance degradation. Try to avoid long running read transactions. + +- libmdbx is extraordinarily fast and provides minimal overhead for data + access, so you should reconsider using brute force techniques and + double check your code. On the one hand, in the case of libmdbx, a + simple linear search may be more profitable than complex indexes. On + the other hand, if you make something suboptimally, you can notice + detrimentally only on sufficiently large data. + +-- +Leonid Yuriev (1): + package/libmdbx: new package (library/database). + + DEVELOPERS | 3 + + package/Config.in | 1 + + .../0001-mdbx-fix-minor-copy-paste-typo.patch | 27 ++++++++ + ...e-fix-missing-installation-of-mdbx.h.patch | 54 +++++++++++++++ + .../0003-mdbx-fix-obsolete-__noreturn.patch | 27 ++++++++ + ...ield-instruction-on-ARM-if-unsupport.patch | 28 ++++++++ + ...fix-minor-false-positive-GCC-warning.patch | 27 ++++++++ + ...ad-workaround-for-buggy-toolchain-cm.patch | 65 +++++++++++++++++++ + ...mdbx-fix-pthread_yield-for-non-GLIBC.patch | 42 ++++++++++++ + package/libmdbx/Config.in | 42 ++++++++++++ + package/libmdbx/libmdbx.hash | 2 + + package/libmdbx/libmdbx.mk | 24 +++++++ + 12 files changed, 342 insertions(+) + create mode 100644 package/libmdbx/0001-mdbx-fix-minor-copy-paste-typo.patch + create mode 100644 package/libmdbx/0002-mdbx-cmake-fix-missing-installation-of-mdbx.h.patch + create mode 100644 package/libmdbx/0003-mdbx-fix-obsolete-__noreturn.patch + create mode 100644 package/libmdbx/0004-mdbx-don-t-use-yield-instruction-on-ARM-if-unsupport.patch + create mode 100644 package/libmdbx/0005-mdbx-load-fix-minor-false-positive-GCC-warning.patch + create mode 100644 package/libmdbx/0006-mdbx-cmake-pthread-workaround-for-buggy-toolchain-cm.patch + create mode 100644 package/libmdbx/0007-mdbx-fix-pthread_yield-for-non-GLIBC.patch + create mode 100644 package/libmdbx/Config.in + create mode 100644 package/libmdbx/libmdbx.hash + create mode 100644 package/libmdbx/libmdbx.mk + +-- +2.28.0 + diff --git a/packages/buildroot/v4-0001-package-libmdbx-new-package-library-database.patch b/packages/buildroot/v4-0001-package-libmdbx-new-package-library-database.patch new file mode 100644 index 00000000..5f103b8c --- /dev/null +++ b/packages/buildroot/v4-0001-package-libmdbx-new-package-library-database.patch @@ -0,0 +1,490 @@ +From 0bf9d06e8b090e2d9783d03074f3752ed708f6cf Mon Sep 17 00:00:00 2001 +In-Reply-To: +References: +From: Leonid Yuriev +Date: Tue, 6 Oct 2020 22:10:00 +0300 +Subject: [PATCH v4 1/1] package/libmdbx: new package (library/database). + +This patch adds libmdbx v0.9.1: + - libmdbx is one of the fastest compact embeddable key-value ACID database. + - libmdbx has a specific set of properties and capabilities, + focused on creating unique lightweight solutions. + - libmdbx surpasses the legendary LMDB (Lightning Memory-Mapped Database) + in terms of reliability, features and performance. + +https://github.com/erthink/libmdbx + +--- +Changes v1 -> v2: + - libmdbx version v0.8.2 -> v0.9.1 (released 2020-09-30) + +Changes v2 -> v3: + - removed outcommented stuff (suggested by Heiko Thiery). + - cleaned up and simplified the makefile (suggested by Heiko Thiery). + - added patch for C++ header installation. + - added patch with fix minor copy&paste typo. + - added patch with pthread workaround for buggy toolchain/cmake/buildroot. + - added patch for `pthread_yield()`. + - passed `utils/check-package package/libmdbx/*` (suggested by Heiko Thiery) + - passed `utils/test-pkg -a -p libmdbx`, + except w/o threads & w/o MMU (suggested by Heiko Thiery). + +Changes v3 -> v4: + - fix passing BR2_PACKAGE_LIBMDBX_TOOLS option to cmake. + - fix using `depend on` instead of `select`, + and add `comment` for C++ toolchain (suggested by Heiko Thiery). + - fix minor help typo. + +Signed-off-by: Leonid Yuriev +--- + DEVELOPERS | 3 + + package/Config.in | 1 + + .../0001-mdbx-fix-minor-copy-paste-typo.patch | 27 ++++++++ + ...e-fix-missing-installation-of-mdbx.h.patch | 54 +++++++++++++++ + .../0003-mdbx-fix-obsolete-__noreturn.patch | 27 ++++++++ + ...ield-instruction-on-ARM-if-unsupport.patch | 28 ++++++++ + ...fix-minor-false-positive-GCC-warning.patch | 27 ++++++++ + ...ad-workaround-for-buggy-toolchain-cm.patch | 65 +++++++++++++++++++ + ...mdbx-fix-pthread_yield-for-non-GLIBC.patch | 42 ++++++++++++ + package/libmdbx/Config.in | 42 ++++++++++++ + package/libmdbx/libmdbx.hash | 2 + + package/libmdbx/libmdbx.mk | 24 +++++++ + 12 files changed, 342 insertions(+) + create mode 100644 package/libmdbx/0001-mdbx-fix-minor-copy-paste-typo.patch + create mode 100644 package/libmdbx/0002-mdbx-cmake-fix-missing-installation-of-mdbx.h.patch + create mode 100644 package/libmdbx/0003-mdbx-fix-obsolete-__noreturn.patch + create mode 100644 package/libmdbx/0004-mdbx-don-t-use-yield-instruction-on-ARM-if-unsupport.patch + create mode 100644 package/libmdbx/0005-mdbx-load-fix-minor-false-positive-GCC-warning.patch + create mode 100644 package/libmdbx/0006-mdbx-cmake-pthread-workaround-for-buggy-toolchain-cm.patch + create mode 100644 package/libmdbx/0007-mdbx-fix-pthread_yield-for-non-GLIBC.patch + create mode 100644 package/libmdbx/Config.in + create mode 100644 package/libmdbx/libmdbx.hash + create mode 100644 package/libmdbx/libmdbx.mk + +diff --git a/DEVELOPERS b/DEVELOPERS +index f8655fa054..924e70e30c 100644 +--- a/DEVELOPERS ++++ b/DEVELOPERS +@@ -1551,6 +1551,9 @@ N: Leon Anavi + F: board/olimex/a10_olinuxino + F: configs/olimex_a10_olinuxino_lime_defconfig + ++N: Leonid Yuriev ++F: package/libmdbx ++ + N: Lionel Flandrin + F: package/python-babel/ + F: package/python-daemonize/ +diff --git a/package/Config.in b/package/Config.in +index 51583d07d6..f87e0388a0 100644 +--- a/package/Config.in ++++ b/package/Config.in +@@ -1370,6 +1370,7 @@ menu "Database" + source "package/kompexsqlite/Config.in" + source "package/leveldb/Config.in" + source "package/libgit2/Config.in" ++ source "package/libmdbx/Config.in" + source "package/libodb/Config.in" + source "package/libodb-boost/Config.in" + source "package/libodb-mysql/Config.in" +diff --git a/package/libmdbx/0001-mdbx-fix-minor-copy-paste-typo.patch b/package/libmdbx/0001-mdbx-fix-minor-copy-paste-typo.patch +new file mode 100644 +index 0000000000..d9ff3c5e71 +--- /dev/null ++++ b/package/libmdbx/0001-mdbx-fix-minor-copy-paste-typo.patch +@@ -0,0 +1,27 @@ ++From 5807e2eda046bff35946972289236bbef5c0c597 Mon Sep 17 00:00:00 2001 ++From: Leonid Yuriev ++Date: Thu, 1 Oct 2020 02:27:29 +0300 ++Subject: [PATCH] mdbx++: fix minor copy&paste typo. ++ ++Change-Id: I0af3e7ffbbd1231069a60f9f48880df3df2141d7 ++Signed-off-by: Leonid Yuriev ++--- ++ mdbx.h++ | 2 +- ++ 1 file changed, 1 insertion(+), 1 deletion(-) ++ ++diff --git a/mdbx.h++ b/mdbx.h++ ++index 095ff9abb..2050f4b92 100644 ++--- a/mdbx.h++ +++++ b/mdbx.h++ ++@@ -538,7 +538,7 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val { ++ byte *from_base58(byte *dest, size_t dest_size, ++ bool ignore_spaces = false) const; ++ ++- /// vReturns the buffer size in bytes needed for conversion +++ /// \brief Returns the buffer size in bytes needed for conversion ++ /// [Base58](https://en.wikipedia.org/wiki/Base58) dump to data. ++ MDBX_CXX11_CONSTEXPR size_t from_base58_bytes() const noexcept { ++ return length() / 11 * 8 + length() % 11 * 32 / 43; ++-- ++2.28.0 ++ +diff --git a/package/libmdbx/0002-mdbx-cmake-fix-missing-installation-of-mdbx.h.patch b/package/libmdbx/0002-mdbx-cmake-fix-missing-installation-of-mdbx.h.patch +new file mode 100644 +index 0000000000..df49342ccb +--- /dev/null ++++ b/package/libmdbx/0002-mdbx-cmake-fix-missing-installation-of-mdbx.h.patch +@@ -0,0 +1,54 @@ ++From dc2cd19d566e84451ee47cf04277f97bc22771c5 Mon Sep 17 00:00:00 2001 ++From: Leonid Yuriev ++Date: Fri, 2 Oct 2020 00:05:02 +0300 ++Subject: [PATCH] mdbx-cmake: fix missing installation of `mdbx.h++` ++ ++Change-Id: I41975e4eeff6583a266b273b9a4f8486982ede90 ++Signed-off-by: Leonid Yuriev ++--- ++ CMakeLists.txt | 8 +++++--- ++ 1 file changed, 5 insertions(+), 3 deletions(-) ++ ++diff --git a/CMakeLists.txt b/CMakeLists.txt ++index 28db425c5..95f116521 100644 ++--- a/CMakeLists.txt +++++ b/CMakeLists.txt ++@@ -485,7 +485,8 @@ fetch_version(MDBX "${CMAKE_CURRENT_SOURCE_DIR}" FALSE) ++ message(STATUS "libmdbx version is ${MDBX_VERSION}") ++ ++ # sources list ++-set(LIBMDBX_SOURCES mdbx.h "${CMAKE_CURRENT_BINARY_DIR}/config.h" ) +++set(LIBMDBX_PUBLIC_HEADERS mdbx.h) +++set(LIBMDBX_SOURCES mdbx.h "${CMAKE_CURRENT_BINARY_DIR}/config.h") ++ if(MDBX_AMALGAMATED_SOURCE) ++ list(APPEND LIBMDBX_SOURCES mdbx.c) ++ else() ++@@ -511,6 +512,7 @@ else() ++ endif(MDBX_AMALGAMATED_SOURCE) ++ if(MDBX_BUILD_CXX) ++ message(STATUS "Use C${MDBX_C_STANDARD} and C++${MDBX_CXX_STANDARD} for libmdbx") +++ list(APPEND LIBMDBX_PUBLIC_HEADERS mdbx.h++) ++ list(APPEND LIBMDBX_SOURCES "${MDBX_SOURCE_DIR}/mdbx.c++" mdbx.h++) ++ else() ++ message(STATUS "Use C${MDBX_C_STANDARD} for libmdbx but C++ portion is disabled") ++@@ -561,7 +563,7 @@ if(MDBX_INSTALL_STATIC) ++ else() ++ add_library(mdbx-static STATIC EXCLUDE_FROM_ALL ${LIBMDBX_SOURCES}) ++ endif() ++-set_target_properties(mdbx-static PROPERTIES PUBLIC_HEADER mdbx.h) +++set_target_properties(mdbx-static PROPERTIES PUBLIC_HEADER "${LIBMDBX_PUBLIC_HEADERS}") ++ target_compile_definitions(mdbx-static PRIVATE MDBX_BUILD_SHARED_LIBRARY=0) ++ target_setup_options(mdbx-static) ++ libmdbx_setup_libs(mdbx-static INTERFACE) ++@@ -576,7 +578,7 @@ endif() ++ # build shared library ++ if(MDBX_BUILD_SHARED_LIBRARY) ++ add_library(mdbx SHARED ${LIBMDBX_SOURCES}) ++- set_target_properties(mdbx PROPERTIES PUBLIC_HEADER mdbx.h) +++ set_target_properties(mdbx PROPERTIES PUBLIC_HEADER "${LIBMDBX_PUBLIC_HEADERS}") ++ target_compile_definitions(mdbx PRIVATE LIBMDBX_EXPORTS MDBX_BUILD_SHARED_LIBRARY=1 INTERFACE LIBMDBX_IMPORTS) ++ target_setup_options(mdbx) ++ libmdbx_setup_libs(mdbx PRIVATE) ++-- ++2.28.0 ++ +diff --git a/package/libmdbx/0003-mdbx-fix-obsolete-__noreturn.patch b/package/libmdbx/0003-mdbx-fix-obsolete-__noreturn.patch +new file mode 100644 +index 0000000000..cb04334220 +--- /dev/null ++++ b/package/libmdbx/0003-mdbx-fix-obsolete-__noreturn.patch +@@ -0,0 +1,27 @@ ++From 280ed17ea2dff464c9688fcc92079f36d8b74621 Mon Sep 17 00:00:00 2001 ++From: Leonid Yuriev ++Date: Sat, 3 Oct 2020 11:35:26 +0300 ++Subject: [PATCH] mdbx: fix obsolete `__noreturn`. ++ ++Change-Id: Ic78843d6f16de2a409c16ceecc7acb2ed8aa3e68 ++Signed-off-by: Leonid Yuriev ++--- ++ mdbx.c | 2 +- ++ 1 file changed, 1 insertion(+), 1 deletion(-) ++ ++diff --git a/mdbx.c b/mdbx.c ++index 04ea5140d..9212640fe 100644 ++--- a/mdbx.c +++++ b/mdbx.c ++@@ -141,7 +141,7 @@ __extern_C void __assert(const char *, const char *, unsigned int, const char *) ++ #else ++ __nothrow ++ #endif /* __THROW */ ++- __noreturn; +++ MDBX_NORETURN; ++ #define __assert_fail(assertion, file, line, function) \ ++ __assert(assertion, file, line, function) ++ ++-- ++2.28.0 ++ +diff --git a/package/libmdbx/0004-mdbx-don-t-use-yield-instruction-on-ARM-if-unsupport.patch b/package/libmdbx/0004-mdbx-don-t-use-yield-instruction-on-ARM-if-unsupport.patch +new file mode 100644 +index 0000000000..23f91d859b +--- /dev/null ++++ b/package/libmdbx/0004-mdbx-don-t-use-yield-instruction-on-ARM-if-unsupport.patch +@@ -0,0 +1,28 @@ ++From 70b615e8d4d10cda2d961a815dd15eb87a1f3925 Mon Sep 17 00:00:00 2001 ++From: Leonid Yuriev ++Date: Sun, 4 Oct 2020 14:54:11 +0300 ++Subject: [PATCH] mdbx: don't use `yield` instruction on ARM if unsupported. ++ ++Change-Id: I0b01d783fe4336b089f4b051fb61c203b5879aa5 ++Signed-off-by: Leonid Yuriev ++--- ++ mdbx.c | 3 ++- ++ 1 file changed, 2 insertions(+), 1 deletion(-) ++ ++diff --git a/mdbx.c b/mdbx.c ++index aba445424..a9ba1ee85 100644 ++--- a/mdbx.c +++++ b/mdbx.c ++@@ -763,7 +763,8 @@ static __always_inline void atomic_yield(void) { ++ #else ++ __asm__ __volatile__("hint @pause"); ++ #endif ++-#elif defined(__arm__) || defined(__aarch64__) +++#elif defined(__aarch64__) || (defined(__ARM_ARCH) && __ARM_ARCH > 6) || \ +++ defined(__ARM_ARCH_6K__) ++ #ifdef __CC_ARM ++ __yield(); ++ #else ++-- ++2.28.0 ++ +diff --git a/package/libmdbx/0005-mdbx-load-fix-minor-false-positive-GCC-warning.patch b/package/libmdbx/0005-mdbx-load-fix-minor-false-positive-GCC-warning.patch +new file mode 100644 +index 0000000000..29d69e3faa +--- /dev/null ++++ b/package/libmdbx/0005-mdbx-load-fix-minor-false-positive-GCC-warning.patch +@@ -0,0 +1,27 @@ ++From 8d4e7994c0c5c0cf69326139717e324f90bff65b Mon Sep 17 00:00:00 2001 ++From: Leonid Yuriev ++Date: Mon, 5 Oct 2020 15:09:10 +0300 ++Subject: [PATCH] mdbx-load: fix minor false-positive GCC warning. ++ ++Change-Id: Ie75c793712d050e8d3da76a4d0a8df9b81dc5275 ++Signed-off-by: Leonid Yuriev ++--- ++ mdbx_load.c | 2 +- ++ 1 file changed, 1 insertion(+), 1 deletion(-) ++ ++diff --git a/mdbx_load.c b/mdbx_load.c ++index e5e72fc8f..54e179553 100644 ++--- a/mdbx_load.c +++++ b/mdbx_load.c ++@@ -318,7 +318,7 @@ static int readhdr(void) { ++ } ++ ++ for (int i = 0; dbflags[i].bit; i++) { ++- bool value; +++ bool value = false; ++ if (valbool(dbuf.iov_base, dbflags[i].name, &value)) { ++ if (value) ++ dbi_flags |= dbflags[i].bit; ++-- ++2.28.0 ++ +diff --git a/package/libmdbx/0006-mdbx-cmake-pthread-workaround-for-buggy-toolchain-cm.patch b/package/libmdbx/0006-mdbx-cmake-pthread-workaround-for-buggy-toolchain-cm.patch +new file mode 100644 +index 0000000000..37525cf0d5 +--- /dev/null ++++ b/package/libmdbx/0006-mdbx-cmake-pthread-workaround-for-buggy-toolchain-cm.patch +@@ -0,0 +1,65 @@ ++From 787eaaa373073e17f3a53658b085c255bc2c8ff8 Mon Sep 17 00:00:00 2001 ++From: Leonid Yuriev ++Date: Mon, 5 Oct 2020 19:12:20 +0300 ++Subject: [PATCH] mdbx-cmake: pthread workaround for buggy ++ toolchain/cmake/buildroot. ++ ++Change-Id: I0d95e783abbd10a63cd1595a9de50593e814a967 ++Signed-off-by: Leonid Yuriev ++--- ++ CMakeLists.txt | 21 ++++++++++++++++++--- ++ 1 file changed, 18 insertions(+), 3 deletions(-) ++ ++diff --git a/CMakeLists.txt b/CMakeLists.txt ++index 95f116521..20a50a453 100644 ++--- a/CMakeLists.txt +++++ b/CMakeLists.txt ++@@ -173,10 +173,27 @@ if(NOT CMAKE_BUILD_TYPE) ++ endif() ++ string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPERCASE) ++ +++set(CMAKE_THREAD_PREFER_PTHREAD TRUE) +++set(THREADS_PREFER_PTHREAD_FLAG TRUE) +++find_package(Threads REQUIRED) +++ ++ include(cmake/utils.cmake) ++ include(cmake/compiler.cmake) ++ include(cmake/profile.cmake) ++ +++# Workaround for `-pthread` toolchain/cmake bug +++if(NOT APPLE AND NOT MSVC +++ AND CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_THREAD_LIBS_INIT +++ AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)) +++ check_compiler_flag("-pthread" CC_HAS_PTHREAD) +++ if(CC_HAS_PTHREAD AND NOT CMAKE_EXE_LINKER_FLAGS MATCHES "-pthread") +++ message(STATUS "Force add -pthread for linker flags to avoid troubles") +++ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") +++ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pthread") +++ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -pthread") +++ endif() +++endif() +++ ++ CHECK_FUNCTION_EXISTS(pow NOT_NEED_LIBM) ++ if(NOT_NEED_LIBM) ++ set(LIB_MATH "") ++@@ -190,8 +207,6 @@ else() ++ endif() ++ endif() ++ ++-find_package(Threads REQUIRED) ++- ++ if(SUBPROJECT) ++ if(NOT DEFINED BUILD_SHARED_LIBS) ++ option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)" OFF) ++@@ -541,7 +556,7 @@ macro(target_setup_options TARGET) ++ endmacro() ++ ++ macro(libmdbx_setup_libs TARGET MODE) ++- target_link_libraries(${TARGET} ${MODE} ${CMAKE_THREAD_LIBS_INIT}) +++ target_link_libraries(${TARGET} ${MODE} Threads::Threads) ++ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") ++ target_link_libraries(${TARGET} ${MODE} ntdll.lib) ++ if(MDBX_NTDLL_EXTRA_IMPLIB AND MDBX_AVOID_CRT) ++-- ++2.28.0 ++ +diff --git a/package/libmdbx/0007-mdbx-fix-pthread_yield-for-non-GLIBC.patch b/package/libmdbx/0007-mdbx-fix-pthread_yield-for-non-GLIBC.patch +new file mode 100644 +index 0000000000..5d7e83d4c7 +--- /dev/null ++++ b/package/libmdbx/0007-mdbx-fix-pthread_yield-for-non-GLIBC.patch +@@ -0,0 +1,42 @@ ++From 16d43332a9d28ba27aa3d127e8f6b77a87b2f5eb Mon Sep 17 00:00:00 2001 ++From: Leonid Yuriev ++Date: Mon, 5 Oct 2020 21:08:09 +0300 ++Subject: [PATCH] mdbx: fix `pthread_yield()` for non-GLIBC. ++ ++Change-Id: I080e37a42b62e524896dea8747e9f23e2fcd584f ++Signed-off-by: Leonid Yuriev ++--- ++ mdbx.c | 4 +++- ++ mdbx.c | 1 + ++ 2 files changed, 4 insertions(+), 1 deletion(-) ++ ++diff --git a/mdbx.c b/mdbx.c ++index a9ba1ee85..ace6f2756 100644 ++--- a/mdbx.c +++++ b/mdbx.c ++@@ -777,7 +777,9 @@ static __always_inline void atomic_yield(void) { ++ defined(__mips64__) || defined(_M_MRX000) || defined(_MIPS_) || \ ++ defined(__MWERKS__) || defined(__sgi) ++ __asm__ __volatile__(".word 0x00000140"); ++-#else +++#elif defined(__linux__) || defined(__gnu_linux__) || defined(_UNIX03_SOURCE) +++ sched_yield(); +++#elif (defined(_GNU_SOURCE) && __GLIBC_PREREQ(2, 1)) || defined(_OPEN_THREADS) ++ pthread_yield(); ++ #endif ++ } ++diff --git a/mdbx.c b/mdbx.c ++index 3509942dc..3af23ce0b 100644 ++--- a/mdbx.c +++++ b/mdbx.c ++@@ -119,6 +119,7 @@ ++ ++ #if defined(__linux__) || defined(__gnu_linux__) ++ #include +++#include ++ #include ++ #include ++ #endif /* Linux */ ++-- ++2.28.0 ++ +diff --git a/package/libmdbx/Config.in b/package/libmdbx/Config.in +new file mode 100644 +index 0000000000..dc36f12348 +--- /dev/null ++++ b/package/libmdbx/Config.in +@@ -0,0 +1,42 @@ ++config BR2_PACKAGE_LIBMDBX ++ bool "libmdbx" ++ depends on BR2_USE_MMU ++ depends on BR2_TOOLCHAIN_HAS_THREADS ++ depends on BR2_TOOLCHAIN_GCC_AT_LEAST_4_4 ++ depends on BR2_TOOLCHAIN_HAS_SYNC_4 ++ help ++ One of the fastest compact key-value ACID database ++ without WAL. libmdbx has a specific set of properties ++ and capabilities, focused on creating unique lightweight ++ solutions. ++ ++ libmdbx surpasses the legendary LMDB in terms of ++ reliability, features and performance. ++ ++ https://github.com/erthink/libmdbx ++ ++if BR2_PACKAGE_LIBMDBX ++ ++config BR2_PACKAGE_LIBMDBX_TOOLS ++ bool "install tools" ++ help ++ Install libmdbx tools for checking, dump, restore ++ and show statistics of databases. ++ ++config BR2_PACKAGE_LIBMDBX_CXX ++ bool "C++ API" ++ depends on BR2_INSTALL_LIBSTDCPP ++ depends on BR2_TOOLCHAIN_GCC_AT_LEAST_4_8 ++ help ++ Enable modern C++11/14/17/20 API for libmdbx. ++ ++comment "libmdbx C++ support needs a toolchain w/ C++11, gcc >= 4.8" ++ depends on !BR2_INSTALL_LIBSTDCPP || \ ++ !BR2_TOOLCHAIN_GCC_AT_LEAST_4_8 ++ ++endif ++ ++comment "libmdbx needs a toolchain w/ threads, gcc >= 4.4" ++ depends on BR2_USE_MMU ++ depends on !BR2_TOOLCHAIN_HAS_THREADS || \ ++ !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4 +diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash +new file mode 100644 +index 0000000000..f48cd81a7d +--- /dev/null ++++ b/package/libmdbx/libmdbx.hash +@@ -0,0 +1,2 @@ ++sha256 310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569 LICENSE ++sha256 c7fb24381eb4d92f2e2edc17e577cb721269683c816c6cca307c58f6f346e786 libmdbx-amalgamated-0.9.1.tar.gz +diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk +new file mode 100644 +index 0000000000..be0c2d7b06 +--- /dev/null ++++ b/package/libmdbx/libmdbx.mk +@@ -0,0 +1,24 @@ ++################################################################################ ++# ++# libmdbx ++# ++################################################################################ ++ ++LIBMDBX_VERSION = 0.9.1 ++LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.gz ++LIBMDBX_SITE = https://github.com/erthink/libmdbx/releases/download/v$(LIBMDBX_VERSION) ++LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO ++LIBMDBX_LICENSE = OLDAP-2.8 ++LIBMDBX_LICENSE_FILES = LICENSE ++LIBMDBX_REDISTRIBUTE = YES ++LIBMDBX_STRIP_COMPONENTS = 0 ++LIBMDBX_INSTALL_STAGING = YES ++ ++LIBMDBX_CONF_OPTS = -DMDBX_INSTALL_MANPAGES=OFF -DBUILD_FOR_NATIVE_CPU=OFF \ ++ -DMDBX_INSTALL_STATIC=$(if $(BR2_STATIC_LIBS),ON,OFF) \ ++ -DMDBX_BUILD_SHARED_LIBRARY=$(if $(BR2_SHARED_LIBS),ON,OFF) \ ++ -DMDBX_BUILD_CXX=$(if $(BR2_PACKAGE_LIBMDBX_CXX),ON,OFF) \ ++ -DMDBX_BUILD_TOOLS=$(if $(BR2_PACKAGE_LIBMDBX_TOOLS),ON,OFF) \ ++ -DMDBX_LINK_TOOLS_NONSTATIC=$(if $(BR2_SHARED_LIBS),ON,OFF) ++ ++$(eval $(cmake-package)) +-- +2.28.0 + From 7ba13d8e72db1c905a5fbd6e29c3c54dd6c7d4f8 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Thu, 8 Oct 2020 23:16:06 +0300 Subject: [PATCH 02/20] mdbx: add internal bits/flags table. Change-Id: Ia9d0e9f678b51d8ffd1830998e9cd5d04c749974 --- src/bits.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/bits.md diff --git a/src/bits.md b/src/bits.md new file mode 100644 index 00000000..4a18c00a --- /dev/null +++ b/src/bits.md @@ -0,0 +1,34 @@ +N | MASK | ENV | TXN | DB | PUT | DBI | NODE | PAGE | +--|---------|-----------|--------------|----------|-----------|------------|---------|----------| +0 |0000 0001| |TXN_FINISHED | | |DBI_DIRTY |F_BIGDATA|P_BRANCH +1 |0000 0002| |TXN_ERROR |REVERSEKEY| |DBI_STALE |F_SUBDATA|P_LEAF +2 |0000 0004| |TXN_DIRTY |DUPSORT | |DBI_FRESH |F_DUPDATA|P_OVERFLOW +3 |0000 0008| |TXN_SPILLS |INTEGERKEY| |DBI_CREAT | |P_META +4 |0000 0010| |TXN_HAS_CHILD |DUPFIXED |NOOVERWRITE|DBI_VALID | |P_DIRTY +5 |0000 0020| | |INTEGERDUP|NODUPDATA |DBI_USRVALID| |P_LEAF2 +6 |0000 0040| | |REVERSEDUP|CURRENT |DBI_DUPDATA | |P_SUBP +7 |0000 0080| | | |ALLDUPS |DBI_AUDITED | | +8 |0000 0100| | | | | | | +9 |0000 0200| | | | | | | +10|0000 0400| | | | | | | +11|0000 0800| | | | | | | +12|0000 1000| | | | | | | +13|0000 2000| | | | | | | +14|0000 4000|NOSUBDIR | | | | | |P_LOOSE +15|0000 8000| | |DB_VALID | | | |P_KEEP +16|0001 0000|SAFE_NOSYNC|TXN_NOSYNC | |RESERVE | |RESERVE | +17|0002 0000|RDONLY |TXN_RDONLY | |APPEND | |APPEND | +18|0004 0000|NOMETASYNC |TXN_NOMETASYNC|CREATE |APPENDDUP +19|0008 0000|WRITEMAP |<= | |MULTIPLE +20|0010 0000|UTTERLY | | +21|0020 0000|NOTLS |<= | +22|0040 0000|EXCLUSIVE | | +23|0080 0000|NORDAHEAD | | +24|0100 0000|NOMEMINIT |TXN_PREPARE | +25|0200 0000|COALESCE | | +26|0400 0000|LIFORECLAIM| | +27|0800 0000|PAGEPERTURB| | +28|1000 0000|ENV_TXKEY |TXN_TRY | +29|2000 0000|ENV_ACTIVE | | +30|4000 0000|ACCEDE |SHRINK_ALLOWED|DB_ACCEDE +31|8000 0000|FATAL_ERROR| | From 9bf7d53dc2434b145c4ab5b72e4a34fdab91c71a Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Fri, 9 Oct 2020 00:14:59 +0300 Subject: [PATCH 03/20] mdbx: `MAX_MAPSIZE32` value has been reduced to `0x7f000000`. Change-Id: Ia45dd56621cd92441a45b8e80420a124cd111fdc --- src/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internals.h b/src/internals.h index 6754ab15..4987d4c3 100644 --- a/src/internals.h +++ b/src/internals.h @@ -619,7 +619,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) From c4e3b9530182956e940efdcfc19eba43678b688e Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Fri, 9 Oct 2020 17:39:21 +0300 Subject: [PATCH 04/20] mdbx: clarify the `mdbx_env_open()`'s `pathname` parameter description. Change-Id: I1afafe621b2047abe4af02d37d51142a94abb982 --- mdbx.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mdbx.h b/mdbx.h index 982f5973..a4282474 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1737,8 +1737,9 @@ LIBMDBX_API int mdbx_env_create(MDBX_env **penv); * \param [in] env An environment handle returned * by \ref mdbx_env_create() * - * \param [in] pathname The directory in which the database files reside. - * This directory must already exist and be writable. + * \param [in] pathname The pathname for the database or the directory in which + * the database files reside. In the case of directory it + * must already exist and be writable. * * \param [in] flags Special options for this environment. This parameter * must be set to 0 or by bitwise OR'ing together one From cd0c7278807fd747e087c0b090aa08f929e6baec Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Fri, 9 Oct 2020 17:51:06 +0300 Subject: [PATCH 05/20] mdbx: internally split-out `mdbx_handle_env_pathname()`. Change-Id: Ibe387662d737d4d1e274ac0e126053872be503f9 --- src/core.c | 109 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 45 deletions(-) diff --git a/src/core.c b/src/core.c index 5c3293be..15e53fcb 100644 --- a/src/core.c +++ b/src/core.c @@ -10368,22 +10368,20 @@ __cold int mdbx_env_open_for_recovery(MDBX_env *env, const char *pathname, 0); } -__cold int mdbx_env_open(MDBX_env *env, const char *pathname, - MDBX_env_flags_t flags, mdbx_mode_t mode) { - int rc = check_env(env); - if (unlikely(rc != MDBX_SUCCESS)) - return rc; +typedef struct { + void *buffer_for_free; + char *lck, *dxb; +} MDBX_handle_env_pathname; +__cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *result, + const char *pathname, + MDBX_env_flags_t *flags, + const mdbx_mode_t mode) { + int rc; + memset(result, 0, sizeof(*result)); if (unlikely(!pathname)) return MDBX_EINVAL; - if (flags & ~ENV_USABLE_FLAGS) - return MDBX_EINVAL; - - if (env->me_lazy_fd != INVALID_HANDLE_VALUE || - (env->me_flags & MDBX_ENV_ACTIVE) != 0) - return MDBX_EPERM; - #if defined(_WIN32) || defined(_WIN64) const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX); if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX) @@ -10391,33 +10389,28 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t)); if (wlen != mbstowcs(pathnameW, pathname, wlen + 1)) return ERROR_INVALID_NAME; -#endif /* Windows */ - /* pickup previously mdbx_env_set_flags(), - * but avoid MDBX_UTTERLY_NOSYNC by disjunction */ - flags = merge_sync_flags(flags, env->me_flags); - -#if defined(_WIN32) || defined(_WIN64) const DWORD dwAttrib = GetFileAttributesW(pathnameW); if (dwAttrib == INVALID_FILE_ATTRIBUTES) { rc = GetLastError(); if (rc != MDBX_ENOFILE) return rc; - if (mode == 0 || (flags & MDBX_RDONLY) != 0) + if (mode == 0 || (*flags & MDBX_RDONLY) != 0) /* can't open existing */ return rc; /* auto-create directory if requested */ - if ((flags & MDBX_NOSUBDIR) == 0 && !CreateDirectoryW(pathnameW, nullptr)) { + if ((*flags & MDBX_NOSUBDIR) == 0 && + !CreateDirectoryW(pathnameW, nullptr)) { rc = GetLastError(); if (rc != ERROR_ALREADY_EXISTS) return rc; } } else { /* ignore passed MDBX_NOSUBDIR flag and set it automatically */ - flags |= MDBX_NOSUBDIR; + *flags |= MDBX_NOSUBDIR; if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) - flags -= MDBX_NOSUBDIR; + *flags -= MDBX_NOSUBDIR; } #else struct stat st; @@ -10425,7 +10418,7 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, rc = errno; if (rc != MDBX_ENOFILE) return rc; - if (mode == 0 || (flags & MDBX_RDONLY) != 0) + if (mode == 0 || (*flags & MDBX_RDONLY) != 0) /* can't open existing */ return rc; @@ -10436,41 +10429,67 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, /* always add read/write/search for owner */ S_IRWXU | ((mode & S_IRGRP) ? /* +search if readable by group */ S_IXGRP : 0) | ((mode & S_IROTH) ? /* +search if readable by others */ S_IXOTH : 0); - if ((flags & MDBX_NOSUBDIR) == 0 && mkdir(pathname, dir_mode)) { + if ((*flags & MDBX_NOSUBDIR) == 0 && mkdir(pathname, dir_mode)) { rc = errno; if (rc != EEXIST) return rc; } } else { /* ignore passed MDBX_NOSUBDIR flag and set it automatically */ - flags |= MDBX_NOSUBDIR; + *flags |= MDBX_NOSUBDIR; if (S_ISDIR(st.st_mode)) - flags -= MDBX_NOSUBDIR; + *flags -= MDBX_NOSUBDIR; } #endif size_t len_full, len = strlen(pathname); - if (flags & MDBX_NOSUBDIR) { + if (*flags & MDBX_NOSUBDIR) { len_full = len + sizeof(MDBX_LOCK_SUFFIX) + len + 1; } else { len_full = len + sizeof(MDBX_LOCKNAME) + len + sizeof(MDBX_DATANAME); } - char *lck_pathname = mdbx_malloc(len_full); - if (!lck_pathname) + + result->buffer_for_free = mdbx_malloc(len_full); + if (!result->buffer_for_free) return MDBX_ENOMEM; - char *dxb_pathname; - if (flags & MDBX_NOSUBDIR) { - dxb_pathname = lck_pathname + len + sizeof(MDBX_LOCK_SUFFIX); - sprintf(lck_pathname, "%s" MDBX_LOCK_SUFFIX, pathname); - strcpy(dxb_pathname, pathname); + result->lck = result->buffer_for_free; + if (*flags & MDBX_NOSUBDIR) { + result->dxb = result->lck + len + sizeof(MDBX_LOCK_SUFFIX); + sprintf(result->lck, "%s" MDBX_LOCK_SUFFIX, pathname); + strcpy(result->dxb, pathname); } else { - dxb_pathname = lck_pathname + len + sizeof(MDBX_LOCKNAME); - sprintf(lck_pathname, "%s" MDBX_LOCKNAME, pathname); - sprintf(dxb_pathname, "%s" MDBX_DATANAME, pathname); + result->dxb = result->lck + len + sizeof(MDBX_LOCKNAME); + sprintf(result->lck, "%s" MDBX_LOCKNAME, pathname); + sprintf(result->dxb, "%s" MDBX_DATANAME, pathname); } - rc = MDBX_SUCCESS; + return MDBX_SUCCESS; +} + +__cold int mdbx_env_open(MDBX_env *env, const char *pathname, + MDBX_env_flags_t flags, mdbx_mode_t mode) { + int rc = check_env(env); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + + if (flags & ~ENV_USABLE_FLAGS) + return MDBX_EINVAL; + + if (env->me_lazy_fd != INVALID_HANDLE_VALUE || + (env->me_flags & MDBX_ENV_ACTIVE) != 0) + return MDBX_EPERM; + + /* pickup previously mdbx_env_set_flags(), + * but avoid MDBX_UTTERLY_NOSYNC by disjunction */ + const uint32_t saved_me_flags = env->me_flags; + flags = merge_sync_flags(flags, env->me_flags); + + MDBX_handle_env_pathname env_pathname; + rc = mdbx_handle_env_pathname(&env_pathname, pathname, &flags, mode); + if (unlikely(rc != MDBX_SUCCESS)) + goto bailout; + if (flags & MDBX_RDONLY) { /* LY: silently ignore irrelevant flags when * we're only getting read access */ @@ -10498,9 +10517,8 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, rc = MDBX_ENOMEM; } - const uint32_t saved_me_flags = env->me_flags; env->me_flags = (flags & ~MDBX_FATAL_ERROR) | MDBX_ENV_ACTIVE; - if (rc) + if (unlikely(rc != MDBX_SUCCESS)) goto bailout; env->me_path = mdbx_strdup(pathname); @@ -10516,20 +10534,20 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, rc = mdbx_openfile(F_ISSET(flags, MDBX_RDONLY) ? MDBX_OPEN_DXB_READ : MDBX_OPEN_DXB_LAZY, - env, dxb_pathname, &env->me_lazy_fd, mode); + env, env_pathname.dxb, &env->me_lazy_fd, mode); if (rc != MDBX_SUCCESS) goto bailout; mdbx_assert(env, env->me_dsync_fd == INVALID_HANDLE_VALUE); if ((flags & (MDBX_RDONLY | MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC)) == 0) { - rc = mdbx_openfile(MDBX_OPEN_DXB_DSYNC, env, dxb_pathname, + rc = mdbx_openfile(MDBX_OPEN_DXB_DSYNC, env, env_pathname.dxb, &env->me_dsync_fd, 0); mdbx_ensure(env, (rc != MDBX_SUCCESS) == (env->me_dsync_fd == INVALID_HANDLE_VALUE)); } #if MDBX_LOCKING == MDBX_LOCKING_SYSV - env->me_sysv_ipc.key = ftok(dxb_pathname, 42); + env->me_sysv_ipc.key = ftok(env_pathname.dxb, 42); if (env->me_sysv_ipc.key == -1) { rc = errno; goto bailout; @@ -10539,6 +10557,7 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, #if !(defined(_WIN32) || defined(_WIN64)) if (mode == 0) { /* pickup mode for lck-file */ + struct stat st; if (fstat(env->me_lazy_fd, &st)) { rc = errno; goto bailout; @@ -10551,7 +10570,7 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, ((mode & S_IRGRP) ? /* +write if readable by group */ S_IWGRP : 0) | ((mode & S_IROTH) ? /* +write if readable by others */ S_IWOTH : 0); #endif /* !Windows */ - const int lck_rc = mdbx_setup_lck(env, lck_pathname, mode); + const int lck_rc = mdbx_setup_lck(env, env_pathname.lck, mode); if (MDBX_IS_ERROR(lck_rc)) { rc = lck_rc; goto bailout; @@ -10686,7 +10705,7 @@ bailout: mdbx_txn_valgrind(env, nullptr); #endif } - mdbx_free(lck_pathname); + mdbx_free(env_pathname.buffer_for_free); return rc; } From 0627d902dd3499ff0dd8424624410cd9d585ef73 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Fri, 9 Oct 2020 22:43:14 +0300 Subject: [PATCH 06/20] mdbx: add `mdbx_env_delete()`. Resolves https://github.com/erthink/libmdbx/issues/119 Related to https://github.com/Kerollmops/heed/issues/58 Change-Id: Iec5bf5978e45bb6843f3ed8dd06ea4d34f2895cb --- ChangeLog.md | 1 + mdbx.h | 42 ++++++++++++++++++++++++++ src/core.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ src/lck-posix.c | 8 +++++ src/lck-windows.c | 9 ++++++ src/osal.c | 23 +++++++++++++++ src/osal.h | 5 +++- 7 files changed, 162 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index c7f4e94a..fe436def 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -11,6 +11,7 @@ TODO: Added features: - Provided package for [buildroot](https://buildroot.org/). + - Added `mdbx_env_delete()` for deletion an environment files in a proper and multiprocess-safe way. Fixes: diff --git a/mdbx.h b/mdbx.h index a4282474..de540016 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1801,6 +1801,48 @@ LIBMDBX_API int mdbx_env_create(MDBX_env **penv); LIBMDBX_API int mdbx_env_open(MDBX_env *env, const char *pathname, MDBX_env_flags_t flags, mdbx_mode_t mode); +/** \brief Deletion modes for \ref mdbx_env_delete() + * \ingroup c_extra + * \see mdbx_env_delete() */ +enum MDBX_env_delete_mode_t { + /** \brief Just delete the environment's files and directory if any. + * \note On POSIX systems, processes already working with the database will + * continue to work without interference until it close the environment. + * \note On Windows, the behavior of `MDB_ENV_JUST_DELETE` is different + * because the system does not support deleting files that are currently + * memory mapped. */ + MDBX_ENV_JUST_DELETE = 0, + /** Make sure that the environment is not being used by other processes, + * or return an error otherwise. */ + MDBX_ENV_ENSURE_UNUSED = 1, + /** Wait until other processes closes the environment before deletion. */ + MDBX_ENV_WAIT_FOR_UNUSED = 2, +}; +#ifndef __cplusplus +/** \c_extra c_statinfo */ +typedef enum MDBX_env_delete_mode_t MDBX_env_delete_mode_t; +#endif + +/** \brief Delete the environment files in a proper and multiprocess-safe way. + * \ingroup c_extra + * + * \param [in] pathname The pathname for the database or the directory in which + * the database files reside. + * + * \param [in] mode Special deletion mode for the environment. This + * parameter must be set to one of the values described + * above in the \ref MDBX_env_delete_mode_t section. + * + * \note The \ref MDBX_ENV_JUST_DELETE don't supported on Windows since system + * unable to delete a memory-mapped files. + * + * \returns A non-zero error value on failure and 0 on success, + * some possible errors are: + * \retval MDBX_RESULT_TRUE No corresponding files or directories were found, + * so no deletion was performed. */ +LIBMDBX_API int mdbx_env_delete(const char *pathname, + MDBX_env_delete_mode_t mode); + /** \brief Copy an MDBX environment to the specified path, with options. * \ingroup c_extra * diff --git a/src/core.c b/src/core.c index 15e53fcb..ae54192f 100644 --- a/src/core.c +++ b/src/core.c @@ -10467,6 +10467,81 @@ __cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *result, return MDBX_SUCCESS; } +__cold int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode) { + switch (mode) { + default: + return MDBX_EINVAL; + case MDBX_ENV_JUST_DELETE: + case MDBX_ENV_ENSURE_UNUSED: + case MDBX_ENV_WAIT_FOR_UNUSED: + break; + } + + MDBX_env dummy_env; + memset(&dummy_env, 0, sizeof(dummy_env)); + dummy_env.me_flags = + (mode == MDBX_ENV_ENSURE_UNUSED) ? MDBX_EXCLUSIVE : MDBX_ENV_DEFAULTS; + dummy_env.me_psize = dummy_env.me_os_psize = (unsigned)mdbx_syspagesize(); + dummy_env.me_path = (char *)pathname; + + MDBX_handle_env_pathname env_pathname; + STATIC_ASSERT(sizeof(dummy_env.me_flags) == sizeof(MDBX_env_flags_t)); + int rc = MDBX_RESULT_TRUE, + err = mdbx_handle_env_pathname( + &env_pathname, pathname, (MDBX_env_flags_t *)&dummy_env.me_flags, 0); + if (likely(err == MDBX_SUCCESS)) { + mdbx_filehandle_t clk_handle = INVALID_HANDLE_VALUE, + dxb_handle = INVALID_HANDLE_VALUE; + if (mode > MDBX_ENV_JUST_DELETE) { + err = mdbx_openfile(MDBX_OPEN_DELETE, &dummy_env, env_pathname.dxb, + &dxb_handle, 0); + err = (err == MDBX_ENOFILE) ? MDBX_SUCCESS : err; + if (err == MDBX_SUCCESS) { + err = mdbx_openfile(MDBX_OPEN_DELETE, &dummy_env, env_pathname.lck, + &clk_handle, 0); + err = (err == MDBX_ENOFILE) ? MDBX_SUCCESS : err; + } + if (err == MDBX_SUCCESS && clk_handle != INVALID_HANDLE_VALUE) + err = mdbx_lockfile(clk_handle, mode == MDBX_ENV_WAIT_FOR_UNUSED); + if (err == MDBX_SUCCESS && dxb_handle != INVALID_HANDLE_VALUE) + err = mdbx_lockfile(dxb_handle, mode == MDBX_ENV_WAIT_FOR_UNUSED); + } + + if (err == MDBX_SUCCESS) { + err = mdbx_removefile(env_pathname.dxb); + if (err == MDBX_SUCCESS) + rc = MDBX_SUCCESS; + else if (err == MDBX_ENOFILE) + err = MDBX_SUCCESS; + } + + if (err == MDBX_SUCCESS) { + err = mdbx_removefile(env_pathname.lck); + if (err == MDBX_SUCCESS) + rc = MDBX_SUCCESS; + else if (err == MDBX_ENOFILE) + err = MDBX_SUCCESS; + } + + if (err == MDBX_SUCCESS && !(dummy_env.me_flags & MDBX_NOSUBDIR)) { + err = mdbx_removedirectory(pathname); + if (err == MDBX_SUCCESS) + rc = MDBX_SUCCESS; + else if (err == MDBX_ENOFILE) + err = MDBX_SUCCESS; + } + + if (dxb_handle != INVALID_HANDLE_VALUE) + mdbx_closefile(dxb_handle); + if (clk_handle != INVALID_HANDLE_VALUE) + mdbx_closefile(clk_handle); + } else if (err == MDBX_ENOFILE) + err = MDBX_SUCCESS; + + mdbx_free(env_pathname.buffer_for_free); + return (err == MDBX_SUCCESS) ? rc : err; +} + __cold int mdbx_env_open(MDBX_env *env, const char *pathname, MDBX_env_flags_t flags, mdbx_mode_t mode) { int rc = check_env(env); diff --git a/src/lck-posix.c b/src/lck-posix.c index f879e4a9..dda7490b 100644 --- a/src/lck-posix.c +++ b/src/lck-posix.c @@ -190,6 +190,14 @@ static int lck_op(mdbx_filehandle_t fd, int cmd, int lck, off_t offset, } } +MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait) { +#if MDBX_USE_OFDLOCKS + if (unlikely(op_setlk == 0)) + choice_fcntl(); +#endif /* MDBX_USE_OFDLOCKS */ + return lck_op(fd, wait ? op_setlkw : op_setlk, F_WRLCK, 0, OFF_T_MAX); +} + MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env) { assert(env->me_lfd != INVALID_HANDLE_VALUE); assert(env->me_pid > 0); diff --git a/src/lck-windows.c b/src/lck-windows.c index 68c93b31..0ddd8c7d 100644 --- a/src/lck-windows.c +++ b/src/lck-windows.c @@ -204,6 +204,15 @@ MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env) { mdbx_srwlock_ReleaseShared(&env->me_remap_guard); } +MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait) { + return flock(fd, + wait ? LCK_EXCLUSIVE | LCK_WAITFOR + : LCK_EXCLUSIVE | LCK_DONTWAIT, + 0, LCK_MAXLEN) + ? MDBX_SUCCESS + : GetLastError(); +} + static int suspend_and_append(mdbx_handle_array_t **array, const DWORD ThreadId) { const unsigned limit = (*array)->limit; diff --git a/src/osal.c b/src/osal.c index 5c4dd2b6..92bcb79f 100644 --- a/src/osal.c +++ b/src/osal.c @@ -521,6 +521,20 @@ MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) { #endif } +MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname) { +#if defined(_WIN32) || defined(_WIN64) + const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX); + if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX) + return ERROR_INVALID_NAME; + wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t)); + if (wlen != mbstowcs(pathnameW, pathname, wlen + 1)) + return ERROR_INVALID_NAME; + return RemoveDirectoryW(pathnameW) ? MDBX_SUCCESS : GetLastError(); +#else + return rmdir(pathname) ? errno : MDBX_SUCCESS; +#endif +} + MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, const MDBX_env *env, const char *pathname, mdbx_filehandle_t *fd, @@ -571,6 +585,12 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, FlagsAndAttributes |= (env->me_psize < env->me_os_psize) ? 0 : FILE_FLAG_NO_BUFFERING; break; + case MDBX_OPEN_DELETE: + CreationDisposition = OPEN_EXISTING; + ShareMode |= FILE_SHARE_DELETE; + DesiredAccess = + FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE; + break; } *fd = CreateFileW(pathnameW, DesiredAccess, ShareMode, NULL, @@ -619,6 +639,9 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, flags |= O_FSYNC; #endif break; + case MDBX_OPEN_DELETE: + flags = O_RDWR; + break; } const bool direct_nocache_for_copy = diff --git a/src/osal.h b/src/osal.h index 8fdf9790..b47c2426 100644 --- a/src/osal.h +++ b/src/osal.h @@ -626,7 +626,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, @@ -635,7 +636,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 From 9afbde9b0ad4fc927b889cd7df73c1b1cfcf578b Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sat, 10 Oct 2020 00:59:12 +0300 Subject: [PATCH 07/20] mdbx-test: use `mdbx_env_delete()` in a test and drop aux functions. Change-Id: I3b0e409c23067abcaefd4f9c5627df804382b348 --- test/copy.cc | 4 ++-- test/main.cc | 19 ++----------------- test/osal-unix.cc | 8 -------- test/osal-windows.cc | 8 -------- test/osal.h | 2 -- 5 files changed, 4 insertions(+), 37 deletions(-) diff --git a/test/copy.cc b/test/copy.cc index 1a1513c1..9e07af7b 100644 --- a/test/copy.cc +++ b/test/copy.cc @@ -1,8 +1,8 @@ #include "test.h" void testcase_copy::copy_db(const bool with_compaction) { - int err = osal_removefile(copy_pathname); - if (err != MDBX_SUCCESS && err != MDBX_ENOFILE) + int err = mdbx_env_delete(copy_pathname.c_str(), MDBX_ENV_JUST_DELETE); + if (err != MDBX_SUCCESS && err != MDBX_RESULT_TRUE) failure_perror("mdbx_removefile()", err); err = mdbx_env_copy(db_guard.get(), copy_pathname.c_str(), diff --git a/test/main.cc b/test/main.cc index fd0bf21c..5d50b043 100644 --- a/test/main.cc +++ b/test/main.cc @@ -212,24 +212,9 @@ std::string thunk_param(const actor_config &config) { void cleanup() { log_trace(">> cleanup"); - const int is_dir = -#if defined(_WIN32) || defined(_WIN64) - ERROR_ACCESS_DENIED /* Windows API is mad */; -#else - EISDIR; -#endif for (const auto &db_path : global::databases) { - int err = osal_removefile(db_path); - if (err == is_dir) { - err = osal_removefile(db_path + MDBX_LOCKNAME); - if (err == MDBX_SUCCESS || err == MDBX_ENOFILE) - err = osal_removefile(db_path + MDBX_DATANAME); - if (err == MDBX_SUCCESS || err == MDBX_ENOFILE) - err = osal_removedirectory(db_path); - } else if (err == MDBX_SUCCESS || err == MDBX_ENOFILE) - err = osal_removefile(db_path + MDBX_LOCK_SUFFIX); - - if (err != MDBX_SUCCESS && err != MDBX_ENOFILE) + int err = mdbx_env_delete(db_path.c_str(), MDBX_ENV_JUST_DELETE); + if (err != MDBX_SUCCESS && err != MDBX_RESULT_TRUE) failure_perror(db_path.c_str(), err); } log_trace("<< cleanup"); diff --git a/test/osal-unix.cc b/test/osal-unix.cc index 7e552e5c..f8b1e1b4 100644 --- a/test/osal-unix.cc +++ b/test/osal-unix.cc @@ -531,12 +531,4 @@ std::string osal_tempdir(void) { return ""; } -int osal_removefile(const std::string &pathname) { - return unlink(pathname.c_str()) ? errno : MDBX_SUCCESS; -} - -int osal_removedirectory(const std::string &pathname) { - return rmdir(pathname.c_str()) ? errno : MDBX_SUCCESS; -} - #endif /* !Windows */ diff --git a/test/osal-windows.cc b/test/osal-windows.cc index ae31919e..94508030 100644 --- a/test/osal-windows.cc +++ b/test/osal-windows.cc @@ -452,12 +452,4 @@ std::string osal_tempdir(void) { return std::string(buf, len); } -int osal_removefile(const std::string &pathname) { - return DeleteFileA(pathname.c_str()) ? MDBX_SUCCESS : GetLastError(); -} - -int osal_removedirectory(const std::string &pathname) { - return RemoveDirectoryA(pathname.c_str()) ? MDBX_SUCCESS : GetLastError(); -} - #endif /* Windows */ diff --git a/test/osal.h b/test/osal.h index 129a9f1c..4318c0eb 100644 --- a/test/osal.h +++ b/test/osal.h @@ -34,8 +34,6 @@ void osal_udelay(unsigned us); void osal_yield(void); bool osal_istty(int fd); std::string osal_tempdir(void); -int osal_removefile(const std::string &pathname); -int osal_removedirectory(const std::string &pathname); #ifdef _MSC_VER #ifndef STDIN_FILENO From 6e82dd5d0c6ff32d20cd30d42c57f91523d7a87b Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sat, 10 Oct 2020 18:30:21 +0300 Subject: [PATCH 08/20] mdbx: minor refine description of `mdbx_env_delete()`. Change-Id: I095c741fba08b08c6302116d9601438d813524a1 --- mdbx.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mdbx.h b/mdbx.h index de540016..e4bd7305 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1801,7 +1801,7 @@ LIBMDBX_API int mdbx_env_create(MDBX_env **penv); LIBMDBX_API int mdbx_env_open(MDBX_env *env, const char *pathname, MDBX_env_flags_t flags, mdbx_mode_t mode); -/** \brief Deletion modes for \ref mdbx_env_delete() +/** \brief Deletion modes for \ref mdbx_env_delete(). * \ingroup c_extra * \see mdbx_env_delete() */ enum MDBX_env_delete_mode_t { @@ -1812,10 +1812,11 @@ enum MDBX_env_delete_mode_t { * because the system does not support deleting files that are currently * memory mapped. */ MDBX_ENV_JUST_DELETE = 0, - /** Make sure that the environment is not being used by other processes, - * or return an error otherwise. */ + /** \brief Make sure that the environment is not being used by other + * processes, or return an error otherwise. */ MDBX_ENV_ENSURE_UNUSED = 1, - /** Wait until other processes closes the environment before deletion. */ + /** \brief Wait until other processes closes the environment before deletion. + */ MDBX_ENV_WAIT_FOR_UNUSED = 2, }; #ifndef __cplusplus @@ -1823,7 +1824,7 @@ enum MDBX_env_delete_mode_t { typedef enum MDBX_env_delete_mode_t MDBX_env_delete_mode_t; #endif -/** \brief Delete the environment files in a proper and multiprocess-safe way. +/** \brief Delete the environment's files in a proper and multiprocess-safe way. * \ingroup c_extra * * \param [in] pathname The pathname for the database or the directory in which From 1d71c677f6b8d68a3ae6f4d542a611d3b948d741 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sat, 10 Oct 2020 18:31:15 +0300 Subject: [PATCH 09/20] mdbx++: add `env::remove()` method. Change-Id: If0396d38738df88d054eb8fb752c7bd3afbd8487 --- mdbx.h++ | 21 +++++++++++++++++++++ src/mdbx.c++ | 6 ++++++ 2 files changed, 27 insertions(+) diff --git a/mdbx.h++ b/mdbx.h++ index 2050f4b9..572ec604 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -1922,6 +1922,27 @@ public: /// \brief Copy an environment to the specified file descriptor. env ©(filehandle fd, bool compactify, bool force_dynamic_size = false); + /// \brief Deletion modes for \ref remove(). + enum remove_mode { + /// \brief Just delete the environment's files and directory if any. + /// \note On POSIX systems, processes already working with the database will + /// continue to work without interference until it close the environment. + /// \note On Windows, the behavior of `just_remove` is different + /// because the system does not support deleting files that are currently + /// memory mapped. + just_remove = MDBX_ENV_JUST_DELETE, + /// \brief Make sure that the environment is not being used by other + /// processes, or return an error otherwise. + ensure_unused = MDBX_ENV_ENSURE_UNUSED, + /// \brief Wait until other processes closes the environment before + /// deletion. + wait_for_unused = MDBX_ENV_WAIT_FOR_UNUSED + }; + + /// \brief Removes the environment's files in a proper and multiprocess-safe + /// way. + static bool remove(const path &, const remove_mode mode = just_remove); + /// \brief Statistics for a database in the MDBX environment. using stat = ::MDBX_stat; diff --git a/src/mdbx.c++ b/src/mdbx.c++ index 9f7d7571..18db236f 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -1119,6 +1119,12 @@ path env::get_path() const { return pchar_to_path(c_str); } +bool env::remove(const path &pathname, const remove_mode mode) { + const path_to_pchar utf8(pathname); + return error::boolean_or_throw( + ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode))); +} + //------------------------------------------------------------------------------ static inline MDBX_env *create_env() { From de1856a73cf79f702e7543abd6babc0050b19aef Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sat, 10 Oct 2020 20:07:00 +0300 Subject: [PATCH 10/20] mdbx: workaround for broken `DEFINE_ENUM_FLAG_OPERATORS` from Windows SDK. Change-Id: I5335c72061b7c5b6b29c683061a5da95544b9753 --- ChangeLog.md | 1 + mdbx.h | 48 ++++++++++++++++++++++++++++++++++++++++-------- mdbx.h++ | 16 ++++++++-------- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index fe436def..2395b116 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -25,6 +25,7 @@ Fixes: - Fixed opening DB on a network shares (in the exclusive mode). - Fixed copy&paste typos. - Fixed minor false-positive GCC warning. + - Added workaround for broken `DEFINE_ENUM_FLAG_OPERATORS` from Windows SDK. ## v0.9.1 2020-09-30 diff --git a/mdbx.h b/mdbx.h index e4bd7305..e04f2790 100644 --- a/mdbx.h +++ b/mdbx.h @@ -440,8 +440,27 @@ typedef mode_t mdbx_mode_t; #endif #endif /* MDBX_PRINTF_ARGS */ +/* Oh, below are some songs and dances since: + * - C++ requires explicit definition of the necessary operators. + * - the proper implementation of DEFINE_ENUM_FLAG_OPERATORS for C++ required + * the constexpr feature which is broken in most old compilers; + * - DEFINE_ENUM_FLAG_OPERATORS may be defined broken as in the Windows SDK. */ #ifndef DEFINE_ENUM_FLAG_OPERATORS -#if defined(__cplusplus) + +#ifdef __cplusplus +#if !defined(__cpp_constexpr) || __cpp_constexpr < 200704L || \ + (defined(__LCC__) && __LCC__ < 124) || \ + (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 407) && \ + !defined(__clang__) && !defined(__LCC__)) || \ + (defined(_MSC_VER) && _MSC_VER < 1910) || \ + (defined(__clang__) && __clang_major__ < 4) +/* The constexpr feature is not available or (may be) broken */ +#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 0 +#else +/* C always allows these operators for enums */ +#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 1 +#endif /* __cpp_constexpr */ + /// Define operator overloads to enable bit operations on enum values that are /// used to define flags (based on Microsoft's DEFINE_ENUM_FLAG_OPERATORS). #define DEFINE_ENUM_FLAG_OPERATORS(ENUM) \ @@ -462,10 +481,23 @@ typedef mode_t mdbx_mode_t; } \ MDBX_CXX14_CONSTEXPR ENUM &operator^=(ENUM &a, ENUM b) { return a = a ^ b; } \ } -#else /* __cplusplus */ -#define DEFINE_ENUM_FLAG_OPERATORS(ENUM) /* nope, C allows these operators */ -#endif /* !__cplusplus */ -#endif /* DEFINE_ENUM_FLAG_OPERATORS */ +#else /* __cplusplus */ +/* nope for C since it always allows these operators for enums */ +#define DEFINE_ENUM_FLAG_OPERATORS(ENUM) +#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 1 +#endif /* !__cplusplus */ + +#elif !defined(CONSTEXPR_ENUM_FLAGS_OPERATIONS) + +#ifdef __cplusplus +/* DEFINE_ENUM_FLAG_OPERATORS may be defined broken as in the Windows SDK */ +#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 0 +#else +/* C always allows these operators for enums */ +#define CONSTEXPR_ENUM_FLAGS_OPERATIONS 1 +#endif + +#endif /* DEFINE_ENUM_FLAG_OPERATORS */ /** @} end of Common Macros */ @@ -1251,10 +1283,10 @@ enum MDBX_txn_flags_t { * will be ready for use with \ref mdbx_txn_renew(). This flag allows to * preallocate memory and assign a reader slot, thus avoiding these operations * at the next start of the transaction. */ -#if defined(__cplusplus) && !defined(__cpp_constexpr) && !defined(DOXYGEN) - MDBX_TXN_RDONLY_PREPARE = uint32_t(MDBX_RDONLY) | uint32_t(MDBX_NOMEMINIT), -#else +#if CONSTEXPR_ENUM_FLAGS_OPERATIONS || defined(DOXYGEN) MDBX_TXN_RDONLY_PREPARE = MDBX_RDONLY | MDBX_NOMEMINIT, +#else + MDBX_TXN_RDONLY_PREPARE = uint32_t(MDBX_RDONLY) | uint32_t(MDBX_NOMEMINIT), #endif /** Do not block when starting a write transaction. */ diff --git a/mdbx.h++ b/mdbx.h++ index 572ec604..6848d705 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -1563,14 +1563,7 @@ enum class value_mode { ///< lexicographic comparison like `std::memcmp()`. ///< In terms of keys, they are not unique, i.e. has ///< duplicates which are sorted by associated data values. -#if !defined(__cpp_constexpr) && !defined(DOXYGEN) - multi_reverse = uint32_t(MDBX_DUPSORT) | uint32_t(MDBX_REVERSEDUP), - multi_samelength = uint32_t(MDBX_DUPSORT) | uint32_t(MDBX_DUPFIXED), - multi_ordinal = uint32_t(MDBX_DUPSORT) | uint32_t(MDBX_DUPFIXED) | - uint32_t(MDBX_INTEGERDUP), - multi_reverse_samelength = uint32_t(MDBX_DUPSORT) | - uint32_t(MDBX_REVERSEDUP) | uint32_t(MDBX_DUPFIXED) -#else +#if CONSTEXPR_ENUM_FLAGS_OPERATIONS || defined(DOXYGEN) multi_reverse = MDBX_DUPSORT | MDBX_REVERSEDUP, ///< A more than one data value could be associated with @@ -1617,6 +1610,13 @@ enum class value_mode { ///< In terms of keys, they are not unique, i.e. has duplicates ///< which are sorted by associated data values. ///< \note Not yet implemented and PRs are welcome. +#else + multi_reverse = uint32_t(MDBX_DUPSORT) | uint32_t(MDBX_REVERSEDUP), + multi_samelength = uint32_t(MDBX_DUPSORT) | uint32_t(MDBX_DUPFIXED), + multi_ordinal = uint32_t(MDBX_DUPSORT) | uint32_t(MDBX_DUPFIXED) | + uint32_t(MDBX_INTEGERDUP), + multi_reverse_samelength = uint32_t(MDBX_DUPSORT) | + uint32_t(MDBX_REVERSEDUP) | uint32_t(MDBX_DUPFIXED) #endif }; From 071ad525c8a66feefea33a2678c19f34ba00cfbd Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sun, 11 Oct 2020 00:14:53 +0300 Subject: [PATCH 11/20] mdbx: refine `handle_env_pathname()` for direct pathname of data-file inside sudir-mode. Change-Id: I5b7e7c7ea5c17e00c344fedb5c96f8d94fc04fc8 --- src/core.c | 54 ++++++++++++++++++++++++++++++------------------- src/internals.h | 2 +- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/core.c b/src/core.c index ae54192f..5cea9d1f 100644 --- a/src/core.c +++ b/src/core.c @@ -10371,14 +10371,15 @@ __cold int mdbx_env_open_for_recovery(MDBX_env *env, const char *pathname, typedef struct { void *buffer_for_free; char *lck, *dxb; + size_t ent_len; } MDBX_handle_env_pathname; -__cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *result, +__cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *ctx, const char *pathname, MDBX_env_flags_t *flags, const mdbx_mode_t mode) { int rc; - memset(result, 0, sizeof(*result)); + memset(ctx, 0, sizeof(*ctx)); if (unlikely(!pathname)) return MDBX_EINVAL; @@ -10442,26 +10443,35 @@ __cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *result, } #endif - size_t len_full, len = strlen(pathname); - if (*flags & MDBX_NOSUBDIR) { - len_full = len + sizeof(MDBX_LOCK_SUFFIX) + len + 1; - } else { - len_full = len + sizeof(MDBX_LOCKNAME) + len + sizeof(MDBX_DATANAME); + static const char dxb_name[] = MDBX_DATANAME; + static const size_t dxb_name_len = sizeof(dxb_name) - 1; + static const char lck_name[] = MDBX_LOCKNAME; + static const char lock_suffix[] = MDBX_LOCK_SUFFIX; + + ctx->ent_len = strlen(pathname); + if ((*flags & MDBX_NOSUBDIR) && ctx->ent_len >= dxb_name_len && + !memcmp(dxb_name, pathname + ctx->ent_len - dxb_name_len, dxb_name_len)) { + *flags -= MDBX_NOSUBDIR; + ctx->ent_len -= dxb_name_len; } - result->buffer_for_free = mdbx_malloc(len_full); - if (!result->buffer_for_free) + const size_t bytes_needed = + ctx->ent_len * 2 + ((*flags & MDBX_NOSUBDIR) + ? sizeof(lock_suffix) + 1 + : sizeof(lck_name) + sizeof(dxb_name)); + ctx->buffer_for_free = mdbx_malloc(bytes_needed); + if (!ctx->buffer_for_free) return MDBX_ENOMEM; - result->lck = result->buffer_for_free; + ctx->lck = ctx->buffer_for_free; if (*flags & MDBX_NOSUBDIR) { - result->dxb = result->lck + len + sizeof(MDBX_LOCK_SUFFIX); - sprintf(result->lck, "%s" MDBX_LOCK_SUFFIX, pathname); - strcpy(result->dxb, pathname); + ctx->dxb = ctx->lck + ctx->ent_len + sizeof(lock_suffix); + sprintf(ctx->lck, "%s%s", pathname, lock_suffix); + strcpy(ctx->dxb, pathname); } else { - result->dxb = result->lck + len + sizeof(MDBX_LOCKNAME); - sprintf(result->lck, "%s" MDBX_LOCKNAME, pathname); - sprintf(result->dxb, "%s" MDBX_DATANAME, pathname); + ctx->dxb = ctx->lck + ctx->ent_len + sizeof(lck_name); + sprintf(ctx->lck, "%.*s%s", (int)ctx->ent_len, pathname, lck_name); + sprintf(ctx->dxb, "%.*s%s", (int)ctx->ent_len, pathname, dxb_name); } return MDBX_SUCCESS; @@ -10482,7 +10492,7 @@ __cold int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode) { dummy_env.me_flags = (mode == MDBX_ENV_ENSURE_UNUSED) ? MDBX_EXCLUSIVE : MDBX_ENV_DEFAULTS; dummy_env.me_psize = dummy_env.me_os_psize = (unsigned)mdbx_syspagesize(); - dummy_env.me_path = (char *)pathname; + dummy_env.me_pathname = (char *)pathname; MDBX_handle_env_pathname env_pathname; STATIC_ASSERT(sizeof(dummy_env.me_flags) == sizeof(MDBX_env_flags_t)); @@ -10596,14 +10606,16 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, if (unlikely(rc != MDBX_SUCCESS)) goto bailout; - env->me_path = mdbx_strdup(pathname); + env->me_pathname = mdbx_calloc(env_pathname.ent_len + 1, 1); env->me_dbxs = mdbx_calloc(env->me_maxdbs, sizeof(MDBX_dbx)); env->me_dbflags = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbflags[0])); env->me_dbiseqs = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbiseqs[0])); - if (!(env->me_dbxs && env->me_path && env->me_dbflags && env->me_dbiseqs)) { + if (!(env->me_dbxs && env->me_pathname && env->me_dbflags && + env->me_dbiseqs)) { rc = MDBX_ENOMEM; goto bailout; } + memcpy(env->me_pathname, env_pathname.dxb, env_pathname.ent_len); env->me_dbxs[FREE_DBI].md_cmp = cmp_int_align4; /* aligned MDBX_INTEGERKEY */ env->me_dbxs[FREE_DBI].md_dcmp = cmp_lenfast; @@ -10841,7 +10853,7 @@ static int __cold mdbx_env_close0(MDBX_env *env) { mdbx_memalign_free(env->me_pbuf); mdbx_free(env->me_dbiseqs); mdbx_free(env->me_dbflags); - mdbx_free(env->me_path); + mdbx_free(env->me_pathname); mdbx_free(env->me_dirtylist); if (env->me_txn0) { mdbx_txl_free(env->me_txn0->tw.lifo_reclaimed); @@ -16812,7 +16824,7 @@ int __cold mdbx_env_get_path(const MDBX_env *env, const char **arg) { if (unlikely(!arg)) return MDBX_EINVAL; - *arg = env->me_path; + *arg = env->me_pathname; return MDBX_SUCCESS; } diff --git a/src/internals.h b/src/internals.h index 4987d4c3..49b8a3c0 100644 --- a/src/internals.h +++ b/src/internals.h @@ -953,7 +953,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 */ From 041a4c0aa533b1b8175304196600a0a80fd7a461 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sun, 11 Oct 2020 01:14:30 +0300 Subject: [PATCH 12/20] mdbx: make enabling of read-ahead strategy more aggressive. Change-Id: I7765c1a1ac27db86ce9676846ec5a723860dc934 --- src/core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core.c b/src/core.c index 5cea9d1f..4d3a0263 100644 --- a/src/core.c +++ b/src/core.c @@ -4820,7 +4820,8 @@ static __cold int mdbx_mapresize(MDBX_env *env, const pgno_t used_pgno, rc = mdbx_mresize(env->me_flags, &env->me_dxb_mmap, size_bytes, limit_bytes, mapping_can_be_moved); if (rc == MDBX_SUCCESS && (env->me_flags & MDBX_NORDAHEAD) == 0) { - const int readahead = mdbx_is_readahead_reasonable(size_bytes, 0); + const int readahead = + mdbx_is_readahead_reasonable(size_bytes, -(intptr_t)prev_size); if (readahead == MDBX_RESULT_FALSE) rc = mdbx_set_readahead( env, 0, (size_bytes > prev_size) ? size_bytes : prev_size, false); @@ -9685,6 +9686,10 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { mdbx_verbose("current boot-id %" PRIx64 "-%" PRIx64 " (%savailable)", bootid.x, bootid.y, (bootid.x | bootid.y) ? "" : "not-"); + /* calculate readahead hint before mmap with zero redundant pages */ + const bool readahead = + (env->me_flags & MDBX_NORDAHEAD) == 0 && + mdbx_is_readahead_reasonable(used_bytes, 0) == MDBX_RESULT_TRUE; err = mdbx_mmap(env->me_flags, &env->me_dxb_mmap, env->me_dbgeo.now, env->me_dbgeo.upper, lck_rc ? MMAP_OPTION_TRUNCATE : 0); if (unlikely(err != MDBX_SUCCESS)) @@ -9948,9 +9953,6 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { #endif /* MADV_DONTNEED */ } - const bool readahead = (env->me_flags & MDBX_NORDAHEAD) == 0 && - mdbx_is_readahead_reasonable(env->me_dxb_mmap.current, - 0) == MDBX_RESULT_TRUE; err = mdbx_set_readahead(env, 0, used_bytes, readahead); if (err != MDBX_SUCCESS && lck_rc == /* lck exclusive */ MDBX_RESULT_TRUE) return err; From 62da4db09a840e9b4ff2452932dc7357b2a3662f Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sun, 11 Oct 2020 18:54:07 +0300 Subject: [PATCH 13/20] mdbx: fix/refine the use of C11 atomics. Change-Id: I5d925d4625b06296fd82f4b35ee36be682e7b2d3 --- .github/actions/spelling/expect.txt | 1 + src/core.c | 66 ++++++++++++++++++++++------- src/osal.h | 59 ++++++++++++++------------ 3 files changed, 83 insertions(+), 43 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 2913488c..0e8631f1 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -208,6 +208,7 @@ csrc CSRSS css cstdarg +cstdatomic cstddef cstdint cstr diff --git a/src/core.c b/src/core.c index 4d3a0263..d91a6503 100644 --- a/src/core.c +++ b/src/core.c @@ -780,12 +780,24 @@ static __always_inline void atomic_yield(void) { #if MDBX_64BIT_CAS static __always_inline bool atomic_cas64(volatile uint64_t *p, uint64_t c, uint64_t v) { -#if defined(ATOMIC_VAR_INIT) || defined(ATOMIC_LLONG_LOCK_FREE) +#if !defined(__STDC_NO_ATOMICS__) && \ + (defined(ATOMIC_VAR_INIT) || defined(ATOMIC_LLONG_LOCK_FREE) || \ + __has_extension(c_atomic)) STATIC_ASSERT(sizeof(long long) >= sizeof(uint64_t)); -#ifndef __COVERITY__ - STATIC_ASSERT(atomic_is_lock_free(p)); -#endif /* Workaround for Coverity */ - return atomic_compare_exchange_strong((_Atomic uint64_t *)p, &c, v); +#ifdef ATOMIC_LLONG_LOCK_FREE + STATIC_ASSERT(ATOMIC_LLONG_LOCK_FREE > 0); +#if ATOMIC_LLONG_LOCK_FREE < 2 + assert(atomic_is_lock_free(p)); +#endif +#else + assert(atomic_is_lock_free(p)); +#endif +#ifdef __clang__ + STATIC_ASSERT(sizeof(_Atomic uint64_t) == sizeof(uint64_t)); + return atomic_compare_exchange_strong((_Atomic volatile uint64_t *)p, &c, v); +#else + return atomic_compare_exchange_strong(p, &c, v); +#endif #elif defined(__GNUC__) || defined(__clang__) return __sync_bool_compare_and_swap(p, c, v); #elif defined(_MSC_VER) @@ -801,12 +813,24 @@ static __always_inline bool atomic_cas64(volatile uint64_t *p, uint64_t c, static __always_inline bool atomic_cas32(volatile uint32_t *p, uint32_t c, uint32_t v) { -#if defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE) +#if !defined(__STDC_NO_ATOMICS__) && \ + (defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE) || \ + __has_extension(c_atomic)) STATIC_ASSERT(sizeof(int) >= sizeof(uint32_t)); -#ifndef __COVERITY__ - STATIC_ASSERT(atomic_is_lock_free(p)); -#endif /* Workaround for Coverity */ - return atomic_compare_exchange_strong((_Atomic uint32_t *)p, &c, v); +#ifdef ATOMIC_INT_LOCK_FREE + STATIC_ASSERT(ATOMIC_INT_LOCK_FREE > 0); +#if ATOMIC_INT_LOCK_FREE < 2 + assert(atomic_is_lock_free(p)); +#endif +#else + assert(atomic_is_lock_free(p)); +#endif +#ifdef __clang__ + STATIC_ASSERT(sizeof(_Atomic uint32_t) == sizeof(uint32_t)); + return atomic_compare_exchange_strong((_Atomic volatile uint32_t *)p, &c, v); +#else + return atomic_compare_exchange_strong(p, &c, v); +#endif #elif defined(__GNUC__) || defined(__clang__) return __sync_bool_compare_and_swap(p, c, v); #elif defined(_MSC_VER) @@ -820,12 +844,24 @@ static __always_inline bool atomic_cas32(volatile uint32_t *p, uint32_t c, } static __always_inline uint32_t atomic_add32(volatile uint32_t *p, uint32_t v) { -#if defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE) +#if !defined(__STDC_NO_ATOMICS__) && \ + (defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE) || \ + __has_extension(c_atomic)) STATIC_ASSERT(sizeof(int) >= sizeof(uint32_t)); -#ifndef __COVERITY__ - STATIC_ASSERT(atomic_is_lock_free(p)); -#endif /* Workaround for Coverity */ - return atomic_fetch_add((_Atomic uint32_t *)p, v); +#ifdef ATOMIC_INT_LOCK_FREE + STATIC_ASSERT(ATOMIC_INT_LOCK_FREE > 0); +#if ATOMIC_INT_LOCK_FREE < 2 + assert(atomic_is_lock_free(p)); +#endif +#else + assert(atomic_is_lock_free(p)); +#endif +#ifdef __clang__ + STATIC_ASSERT(sizeof(_Atomic uint32_t) == sizeof(uint32_t)); + return atomic_fetch_add((_Atomic volatile uint32_t *)p, v); +#else + return atomic_fetch_add(p, v); +#endif #elif defined(__GNUC__) || defined(__clang__) return __sync_fetch_and_add(p, v); #elif defined(_MSC_VER) diff --git a/src/osal.h b/src/osal.h index b47c2426..aa839ac1 100644 --- a/src/osal.h +++ b/src/osal.h @@ -459,6 +459,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() +#include +#elif !defined(__cplusplus) && (__STDC_VERSION__ >= 201112L) && \ + !defined(__STDC_NO_ATOMICS__) && \ + (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) || \ + !(defined(__GNUC__) || defined(__clang__))) +#include +#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 +#else +#error FIXME atomic-ops +#endif + /*----------------------------------------------------------------------------*/ /* Memory/Compiler barriers, cache coherence */ @@ -500,8 +529,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__) @@ -898,32 +927,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 -#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 -#else -#error FIXME atomic-ops -#endif - #endif /* !__cplusplus */ /*----------------------------------------------------------------------------*/ From 112ce742f501ee31190fda1060b6356f437fcef3 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Mon, 12 Oct 2020 00:09:06 +0300 Subject: [PATCH 14/20] mdbx: refine `update_gc()`. Change-Id: I877cdf2efb623c61dc810ec1cebb985fe925a120 --- src/core.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/core.c b/src/core.c index d91a6503..f91c934f 100644 --- a/src/core.c +++ b/src/core.c @@ -5253,7 +5253,7 @@ skip_cache: } } - /* Append PNL from GC record to me_reclaimed_pglist */ + /* Append PNL from GC record to tw.reclaimed_pglist */ mdbx_cassert(mc, (mc->mc_flags & C_GCFREEZE) == 0); pgno_t *gc_pnl = (pgno_t *)data.iov_base; mdbx_tassert(txn, data.iov_len >= MDBX_PNL_SIZEOF(gc_pnl)); @@ -5485,7 +5485,7 @@ done: mdbx_cassert(mc, (mc->mc_flags & C_GCFREEZE) == 0); mdbx_tassert(txn, pgno < txn->mt_next_pgno); mdbx_tassert(txn, pgno == re_list[range_begin]); - /* Cutoff allocated pages from me_reclaimed_pglist */ + /* Cutoff allocated pages from tw.reclaimed_pglist */ #if MDBX_PNL_ASCENDING for (unsigned i = range_begin + num; i <= re_len;) re_list[range_begin++] = re_list[i++]; @@ -7244,8 +7244,10 @@ retry_noaccount: mdbx_tassert(txn, mdbx_pnl_check4assert(txn->tw.reclaimed_pglist, txn->mt_next_pgno)); - if (txn->tw.lifo_reclaimed) { - if (cleaned_gc_slot < MDBX_PNL_SIZE(txn->tw.lifo_reclaimed)) { + if (lifo) { + if (cleaned_gc_slot < (txn->tw.lifo_reclaimed + ? MDBX_PNL_SIZE(txn->tw.lifo_reclaimed) + : 0)) { settled = 0; cleaned_gc_slot = 0; reused_gc_slot = 0; @@ -7276,7 +7278,7 @@ retry_noaccount: } } else { /* If using records from GC which we have not yet deleted, - * now delete them and any we reserved for me_reclaimed_pglist. */ + * now delete them and any we reserved for tw.reclaimed_pglist. */ while (cleaned_gc_id <= txn->tw.last_reclaimed) { gc_rid = cleaned_gc_id; settled = 0; @@ -7336,13 +7338,13 @@ retry_noaccount: /* handle loose pages - put ones into the reclaimed- or retired-list */ if (txn->tw.loose_pages) { - /* Return loose page numbers to me_reclaimed_pglist, + /* Return loose page numbers to tw.reclaimed_pglist, * though usually none are left at this point. * The pages themselves remain in dirtylist. */ if (unlikely(!txn->tw.lifo_reclaimed && txn->tw.last_reclaimed < 1)) { if (txn->tw.loose_count > 0) { /* Put loose page numbers in tw.retired_pages, - * since unable to return them to me_reclaimed_pglist. */ + * since unable to return them to tw.reclaimed_pglist. */ if (unlikely((rc = mdbx_pnl_need(&txn->tw.retired_pages, txn->tw.loose_count)) != 0)) goto bailout; @@ -7520,6 +7522,8 @@ retry_noaccount: gc_rid = MDBX_PNL_LAST(txn->tw.lifo_reclaimed); } else { mdbx_tassert(txn, txn->tw.last_reclaimed == 0); + /* no reclaimable GC entries, + * therefore no entries with ID < mdbx_find_oldest(txn) */ txn->tw.last_reclaimed = gc_rid = mdbx_find_oldest(txn) - 1; mdbx_trace("%s: none recycled yet, set rid to @%" PRIaTXN, dbg_prefix_mode, gc_rid); From 38485c9f30f2f621a66c2b6acb7469684ffabb48 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Tue, 13 Oct 2020 13:26:55 +0300 Subject: [PATCH 15/20] mdbx: minor refine `cursor_sibling()`. Change-Id: I2c92ef2c3081dfa0a9bdcd47de0f912a9927519e --- src/core.c | 64 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/core.c b/src/core.c index f91c934f..498e4586 100644 --- a/src/core.c +++ b/src/core.c @@ -3214,8 +3214,9 @@ static int __must_check_result mdbx_cursor_del0(MDBX_cursor *mc); static int __must_check_result mdbx_del0(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *data, unsigned flags); -static int __must_check_result mdbx_cursor_sibling(MDBX_cursor *mc, - int move_right); +#define SIBLING_LEFT 0 +#define SIBLING_RIGHT 2 +static int __must_check_result mdbx_cursor_sibling(MDBX_cursor *mc, int dir); static int __must_check_result mdbx_cursor_next(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, MDBX_cursor_op op); @@ -7099,7 +7100,7 @@ static __cold int mdbx_audit_ex(MDBX_txn *txn, unsigned retired_stored, db->md_branch_pages + db->md_leaf_pages + db->md_overflow_pages; } } - rc = mdbx_cursor_sibling(&cx.outer, 1); + rc = mdbx_cursor_sibling(&cx.outer, SIBLING_RIGHT); } mdbx_tassert(txn, rc == MDBX_NOTFOUND); } @@ -11706,15 +11707,15 @@ int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data, * Replaces the page at the top of the cursor's stack with the specified * sibling, if one exists. * - * [in] mc The cursor for this operation. - * [in] move_right Non-zero if the right sibling is requested, - * otherwise the left sibling. + * [in] mc The cursor for this operation. + * [in] dir SIBLING_LEFT or SIBLING_RIGHT. * * Returns 0 on success, non-zero on failure. */ -static int mdbx_cursor_sibling(MDBX_cursor *mc, int move_right) { +static int mdbx_cursor_sibling(MDBX_cursor *mc, int dir) { int rc; - MDBX_node *indx; + MDBX_node *node; MDBX_page *mp; + assert(dir == SIBLING_LEFT || dir == SIBLING_RIGHT); if (unlikely(mc->mc_snum < 2)) return MDBX_NOTFOUND; /* root has no siblings */ @@ -11723,29 +11724,28 @@ static int mdbx_cursor_sibling(MDBX_cursor *mc, int move_right) { mdbx_debug("parent page is page %" PRIaPGNO ", index %u", mc->mc_pg[mc->mc_top]->mp_pgno, mc->mc_ki[mc->mc_top]); - if (move_right + if ((dir == SIBLING_RIGHT) ? (mc->mc_ki[mc->mc_top] + 1u >= page_numkeys(mc->mc_pg[mc->mc_top])) : (mc->mc_ki[mc->mc_top] == 0)) { mdbx_debug("no more keys left, moving to %s sibling", - move_right ? "right" : "left"); - if (unlikely((rc = mdbx_cursor_sibling(mc, move_right)) != MDBX_SUCCESS)) { + dir ? "right" : "left"); + if (unlikely((rc = mdbx_cursor_sibling(mc, dir)) != MDBX_SUCCESS)) { /* undo cursor_pop before returning */ mc->mc_top++; mc->mc_snum++; return rc; } } else { - if (move_right) - mc->mc_ki[mc->mc_top]++; - else - mc->mc_ki[mc->mc_top]--; - mdbx_debug("just moving to %s index key %u", move_right ? "right" : "left", + assert((dir - 1) == -1 || (dir - 1) == 1); + mc->mc_ki[mc->mc_top] += dir - 1; + mdbx_debug("just moving to %s index key %u", + (dir == SIBLING_RIGHT) ? "right" : "left", mc->mc_ki[mc->mc_top]); } mdbx_cassert(mc, IS_BRANCH(mc->mc_pg[mc->mc_top])); - indx = page_node(mp = mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); - if (unlikely((rc = mdbx_page_get(mc, node_pgno(indx), &mp, NULL, + node = page_node(mp = mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + if (unlikely((rc = mdbx_page_get(mc, node_pgno(node), &mp, NULL, pp_txnid4chk(mp, mc->mc_txn))) != 0)) { /* mc will be inconsistent if caller does mc_snum++ as above */ mc->mc_flags &= ~(C_INITIALIZED | C_EOF); @@ -11755,7 +11755,7 @@ static int mdbx_cursor_sibling(MDBX_cursor *mc, int move_right) { rc = mdbx_cursor_push(mc, mp); if (unlikely(rc != MDBX_SUCCESS)) return rc; - if (!move_right) + if (dir == SIBLING_LEFT) mc->mc_ki[mc->mc_top] = (indx_t)page_numkeys(mp) - 1; return MDBX_SUCCESS; @@ -11809,7 +11809,8 @@ static int mdbx_cursor_next(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, if (mc->mc_ki[mc->mc_top] + 1u >= page_numkeys(mp)) { mdbx_debug("%s", "=====> move to next sibling page"); - if (unlikely((rc = mdbx_cursor_sibling(mc, 1)) != MDBX_SUCCESS)) { + if (unlikely((rc = mdbx_cursor_sibling(mc, SIBLING_RIGHT)) != + MDBX_SUCCESS)) { mc->mc_flags |= C_EOF; return rc; } @@ -11905,7 +11906,7 @@ static int mdbx_cursor_prev(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, if (mc->mc_ki[mc->mc_top] == 0) { mdbx_debug("%s", "=====> move to prev sibling page"); - if ((rc = mdbx_cursor_sibling(mc, 0)) != MDBX_SUCCESS) { + if ((rc = mdbx_cursor_sibling(mc, SIBLING_LEFT)) != MDBX_SUCCESS) { return rc; } mp = mc->mc_pg[mc->mc_top]; @@ -12100,7 +12101,8 @@ set2: if (node == NULL) { mdbx_debug("%s", "===> inexact leaf not found, goto sibling"); - if (unlikely((rc = mdbx_cursor_sibling(mc, 1)) != MDBX_SUCCESS)) { + if (unlikely((rc = mdbx_cursor_sibling(mc, SIBLING_RIGHT)) != + MDBX_SUCCESS)) { mc->mc_flags |= C_EOF; return rc; /* no entries matched */ } @@ -12405,7 +12407,7 @@ int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, if (rc == MDBX_SUCCESS) { MDBX_cursor *mx = &mc->mc_xcursor->mx_cursor; if (mx->mc_flags & C_INITIALIZED) { - rc = mdbx_cursor_sibling(mx, 0); + rc = mdbx_cursor_sibling(mx, SIBLING_LEFT); if (rc == MDBX_SUCCESS) goto fetchm; } else { @@ -12692,7 +12694,7 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, mc->mc_ki[mc->mc_top]++; /* step forward for appending */ rc = MDBX_NOTFOUND; } else { - if (unlikely(rc != 0 || !(flags & MDBX_APPENDDUP))) + if (unlikely(rc != MDBX_SUCCESS || !(flags & MDBX_APPENDDUP))) /* new-key < last-key * or new-key == last-key without MDBX_APPENDDUP */ return MDBX_EKEYMISMATCH; @@ -15463,7 +15465,7 @@ static int mdbx_cursor_del0(MDBX_cursor *mc) { if (m3->mc_pg[mc->mc_top] == mp) { /* if m3 points past last node in page, find next sibling */ if (m3->mc_ki[mc->mc_top] >= nkeys) { - rc = mdbx_cursor_sibling(m3, true); + rc = mdbx_cursor_sibling(m3, SIBLING_RIGHT); if (rc == MDBX_NOTFOUND) { m3->mc_flags |= C_EOF; rc = MDBX_SUCCESS; @@ -15496,11 +15498,11 @@ static int mdbx_cursor_del0(MDBX_cursor *mc) { } } - if (mc->mc_ki[mc->mc_top] >= nkeys) { - rc = mdbx_cursor_sibling(mc, true); - if (rc == MDBX_NOTFOUND) { + if (unlikely(mc->mc_ki[mc->mc_top] >= nkeys)) { + rc = mdbx_cursor_sibling(mc, SIBLING_RIGHT); + if (unlikely(rc == MDBX_NOTFOUND)) { mc->mc_flags |= C_EOF; - rc = MDBX_SUCCESS; + return MDBX_SUCCESS; } } if ((mc->mc_db->md_flags & MDBX_DUPSORT) != 0 && @@ -15866,7 +15868,7 @@ static int mdbx_page_split(MDBX_cursor *mc, const MDBX_val *newkey, } else { /* find right page's left sibling */ mc->mc_ki[ptop] = mn.mc_ki[ptop]; - rc = mdbx_cursor_sibling(mc, false); + rc = mdbx_cursor_sibling(mc, SIBLING_LEFT); } } } else { @@ -17568,7 +17570,7 @@ static int mdbx_drop0(MDBX_cursor *mc, int subs) { break; mdbx_cassert(mc, i <= UINT16_MAX); mc->mc_ki[mc->mc_top] = (indx_t)i; - rc = mdbx_cursor_sibling(mc, 1); + rc = mdbx_cursor_sibling(mc, SIBLING_RIGHT); if (rc) { if (unlikely(rc != MDBX_NOTFOUND)) goto done; From 7cf92b66cf2caa5fc78863a7bd35bb74778bd0bf Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Wed, 14 Oct 2020 18:15:50 +0300 Subject: [PATCH 16/20] mdbx: add LIBMDBX_INLINE_API (both inline and non-inline of some API functions). Change-Id: I00c2b6d3d2a0467080791ea0c1c2242742a20c78 --- mdbx.h | 177 +++++++++++++++++++++++++++++------------------- src/core.c | 131 +++++++++++++++++++---------------- src/internals.h | 10 +-- 3 files changed, 183 insertions(+), 135 deletions(-) diff --git a/mdbx.h b/mdbx.h index e04f2790..6ecc1f75 100644 --- a/mdbx.h +++ b/mdbx.h @@ -350,6 +350,17 @@ typedef mode_t mdbx_mode_t; #endif #endif /* __dll_import */ +/** \brief Auxiliary macro for robustly define the both inline version of API + * function and non-inline fallback dll-exported version for applications linked + * with old version of libmdbx, with a strictly ODR-common implementation. */ +#if !defined(LIBMDBX_INTERNALS) || defined(DOXYGEN) +#define LIBMDBX_INLINE_API(TYPE, NAME, ARGS) static __inline TYPE NAME ARGS +#else +#define LIBMDBX_INLINE_API(TYPE, NAME, ARGS) \ + /* proto of exported which uses common impl */ LIBMDBX_API TYPE NAME ARGS; \ + /* definition of common impl */ static __inline TYPE __inline_##NAME ARGS +#endif /* LIBMDBX_INLINE_API */ + /*----------------------------------------------------------------------------*/ #ifndef __cplusplus @@ -1971,11 +1982,15 @@ typedef struct MDBX_stat MDBX_stat; * \returns A non-zero error value on failure and 0 on success. */ LIBMDBX_API int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn, MDBX_stat *stat, size_t bytes); + /** \brief Return statistics about the MDBX environment. * \ingroup c_statinfo * \deprecated Please use mdbx_env_stat_ex() instead. */ -MDBX_DEPRECATED LIBMDBX_API int mdbx_env_stat(MDBX_env *env, MDBX_stat *stat, - size_t bytes); +MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_stat, + (const MDBX_env *env, MDBX_stat *stat, + size_t bytes)) { + return mdbx_env_stat_ex(env, NULL, stat, bytes); +} /** \brief Information about the environment * \ingroup c_statinfo @@ -2061,8 +2076,11 @@ LIBMDBX_API int mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn, /** \brief Return information about the MDBX environment. * \ingroup c_statinfo * \deprecated Please use mdbx_env_info_ex() instead. */ -MDBX_DEPRECATED LIBMDBX_API int mdbx_env_info(MDBX_env *env, MDBX_envinfo *info, - size_t bytes); +MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_info, + (const MDBX_env *env, MDBX_envinfo *info, + size_t bytes)) { + return mdbx_env_info_ex(env, NULL, info, bytes); +} /** \brief Flush the environment data buffers to disk. * \ingroup c_extra @@ -2104,12 +2122,16 @@ 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 * the `force=true` and `nonblock=false` arguments. * \ingroup c_extra */ -LIBMDBX_API int mdbx_env_sync(MDBX_env *env); +LIBMDBX_INLINE_API(int, mdbx_env_sync, (MDBX_env * env)) { + return mdbx_env_sync_ex(env, true, false); +} /** \brief The shortcut to calling \ref mdbx_env_sync_ex() with * the `force=false` and `nonblock=true` arguments. * \ingroup c_extra */ -LIBMDBX_API int mdbx_env_sync_poll(MDBX_env *env); +LIBMDBX_INLINE_API(int, mdbx_env_sync_poll, (MDBX_env * env)) { + return mdbx_env_sync_ex(env, false, true); +} /** \brief Sets threshold to force flush the data buffers to disk, even any of * \ref MDBX_SAFE_NOSYNC flag in the environment. @@ -2211,7 +2233,9 @@ LIBMDBX_API int mdbx_env_close_ex(MDBX_env *env, bool dont_sync); /** \brief The shortcut to calling \ref mdbx_env_close_ex() with * the `dont_sync=false` argument. * \ingroup c_opening */ -LIBMDBX_API int mdbx_env_close(MDBX_env *env); +LIBMDBX_INLINE_API(int, mdbx_env_close, (MDBX_env * env)) { + return mdbx_env_close_ex(env, false); +} /** \brief Set environment flags. * \ingroup c_settings @@ -2465,8 +2489,10 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, /** \deprecated Please use \ref mdbx_env_set_geometry() instead. * \ingroup c_settings */ -MDBX_DEPRECATED LIBMDBX_API int mdbx_env_set_mapsize(MDBX_env *env, - size_t size); +MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_set_mapsize, + (MDBX_env * env, size_t size)) { + return mdbx_env_set_geometry(env, size, size, size, -1, -1, -1); +} /** \brief Find out whether to use readahead or not, based on the given database * size and the amount of available memory. \ingroup c_extra @@ -2487,13 +2513,15 @@ LIBMDBX_API int mdbx_is_readahead_reasonable(size_t volume, /** \brief Returns the minimal database page size in bytes. * \ingroup c_statinfo */ -MDBX_NOTHROW_CONST_FUNCTION __inline intptr_t mdbx_limits_pgsize_min(void) { +MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_INLINE_API(intptr_t, mdbx_limits_pgsize_min, + (void)) { return MDBX_MIN_PAGESIZE; } /** \brief Returns the maximal database page size in bytes. * \ingroup c_statinfo */ -MDBX_NOTHROW_CONST_FUNCTION __inline intptr_t mdbx_limits_pgsize_max(void) { +MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_INLINE_API(intptr_t, mdbx_limits_pgsize_max, + (void)) { return MDBX_MAX_PAGESIZE; } @@ -2650,60 +2678,6 @@ LIBMDBX_API int mdbx_env_set_userctx(MDBX_env *env, void *ctx); MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void * mdbx_env_get_userctx(const MDBX_env *env); -/** \brief Create a transaction for use with the environment. - * \ingroup c_transactions - * - * The transaction handle may be discarded using \ref mdbx_txn_abort() - * or \ref mdbx_txn_commit(). - * \see mdbx_txn_begin_ex() - * - * \note A transaction and its cursors must only be used by a single thread, - * and a thread may only have a single transaction at a time. If \ref MDBX_NOTLS - * is in use, this does not apply to read-only transactions. - * - * \note Cursors may not span transactions. - * - * \param [in] env An environment handle returned by \ref mdbx_env_create() - * \param [in] parent If this parameter is non-NULL, the new transaction will - * be a nested transaction, with the transaction indicated - * by parent as its parent. Transactions may be nested - * to any level. A parent transaction and its cursors may - * not issue any other operations than mdbx_txn_commit and - * \ref mdbx_txn_abort() while it has active child - * transactions. - * \param [in] flags Special options for this transaction. This parameter - * must be set to 0 or by bitwise OR'ing together one - * or more of the values described here: - * - \ref MDBX_RDONLY This transaction will not perform - * any write operations. - * - * - \ref MDBX_TXN_TRY Do not block when starting - * a write transaction. - * - * - \ref MDBX_SAFE_NOSYNC, \ref MDBX_NOMETASYNC. - * Do not sync data to disk corresponding - * to \ref MDBX_NOMETASYNC or \ref MDBX_SAFE_NOSYNC - * description. \see sync_modes - * - * \param [out] txn Address where the new MDBX_txn handle will be stored. - * - * \returns A non-zero error value on failure and 0 on success, - * some possible errors are: - * \retval MDBX_PANIC A fatal error occurred earlier and the - * environment must be shut down. - * \retval MDBX_UNABLE_EXTEND_MAPSIZE Another process wrote data beyond - * this MDBX_env's mapsize and this - * environment map must be resized as well. - * See \ref mdbx_env_set_mapsize(). - * \retval MDBX_READERS_FULL A read-only transaction was requested and - * the reader lock table is full. - * See \ref mdbx_env_set_maxreaders(). - * \retval MDBX_ENOMEM Out of memory. - * \retval MDBX_BUSY The write transaction is already started by the - * current thread. */ -LIBMDBX_API int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, - MDBX_txn_flags_t flags, MDBX_txn **txn); - /** \brief Create a transaction with a user provided context pointer * for use with the environment. * \ingroup c_transactions @@ -2766,6 +2740,65 @@ LIBMDBX_API int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, MDBX_txn **txn, void *context); +/** \brief Create a transaction for use with the environment. + * \ingroup c_transactions + * + * The transaction handle may be discarded using \ref mdbx_txn_abort() + * or \ref mdbx_txn_commit(). + * \see mdbx_txn_begin_ex() + * + * \note A transaction and its cursors must only be used by a single thread, + * and a thread may only have a single transaction at a time. If \ref MDBX_NOTLS + * is in use, this does not apply to read-only transactions. + * + * \note Cursors may not span transactions. + * + * \param [in] env An environment handle returned by \ref mdbx_env_create(). + * + * \param [in] parent If this parameter is non-NULL, the new transaction will + * be a nested transaction, with the transaction indicated + * by parent as its parent. Transactions may be nested + * to any level. A parent transaction and its cursors may + * not issue any other operations than mdbx_txn_commit and + * \ref mdbx_txn_abort() while it has active child + * transactions. + * + * \param [in] flags Special options for this transaction. This parameter + * must be set to 0 or by bitwise OR'ing together one + * or more of the values described here: + * - \ref MDBX_RDONLY This transaction will not perform + * any write operations. + * + * - \ref MDBX_TXN_TRY Do not block when starting + * a write transaction. + * + * - \ref MDBX_SAFE_NOSYNC, \ref MDBX_NOMETASYNC. + * Do not sync data to disk corresponding + * to \ref MDBX_NOMETASYNC or \ref MDBX_SAFE_NOSYNC + * description. \see sync_modes + * + * \param [out] txn Address where the new MDBX_txn handle will be stored. + * + * \returns A non-zero error value on failure and 0 on success, + * some possible errors are: + * \retval MDBX_PANIC A fatal error occurred earlier and the + * environment must be shut down. + * \retval MDBX_UNABLE_EXTEND_MAPSIZE Another process wrote data beyond + * this MDBX_env's mapsize and this + * environment map must be resized as well. + * See \ref mdbx_env_set_mapsize(). + * \retval MDBX_READERS_FULL A read-only transaction was requested and + * the reader lock table is full. + * See \ref mdbx_env_set_maxreaders(). + * \retval MDBX_ENOMEM Out of memory. + * \retval MDBX_BUSY The write transaction is already started by the + * current thread. */ +LIBMDBX_INLINE_API(int, mdbx_txn_begin, + (MDBX_env * env, MDBX_txn *parent, MDBX_txn_flags_t flags, + MDBX_txn **txn)) { + return mdbx_txn_begin_ex(env, parent, flags, txn, NULL); +} + /** \brief Set application information associated with the \ref MDBX_txn. * \ingroup c_transactions * \see mdbx_txn_get_userctx() @@ -3225,13 +3258,13 @@ mdbx_key_from_float(const float ieee754_32bit); MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API uint32_t mdbx_key_from_ptrfloat(const float *const ieee754_32bit); -MDBX_NOTHROW_CONST_FUNCTION __inline uint64_t -mdbx_key_from_int64(const int64_t i64) { +MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_INLINE_API(uint64_t, mdbx_key_from_int64, + (const int64_t i64)) { return UINT64_C(0x8000000000000000) + i64; } -MDBX_NOTHROW_CONST_FUNCTION __inline uint32_t -mdbx_key_from_int32(const int32_t i32) { +MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_INLINE_API(uint32_t, mdbx_key_from_int32, + (const int32_t i32)) { return UINT32_C(0x80000000) + i32; } /** @} */ @@ -3323,7 +3356,11 @@ LIBMDBX_API int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags, unsigned *state); /** \brief The shortcut to calling \ref mdbx_dbi_flags_ex() with `state=NULL` * for discarding it result. \ingroup c_statinfo */ -LIBMDBX_API int mdbx_dbi_flags(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags); +LIBMDBX_INLINE_API(int, mdbx_dbi_flags, + (MDBX_txn * txn, MDBX_dbi dbi, unsigned *flags)) { + unsigned state; + return mdbx_dbi_flags_ex(txn, dbi, flags, &state); +} /** \brief Close a database handle. Normally unnecessary. * \ingroup c_dbi diff --git a/src/core.c b/src/core.c index 498e4586..f4fac622 100644 --- a/src/core.c +++ b/src/core.c @@ -4663,7 +4663,7 @@ static __always_inline __maybe_unused int ignore_enosys(int err) { #endif /* defined(_WIN32) || defined(_WIN64) */ /* Turn on/off readahead. It's harmful when the DB is larger than RAM. */ -static int __cold mdbx_set_readahead(MDBX_env *env, const size_t offset, +static __cold int mdbx_set_readahead(MDBX_env *env, const size_t offset, const size_t length, const bool enable) { assert(length > 0); mdbx_notice("readahead %s %u..%u", enable ? "ON" : "OFF", @@ -5830,12 +5830,10 @@ __cold int mdbx_env_sync_ex(MDBX_env *env, bool force, bool nonblock) { return mdbx_env_sync_internal(env, force, nonblock); } -__cold int mdbx_env_sync(MDBX_env *env) { - return mdbx_env_sync_ex(env, true, false); -} +__cold int mdbx_env_sync(MDBX_env *env) { return __inline_mdbx_env_sync(env); } __cold int mdbx_env_sync_poll(MDBX_env *env) { - return mdbx_env_sync_ex(env, false, true); + return __inline_mdbx_env_sync_poll(env); } /* Back up parent txn's cursors, then grab the originals for tracking */ @@ -6483,7 +6481,7 @@ int mdbx_txn_renew(MDBX_txn *txn) { int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, MDBX_txn **ret) { - return mdbx_txn_begin_ex(env, parent, flags, ret, nullptr); + return __inline_mdbx_txn_begin(env, parent, flags, ret); } int mdbx_txn_set_userctx(MDBX_txn *txn, void *ctx) { @@ -8409,12 +8407,10 @@ fail: return rc; } -static int __cold mdbx_validate_meta(MDBX_env *env, MDBX_meta *const meta, - uint64_t *filesize, - const MDBX_page *const page, - const unsigned meta_number, - MDBX_meta *dest, - const unsigned guess_pagesize) { +static __cold int +mdbx_validate_meta(MDBX_env *env, MDBX_meta *const meta, uint64_t *filesize, + const MDBX_page *const page, const unsigned meta_number, + MDBX_meta *dest, const unsigned guess_pagesize) { if (meta->mm_magic_and_version != MDBX_DATA_MAGIC && meta->mm_magic_and_version != MDBX_DATA_MAGIC_DEVEL) { mdbx_error("meta[%u] has invalid magic/version %" PRIx64, meta_number, @@ -8606,7 +8602,7 @@ static int __cold mdbx_validate_meta(MDBX_env *env, MDBX_meta *const meta, /* Read the environment parameters of a DB environment * before mapping it into memory. */ -static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *dest, +static __cold int mdbx_read_header(MDBX_env *env, MDBX_meta *dest, uint64_t *filesize, const int lck_exclusive) { int rc = mdbx_filesize(env->me_lazy_fd, filesize); @@ -9096,7 +9092,7 @@ static void __cold mdbx_setup_pagesize(MDBX_env *env, const size_t pagesize) { mdbx_assert(env, bytes2pgno(env, pagesize + pagesize) == 2); } -int __cold mdbx_env_create(MDBX_env **penv) { +__cold int mdbx_env_create(MDBX_env **penv) { MDBX_env *env = mdbx_calloc(1, sizeof(MDBX_env)); if (unlikely(!env)) return MDBX_ENOMEM; @@ -9497,11 +9493,11 @@ bailout: return rc; } -int __cold mdbx_env_set_mapsize(MDBX_env *env, size_t size) { - return mdbx_env_set_geometry(env, size, size, size, -1, -1, -1); +__cold int mdbx_env_set_mapsize(MDBX_env *env, size_t size) { + return __inline_mdbx_env_set_mapsize(env, size); } -int __cold mdbx_env_set_maxdbs(MDBX_env *env, MDBX_dbi dbs) { +__cold int mdbx_env_set_maxdbs(MDBX_env *env, MDBX_dbi dbs) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -9516,7 +9512,7 @@ int __cold mdbx_env_set_maxdbs(MDBX_env *env, MDBX_dbi dbs) { return MDBX_SUCCESS; } -int __cold mdbx_env_get_maxdbs(MDBX_env *env, MDBX_dbi *dbs) { +__cold int mdbx_env_get_maxdbs(MDBX_env *env, MDBX_dbi *dbs) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -9528,7 +9524,7 @@ int __cold mdbx_env_get_maxdbs(MDBX_env *env, MDBX_dbi *dbs) { return MDBX_SUCCESS; } -int __cold mdbx_env_set_maxreaders(MDBX_env *env, unsigned readers) { +__cold int mdbx_env_set_maxreaders(MDBX_env *env, unsigned readers) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -9543,7 +9539,7 @@ int __cold mdbx_env_set_maxreaders(MDBX_env *env, unsigned readers) { return MDBX_SUCCESS; } -int __cold mdbx_env_get_maxreaders(const MDBX_env *env, unsigned *readers) { +__cold int mdbx_env_get_maxreaders(const MDBX_env *env, unsigned *readers) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -9556,7 +9552,7 @@ int __cold mdbx_env_get_maxreaders(const MDBX_env *env, unsigned *readers) { } /* Further setup required for opening an MDBX environment */ -static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { +static __cold int mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { uint64_t filesize_before; MDBX_meta meta; int rc = MDBX_RESULT_FALSE; @@ -10004,7 +10000,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { /******************************************************************************/ /* Open and/or initialize the lock region for the environment. */ -static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname, +static __cold int mdbx_setup_lck(MDBX_env *env, char *lck_pathname, mdbx_mode_t mode) { mdbx_assert(env, env->me_lazy_fd != INVALID_HANDLE_VALUE); mdbx_assert(env, env->me_lfd == INVALID_HANDLE_VALUE); @@ -10840,7 +10836,7 @@ bailout: } /* Destroy resources from mdbx_env_open(), clear our readers & DBIs */ -static int __cold mdbx_env_close0(MDBX_env *env) { +static __cold int mdbx_env_close0(MDBX_env *env) { env->me_stuck_meta = -1; if (!(env->me_flags & MDBX_ENV_ACTIVE)) { mdbx_ensure(env, env->me_lcklist_next == nullptr); @@ -10909,7 +10905,7 @@ static int __cold mdbx_env_close0(MDBX_env *env) { return rc; } -int __cold mdbx_env_close_ex(MDBX_env *env, bool dont_sync) { +__cold int mdbx_env_close_ex(MDBX_env *env, bool dont_sync) { MDBX_page *dp; int rc = MDBX_SUCCESS; @@ -10989,7 +10985,7 @@ int __cold mdbx_env_close_ex(MDBX_env *env, bool dont_sync) { } __cold int mdbx_env_close(MDBX_env *env) { - return mdbx_env_close_ex(env, false); + return __inline_mdbx_env_close(env); } /* Compare two items pointing at aligned unsigned int's. */ @@ -16202,7 +16198,7 @@ bailout: * * [in] my control structure. * [in] adjust (1 to hand off 1 buffer) | (MDBX_EOF when ending). */ -static int __cold mdbx_env_cthr_toggle(mdbx_copy *my, int adjust) { +static __cold int mdbx_env_cthr_toggle(mdbx_copy *my, int adjust) { mdbx_condpair_lock(&my->mc_condpair); my->mc_new += (short)adjust; mdbx_condpair_signal(&my->mc_condpair, true); @@ -16223,7 +16219,7 @@ static int __cold mdbx_env_cthr_toggle(mdbx_copy *my, int adjust) { * [in] my control structure. * [in,out] pg database root. * [in] flags includes F_DUPDATA if it is a sorted-duplicate sub-DB. */ -static int __cold mdbx_env_cwalk(mdbx_copy *my, pgno_t *pg, int flags) { +static __cold int mdbx_env_cwalk(mdbx_copy *my, pgno_t *pg, int flags) { MDBX_cursor_couple couple; MDBX_page *mo, *mp, *leaf; char *buf, *ptr; @@ -16422,7 +16418,7 @@ static __cold void make_sizeable(MDBX_meta *meta) { } /* Copy environment with compaction. */ -static int __cold mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn, +static __cold int mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn, mdbx_filehandle_t fd, uint8_t *buffer, const bool dest_is_pipe, const int flags) { const size_t meta_bytes = pgno2bytes(env, NUM_METAS); @@ -16559,7 +16555,7 @@ static int __cold mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn, } /* Copy environment as-is. */ -static int __cold mdbx_env_copy_asis(MDBX_env *env, MDBX_txn *read_txn, +static __cold int mdbx_env_copy_asis(MDBX_env *env, MDBX_txn *read_txn, mdbx_filehandle_t fd, uint8_t *buffer, const bool dest_is_pipe, const int flags) { /* We must start the actual read txn after blocking writers */ @@ -16666,7 +16662,7 @@ static int __cold mdbx_env_copy_asis(MDBX_env *env, MDBX_txn *read_txn, return rc; } -int __cold mdbx_env_copy2fd(MDBX_env *env, mdbx_filehandle_t fd, +__cold int mdbx_env_copy2fd(MDBX_env *env, mdbx_filehandle_t fd, unsigned flags) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) @@ -16731,7 +16727,7 @@ int __cold mdbx_env_copy2fd(MDBX_env *env, mdbx_filehandle_t fd, return rc; } -int __cold mdbx_env_copy(MDBX_env *env, const char *dest_path, +__cold int mdbx_env_copy(MDBX_env *env, const char *dest_path, MDBX_copy_flags_t flags) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) @@ -16793,7 +16789,7 @@ int __cold mdbx_env_copy(MDBX_env *env, const char *dest_path, /******************************************************************************/ -int __cold mdbx_env_set_flags(MDBX_env *env, MDBX_env_flags_t flags, +__cold int mdbx_env_set_flags(MDBX_env *env, MDBX_env_flags_t flags, bool onoff) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) @@ -16821,7 +16817,7 @@ int __cold mdbx_env_set_flags(MDBX_env *env, MDBX_env_flags_t flags, return MDBX_SUCCESS; } -int __cold mdbx_env_get_flags(const MDBX_env *env, unsigned *arg) { +__cold int mdbx_env_get_flags(const MDBX_env *env, unsigned *arg) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -16833,7 +16829,7 @@ int __cold mdbx_env_get_flags(const MDBX_env *env, unsigned *arg) { return MDBX_SUCCESS; } -int __cold mdbx_env_set_userctx(MDBX_env *env, void *ctx) { +__cold int mdbx_env_set_userctx(MDBX_env *env, void *ctx) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -16846,7 +16842,7 @@ void *__cold mdbx_env_get_userctx(const MDBX_env *env) { return env ? env->me_userctx : NULL; } -int __cold mdbx_env_set_assert(MDBX_env *env, MDBX_assert_func *func) { +__cold int mdbx_env_set_assert(MDBX_env *env, MDBX_assert_func *func) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -16860,7 +16856,7 @@ int __cold mdbx_env_set_assert(MDBX_env *env, MDBX_assert_func *func) { #endif } -int __cold mdbx_env_get_path(const MDBX_env *env, const char **arg) { +__cold int mdbx_env_get_path(const MDBX_env *env, const char **arg) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -16872,7 +16868,7 @@ int __cold mdbx_env_get_path(const MDBX_env *env, const char **arg) { return MDBX_SUCCESS; } -int __cold mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *arg) { +__cold int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *arg) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -16902,11 +16898,11 @@ static void mdbx_stat0(const MDBX_env *env, const MDBX_db *db, MDBX_stat *dest, dest->ms_mod_txnid = db->md_mod_txnid; } -int __cold mdbx_env_stat(MDBX_env *env, MDBX_stat *dest, size_t bytes) { - return mdbx_env_stat_ex(env, NULL, dest, bytes); +__cold int mdbx_env_stat(const MDBX_env *env, MDBX_stat *stat, size_t bytes) { + return __inline_mdbx_env_stat(env, stat, bytes); } -int __cold mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn, +__cold int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn, MDBX_stat *dest, size_t bytes) { if (unlikely((env == NULL && txn == NULL) || dest == NULL)) return MDBX_EINVAL; @@ -16944,7 +16940,7 @@ int __cold mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn, } } -int __cold mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi, +__cold int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi, uint32_t *mask) { int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) @@ -16995,11 +16991,12 @@ int __cold mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi, return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc; } -int __cold mdbx_env_info(MDBX_env *env, MDBX_envinfo *arg, size_t bytes) { - return mdbx_env_info_ex(env, NULL, arg, bytes); +__cold int mdbx_env_info(const MDBX_env *env, MDBX_envinfo *info, + size_t bytes) { + return __inline_mdbx_env_info(env, info, bytes); } -int __cold mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn, +__cold int mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn, MDBX_envinfo *arg, size_t bytes) { if (unlikely((env == NULL && txn == NULL) || arg == NULL)) return MDBX_EINVAL; @@ -17418,7 +17415,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, return dbi_open(txn, table_name, table_flags, dbi, keycmp, datacmp); } -int __cold mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest, +__cold int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest, size_t bytes) { int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) @@ -17500,8 +17497,7 @@ int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags, } int mdbx_dbi_flags(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags) { - unsigned state; - return mdbx_dbi_flags_ex(txn, dbi, flags, &state); + return __inline_mdbx_dbi_flags(txn, dbi, flags); } /* Add all the DB's pages to the free list. @@ -17690,7 +17686,7 @@ int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) { return MDBX_SUCCESS; } -int __cold mdbx_reader_list(const MDBX_env *env, MDBX_reader_list_func *func, +__cold int mdbx_reader_list(const MDBX_env *env, MDBX_reader_list_func *func, void *ctx) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) @@ -17790,7 +17786,7 @@ static bool __cold mdbx_pid_insert(uint32_t *ids, uint32_t pid) { return true; } -int __cold mdbx_reader_check(MDBX_env *env, int *dead) { +__cold int mdbx_reader_check(MDBX_env *env, int *dead) { if (dead) *dead = 0; return mdbx_cleanup_dead_readers(env, false, dead); @@ -17800,9 +17796,8 @@ int __cold mdbx_reader_check(MDBX_env *env, int *dead) { * MDBX_RESULT_TRUE - done and mutex recovered * MDBX_SUCCESS - done * Otherwise errcode. */ -MDBX_INTERNAL_FUNC int __cold mdbx_cleanup_dead_readers(MDBX_env *env, - int rdt_locked, - int *dead) { +MDBX_INTERNAL_FUNC __cold int +mdbx_cleanup_dead_readers(MDBX_env *env, int rdt_locked, int *dead) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -17899,7 +17894,7 @@ MDBX_INTERNAL_FUNC int __cold mdbx_cleanup_dead_readers(MDBX_env *env, return rc; } -int __cold mdbx_setup_debug(int loglevel, int flags, MDBX_debug_func *logger) { +__cold int mdbx_setup_debug(int loglevel, int flags, MDBX_debug_func *logger) { const int rc = mdbx_runtime_flags | (mdbx_loglevel << 16); if (loglevel != MDBX_LOG_DONTCHANGE) @@ -18017,7 +18012,7 @@ static txnid_t __cold mdbx_kick_longlived_readers(MDBX_env *env, return mdbx_find_oldest(env->me_txn); } -int __cold mdbx_env_set_syncbytes(MDBX_env *env, size_t threshold) { +__cold int mdbx_env_set_syncbytes(MDBX_env *env, size_t threshold) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -18037,7 +18032,7 @@ int __cold mdbx_env_set_syncbytes(MDBX_env *env, size_t threshold) { return MDBX_SUCCESS; } -int __cold mdbx_env_set_syncperiod(MDBX_env *env, unsigned seconds_16dot16) { +__cold int mdbx_env_set_syncperiod(MDBX_env *env, unsigned seconds_16dot16) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -18057,7 +18052,7 @@ int __cold mdbx_env_set_syncperiod(MDBX_env *env, unsigned seconds_16dot16) { return MDBX_SUCCESS; } -int __cold mdbx_env_set_hsr(MDBX_env *env, MDBX_hsr_func *hsr) { +__cold int mdbx_env_set_hsr(MDBX_env *env, MDBX_hsr_func *hsr) { int rc = check_env(env); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -18114,7 +18109,7 @@ typedef struct mdbx_walk_ctx { bool mw_dont_check_keys_ordering; } mdbx_walk_ctx_t; -static int __cold mdbx_walk_sdb(mdbx_walk_ctx_t *ctx, MDBX_db *const db, +static __cold int mdbx_walk_sdb(mdbx_walk_ctx_t *ctx, MDBX_db *const db, const char *name, int deep); static MDBX_page_type_t walk_page_type(const MDBX_page *mp) { @@ -18135,7 +18130,7 @@ static MDBX_page_type_t walk_page_type(const MDBX_page *mp) { } /* Depth-first tree traversal. */ -static int __cold mdbx_walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno, +static __cold int mdbx_walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno, const char *name, int deep, txnid_t parent_txnid) { assert(pgno != P_INVALID); @@ -18373,7 +18368,7 @@ static int __cold mdbx_walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno, return MDBX_SUCCESS; } -static int __cold mdbx_walk_sdb(mdbx_walk_ctx_t *ctx, MDBX_db *const db, +static __cold int mdbx_walk_sdb(mdbx_walk_ctx_t *ctx, MDBX_db *const db, const char *name, int deep) { if (unlikely(db->md_root == P_INVALID)) return MDBX_SUCCESS; /* empty db */ @@ -18396,7 +18391,7 @@ static int __cold mdbx_walk_sdb(mdbx_walk_ctx_t *ctx, MDBX_db *const db, return rc; } -int __cold mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor, +__cold int mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor, void *user, bool dont_check_keys_ordering) { int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) @@ -19164,6 +19159,14 @@ int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result, /*----------------------------------------------------------------------------*/ +__cold MDBX_NOTHROW_CONST_FUNCTION intptr_t mdbx_limits_pgsize_min(void) { + return __inline_mdbx_limits_pgsize_min(); +} + +__cold MDBX_NOTHROW_CONST_FUNCTION intptr_t mdbx_limits_pgsize_max(void) { + return __inline_mdbx_limits_pgsize_max(); +} + __cold intptr_t mdbx_limits_dbsize_min(intptr_t pagesize) { if (pagesize < 1) pagesize = (intptr_t)mdbx_syspagesize(); @@ -19267,6 +19270,14 @@ uint32_t mdbx_key_from_ptrfloat(const float *const ieee754_32bit) { return float2key(ieee754_32bit); } +MDBX_NOTHROW_CONST_FUNCTION uint64_t mdbx_key_from_int64(const int64_t i64) { + return __inline_mdbx_key_from_int64(i64); +} + +MDBX_NOTHROW_CONST_FUNCTION uint32_t mdbx_key_from_int32(const int32_t i32) { + return __inline_mdbx_key_from_int32(i32); +} + #define IEEE754_DOUBLE_MANTISSA_SIZE 52 #define IEEE754_DOUBLE_EXPONENTA_BIAS 0x3FF #define IEEE754_DOUBLE_EXPONENTA_MAX 0x7FF diff --git a/src/internals.h b/src/internals.h index 49b8a3c0..aa29665b 100644 --- a/src/internals.h +++ b/src/internals.h @@ -16,6 +16,11 @@ #include MDBX_CONFIG_H #endif +#define LIBMDBX_INTERNALS +#ifdef MDBX_TOOLS +#define MDBX_DEPRECATED +#endif /* MDBX_TOOLS */ + /* *INDENT-OFF* */ /* clang-format off */ @@ -96,11 +101,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" #include "defs.h" From f73a8a868083490383aeb42f5abae1835bfddcfe Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Thu, 15 Oct 2020 19:23:14 +0300 Subject: [PATCH 17/20] mdbx: add latency gathering for commit stages. Change-Id: If68ceb6e69e5e565ce9de0fd9a80424b6da280c5 --- ChangeLog.md | 1 + mdbx.h | 36 ++++++++++++++++++++++++++++++++++- src/core.c | 54 +++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 81 insertions(+), 10 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 2395b116..bfa3eadb 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -12,6 +12,7 @@ TODO: Added features: - Provided package for [buildroot](https://buildroot.org/). - Added `mdbx_env_delete()` for deletion an environment files in a proper and multiprocess-safe way. + - Added `mdbx_txn_commit_ex()` with collecting latency information. Fixes: diff --git a/mdbx.h b/mdbx.h index 6ecc1f75..009b6de4 100644 --- a/mdbx.h +++ b/mdbx.h @@ -2921,6 +2921,38 @@ MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_txn_flags(const MDBX_txn *txn); MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API uint64_t mdbx_txn_id(const MDBX_txn *txn); +/** \brief Latency of commit stages in 1/65536 of seconds units. + * \warning This structure may be changed in future releases. + * \see mdbx_txn_commit_ex() */ +struct MDBX_commit_latency { + /** \brief Duration of preparation (commit child transactions, update + * sub-databases records and cursors destroying). */ + uint32_t preparation; + /** \brief Duration of GC/freeDB handling & updation. */ + uint32_t gc; + /** \brief Duration of internal audit if enabled. */ + uint32_t audit; + /** \brief Duration of writing dirty/modified data pages. */ + uint32_t write; + /** \brief Duration of syncing written data to the dist/storage. */ + uint32_t sync; + /** \brief Duration of transaction ending (releasing resources). */ + uint32_t ending; + /** \brief The total duration of a commit. */ + uint32_t whole; +}; +#ifndef __cplusplus +/** \ingroup c_statinfo */ +typedef struct MDBX_commit_latency MDBX_commit_latency; +#endif + +/** \brief Commit all the operations of a transaction into the database and + * collect latency information. + * \see mdbx_txn_commit() + * \ingroup c_statinfo + * \warning This function may be changed in future releases. */ +LIBMDBX_API int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency); + /** \brief Commit all the operations of a transaction into the database. * \ingroup c_transactions * @@ -2958,7 +2990,9 @@ mdbx_txn_id(const MDBX_txn *txn); * \retval MDBX_ENOSPC No more disk space. * \retval MDBX_EIO A system-level I/O error occurred. * \retval MDBX_ENOMEM Out of memory. */ -LIBMDBX_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); +} /** \brief Abandon all the operations of the transaction instead of saving them. * \ingroup c_transactions diff --git a/src/core.c b/src/core.c index f4fac622..f7bfef63 100644 --- a/src/core.c +++ b/src/core.c @@ -8025,12 +8025,18 @@ static __always_inline bool mdbx_txn_dbi_exists(MDBX_txn *txn, MDBX_dbi dbi, return mdbx_txn_import_dbi(txn, dbi); } -int mdbx_txn_commit(MDBX_txn *txn) { +int mdbx_txn_commit(MDBX_txn *txn) { return __inline_mdbx_txn_commit(txn); } + +int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) { STATIC_ASSERT(MDBX_TXN_FINISHED == MDBX_TXN_BLOCKED - MDBX_TXN_HAS_CHILD - MDBX_TXN_ERROR); + const uint64_t ts_0 = latency ? mdbx_osal_monotime() : 0; + uint64_t ts_1 = 0, ts_2 = 0, ts_3 = 0, ts_4 = 0; + uint32_t audit_duration = 0; + int rc = check_txn(txn, MDBX_TXN_FINISHED); if (unlikely(rc != MDBX_SUCCESS)) - return rc; + goto provide_latency; if (unlikely(txn->mt_flags & MDBX_TXN_ERROR)) { rc = MDBX_RESULT_TRUE; @@ -8041,7 +8047,8 @@ int mdbx_txn_commit(MDBX_txn *txn) { #if MDBX_ENV_CHECKPID if (unlikely(env->me_pid != mdbx_getpid())) { env->me_flags |= MDBX_FATAL_ERROR; - return MDBX_PANIC; + rc = MDBX_PANIC; + goto provide_latency; } #endif /* MDBX_ENV_CHECKPID */ @@ -8052,7 +8059,7 @@ int mdbx_txn_commit(MDBX_txn *txn) { goto done; if (txn->mt_child) { - rc = mdbx_txn_commit(txn->mt_child); + rc = mdbx_txn_commit_ex(txn->mt_child, NULL); mdbx_tassert(txn, txn->mt_child == NULL); if (unlikely(rc != MDBX_SUCCESS)) goto fail; @@ -8107,6 +8114,7 @@ int mdbx_txn_commit(MDBX_txn *txn) { parent->mt_dbistate[i] = txn->mt_dbistate[i] | (parent->mt_dbistate[i] & (DBI_CREAT | DBI_FRESH)); } + ts_1 = latency ? mdbx_osal_monotime() : 0; /* Remove refunded pages from parent's dirty & spill lists */ MDBX_DPL dst = mdbx_dpl_sort(parent->tw.dirtylist); @@ -8278,6 +8286,7 @@ int mdbx_txn_commit(MDBX_txn *txn) { parent->mt_flags |= MDBX_TXN_SPILLS; } + ts_2 = latency ? mdbx_osal_monotime() : 0; /* Append our loose page list to parent's */ if (txn->tw.loose_pages) { MDBX_page **lp = &parent->tw.loose_pages; @@ -8299,8 +8308,6 @@ int mdbx_txn_commit(MDBX_txn *txn) { env->me_txn = parent; parent->mt_child = NULL; - txn->mt_signature = 0; - mdbx_free(txn); mdbx_tassert(parent, mdbx_dirtylist_check(parent)); /* Scan parent's loose page for suitable for refund */ @@ -8310,8 +8317,13 @@ int mdbx_txn_commit(MDBX_txn *txn) { break; } } + + ts_4 = ts_3 = latency ? mdbx_osal_monotime() : 0; + txn->mt_signature = 0; + mdbx_free(txn); mdbx_tassert(parent, mdbx_dirtylist_check(parent)); - return MDBX_SUCCESS; + rc = MDBX_SUCCESS; + goto provide_latency; } mdbx_tassert(txn, txn->tw.dirtyroom + txn->tw.dirtylist->length == @@ -8360,17 +8372,23 @@ int mdbx_txn_commit(MDBX_txn *txn) { } } + ts_1 = latency ? mdbx_osal_monotime() : 0; rc = mdbx_update_gc(txn); if (unlikely(rc != MDBX_SUCCESS)) goto fail; + ts_2 = latency ? mdbx_osal_monotime() : 0; if (mdbx_audit_enabled()) { rc = mdbx_audit_ex(txn, MDBX_PNL_SIZE(txn->tw.retired_pages), true); + const uint64_t audit_end = mdbx_osal_monotime(); + audit_duration = mdbx_osal_monotime_to_16dot16(audit_end - ts_2); + ts_2 = audit_end; if (unlikely(rc != MDBX_SUCCESS)) goto fail; } rc = mdbx_page_flush(txn, 0); + ts_3 = latency ? mdbx_osal_monotime() : 0; if (likely(rc == MDBX_SUCCESS)) { if (txn->mt_dbs[MAIN_DBI].md_flags & DBI_DIRTY) txn->mt_dbs[MAIN_DBI].md_mod_txnid = pp_txnid2chk(txn); @@ -8392,6 +8410,7 @@ int mdbx_txn_commit(MDBX_txn *txn) { rc = mdbx_sync_locked( env, env->me_flags | txn->mt_flags | MDBX_SHRINK_ALLOWED, &meta); } + ts_4 = latency ? mdbx_osal_monotime() : 0; if (unlikely(rc != MDBX_SUCCESS)) { env->me_flags |= MDBX_FATAL_ERROR; goto fail; @@ -8400,11 +8419,28 @@ int mdbx_txn_commit(MDBX_txn *txn) { end_mode = MDBX_END_COMMITTED | MDBX_END_UPDATE | MDBX_END_EOTDONE; done: - return mdbx_txn_end(txn, end_mode); + rc = mdbx_txn_end(txn, end_mode); + +provide_latency: + if (latency) { + latency->audit = audit_duration; + latency->preparation = + ts_1 ? mdbx_osal_monotime_to_16dot16(ts_1 - ts_0) : 0; + latency->gc = + (ts_1 && ts_2) ? mdbx_osal_monotime_to_16dot16(ts_2 - ts_1) : 0; + latency->write = + (ts_2 && ts_3) ? mdbx_osal_monotime_to_16dot16(ts_3 - ts_2) : 0; + latency->sync = + (ts_3 && ts_4) ? mdbx_osal_monotime_to_16dot16(ts_4 - ts_3) : 0; + const uint64_t ts_5 = mdbx_osal_monotime(); + latency->ending = ts_4 ? mdbx_osal_monotime_to_16dot16(ts_5 - ts_4) : 0; + latency->whole = mdbx_osal_monotime_to_16dot16(ts_5 - ts_0); + } + return rc; fail: mdbx_txn_abort(txn); - return rc; + goto provide_latency; } static __cold int From 7001d971e189f43220b40561aa377f40707cf325 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sun, 18 Oct 2020 02:34:55 +0300 Subject: [PATCH 18/20] mdbx: clarify/refine mdbx_flush_iov(). Change-Id: Ib9462efdbf97e42b1e80bf130f8150072102d9ed --- src/core.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/core.c b/src/core.c index f7bfef63..d609222d 100644 --- a/src/core.c +++ b/src/core.c @@ -7869,24 +7869,23 @@ static int mdbx_flush_iov(MDBX_txn *const txn, struct iovec *iov, size_t iov_bytes) { MDBX_env *const env = txn->mt_env; mdbx_assert(env, iov_items > 0); + int rc; if (likely(iov_items == 1)) { mdbx_assert(env, iov->iov_len == iov_bytes); - int rc = mdbx_pwrite(env->me_lazy_fd, iov->iov_base, iov_bytes, iov_off); - mdbx_dpage_free(env, (MDBX_page *)iov->iov_base, - bytes2pgno(env, iov_bytes)); - return rc; + rc = mdbx_pwrite(env->me_lazy_fd, iov->iov_base, iov_bytes, iov_off); } else { - int rc = mdbx_pwritev(env->me_lazy_fd, iov, iov_items, iov_off, iov_bytes); - if (unlikely(rc != MDBX_SUCCESS)) { - mdbx_error("Write error: %s", mdbx_strerror(rc)); - txn->mt_flags |= MDBX_TXN_ERROR; - } - - for (unsigned i = 0; i < iov_items; i++) - mdbx_dpage_free(env, (MDBX_page *)iov[i].iov_base, - bytes2pgno(env, iov[i].iov_len)); - return rc; + rc = mdbx_pwritev(env->me_lazy_fd, iov, iov_items, iov_off, iov_bytes); } + + if (unlikely(rc != MDBX_SUCCESS)) { + mdbx_error("Write error: %s", mdbx_strerror(rc)); + txn->mt_flags |= MDBX_TXN_ERROR; + } + + for (unsigned i = 0; i < iov_items; i++) + mdbx_dpage_free(env, (MDBX_page *)iov[i].iov_base, + bytes2pgno(env, iov[i].iov_len)); + return rc; } /* Flush (some) dirty pages to the map, after clearing their dirty flag. From 603e25074533ce28d76a9a8ec181fb51a29715cf Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Mon, 19 Oct 2020 16:19:48 +0300 Subject: [PATCH 19/20] mdbx-cmake: fix/refine `git-fetch_version` macro for old branches. Change-Id: Ied5b7c839da75de065fd86ec46da7b391022c948 --- cmake/utils.cmake | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index dc6a240e..8f4babd4 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -113,23 +113,34 @@ macro(fetch_version name source_root_directory parent_scope) message(FATAL_ERROR "Please install latest version of git ('show --no-patch --format=%H HEAD' failed)") endif() - execute_process(COMMAND ${GIT} tag --sort=-version:refname - OUTPUT_VARIABLE tag_list + execute_process(COMMAND ${GIT} describe --tags --abbrev=0 "--match=v[0-9]*" + OUTPUT_VARIABLE last_release_tag OUTPUT_STRIP_TRAILING_WHITESPACE WORKING_DIRECTORY ${source_root_directory} RESULT_VARIABLE rc) if(rc) - message(FATAL_ERROR "Please install latest version of git ('tag --sort=-version:refname' failed)") + message(FATAL_ERROR "Please install latest version of git ('describe --tags --abbrev=0 --match=v[0-9]*' failed)") endif() - string(REGEX REPLACE "\n" ";" tag_list "${tag_list}") - set(last_release_tag "") - set(git_revlist_arg "HEAD") - foreach(tag IN LISTS tag_list) - if(NOT last_release_tag) - string(REGEX MATCH "^v[0-9]+(\.[0-9]+)+" last_release_tag "${tag}") - set(git_revlist_arg "${tag}..HEAD") + if (last_release_tag) + set(git_revlist_arg "${last_release_tag}..HEAD") + else() + execute_process(COMMAND ${GIT} tag --sort=-version:refname + OUTPUT_VARIABLE tag_list + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${source_root_directory} + RESULT_VARIABLE rc) + if(rc) + message(FATAL_ERROR "Please install latest version of git ('tag --sort=-version:refname' failed)") endif() - endforeach(tag) + string(REGEX REPLACE "\n" ";" tag_list "${tag_list}") + set(git_revlist_arg "HEAD") + foreach(tag IN LISTS tag_list) + if(NOT last_release_tag) + string(REGEX MATCH "^v[0-9]+(\.[0-9]+)+" last_release_tag "${tag}") + set(git_revlist_arg "${tag}..HEAD") + endif() + endforeach(tag) + endif() execute_process(COMMAND ${GIT} rev-list --count "${git_revlist_arg}" OUTPUT_VARIABLE ${name}_GIT_REVISION OUTPUT_STRIP_TRAILING_WHITESPACE From b964b2abf525db37e733971af28c03923896b69e Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Tue, 20 Oct 2020 15:42:50 +0300 Subject: [PATCH 20/20] mdbx: more spelling. Change-Id: I45e42c1d8ef51f910b8e41279b92e54a6b2ce772 --- .github/actions/spelling/expect.txt | 15 ++++++ GNUmakefile | 2 +- cmake/utils.cmake | 4 +- mdbx.h | 6 +-- mdbx.h++ | 2 +- src/core.c | 10 ++-- src/internals.h | 4 +- src/mdbx_load.c | 2 +- src/osal.h | 2 +- test/append.cc | 20 ++++---- test/hill.cc | 76 ++++++++++++++--------------- test/nested.cc | 6 +-- test/osal-unix.cc | 2 +- test/test.cc | 14 +++--- test/test.h | 2 +- 15 files changed, 91 insertions(+), 76 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 0e8631f1..ae692c27 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -133,6 +133,7 @@ cadabra callergraph callgraph calloc +cas casename cassert castortech @@ -250,6 +251,7 @@ dbiseqs dbistate dbm dbpath +dbs dbsize dbstate DBT @@ -326,6 +328,7 @@ dpage DPK dpl dprefix +DPs dqiqg dreamsxin dsize @@ -427,6 +430,7 @@ errcode errno errnum ERRORCHECK +errored erthink esac eturn @@ -554,6 +558,7 @@ gitdir github githubusercontent glibc +globals gmail gmake gmx @@ -649,6 +654,7 @@ indx INDXSIZE ini initd +INITED initialiser inl inlined @@ -661,6 +667,7 @@ interprocedural intlimits intptr intrin +intrinsics inttypes ioarena IODQ @@ -735,6 +742,7 @@ klen KMGTPEZY knipp kp +ks ksize kstat kurt @@ -849,6 +857,7 @@ mathjax mattr MAXDATASIZE maxdbs +maxed maxgc maxkey maxkeysize @@ -1386,6 +1395,7 @@ semctl semget semid semop +sems sendfile sepkey SETALL @@ -1408,6 +1418,7 @@ Shipitsin shm showinitializer showned +shrinked sideeffect sigaction sigaddset @@ -1513,6 +1524,7 @@ strstr strtol strtoul strtoull +structs stylesheet subalign SUBDATA @@ -1663,6 +1675,7 @@ unregister unspill unsync UNTRACK +updation upsert UPSERTING upsertion @@ -1697,6 +1710,7 @@ valuemode vasprintf vedisdb VERINFO +versioned versioning Veyor vfprintf @@ -1745,6 +1759,7 @@ WIFSTOPPED wiki wikipedia wiktionary +wildcards WILLNEED WINAPI windowsbug diff --git a/GNUmakefile b/GNUmakefile index f9d7830b..3866e92d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -87,7 +87,7 @@ ifeq ($(wildcard mdbx.c),mdbx.c) #< dist-cutoff-end ################################################################################ -# Amalgamated source code, i.e. distributed after `make dists` +# Amalgamated source code, i.e. distributed after `make dist` MAN_SRCDIR := man1/ config.h: mdbx.c $(lastword $(MAKEFILE_LIST)) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 8f4babd4..4a48a15a 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -17,8 +17,8 @@ cmake_minimum_required(VERSION 3.8.2) cmake_policy(PUSH) cmake_policy(VERSION 3.8.2) -macro(add_compile_flags langs) - foreach(_lang ${langs}) +macro(add_compile_flags languages) + foreach(_lang ${languages}) string(REPLACE ";" " " _flags "${ARGN}") if(CMAKE_CXX_COMPILER_LOADED AND _lang STREQUAL "CXX") set("${_lang}_FLAGS" "${${_lang}_FLAGS} ${_flags}") diff --git a/mdbx.h b/mdbx.h index 009b6de4..3b40b98f 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1245,7 +1245,7 @@ enum MDBX_env_flags_t { * - a system crash immediately after commit the write transaction * high likely lead to database corruption. * - successful completion of mdbx_env_sync(force = true) after one or - * more commited transactions guarantees consistency and durability. + * more committed transactions guarantees consistency and durability. * - BUT by committing two or more transactions you back database into * a weak state, in which a system crash may lead to database corruption! * In case single transaction after mdbx_env_sync, you may lose transaction @@ -1954,7 +1954,7 @@ struct MDBX_stat { uint64_t ms_leaf_pages; /**< Number of leaf pages */ uint64_t ms_overflow_pages; /**< Number of overflow pages */ uint64_t ms_entries; /**< Number of data items */ - uint64_t ms_mod_txnid; /**< Transaction ID of commited last modification */ + uint64_t ms_mod_txnid; /**< Transaction ID of committed last modification */ }; #ifndef __cplusplus /** \ingroup c_statinfo */ @@ -4398,7 +4398,7 @@ LIBMDBX_API int mdbx_thread_unregister(const MDBX_env *env); * \param [in] pid A pid of the reader process. * \param [in] tid A thread_id of the reader thread. * \param [in] laggard An oldest read transaction number on which stalled. - * \param [in] gap A lag from the last commited txn. + * \param [in] gap A lag from the last committed txn. * \param [in] space A space that actually become available for reuse after * this reader finished. The callback function can take * this value into account to evaluate the impact that diff --git a/mdbx.h++ b/mdbx.h++ index 6848d705..07d65058 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -2081,7 +2081,7 @@ public: /// \ref MDBX_BAD_DBI (since the DB name is gone). inline void close_map(const map_handle &); - /// \brief Readed information + /// \brief Reader information struct reader_info { int slot; ///< The reader lock table slot number. mdbx_pid_t pid; ///< The reader process ID. diff --git a/src/core.c b/src/core.c index d609222d..806c77d6 100644 --- a/src/core.c +++ b/src/core.c @@ -38,7 +38,7 @@ #include "internals.h" /*------------------------------------------------------------------------------ - * Internal inlines */ + * Internal inline functions */ MDBX_NOTHROW_CONST_FUNCTION static unsigned log2n(size_t value) { assert(value > 0 && value < INT32_MAX && is_powerof2(value)); @@ -3584,7 +3584,7 @@ static __maybe_unused void mdbx_page_list(MDBX_page *mp) { /*----------------------------------------------------------------------------*/ -/* Check if there is an inited xcursor, so XCURSOR_REFRESH() is proper */ +/* Check if there is an initialized xcursor, so XCURSOR_REFRESH() is proper */ #define XCURSOR_INITED(mc) \ ((mc)->mc_xcursor && ((mc)->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) @@ -11057,7 +11057,7 @@ static int __hot cmp_int_align2(const MDBX_val *a, const MDBX_val *b) { } } -/* Compare two items pointing at unsigneds of unknown alignment. +/* Compare two items pointing at unsigned values with unknown alignment. * * This is also set as MDBX_INTEGERDUP|MDBX_DUPFIXED's MDBX_dbx.md_dcmp. */ static int __hot cmp_int_unaligned(const MDBX_val *a, const MDBX_val *b) { @@ -14197,8 +14197,8 @@ static int mdbx_update_key(MDBX_cursor *mc, const MDBX_val *key) { char kbuf2[DKBUF_MAXKEYSIZE * 2 + 1]; k2.iov_base = node_key(node); k2.iov_len = node_ks(node); - mdbx_debug("update key %u (ofs %u) [%s] to [%s] on page %" PRIaPGNO, indx, - ptr, mdbx_dump_val(&k2, kbuf2, sizeof(kbuf2)), DKEY(key), + mdbx_debug("update key %u (offset %u) [%s] to [%s] on page %" PRIaPGNO, + indx, ptr, mdbx_dump_val(&k2, kbuf2, sizeof(kbuf2)), DKEY(key), mp->mp_pgno); } diff --git a/src/internals.h b/src/internals.h index aa29665b..81e3fc79 100644 --- a/src/internals.h +++ b/src/internals.h @@ -287,7 +287,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 */ @@ -943,7 +943,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() */ diff --git a/src/mdbx_load.c b/src/mdbx_load.c index 54e17955..2c59ede6 100644 --- a/src/mdbx_load.c +++ b/src/mdbx_load.c @@ -678,7 +678,7 @@ int main(int argc, char *argv[]) { if (present_sequence > sequence) { fprintf(stderr, "present sequence for '%s' value (%" PRIu64 - ") is greated than loaded (%" PRIu64 ")\n", + ") is greater than loaded (%" PRIu64 ")\n", dbi_name, present_sequence, sequence); rc = MDBX_RESULT_TRUE; goto txn_abort; diff --git a/src/osal.h b/src/osal.h index aa839ac1..30b342d0 100644 --- a/src/osal.h +++ b/src/osal.h @@ -283,7 +283,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__) || \ diff --git a/test/append.cc b/test/append.cc index c6340d99..c7469b4a 100644 --- a/test/append.cc +++ b/test/append.cc @@ -43,8 +43,8 @@ bool testcase_append::run() { uint64_t serial_count = 0; unsigned txn_nops = 0; - uint64_t commited_inserted_number = inserted_number; - simple_checksum commited_inserted_checksum = inserted_checksum; + uint64_t committed_inserted_number = inserted_number; + simple_checksum committed_inserted_checksum = inserted_checksum; while (should_continue()) { const keygen::serial_t serial = serial_count; if (!keyvalue_maker.increment(serial_count, 1)) { @@ -64,8 +64,8 @@ bool testcase_append::run() { if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { log_notice("append: bailout-insert due '%s'", mdbx_strerror(err)); txn_end(true); - inserted_number = commited_inserted_number; - inserted_checksum = commited_inserted_checksum; + inserted_number = committed_inserted_number; + inserted_checksum = committed_inserted_checksum; break; } @@ -89,12 +89,12 @@ bool testcase_append::run() { err = breakable_restart(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("append: bailout-commit due '%s'", mdbx_strerror(err)); - inserted_number = commited_inserted_number; - inserted_checksum = commited_inserted_checksum; + inserted_number = committed_inserted_number; + inserted_checksum = committed_inserted_checksum; break; } - commited_inserted_number = inserted_number; - commited_inserted_checksum = inserted_checksum; + committed_inserted_number = inserted_number; + committed_inserted_checksum = inserted_checksum; txn_nops = 0; } @@ -105,8 +105,8 @@ bool testcase_append::run() { err = breakable_commit(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("append: bailout-commit due '%s'", mdbx_strerror(err)); - inserted_number = commited_inserted_number; - inserted_checksum = commited_inserted_checksum; + inserted_number = committed_inserted_number; + inserted_checksum = committed_inserted_checksum; } } //---------------------------------------------------------------------------- diff --git a/test/hill.cc b/test/hill.cc index 97864f0c..b45ab341 100644 --- a/test/hill.cc +++ b/test/hill.cc @@ -21,7 +21,7 @@ bool testcase_hill::run() { return false; } speculum.clear(); - speculum_commited.clear(); + speculum_committed.clear(); /* LY: тест "холмиком": * - сначала наполняем таблицу циклическими CRUD-манипуляциями, @@ -62,7 +62,7 @@ bool testcase_hill::run() { : MDBX_NODUPDATA; uint64_t serial_count = 0; - uint64_t commited_serial = serial_count; + uint64_t committed_serial = serial_count; unsigned txn_nops = 0; bool rc = false; @@ -87,8 +87,8 @@ bool testcase_hill::run() { if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { log_notice("uphill: bailout at insert-a due '%s'", mdbx_strerror(err)); txn_restart(true, false); - serial_count = commited_serial; - speculum = speculum_commited; + serial_count = committed_serial; + speculum = speculum_committed; break; } failure_perror("mdbx_put(insert-a.1)", err); @@ -102,12 +102,12 @@ bool testcase_hill::run() { err = breakable_restart(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("uphill: bailout at commit due '%s'", mdbx_strerror(err)); - serial_count = commited_serial; - speculum = speculum_commited; + serial_count = committed_serial; + speculum = speculum_committed; break; } - speculum_commited = speculum; - commited_serial = a_serial; + speculum_committed = speculum; + committed_serial = a_serial; txn_nops = 0; if (!speculum_verify()) { log_notice("uphill: bailout after insert-a, after commit"); @@ -123,8 +123,8 @@ bool testcase_hill::run() { if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { log_notice("uphill: bailout at insert-b due '%s'", mdbx_strerror(err)); txn_restart(true, false); - serial_count = commited_serial; - speculum = speculum_commited; + serial_count = committed_serial; + speculum = speculum_committed; break; } failure_perror("mdbx_put(insert-b)", err); @@ -138,12 +138,12 @@ bool testcase_hill::run() { err = breakable_restart(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("uphill: bailout at commit due '%s'", mdbx_strerror(err)); - serial_count = commited_serial; - speculum = speculum_commited; + serial_count = committed_serial; + speculum = speculum_committed; break; } - speculum_commited = speculum; - commited_serial = a_serial; + speculum_committed = speculum; + committed_serial = a_serial; txn_nops = 0; if (!speculum_verify()) { log_notice("uphill: bailout after insert-b, after commit"); @@ -161,8 +161,8 @@ bool testcase_hill::run() { if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { log_notice("uphill: bailout at update-a due '%s'", mdbx_strerror(err)); txn_restart(true, false); - serial_count = commited_serial; - speculum = speculum_commited; + serial_count = committed_serial; + speculum = speculum_committed; break; } failure_perror("mdbx_replace(update-a: 1->0)", err); @@ -176,12 +176,12 @@ bool testcase_hill::run() { err = breakable_restart(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("uphill: bailout at commit due '%s'", mdbx_strerror(err)); - serial_count = commited_serial; - speculum = speculum_commited; + serial_count = committed_serial; + speculum = speculum_committed; break; } - speculum_commited = speculum; - commited_serial = a_serial; + speculum_committed = speculum; + committed_serial = a_serial; txn_nops = 0; if (!speculum_verify()) { log_notice("uphill: bailout after update-a, after commit"); @@ -197,8 +197,8 @@ bool testcase_hill::run() { if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { log_notice("uphill: bailout at delete-b due '%s'", mdbx_strerror(err)); txn_restart(true, false); - serial_count = commited_serial; - speculum = speculum_commited; + serial_count = committed_serial; + speculum = speculum_committed; break; } failure_perror("mdbx_del(b)", err); @@ -212,12 +212,12 @@ bool testcase_hill::run() { err = breakable_restart(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("uphill: bailout at commit due '%s'", mdbx_strerror(err)); - serial_count = commited_serial; - speculum = speculum_commited; + serial_count = committed_serial; + speculum = speculum_committed; break; } - speculum_commited = speculum; - commited_serial = a_serial; + speculum_committed = speculum; + committed_serial = a_serial; txn_nops = 0; if (!speculum_verify()) { log_notice("uphill: bailout after delete-b, after commit"); @@ -296,7 +296,7 @@ bool testcase_hill::run() { log_notice("downhill: bailout at update-a due '%s'", mdbx_strerror(err)); txn_end(true); - speculum = speculum_commited; + speculum = speculum_committed; break; } failure_perror("mdbx_put(update-a: 0->1)", err); @@ -310,10 +310,10 @@ bool testcase_hill::run() { err = breakable_restart(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("downhill: bailout at commit due '%s'", mdbx_strerror(err)); - speculum = speculum_commited; + speculum = speculum_committed; break; } - speculum_commited = speculum; + speculum_committed = speculum; txn_nops = 0; if (!speculum_verify()) { log_notice("downhill: bailout after update-a, after commit"); @@ -330,7 +330,7 @@ bool testcase_hill::run() { log_notice("downhill: bailout at insert-a due '%s'", mdbx_strerror(err)); txn_end(true); - speculum = speculum_commited; + speculum = speculum_committed; break; } failure_perror("mdbx_put(insert-b)", err); @@ -344,10 +344,10 @@ bool testcase_hill::run() { err = breakable_restart(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("downhill: bailout at commit due '%s'", mdbx_strerror(err)); - speculum = speculum_commited; + speculum = speculum_committed; break; } - speculum_commited = speculum; + speculum_committed = speculum; txn_nops = 0; if (!speculum_verify()) { log_notice("downhill: bailout after insert-b, after commit"); @@ -365,7 +365,7 @@ bool testcase_hill::run() { log_notice("downhill: bailout at delete-a due '%s'", mdbx_strerror(err)); txn_end(true); - speculum = speculum_commited; + speculum = speculum_committed; break; } failure_perror("mdbx_del(a)", err); @@ -379,10 +379,10 @@ bool testcase_hill::run() { err = breakable_restart(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("downhill: bailout at commit due '%s'", mdbx_strerror(err)); - speculum = speculum_commited; + speculum = speculum_committed; break; } - speculum_commited = speculum; + speculum_committed = speculum; txn_nops = 0; if (!speculum_verify()) { log_notice("downhill: bailout after delete-a, after commit"); @@ -399,7 +399,7 @@ bool testcase_hill::run() { log_notice("downhill: bailout at delete-b due '%s'", mdbx_strerror(err)); txn_end(true); - speculum = speculum_commited; + speculum = speculum_committed; break; } failure_perror("mdbx_del(b)", err); @@ -413,10 +413,10 @@ bool testcase_hill::run() { err = breakable_restart(); if (unlikely(err != MDBX_SUCCESS)) { log_notice("downhill: bailout at commit due '%s'", mdbx_strerror(err)); - speculum = speculum_commited; + speculum = speculum_committed; break; } - speculum_commited = speculum; + speculum_committed = speculum; txn_nops = 0; if (!speculum_verify()) { log_notice("downhill: bailout after delete-b, after commit"); diff --git a/test/nested.cc b/test/nested.cc index 3f9eac02..2456886e 100644 --- a/test/nested.cc +++ b/test/nested.cc @@ -92,7 +92,7 @@ bool testcase_nested::pop_txn(bool abort) { assert(txn_guard && !stack.empty()); bool should_continue = true; MDBX_txn *txn = txn_guard.release(); - bool commited = false; + bool committed = false; if (abort) { log_verbose( "abort level#%zu txn #%" PRIu64 ", undo serial %" PRIu64 " <- %" PRIu64, @@ -105,7 +105,7 @@ bool testcase_nested::pop_txn(bool abort) { stack.size(), serial, std::get<1>(stack.top())); int err = mdbx_txn_commit(txn); if (likely(err == MDBX_SUCCESS)) - commited = true; + committed = true; else { should_continue = false; if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { @@ -119,7 +119,7 @@ bool testcase_nested::pop_txn(bool abort) { } std::swap(txn_guard, std::get<0>(stack.top())); - if (!commited) { + if (!committed) { serial = std::get<1>(stack.top()); std::swap(fifo, std::get<2>(stack.top())); std::swap(speculum, std::get<3>(stack.top())); diff --git a/test/osal-unix.cc b/test/osal-unix.cc index f8b1e1b4..57643667 100644 --- a/test/osal-unix.cc +++ b/test/osal-unix.cc @@ -164,7 +164,7 @@ void osal_setup(const std::vector &actors) { , -1, 0); if (MAP_FAILED == (void *)shared) - failure_perror("mmap(shared_conds)", errno); + failure_perror("mmap(shared)", errno); shared->count = actors.size() + 1; diff --git a/test/test.cc b/test/test.cc index ff0cf5f4..c676cff3 100644 --- a/test/test.cc +++ b/test/test.cc @@ -207,9 +207,9 @@ int testcase::breakable_commit() { if (need_speculum_assign) { need_speculum_assign = false; if (unlikely(rc != MDBX_SUCCESS)) - speculum = speculum_commited; + speculum = speculum_committed; else - speculum_commited = speculum; + speculum_committed = speculum; } log_trace("<< txn_commit: %s", rc ? "failed" : "Ok"); @@ -240,14 +240,14 @@ void testcase::txn_end(bool abort) { if (unlikely(err != MDBX_SUCCESS)) failure_perror("mdbx_txn_abort()", err); if (need_speculum_assign) - speculum = speculum_commited; + speculum = speculum_committed; } else { txn_inject_writefault(txn); int err = mdbx_txn_commit(txn); if (unlikely(err != MDBX_SUCCESS)) failure_perror("mdbx_txn_commit()", err); if (need_speculum_assign) - speculum_commited = speculum; + speculum_committed = speculum; } log_trace("<< txn_end(%s)", abort ? "abort" : "commit"); @@ -615,13 +615,13 @@ bool test_execute(const actor_config &config_const) { } if (config.params.nrepeat == 1) - log_verbose("test successed"); + log_verbose("test successfully"); else { if (config.params.nrepeat) - log_verbose("test successed (iteration %zi of %zi)", iter, + log_verbose("test successfully (iteration %zi of %zi)", iter, size_t(config.params.nrepeat)); else - log_verbose("test successed (iteration %zi)", iter); + log_verbose("test successfully (iteration %zi)", iter); config.params.keygen.seed += INT32_C(0xA4F4D37B); } diff --git a/test/test.h b/test/test.h index 309ef1df..21420d99 100644 --- a/test/test.h +++ b/test/test.h @@ -158,7 +158,7 @@ protected: MDBX_canary canary; } last; - SET speculum{ItemCompare(this)}, speculum_commited{ItemCompare(this)}; + SET speculum{ItemCompare(this)}, speculum_committed{ItemCompare(this)}; bool speculum_verify(); int insert(const keygen::buffer &akey, const keygen::buffer &adata, MDBX_put_flags_t flags);