Compare commits

...

223 Commits

Author SHA1 Message Date
Леонид Юрьев (Leonid Yuriev)
d47eed079e mdbx: release v0.11.2
Acknowledgements:
-----------------

 - [장세연 (Чан Се Ен)](https://github.com/sasgas) for contributing to C++ API.
 - [Alain Picard](https://github.com/castortech) for [Java bindings](https://github.com/castortech/mdbxjni).
 - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
 - [Kris Zyp](https://github.com/kriszyp) for reporting and testing.
 - [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs).

Fixes:
------

 - [Fixed compilation](https://github.com/erthink/libmdbx/pull/239) with `devtoolset-9` on CentOS/RHEL 7.
 - [Fixed unexpected `MDBX_PROBLEM` error](https://github.com/erthink/libmdbx/issues/242) because of update an obsolete meta-page.
 - [Fixed returning `MDBX_NOTFOUND` error](https://github.com/erthink/libmdbx/issues/243) in case an inexact value found for `MDBX_GET_BOTH` operation.
 - [Fixed compilation](https://github.com/erthink/libmdbx/issues/245) without kernel/libc-devel headers.

Minors:
-------

 - Fixed `constexpr`-related macros for legacy compilers.
 - Allowed to define 'CMAKE_CXX_STANDARD` using an environment variable.
 - Simplified collection statistics of page operation .
 - Added `MDBX_FORCE_BUILD_AS_MAIN_PROJECT` cmake option.
 - Remove unneeded `#undef P_DIRTY`.

Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
2021-12-02 21:55:52 +03:00
Леонид Юрьев (Leonid Yuriev)
d2b15b5958 mdbx: more unlikely(). 2021-12-02 20:22:37 +03:00
Леонид Юрьев (Leonid Yuriev)
d96bc98244 mdbx: minor refine/fix MDBX_ENODATA for compatibility.
Related to https://github.com/erthink/libmdbx/issues/243
2021-12-02 20:22:37 +03:00
Леонид Юрьев (Leonid Yuriev)
c2cab7a6a8 mdbx: using clang-format-13 (cosmetics). 2021-12-02 20:22:31 +03:00
Леонид Юрьев (Leonid Yuriev)
38df3ca5ad mdbx: update/fix new libmdbx-rs library name. 2021-12-02 15:10:06 +03:00
Leonid Yuriev
5e4b2c9ddf mdbx: add BTC address for donations/sponsorship. 2021-11-27 17:02:27 +03:00
Leonid Yuriev
d777f5bb38 mdbx: update ChangeLog. 2021-11-27 00:29:36 +03:00
Leonid Yuriev
e912f87b2a mdbx: clarify notes about custom comparators usage. 2021-11-26 23:49:38 +03:00
Leonid Yuriev
0cc3aa3af8 mdbx: remove unneeded #undef P_DIRTY. 2021-11-26 17:51:37 +03:00
Leonid Yuriev
adac03729d mdbx: remove unneeded usage of <linux/sysctl.h>.
Fixed https://github.com/erthink/libmdbx/issues/245
2021-11-26 17:34:04 +03:00
Leonid Yuriev
17a14ec25f mdbx: update/fix new lmdbx-js library name. 2021-11-26 00:31:00 +03:00
Leonid Yuriev
4e73cdf9c6 mdbx: update ChangeLog. 2021-11-26 00:24:14 +03:00
Leonid Yuriev
66c354baff mdbx-test: add seek-test for MDBX_GET_BOTH.
Related to https://github.com/erthink/libmdbx/issues/243
2021-11-25 19:19:15 +03:00
Leonid Yuriev
76399bd643 mdbx: fix returning MDBX_NOTFOUND for non-exact seek case of MDBX_GET_BOTH.
Fixed https://github.com/erthink/libmdbx/issues/243
2021-11-25 19:19:04 +03:00
Leonid Yuriev
4f2aba2d22 mdbx: minor fix formatting (cosmetics). 2021-11-25 19:15:02 +03:00
Leonid Yuriev
085a97f835 mdbx: define MDBX_ENODATA == 9919 on systems without ENODATA.
As workaround for incompatibility C and C++ code using LLVM's C++ libraries/headers on on systems without native `ENODATA`.
2021-11-22 16:09:08 +03:00
Leonid Yuriev
a2141ceaac mdbx: slightly more cases to return MDBX_ENODATA. 2021-11-22 13:48:08 +03:00
Leonid Yuriev
9d55d06a20 mdbx-test: add check for MDBX_ENODATA condition. 2021-11-22 13:43:51 +03:00
Leonid Yuriev
e93d53ed92 mdbx: update ChangeLog. 2021-11-21 02:38:14 +03:00
Leonid Yuriev
8cb7c0f4fb mdbx: fix MDBX_PROBLEM while update an obsolete meta-page.
Fixes https://github.com/erthink/libmdbx/issues/242
2021-11-21 02:37:56 +03:00
Leonid Yuriev
773172cc99 mdbx: minor clarify descriptions of the MDBX_commit_latency fields. 2021-11-19 18:36:14 +03:00
Leonid Yuriev
937b38371f mdbx: remove obsolete remark from the reference to Java bindings. 2021-11-19 17:00:29 +03:00
Леонид Юрьев (Leonid Yuriev)
c312fead97 mdbx: update ChangeLog. 2021-11-19 16:21:44 +03:00
Леонид Юрьев (Leonid Yuriev)
bfff6cfe85 mdbx: fix nasty sizeof(bytes) typo. 2021-11-19 16:21:44 +03:00
Leonid Yuriev
86c735637e mdbx-cmake: add MDBX_FORCE_BUILD_AS_MAIN_PROJECT. 2021-11-19 16:21:40 +03:00
Leonid Yuriev
ff26d30362 mdbx: minor clarity enum MDBX_db_flags_t (database flags) descriptions.
Related to https://github.com/erthink/libmdbx/issues/241
2021-11-12 19:38:48 +03:00
Leonid Yuriev
79a5802ad4 mdbx: add the note about "Visual Studio 2015 Update 3". 2021-11-11 20:38:39 +03:00
Leonid Yuriev
0e2ca3eb51 mdbx: more parallelable CMP2INT for E2K. 2021-11-10 03:17:59 +03:00
Leonid Yuriev
e488604448 mdbx: minor fix mdbx_jitter4testing() for case MDBX_DEBUG >= 2. 2021-11-10 03:05:51 +03:00
Leonid Yuriev
eaa77c91cd mdbx: drop obsolete internal mm_flags macro. 2021-11-10 02:43:43 +03:00
Leonid Yuriev
8ed0a5946b mdbx: update ChangeLog. 2021-11-10 00:34:45 +03:00
Leonid Yuriev
0cd7dfb465 mdbx-ci: add dll-path-workaround to MinGW scenario with minor cleanup. 2021-11-10 00:23:01 +03:00
Leonid Yuriev
f38b1dab13 mdbx-ci: avoid spelling warnings. 2021-11-09 13:31:23 +03:00
sasgas
74d5a42578 mdbx: fix compilation with devtoolset-9 on CentOS/RHEL 7.
devtoolset is always using the old ABI
https://bugzilla.redhat.com/show_bug.cgi?id=1546704
https://stackoverflow.com/questions/49393888/how-can-i-use-the-new-c-11-abi-with-devtoolset-7-on-centos-rhel
2021-11-09 13:29:23 +03:00
Leonid Yuriev
6ecadba69a mdbx: update ChangeLog. 2021-11-08 18:37:21 +03:00
Leonid Yuriev
b46e5c4ce8 mdbx: simplify collection of page-ops statistic. 2021-11-07 22:14:33 +03:00
Leonid Yuriev
96139eef48 mdbx: a whole snapshot inside mdbx_env_info_ex(). 2021-11-07 21:18:10 +03:00
Leonid Yuriev
0c3a5da3cb mdbx: refine visibility of internal mdbx_osal_jitter(). 2021-11-07 19:48:14 +03:00
Leonid Yuriev
c456625ef2 mdbx-cmake: initial support for C++23. 2021-11-07 02:18:56 +03:00
Leonid Yuriev
630ef98951 mdbx-cmake: allow to define CMAKE_CXX_STANDARD by the environment variable. 2021-11-07 02:18:56 +03:00
Leonid Yuriev
7179823d56 mdbx-make: extpanded list of c++std for probing. 2021-11-07 02:18:56 +03:00
Leonid Yuriev
8870d33fcd mdbx++: refine MDBX_CXX01_CONSTEXPR for legacy compilers.
Enable `constexpr` via `MDBX_CXX01_CONSTEXPR` if __cplusplus == 201103L but __cpp_constexpr is undefined.
2021-11-07 02:18:56 +03:00
Leonid Yuriev
710fc95d9a mdbx: update patch for old buildroot versions. 2021-10-24 20:43:37 +03:00
Leonid Yuriev
93a24abbab mdbx: fix minor/paranoid MSVC warning. 2021-10-24 02:28:28 +03:00
Leonid Yuriev
113162b651 mdbx: release v0.11.1
Backward compatibility break:
-----------------------------

The database format signature has been changed to prevent
forward-interoperability with an previous releases, which may lead to a
[false positive diagnosis of database corruption](https://github.com/erthink/libmdbx/issues/238)
due to flaws of an old library versions.

This change is mostly invisible:

 - previously versions are unable to read/write a new DBs;
 - but the new release is able to handle an old DBs and will silently upgrade ones.

Acknowledgements:
-----------------
 - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.

Signed-off-by: Leonid Yuriev <leo@yuriev.ru>
2021-10-23 20:15:50 +03:00
Leonid Yuriev
5babf0872e mdbx++: add ifndef-guard for _CRT_SECURE_NO_WARNINGS. 2021-10-22 20:14:12 +03:00
Leonid Yuriev
331232858a adds updating db-format signature during DB open.
Fixes https://github.com/erthink/libmdbx/issues/238.
2021-10-22 20:13:57 +03:00
Leonid Yuriev
fcb8cd2145 mdbx: alter DB-format' signature and change version to v0.11.x (not a release).
Related to https://github.com/erthink/libmdbx/issues/238

Signed-off-by: Leonid Yuriev <leo@yuriev.ru>
2021-10-21 15:17:18 +03:00
Leonid Yuriev
514910621e mdbx: return MDBX_CORRUPTED instead of MDBX_PAGE_NOTFOUND for invalid pages. 2021-10-15 01:11:20 +03:00
Leonid Yuriev
7251f47d5b mdbx: fix typo which lead any error conversion to the 1. 2021-10-14 20:03:37 +03:00
Leonid Yuriev
edda9515d6 mdbx: release v0.10.5 (hotfix).
Acknowledgements:
-----------------
 - [Noel Kuntze](https://github.com/Thermi) for immediately bug reporting.

Fixes:
------
 - Fixed unaligned access regression after the `#pragma pack` fix for modern compilers.
 - Added UBSAN-test to CI to avoid a regression(s) similar to lately fixed.
 - Fixed possibility of meta-pages clashing after manually turn to a particular meta-page using `mdbx_chk` utility.

Minors:
-------
 - Refined handling of weak or invalid meta-pages while a DB opening.
 - Refined providing information for the @MAIN and @GC sub-databases of a last committed modification transaction's ID.

Signed-off-by: Leonid Yuriev <leo@yuriev.ru>
2021-10-13 16:35:26 +03:00
Leonid Yuriev
4632df5661 mdbx: cleanup non-persistent flags from meta-model. 2021-10-13 16:34:53 +03:00
Leonid Yuriev
11a5c50591 mdbx: fix turn_for_recovery() for possibility of meta-pages clashing after turn to a particular meta-page. 2021-10-13 16:34:53 +03:00
Leonid Yuriev
3092078709 mdbx: refine handling of weak or invalid meta-pages while a DB opening. 2021-10-13 16:34:53 +03:00
Leonid Yuriev
cbb71058ca mdbx: refine providing information for the @MAIN and @GC sub-databases of a last committed modification transaction's ID. 2021-10-13 16:34:25 +03:00
Leonid Yuriev
9dd15a4415 mdbx-ci: use Circle-CI for UBSAN-test pass. 2021-10-13 16:13:30 +03:00
Leonid Yuriev
30745e0621 mdbx: refix #pragma pack for modern compilers and aligned-required arches (hotfix).
Fix a regression after the https://github.com/erthink/libmdbx/issues/235
2021-10-13 16:13:22 +03:00
Leonid Yuriev
c9659e1aca mdbx: fix minor ChangeLog typo. 2021-10-11 17:18:06 +03:00
Leonid Yuriev
1fed51ac0d mdbx: update patch for buildroot (old versions). 2021-10-10 15:45:07 +03:00
Leonid Yuriev
590b225fcc mdbx: release v0.10.4
Acknowledgements:
-----------------
 - [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/mdbx-rs).
 - [Andrew Ashikhmin](https://github.com/yperbasis) for contributing to C++ API.

Fixes:
------
 - Fixed possibility of looping update GC during transaction commit (no public issue since the problem was discovered inside [Positive Technologies](https://www.ptsecurity.ru).
 - Fixed `#pragma pack` to avoid provoking some compilers to generate code with [unaligned access](https://github.com/erthink/libmdbx/issues/235).
 - Fixed `noexcept` for potentially throwing `txn::put()` of C++ API.

Minors:
-------
 - Added stochastic test script for checking small transactions cases.
 - Removed extra transaction commit/restart inside test framework.
 - In debugging builds fixed a too small (single page) by default DB shrink threshold.
2021-10-10 13:31:33 +03:00
Leonid Yuriev
2f8a429f91 mdbx: update ChangeLog. 2021-10-10 00:51:38 +03:00
Leonid Yuriev
64e6fa93fd mdbx: fix #pragma pack to avoid misalignment for some compilers.
Fixes https://github.com/erthink/libmdbx/issues/235.
2021-10-09 12:36:40 +03:00
Leonid Yuriev
ee917209fe mdbx-test: add stochastic-small script. 2021-10-09 12:30:39 +03:00
Leonid Yuriev
fa0a38c1ac mdbx: avoid single-page (too small) shrink threshold by default when MDBX_DEBUG > 0. 2021-10-09 12:30:39 +03:00
Leonid Yuriev
f936217309 mdbx-test: avoid extra transaction restart. 2021-10-09 12:30:35 +03:00
Leonid Yuriev
fe0ec8ceca mdbx: fix and refine mdbx_update_gc() to avoid infinite looping possibility (squashed). 2021-10-09 12:29:10 +03:00
Leonid Yuriev
6737d304a6 mdbx-ci: MDBX_FORCE_ASSERTION=1 for CI-build. 2021-10-09 12:29:05 +03:00
Leonid Yuriev
fe7186d549 mdbx: reflow comment (cosmetic). 2021-09-30 16:38:07 +03:00
Leonid Yuriev
c81226906a mdbx: update ChangeLog and Contributors list. 2021-09-28 00:37:33 +03:00
Leonid Yuriev
699361c5d0 mdbx: update bindings/wrappers list. 2021-09-27 20:39:19 +03:00
Leonid Yuriev
903bcd2466 mdbx-ci: switch github action from Ubuntu 16.04 to 18.04 2021-09-27 03:18:36 +03:00
yperbasis
c714ee9b55 mdbx++: remove noexcept from potentially throwing txn::put(). 2021-09-03 23:10:22 +03:00
Leonid Yuriev
bf603bdffc mdbx: release v0.10.3
Acknowledgements:
-----------------
 - [Francisco Vallarino](https://github.com/fjvallarino) for [Haskell bindings for libmdbx](https://hackage.haskell.org/package/libmdbx).
 - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
 - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for contributing.

Extensions and improvements:
----------------------------
 - Added `cursor::erase()` overloads for `key` and for `key-value`.
 - Resolve minor Coverity Scan issues (no fixes but some hint/comment were added).
 - Resolve minor UndefinedBehaviorSanitizer issues (no fixes but some workaround were added).

Fixes:
------
 - Always setup `madvise` while opening DB (fixes https://github.com/erthink/libmdbx/issues/231).
 - Fixed checking legacy `P_DIRTY` flag (`0x10`) for nested/sub-pages.

Minors:
-------
 - Fixed getting revision number from middle of history during amalgamation (GNU Makefile).
 - Fixed search GCC tools for LTO (CMake scripts).
 - Fixed/reorder dirs list for search CLANG tools for LTO (CMake scripts).
 - Fixed/workarounds for CLANG < 9.x
 - Fixed CMake warning about compatibility with 3.8.2
2021-08-27 22:47:12 +03:00
Leonid Yuriev
cd73caac1c mdbx-test: remove entropy source and use fully determined PRNG. 2021-08-27 15:03:59 +03:00
Leonid Yuriev
aec884f0d1 mdbx-make: extend cross-qemu target.
Change-Id: I889e53207904a8aaec8469165ba2de7574bf417b
2021-08-26 17:56:39 +03:00
Leonid Yuriev
e3ce6d645a mdbx-make: fix/filter-out cross-qemu target arch list.
Change-Id: Ibafe6217aefcbee9f7a14fa216cf331d2e56c7ce
2021-08-26 17:56:10 +03:00
Leonid Yuriev
d2cba98f70 mdbx: always setup madvise while opening DB.
This partially revert 7da64b725d.

Hope fix https://github.com/erthink/libmdbx/issues/231
2021-08-25 14:13:07 +03:00
Leonid Yuriev
217e951e68 mdbx-make: fix getting revision number from middle of history. 2021-08-25 13:24:22 +03:00
Leonid Yuriev
99b75b5004 mdbx: fix/model minor Coverity issues. 2021-08-16 23:45:56 +03:00
Leonid Yuriev
42d545e579 mdbx: fix minor zero-length memcmp() UB. 2021-08-14 17:46:34 +03:00
Leonid Yuriev
e3300259ff mdbx: add minor enum-related workarounds for UndefinedBeheviorSanitizer. 2021-08-14 16:43:16 +03:00
Leonid Yuriev
68273acc2a mdbx: add and use MDBX_NOSANITIZE_ENUM macro. 2021-08-14 16:43:12 +03:00
Leonid Yuriev
e20664fe55 mdbx: Merge branch 'master' into devel branch. 2021-08-14 16:01:16 +03:00
Leonid Yuriev
8c761f5774 mdbx: update Ethereum address. 2021-08-14 00:19:40 +03:00
Leonid Yuriev
b6ffec12e4 "mdbx: ignore legacy P_DIRTY flag (0x10) for nested/sub-pages. 2021-08-11 15:49:46 +03:00
Leonid Yuriev
5d4d02617d mdbx-cmake: fix search GCC tools for LTO. 2021-08-05 02:26:36 +03:00
Leonid Yuriev
327b283136 mdbx-cmake: fix/reorder dirs list for search CLANG tools for LTO. 2021-08-05 02:26:36 +03:00
Leonid Yuriev
4bb0c57e29 mdbx: minor fixes/workarounds for CLANG < 9.x 2021-08-04 15:43:32 +03:00
Leonid Yuriev
a9cae5e314 mdbx-cmake: avoid CMake warning about compatibility with 3.8.2 2021-08-04 14:09:47 +03:00
Leonid Yuriev
b9ac607a5e mdbx: update patch for buildroot (old versions). 2021-08-03 00:57:22 +03:00
Leonid Yuriev
7e035115bb mdbx-doc: add ref to Haskell bindings. 2021-08-02 09:05:50 +03:00
Leonid Yuriev
099dd68630 mdbx-doc: add a note about the need for git tags.
Related to https://github.com/erthink/libmdbx/issues/227.
2021-08-01 17:58:42 +03:00
Leonid Yuriev
5d7ef50054 mdbx-ci: disable RDP by default for AppVeyor. 2021-08-01 17:41:18 +03:00
Andrea Lanfranchi
2395564c17 mdbx++: add cursor::erase() overloads for key and for key-value.
Resolves https://github.com/erthink/libmdbx/pull/226
2021-07-27 01:27:57 +03:00
Andrea Lanfranchi
5e7a685ba8 mdbx: add basic CMakeSettings.json for Visual Studio.
* move build files out of project dir
2021-07-27 01:27:57 +03:00
Andrea Lanfranchi
f7cbf41f03 mdbx: add .vscode to gitignore. 2021-07-27 01:03:48 +03:00
Leonid Yuriev
70933d81a8 mdbx: release v0.10.2
Acknowledgements:
-----------------
 - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
 - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for reporting bugs.
 - [Lionel Debroux](https://github.com/debrouxl) for fuzzing tests and reporting bugs.
 - [Sergey Fedotov](https://github.com/SergeyFromHell/) for [`node-mdbx` NodeJS bindings](https://www.npmjs.com/package/node-mdbx).
 - [Kris Zyp](https://github.com/kriszyp) for [`lmdbx-store` NodeJS bindings](https://github.com/kriszyp/lmdbx-store).
 - [Noel Kuntze](https://github.com/Thermi) for [draft Python bindings](https://github.com/erthink/libmdbx/commits/python-bindings).

New features, extensions and improvements:
------------------------------------------
 - [Allow to predefine/override `MDBX_BUILD_TIMESTAMP` for builds reproducibility](https://github.com/erthink/libmdbx/issues/201).
 - Added options support for `long-stochastic` script.
 - Avoided `MDBX_TXN_FULL` error for large transactions when possible.
 - The `MDBX_READERS_LIMIT` increased to `32767`.
 - Raise `MDBX_TOO_LARGE` under Valgrind/ASAN if being opened DB is 100 larger than RAM (to avoid hangs and OOM).
 - Minimized the size of poisoned/unpoisoned regions to avoid Valgrind/ASAN stuck.
 - Added more workarounds for QEMU for testing builds for 32-bit platforms, Alpha and Sparc architectures.
 - `mdbx_chk` now skips iteration & checking of DB' records if corresponding page-tree is corrupted (to avoid `SIGSEGV`, ASAN failures, etc).
 - Added more checks for [rare/fuzzing corruption cases](https://github.com/erthink/libmdbx/issues/217).

Backward compatibility break:
-----------------------------
 - Use file `VERSION.txt` for version information instead of `VERSION` to avoid collision with `#include <version>`.
 - Rename `slice::from/to_FOO_bytes()` to `slice::envisage_from/to_FOO_length()'.
 - Rename `MDBX_TEST_EXTRA` make's variable to `MDBX_SMOKE_EXTRA`.
 - Some details of the C++ API have been changed for subsequent freezing.

Fixes:
------
 - Fixed excess meta-pages checks in case `mdbx_chk` is called to check the DB for a specific meta page and thus could prevent switching to the selected meta page, even if the check passed without errors.
 - Fixed [recursive use of SRW-lock on Windows cause by `MDBX_NOTLS` option](https://github.com/erthink/libmdbx/issues/203).
 - Fixed [log a warning during a new DB creation](https://github.com/erthink/libmdbx/issues/205).
 - Fixed [false-negative `mdbx_cursor_eof()` result](https://github.com/erthink/libmdbx/issues/207).
 - Fixed [`make install` with non-GNU `install` utility (OSX, BSD)](https://github.com/erthink/libmdbx/issues/208).
 - Fixed [installation by `CMake` in special cases by complete use `GNUInstallDirs`'s variables](https://github.com/erthink/libmdbx/issues/209).
 - Fixed [C++ Buffer issue with `std::string` and alignment](https://github.com/erthink/libmdbx/issues/191).
 - Fixed `safe64_reset()` for platforms without atomic 64-bit compare-and-swap.
 - Fixed hang/shutdown on big-endian platforms without `__cxa_thread_atexit()`.
 - Fixed [using bad meta-pages if DB was partially/recoverable corrupted](https://github.com/erthink/libmdbx/issues/217).
 - Fixed extra `noexcept` for `buffer::&assign_reference()`.
 - Fixed `bootid` generation on Windows for case of change system' time.
 - Fixed [test framework keygen-related issue](https://github.com/erthink/libmdbx/issues/127).
2021-07-26 05:23:52 +03:00
Leonid Yuriev
a8115267a6 mdbx++: disable using C++20 concepts for CLANG < 12. 2021-07-26 05:16:29 +03:00
Leonid Yuriev
a9e99241b7 mdbx-make: fix/clean dependencies for make dist. 2021-07-26 03:53:11 +03:00
Leonid Yuriev
bca4adcdc7 mdbx-make: show compier and version by make show-options. 2021-07-26 03:53:11 +03:00
Leonid Yuriev
79281d59c7 mdbx++: workaround macro for clang bugs. 2021-07-26 03:53:11 +03:00
Leonid Yuriev
e6a83654a8 mdbx-make: add stub bench-related targets for case no ioarena. 2021-07-26 03:53:11 +03:00
Leonid Yuriev
f4f166a66d mdbx-make: avoid multiple tips about ioarena. 2021-07-26 03:53:11 +03:00
Leonid Yuriev
65fa0cf8ed mdbx++: revive encode/decode to hex/base58/base64 (squashed). 2021-07-26 03:53:11 +03:00
Leonid Yuriev
046dc02f73 mdbx: make MDBX_STRINGIFYmacro public. 2021-07-26 03:53:11 +03:00
Leonid Yuriev
c2fa453725 mdbx-test: fix keygen-related issue.
Fixes https://github.com/erthink/libmdbx/issues/127
2021-07-26 03:52:46 +03:00
Leonid Yuriev
e731260056 mdbx: fix SIGSEGV regression while copying DB with enabled audit. 2021-07-26 02:24:15 +03:00
Leonid Yuriev
9a04c9a350 mdbx: update available Bindings list. 2021-07-21 17:39:34 +03:00
Leonid Yuriev
13912be35d mdbx: update ChangeLog. 2021-07-21 13:37:42 +03:00
Leonid Yuriev
2e68adefb3 mdbx-doc: add README paragraph for testing. 2021-07-21 02:28:44 +03:00
Leonid Yuriev
bf9e6146df mdbx-make: add missing long-test to make help output. 2021-07-21 02:25:34 +03:00
Leonid Yuriev
2c190cfb56 mdbx-doc: add README paragraph for containers. 2021-07-21 02:24:24 +03:00
Leonid Yuriev
5fa2e30709 mdbx-test: add exclusive and accede options for DB operation mode. 2021-07-21 02:23:36 +03:00
Leonid Yuriev
faafa21480 mdbx-doc: refine Dixygen comments related to use custom comparators. 2021-07-21 02:23:10 +03:00
Leonid Yuriev
3f929e3766 mdbx-make: update thunk-makefile's target-list. 2021-07-21 02:22:33 +03:00
Leonid Yuriev
9a1dffc7dc mdbx: update ChangeLog. 2021-07-19 13:21:47 +03:00
Leonid Yuriev
c81ab53eb2 mdbx-test: add usage for long-stochastic scripts. 2021-07-19 12:42:57 +03:00
Leonid Yuriev
7759e52850 mdbx-windows: use MachineGuid of any size for bootid generation. 2021-07-19 12:07:45 +03:00
Leonid Yuriev
e7336e1d5e mdbx: add checks for unexpected LEAF2-pages.
The fourth case of https://github.com/erthink/libmdbx/issues/217.
2021-07-19 12:06:08 +03:00
Leonid Yuriev
68aef96f0a mdbx-tool: minor clarify mdbx_chk' logic key/data checks. 2021-07-19 12:06:08 +03:00
Leonid Yuriev
0b120b8fa9 mdbx-windows: fix bootid generation for case of change system' time. 2021-07-19 12:05:55 +03:00
Leonid Yuriev
28c36af67c mdbx: refine built-in ASAN option. 2021-07-16 16:04:09 +03:00
Leonid Yuriev
d67b9eaf17 mdbx: fix ASAN-regression after 1740043678.
Related to https://github.com/erthink/libmdbx/issues/217
2021-07-16 16:03:49 +03:00
Leonid Yuriev
6034985686 mdbx: add MDBX_ASAN_(UN)POISON_MEMORY_REGION() macros. 2021-07-16 16:03:49 +03:00
Leonid Yuriev
7da64b725d mdbx: perform madvise only for the first process opens a DB. 2021-07-16 16:03:49 +03:00
Leonid Yuriev
ba22ae9ab3 mdbx: update .gitignore 2021-07-16 16:03:49 +03:00
Leonid Yuriev
8aaf5d071b mdbx: fix pagecheck().
Added a check that the data of the BIGDATA node (containing the target page number) is located within the boundaries of the page being checked.

The third case of https://github.com/erthink/libmdbx/issues/217.
2021-07-16 15:55:18 +03:00
Leonid Yuriev
6a6ead6cfb mdbx-make: rename buildflags_tag to buildflags.tag (cosmetic). 2021-07-15 16:55:38 +03:00
Leonid Yuriev
10fefe87a6 mdbx-make: minor fix to save dist-check logs. 2021-07-15 16:53:16 +03:00
Leonid Yuriev
de3c028f0d mdbx-make: fix buildflags_tag embedding into config.h. 2021-07-14 10:30:29 +03:00
Leonid Yuriev
b6233ae2e5 mdbx-tools: minor fix/unify error counters. 2021-07-14 10:29:54 +03:00
Leonid Yuriev
fe5f008d39 mdbx-tools: skip iteration & checking records if corresponding tree is corrupted.
Hope final for https://github.com/erthink/libmdbx/issues/217
2021-07-14 03:59:56 +03:00
Leonid Yuriev
c8743cb9c4 mdbx: fix null-deref while override invalid meta-pages.
Related to https://github.com/erthink/libmdbx/issues/217
2021-07-14 03:59:52 +03:00
Leonid Yuriev
1995754bc3 mdbx-test: add workarounds for QEMU (all 32-bit, Alpha, Sparc). 2021-07-13 17:38:08 +03:00
Leonid Yuriev
f749b3deee mdbx-test: minor refine stochastic script to be able use arithmetic in the arguments. 2021-07-13 13:51:24 +03:00
Leonid Yuriev
ebfffe3f2b mdbx-make: use --db-upto-mb option to be able testing 32-bit targets under QEMU. 2021-07-13 13:49:58 +03:00
Leonid Yuriev
de4a6baf80 mdbx-test: add --db-upto-mb option for stochastic script. 2021-07-13 13:49:33 +03:00
Leonid Yuriev
584326e9b6 mdbx-make: rename MDBX_TEST_EXTRA to MDBX_SMOKE_EXTRA. 2021-07-13 13:48:56 +03:00
Leonid Yuriev
a7becdc6b3 mdbx-test: add --size-upper-upto for simplify cross-testing 32-bit code with QEMU on 64-bit host. 2021-07-13 13:48:12 +03:00
Leonid Yuriev
4de2dcebb5 mdbx: increase the MDBX_READERS_LIMIT to 32767.
Fixes https://github.com/erthink/libmdbx/issues/219.
2021-07-11 02:44:19 +03:00
Leonid Yuriev
678a80dd19 mdbx: fix hang/shutdown on big-endian platforms without __cxa_thread_atexit().
Change-Id: I1bf706abaaf42d5b40751d85ed7c7a83d02acaf5
2021-07-11 02:25:39 +03:00
Leonid Yuriev
55d1f5e9c0 mdbx++: remove extra noexcept for buffer::&assign_reference(). 2021-07-11 02:25:39 +03:00
Leonid Yuriev
c18bf4f898 mdbx: minor clarify mdbx_mapresize(). 2021-07-11 02:25:39 +03:00
Leonid Yuriev
728e7f92b2 mdbx: minor fix mdbx_mresize() to preserve result code for read-only cases. 2021-07-11 02:25:39 +03:00
Leonid Yuriev
1740043678 mdbx: minimize the size of poisoned/unpoisoned regions to avoid ASAN hangs.
More for second case of https://github.com/erthink/libmdbx/issues/217
2021-07-11 02:25:26 +03:00
Leonid Yuriev
891d68838a mdbx: return MDBX_TOO_LARGE under Valgrind/ASAN if being opened DB is 100 larger than RAM.
More for second case of https://github.com/erthink/libmdbx/issues/217
2021-07-11 02:25:07 +03:00
Leonid Yuriev
108398c213 mdbx: refine rollback while opening weak/invalid DB.
More for https://github.com/erthink/libmdbx/issues/217
2021-07-11 02:24:51 +03:00
Leonid Yuriev
8bdee27248 mdbx: create/refactoring override_meta(). 2021-07-11 02:24:51 +03:00
Leonid Yuriev
00c6dc9788 mdbx: re-verify head and steady meta-pages while opening db by the first process.
Basic fix for https://github.com/erthink/libmdbx/issues/217
2021-07-11 02:24:06 +03:00
Leonid Yuriev
fb67682a79 mdbx: refine mdbx_validate_meta(). 2021-07-10 17:24:26 +03:00
Leonid Yuriev
5ed50a4739 mdbx: remove filesize arg from header/meta read functions (refactoring). 2021-07-10 16:10:30 +03:00
Leonid Yuriev
c30c3def8b mdbx: the filesize field of mdbx_mmap_t now is not specific for Windows. 2021-07-10 16:10:30 +03:00
Леонид Юрьев (Leonid Yuriev)
2f74f405ae mdbx: avoid returning MDBX_TXN_FULL error when possible. 2021-07-09 18:29:31 +03:00
Леонид Юрьев (Leonid Yuriev)
c7e05f63e6 mdbx-test: remove vector[...] from Valgrind's suppressions. 2021-07-09 17:44:27 +03:00
Leonid Yuriev
d65305564f mdbx-test: more suppressions for Valrgind (for case db-page less than systen-page). 2021-07-09 17:44:27 +03:00
Leonid Yuriev
660c302525 mdbx-test: adapt long-stochastic script for old bash version (Mac OS). 2021-07-09 17:44:27 +03:00
Leonid Yuriev
d7aad3a7cf mdbx-make: distinct smoke* and test* targets. 2021-07-09 17:44:27 +03:00
Leonid Yuriev
15ed0f6a84 mdbx++: workaround for compile-time 'uninitialized' warning (i.e. a GCC's bug) from GCC 10.x with enabled UB-sanitizer. 2021-07-09 17:44:27 +03:00
Leonid Yuriev
ffb8d23632 mdbx++: minor fixes for UN-sanitizer. 2021-07-09 17:44:27 +03:00
Leonid Yuriev
682632756f mdbx-test: add options support for long-stochastic script. 2021-07-09 17:44:27 +03:00
Leonid Yuriev
39c5e66ed1 mdbx: fix safe64_reset() for platforms without atomic 64-bit compare-and-swap. 2021-07-09 17:44:27 +03:00
Leonid Yuriev
b66780633e mdbx-tools: linking with math library (-lm). 2021-07-06 13:45:26 +03:00
Leonid Yuriev
bd2bb51f0f mdbx++: rework buffer::silo to avoid use std::string. 2021-07-06 13:45:26 +03:00
Леонид Юрьев (Leonid Yuriev)
ac69464143 mdbx-make: change prefix of the 'TIP' messages (cosmetics). 2021-07-04 13:23:53 +03:00
Leonid Yuriev
62889b5b7f mdbx-test: use mdbx::buffer from mdbx++. 2021-07-04 13:23:53 +03:00
Leonid Yuriev
c4a696be1d mdbx-test: add workaround for CLANG/LLVM STL stupidity of std::set<>. 2021-07-04 00:11:04 +03:00
Leonid Yuriev
cf5f31c577 mdbx: make __cold attribute first (cosmetic). 2021-07-03 01:51:04 +03:00
Leonid Yuriev
fa49e5a57b mdbx++: rename slice::from/to_FOO_bytes() to `slice::envisage_from/to_FOO_length()'. 2021-07-02 21:20:04 +03:00
Leonid Yuriev
750a17e41e mdbx: more spelling. 2021-07-02 21:19:58 +03:00
Leonid Yuriev
5d4281fbbe mdbx: minor fix spelling. 2021-06-26 18:54:00 +03:00
Leonid Yuriev
2c18225654 mdbx-make: minor cleanup shell in/out redirection spaces. 2021-06-26 17:38:52 +03:00
Leonid Yuriev
cc6610f42c mdbx: more/refine C++ crutches for mad MSVC compiler. 2021-06-24 15:42:03 +03:00
Leonid Yuriev
77a1f32e2a mdbx: use VERSION.txt instead of VERSION to avoid collision with #include <version>. 2021-06-24 14:59:29 +03:00
Leonid Yuriev
63e7276c7d mdbx: update ChangeLog. 2021-06-18 15:13:51 +03:00
Leonid Yuriev
a5e10b4ea1 mdbx: minor refine mdbx_cursor_eof(). 2021-06-18 01:17:48 +03:00
Leonid Yuriev
b8e621cb2f mdbx: mdbx: avoid log a warning about empty header during DB creation.
Resolve https://github.com/erthink/libmdbx/issues/205.
2021-06-18 01:09:26 +03:00
Leonid Yuriev
68a164da2b mdbx-test: add mdbx_cursor_eof() checking.
Related to https://github.com/erthink/libmdbx/issues/207.
2021-06-17 21:44:48 +03:00
Leonid Yuriev
5db855d728 mdbx: fix false-negative mdbx_cursor_eof() result.
Fixes https://github.com/erthink/libmdbx/issues/207.
2021-06-17 21:44:24 +03:00
Leonid Yuriev
06aa596519 mdbx-test: fix minor warnings from old GCC versions. 2021-06-17 21:43:15 +03:00
Leonid Yuriev
d47864dedf mdbx-cmake: use GNUInstallDirs variables for all cases.
Resolves https://github.com/erthink/libmdbx/issues/209.
2021-06-17 17:21:20 +03:00
Leonid Yuriev
581ca4fdf4 mdbx-ci: performs make's install target during check.
Related to https://github.com/erthink/libmdbx/issues/208.
2021-06-17 15:15:57 +03:00
Leonid Yuriev
6771b7526c mdbx-make: use only portable option of install utility.
Fixes https://github.com/erthink/libmdbx/issues/208.
2021-06-17 15:15:54 +03:00
Leonid Yuriev
d7c06b1337 mdbx: partial fix for recursive SRW-lock with MDBX_NOTLS on Windows.
Here are some changes to avoid recursive acquisition of SRW-lock,
which is still in use:
 - Read transactions don't acquire the shared SRW-lock with `MDBX_NOTLS.
 - Memory-mapping of DB is always kept while DB opened,
   therefore following limitations are:
 - DB file can't be shrinked while it used,
   including auto-shrink due to auto-compactification with corresponding geometry settings.
 - The upper limit of DB size can't be changed while DB is used.
 - The DB can grow within the upper size limit defined while opening by a first process,
   but this does not work under Wine since there is no `NtExtendSection()` function.

Partially fix https://github.com/erthink/libmdbx/issues/203
2021-06-10 13:42:30 +03:00
Leonid Yuriev
18bc28bea2 mdbx: announce more TODO. 2021-06-10 02:47:40 +03:00
Leonid Yuriev
93e6e64eb0 mdbx: update ChangeLog. 2021-06-09 13:48:03 +03:00
Leonid Yuriev
0cd1eac6a8 mdbx: don't check other meta pages if one is specified for verification/recovery.
Fixes https://github.com/erthink/libmdbx/issues/202
2021-06-08 20:27:18 +03:00
Leonid Yuriev
0e83a8e5ef mdbx-doc: add note for Reproducible builds.
More for https://github.com/erthink/libmdbx/issues/201
2021-06-02 17:08:40 +03:00
Leonid Yuriev
f951f246b8 mdbx: allow to predefine/override MDBX_BUILD_TIMESTAMP for builds reproducibility.
Resolve https://github.com/erthink/libmdbx/issues/201
2021-06-02 14:50:22 +03:00
Leonid Yuriev
50328de63c mdbx: release v0.10.1
Acknowledgements:
-----------------
 - [Alexey Akhunov](https://github.com/AlexeyAkhunov) and [Alex Sharov](https://github.com/AskAlexSharov) for bug reporting and testing.

New features:
-------------
 - Added `-p` option to `mdbx_stat` utility for printing page operations statistic.
 - Added explicit checking for and warning about using unfit github's archives.

Fixes:
------
 - Fixed minor "foo not used" warnings from modern C++ compilers when building the C++ part of the library.
 - Fixed confusing/messy errors when build library from unfit github's archives (https://github.com/erthink/libmdbx/issues/197).
 - Fixed `#​e​l​s​i​f` typo.
 - Fixed rare unexpected `MDBX_PROBLEM` error during altering data in huge transactions due to wrong spilling/oust of dirty pages (https://github.com/erthink/libmdbx/issues/195).
2021-06-01 03:21:59 +03:00
Leonid Yuriev
a6c8c20bd9 mdbx: update ChangeLog. 2021-05-28 01:46:24 +03:00
Leonid Yuriev
ea1fcc2246 mdbx: fix insignificantly Coverity warnings. 2021-05-28 00:54:11 +03:00
Leonid Yuriev
8915db5f83 mdbx-tools: cleanup MDBX_NOSUBDIR (needless). 2021-05-28 00:36:24 +03:00
Leonid Yuriev
a7167ce715 mdbx: allow open DB on 9P/WSL2 filesystem in exclusive mode.
Related to https://github.com/erthink/libmdbx/issues/97
2021-05-26 21:08:37 +03:00
Leonid Yuriev
3e0c7758ef mdbx: fallback to non-OFD locks after EINVAL.
Related to https://github.com/erthink/libmdbx/issues/97
2021-05-26 20:33:55 +03:00
Leonid Yuriev
b0830db25a mdbx: add 9P (WSL2 DrvFs) to blacklist of remote filesystems.
Related to https://github.com/erthink/libmdbx/issues/97
2021-05-26 20:33:08 +03:00
Leonid Yuriev
bcc546bdfa mdbx-windows: refix WSL1/WSL2 detection.
Refix https://github.com/erthink/libmdbx/issues/97
2021-05-25 15:18:15 +03:00
Leonid Yuriev
2b161db6d8 mdbx: update ChangeLog. 2021-05-21 00:12:55 +03:00
Leonid Yuriev
6bedb02ac0 mdbx: fix lru-counter overflow by module 2^31.
2 of 2 fixes for https://github.com/erthink/libmdbx/issues/195
2021-05-20 17:42:22 +03:00
Leonid Yuriev
bc6a690733 mdbx: simplify & fix mdbx_txn_keep() and mdbx_cursor_keep().
1 of 2 fixes for https://github.com/erthink/libmdbx/issues/195
2021-05-20 15:10:38 +03:00
Leonid Yuriev
84b699a47c mdbx: fix elsif typo. 2021-05-18 22:44:31 +03:00
Leonid Yuriev
7addfc8358 mdbx: explicit checking for and warning about using unfit github's archives.
Related to https://github.com/erthink/libmdbx/issues/197 and https://github.community/t/disable-tarball
2021-05-13 12:19:18 +03:00
Leonid Yuriev
841fc15dd3 mdbx: little more likely/unlikely. 2021-05-12 19:24:19 +03:00
Leonid Yuriev
0875d16656 mdbx: fix/refine mdbx_env_info_ex() to distinguish a not-available and overflow cases for returned timestamps. 2021-05-12 17:51:31 +03:00
Leonid Yuriev
9c7c709b3e mdbx: avoid underflow during monotime/16dot16 conversion. 2021-05-12 17:44:18 +03:00
Leonid Yuriev
c5268f1da7 mdbx-tools: add support of page operations stat to mdbx_stat. 2021-05-12 14:41:09 +03:00
Leonid Yuriev
16d686bc42 mdbx: account msync/fsync write in page operations. 2021-05-12 14:40:58 +03:00
Leonid Yuriev
137f80e177 mdbx: refile rollback-writes inside mdbx_setup_dxb(). 2021-05-12 14:40:58 +03:00
Leonid Yuriev
7d8099fc77 mdbx: refine mdbx_wipe_steady(). 2021-05-12 14:40:58 +03:00
Leonid Yuriev
5731ad11c8 mdbx: don't use bool flags for mdbx_msync(). 2021-05-12 14:40:58 +03:00
Leonid Yuriev
23e11e3a57 mdbx: refine/fix MDBX_MAYBE_UNUSED for modern GCC 11.x and C20. 2021-05-12 14:40:58 +03:00
Leonid Yuriev
76b9cb5dcc mdbx-tools: minor refine built-in usage/help. 2021-05-12 11:33:25 +03:00
Leonid Yuriev
9746dd20df mdbx-tools: refine/fix quiet mode. 2021-05-12 11:33:25 +03:00
Leonid Yuriev
dc9869f1a1 mdbx-ci: minor fix 'mingw' workflow (prev commit). 2021-05-11 21:25:16 +03:00
Leonid Yuriev
1d9f495c46 mdbx-ci: build both dll and static library by MinGW for testing.
Related to https://github.com/erthink/libmdbx/issues/196
2021-05-11 21:25:16 +03:00
Leonid Yuriev
ebab75642e mdbx: add public MDBX_MAYBE_UNUSED.
This also should fix C++ mdbx API build by MSVC 2015.
2021-05-11 21:07:40 +03:00
Leonid Yuriev
ed58ff9f81 mdbx++: add [[maybe_unused]] to internal functions which depends on platform and compiler features. 2021-05-11 16:53:47 +03:00
Leonid Yuriev
605326b6e8 mdbx-cmake: don't specify filename extension while linking with ntdll. 2021-05-11 08:07:42 +03:00
Leonid Yuriev
2071958f35 mdbx: remove extra notice/debug logging. 2021-05-11 00:24:01 +03:00
Leonid Yuriev
4fee14d1cf mdbx: logging all reasons of MDBX_PROBLEM.
Related to https://github.com/erthink/libmdbx/issues/195
2021-05-10 16:15:58 +03:00
Leonid Yuriev
244fab6c04 mdbx: fix extra conversion of an error during nested dupsort-DB update to MDBX_PROBLEM.
Hope this fixes https://github.com/erthink/libmdbx/issues/195
2021-05-10 16:15:03 +03:00
Leonid Yuriev
74ea79ac1b mdbx: minor reorder/shrink transaction fields. 2021-05-10 16:05:19 +03:00
Leonid Yuriev
0d100a898f mdbx: minor more const. 2021-05-10 15:53:07 +03:00
Leonid Yuriev
0a28b28da3 mdbx-doc: actualize key size limits. 2021-05-09 23:29:55 +03:00
59 changed files with 5432 additions and 2946 deletions

View File

@@ -11,8 +11,7 @@ jobs:
- TESTLOG: /tmp/test.log
steps:
- checkout
- run: make all
- run: ulimit -c unlimited && make check
- run: ulimit -c unlimited && MDBX_BUILD_OPTIONS="-DNDEBUG=1 -DMDBX_FORCE_ASSERTIONS=1" make test-ubsan
- run:
command: |
mkdir -p /tmp/artifacts

View File

@@ -3,4 +3,4 @@ freebsd_instance:
task:
install_script: pkg install -y gmake bash git
script: git fetch --tags --force && gmake check
script: git fetch --tags --force && gmake MDBX_BUILD_OPTIONS="-DNDEBUG=1 -DMDBX_FORCE_ASSERTIONS=1" check

2
.github/FUNDING.yml vendored
View File

@@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://sobe.ru/na/libmdbx', 'https://paypal.me/erthink', 'https://etherscan.io/address/0xe8a741a2a0a4850c5bdbb415aaaaf8fb46f06fb7']
custom: ['https://sobe.ru/na/libmdbx', 'https://paypal.me/erthink', 'https://www.blockchain.com/en/eth/address/0x19291d8658f762f3baceae1700c0b9466572ceab', 'https://www.blockchain.com/en/btc/address/152u2KXNWWGHQS3qiBEoQaveWyPvaSWYGC']

View File

@@ -8,3 +8,4 @@
^\.gitignore$
^\.travis\.yml$
^packages/buildroot/
^CMakeSettings\.json$

View File

@@ -9,6 +9,7 @@ acision
AClass
adata
addprefix
addressof
addsuffix
addtogroup
advapi
@@ -22,6 +23,7 @@ alevel
alexey
Alfke
alignas
alignof
alldbs
ALLDUPS
ALLEXTERNALS
@@ -59,12 +61,14 @@ ARMEL
ARMT
Artem
asan
Ashikhmin
asis
asm
asprintf
aspx
assection
AstraLinux
astralinux
atal
atexit
atfork
@@ -96,6 +100,7 @@ bfin
biarch
bibtex
BIGDATA
bigdata
bindir
binfmt
binutils
@@ -103,6 +108,7 @@ bitfield
bitmaps
bitmask
bitness
bitops
blogger
blogs
blogspot
@@ -126,6 +132,7 @@ buflen
bufsize
BUGLIST
bugzilla
buildflags
buildpack
buildroot
builtins
@@ -170,6 +177,7 @@ cifs
cinttypes
circleci
claude
climits
clockid
CLOEXEC
closefile
@@ -283,6 +291,8 @@ ddl
deadread
deadwrite
debian
Debroux
debrouxl
debruijn
DECC
declspec
@@ -350,6 +360,8 @@ dprefix
DPs
dqiqg
dreamsxin
drv
drvfs
dsize
dso
dst
@@ -401,7 +413,6 @@ ELBRUSC
ELBRUSCXX
elif
elseif
elsif
emoji
emscripten
EMULTIVAL
@@ -470,6 +481,7 @@ exactkey
exactp
excpt
exe
executables
exename
exherbo
exitcode
@@ -488,6 +500,7 @@ FCXX
fd
fdatasync
featuredarticles
fedotov
FEEDNAME
feof
ferror
@@ -510,6 +523,7 @@ Firefox
firstvalue
fixedpoint
FIXME
fjvallarino
flagbit
flg
flipcoin
@@ -588,6 +602,7 @@ github
githubusercontent
gitignore
glibc
GLIBCXX
globals
gmail
gmake
@@ -607,9 +622,11 @@ grep
gtags
gz
gzip
hackage
HAGL
hallvard
hardcoded
haskell
HASSEMAPHORE
hdiutil
hdr
@@ -680,6 +697,7 @@ img
impl
IMPLIB
inblock
INCLUDEDIR
indx
INDXSIZE
ini
@@ -694,6 +712,7 @@ inprocess
INSTEADOF
integerdup
integerkey
interoperability
interprocedural
intlimits
intptr
@@ -774,6 +793,7 @@ klen
KMGTPEZY
knipp
kp
kriszyp
ks
ksize
kstat
@@ -781,8 +801,10 @@ Kuntze
kurt
kuznik
kval
Lanfranchi
largedata
largepage
lastbyte
lastest
lastvalue
lastword
@@ -828,6 +850,7 @@ LLV
llvm
lmb
lmdb
lmdbx
LMEM
LNK
lnps
@@ -873,6 +896,7 @@ MACROFILE
MADV
madvise
mahlonsmith
mailto
maindb
mainpage
maj
@@ -958,6 +982,8 @@ microsoft
Mikkelson
minflt
MINGW
mingw
minimalistic
minkeys
minlen
MINSIZEREL
@@ -1095,6 +1121,7 @@ nordahead
NOREPLACE
NORESERVE
noreturn
NOSANITIZE
nospill
nosubdir
nosync
@@ -1105,8 +1132,10 @@ notls
notracking
NOWAIT
npages
npmjs
npos
npr
nproc
nptl
nreaders
nrepeat
@@ -1252,6 +1281,7 @@ pmax
pmccntr
pmcntenset
pmedvedev
pmeta
pmr
pmuseren
pmwkaa
@@ -1270,7 +1300,6 @@ ppc
pragma
pread
prealloc
prealloc'd
PREDEF
prefetch
Prefetcher
@@ -1284,7 +1313,7 @@ PRIa
PRId
PRIi
printf
Prioritization
prioritization
PRIu
prng
prno
@@ -1292,6 +1321,7 @@ proba
proces
procfs
progname
programdata
PROGRAMLISTING
projectbrief
projectlogo
@@ -1320,6 +1350,7 @@ putflags
pv
pvalue
PVOID
pwd
PWIM
PWIN
PWOF
@@ -1379,11 +1410,13 @@ REALMEM
REALPATH
realtime
Rebuffo
rebuffo
RECO
redis
reedom
reefont
refname
refreshenv
REGEX
regexp
reinited
@@ -1464,6 +1497,7 @@ semop
sems
sendfile
sepkey
sergey
SETALL
SETFD
setlen
@@ -1646,6 +1680,7 @@ svg
svnweb
svr
swait
swappable
symas
SYMLINKS
syncbytes
@@ -1714,6 +1749,7 @@ toolset
tooltip
torquem
TOUPPER
transcoder
transcoding
treeview
tribudubois
@@ -1769,6 +1805,7 @@ underfilled
UNDOC
unicode
UNIFORUM
uninit
uninstall
UNINSTALLING
uniq
@@ -1787,6 +1824,7 @@ updation
upsert
UPSERTING
upsertion
upto
URG
url
usec
@@ -1812,6 +1850,7 @@ Vaefnrs
valbool
valgrind
validator
Vallarino
valnum
valsize
valstr
@@ -1863,6 +1902,7 @@ webclient
WERROR
WEXITSTATUS
WEXTRA
whitelist
wholetable
WIFCONTINUED
WIFEXITED
@@ -1932,6 +1972,7 @@ xsize
yml
Yota
Yotta
yperbasis
Yq
yuriev
Zano
@@ -1945,3 +1986,4 @@ zi
ZLIB
zu
zx
Zyp

View File

@@ -3,8 +3,7 @@ name: MinGW
on:
pull_request:
push:
branches-ignore:
- coverity_scan
branches: mingw
paths-ignore:
- '.circleci/**'
- '.github/actions/spelling/**'
@@ -23,25 +22,44 @@ on:
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest]
runs-on: [windows-latest]
steps:
- uses: actions/checkout@v2
- name: fetch tags
run: git fetch --unshallow --tags --prune --force
- name: configure
run: cmake -G "MinGW Makefiles" .
- name: build
run: cmake --build .
# - name: test
# shell: pwsh
# run: |
# & mdbx_test.exe --progress --console=no --pathname=test.db --dont-cleanup-after basic > test.log
# Get-Content test.log | Select-Object -last 42
# if ($LastExitCode -ne 0) {
# throw "Exec: $ErrorMessage"
# } else {
# & mdbx_chk.exe -nvv test.db | Tee-Object -file chk.log | Select-Object -last 42
# }
- name: append PATH
run: echo 'C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/bin' >> $GITHUB_PATH
- name: update mingw64
# wanna version >= 10.2
run: choco upgrade mingw -y --no-progress && refreshenv
- name: configure-dll
shell: bash
run: |
mkdir build-dll && cd build-dll && \
cmake -G "MinGW Makefiles" -DMDBX_BUILD_SHARED_LIBRARY:BOOL=ON -DMDBX_INSTALL_STATIC:BOOL=OFF -DMDBX_ENABLE_TESTS:BOOL=ON ..
- name: build-dll
shell: bash
run: cd build-dll && cmake --build .
- name: test-dll
shell: bash
run: |
export "PATH=/c/programdata/chocolatey/lib/mingw/tools/install/mingw64/bin:$PATH" && \
cd build-dll && \
./mdbx_test.exe --progress --console=no --pathname=test.db --dont-cleanup-after basic && \
./mdbx_chk.exe -nvv test.db
- name: configure-static
shell: bash
run: |
mkdir build-static && cd build-static && \
cmake -G "MinGW Makefiles" -DMDBX_BUILD_SHARED_LIBRARY:BOOL=OFF -DMDBX_INSTALL_STATIC:BOOL=ON -DMDBX_ENABLE_TESTS:BOOL=ON ..
- name: build-static
shell: bash
run: |
cd build-static && cmake --build .
- name: test-static
shell: bash
run: |
export "PATH=/c/programdata/chocolatey/lib/mingw/tools/install/mingw64/bin:$PATH" && \
cd build-static && \
./mdbx_test.exe --progress --console=no --pathname=test.db --dont-cleanup-after basic && \
./mdbx_chk.exe -nvv test.db

View File

@@ -27,11 +27,11 @@ jobs:
strategy:
matrix:
#, windows-latest
os: [ubuntu-latest, macos-latest, ubuntu-16.04]
os: [ubuntu-latest, macos-latest, ubuntu-18.04]
steps:
- uses: actions/checkout@v2
- name: fetch tags
run: git fetch --unshallow --tags --prune --force
- name: make check
run: make --keep-going all && MALLOC_CHECK_=7 MALLOC_PERTURB_=42 make --keep-going check
run: make MDBX_BUILD_OPTIONS="-DNDEBUG=1 -DMDBX_FORCE_ASSERTIONS=1" --keep-going all && MALLOC_CHECK_=7 MALLOC_PERTURB_=42 make MDBX_BUILD_OPTIONS="-DNDEBUG=1 -DMDBX_FORCE_ASSERTIONS=1" --keep-going check
shell: bash

View File

@@ -24,8 +24,8 @@ jobs:
run: |
echo "::set-output name=tarball::$(ls *.tar.gz)"
echo "::set-output name=zip::$(ls *.zip)"
echo "::set-output name=suffix_unix::$(sed 's|^\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\.\(.*\)$|\1|' dist/VERSION)"
echo "::set-output name=suffix_dos::$(sed 's|^\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\.\(.*\)$|\1|' dist/VERSION | tr . _)"
echo "::set-output name=suffix_unix::$(sed 's|^\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\.\(.*\)$|\1|' dist/VERSION.txt)"
echo "::set-output name=suffix_dos::$(sed 's|^\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\.\(.*\)$|\1|' dist/VERSION.txt | tr . _)"
- name: Create Release
id: create_release
uses: actions/create-release@v1

5
.gitignore vendored
View File

@@ -15,11 +15,13 @@
.idea
.le.ini
.vs/
.vscode/
cmake-build-*
@*
core
mdbx_example
libmdbx.creator.user
CMakeLists.txt.user
mdbx_chk
mdbx_copy
mdbx_drop
@@ -36,6 +38,9 @@ valgrind.*
src/version.c
src/config.h
dist/
dist-check/
dist-checked.tag
*.tar*
docs/Doxyfile
docs/html/
buildflags.tag

View File

@@ -2,6 +2,7 @@ Contributors
============
- Alexey Naumov <alexey.naumov@gmail.com>
- Andrew Ashikhmin <andrey.ashikhmin@gmail.com>
- Chris Mikkelson <cmikk@qwest.net>
- Claude Brisson <claude.brisson@gmail.com>
- David Barbour <dmbarbour@gmail.com>
@@ -16,7 +17,7 @@ Contributors
- John Hewson <john@jahewson.com>
- Klaus Malorny <klaus.malorny@knipp.de>
- Kurt Zeilenga <kurt.zeilenga@isode.com>
- Leonid Yuriev <leo@yuriev.ru>, <lyuryev@ptsecurity.com>
- Leonid Yuriev <leo@yuriev.ru>, <lyuryev@ptsecurity.ru>
- Lorenz Bauer <lmb@cloudflare.com>
- Luke Yeager <lyeager@nvidia.com>
- Martin Hedenfalk <martin@bzero.se>

View File

@@ -34,10 +34,14 @@
## The Future will (be) Positive. Всё будет хорошо.
##
cmake_minimum_required(VERSION 3.8.2)
if(CMAKE_VERSION VERSION_LESS 3.12)
cmake_minimum_required(VERSION 3.8.2)
else()
cmake_minimum_required(VERSION 3.12)
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 3.8.2)
cmake_policy(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
if(NOT CMAKE_VERSION VERSION_LESS 3.15)
cmake_policy(SET CMP0091 NEW)
endif()
@@ -70,7 +74,7 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND
message(SEND_ERROR "Git command-line tool not found")
endif()
set(MDBX_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" AND
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION.txt" AND
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mdbx.c" AND
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mdbx.c++" AND
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" AND
@@ -79,10 +83,20 @@ elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" AND
set(MDBX_AMALGAMATED_SOURCE TRUE)
set(MDBX_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
else()
message(FATAL_ERROR "Please use libmdbx as a git-submodule or the amalgamated source code")
message(FATAL_ERROR "\n"
"Please don't use tarballs nor zips which are automatically provided by Github! "
"These archives do not contain version information and thus are unfit to build libmdbx. "
"You can vote for ability of disabling auto-creation such unsuitable archives at https://github.community/t/disable-tarball\n"
"Instead of above, just clone the git repository, either download a tarball or zip with the properly amalgamated source core. "
"For embedding libmdbx use a git-submodule or the amalgamated source code.\n"
"Please, avoid using any other techniques.")
endif()
if(DEFINED PROJECT_NAME)
option(MDBX_FORCE_BUILD_AS_MAIN_PROJECT "Force libmdbx to full control build options even it added as a subdirectory to your project." OFF)
endif()
if(DEFINED PROJECT_NAME AND NOT MDBX_FORCE_BUILD_AS_MAIN_PROJECT)
set(SUBPROJECT ON)
set(NOT_SUBPROJECT OFF)
if(NOT MDBX_AMALGAMATED_SOURCE AND NOT DEFINED BUILD_TESTING)
@@ -222,8 +236,13 @@ else()
endif()
if(CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE
OR GCC_LTO_AVAILABLE OR MSVC_LTO_AVAILABLE OR CLANG_LTO_AVAILABLE)
OR GCC_LTO_AVAILABLE OR MSVC_LTO_AVAILABLE OR
(CLANG_LTO_AVAILABLE AND
((DEFINED MDBX_ENABLE_TESTS AND NOT MDBX_ENABLE_TESTS)
OR NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)))
option(INTERPROCEDURAL_OPTIMIZATION "Enable interprocedural/LTO optimization" ${INTERPROCEDURAL_OPTIMIZATION_DEFAULT})
else()
set(INTERPROCEDURAL_OPTIMIZATION OFF)
endif()
if(INTERPROCEDURAL_OPTIMIZATION)
@@ -279,11 +298,11 @@ else()
if(UNIX)
find_program(CLANG_FORMAT
NAMES clang-format-12 clang-format-11 clang-format-10 clang-format)
NAMES clang-format-13 clang-format)
if(CLANG_FORMAT)
execute_process(COMMAND ${CLANG_FORMAT} "--version" OUTPUT_VARIABLE clang_format_version_info)
string(REGEX MATCH "version ([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" clang_format_version_info CLANG_FORMAT_VERSION)
if(clang_format_version_info AND NOT CLANG_FORMAT_VERSION VERSION_LESS 10.0)
if(clang_format_version_info AND NOT CLANG_FORMAT_VERSION VERSION_LESS 13.0)
# Enable 'make reformat' target.
add_custom_target(reformat
VERBATIM
@@ -319,12 +338,21 @@ list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 HAS_CXX11)
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_14 HAS_CXX14)
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_17 HAS_CXX17)
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_20 HAS_CXX20)
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_23 HAS_CXX23)
if(NOT DEFINED MDBX_CXX_STANDARD)
if(DEFINED ENV{CMAKE_CXX_STANDARD})
set(CMAKE_CXX_STANDARD $ENV{CMAKE_CXX_STANDARD})
endif()
if(DEFINED CMAKE_CXX_STANDARD)
set(MDBX_CXX_STANDARD ${CMAKE_CXX_STANDARD})
elseif(NOT HAS_CXX20 LESS 0)
elseif(NOT HAS_CXX23 LESS 0
AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12))
set(MDBX_CXX_STANDARD 23)
elseif(NOT HAS_CXX20 LESS 0
AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9))
set(MDBX_CXX_STANDARD 20)
elseif(NOT HAS_CXX17 LESS 0)
elseif(NOT HAS_CXX17 LESS 0
AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5))
set(MDBX_CXX_STANDARD 17)
elseif(NOT HAS_CXX14 LESS 0)
set(MDBX_CXX_STANDARD 14)
@@ -477,7 +505,7 @@ if(CMAKE_CXX_COMPILER_LOADED AND MDBX_CXX_STANDARD GREATER_EQUAL 11 AND MDBX_CXX
endif()
if(NOT MDBX_WITHOUT_MSVC_CRT
AND NOT (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4)
AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.9)
AND NOT (MSVC AND MSVC_VERSION LESS 1900))
option(MDBX_BUILD_CXX "Build C++ portion" ON)
else()
@@ -533,6 +561,13 @@ else()
message(STATUS "Use C${MDBX_C_STANDARD} for libmdbx but C++ portion is disabled")
endif()
if(SUBPROJECT AND MSVC)
if(MSVC_VERSION LESS 1900)
message(FATAL_ERROR "At least \"Microsoft C/C++ Compiler\" version 19.0.24234.1 (Visual Studio 2015 Update 3) is required.")
endif()
add_compile_options("/utf-8")
endif()
macro(target_setup_options TARGET)
if(DEFINED INTERPROCEDURAL_OPTIMIZATION)
set_target_properties(${TARGET} PROPERTIES
@@ -543,22 +578,26 @@ macro(target_setup_options TARGET)
if(MDBX_BUILD_CXX)
set_target_properties(${TARGET} PROPERTIES
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
if(MSVC AND NOT MSVC_VERSION LESS 1910)
target_compile_options(${TARGET} INTERFACE "/Zc:__cplusplus")
endif()
endif()
if(CC_HAS_FASTMATH)
if(CC_HAS_FASTMATH
AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10))
target_compile_options(${TARGET} PRIVATE "-ffast-math")
endif()
if(CC_HAS_VISIBILITY)
target_compile_options(${TARGET} PRIVATE "-fvisibility=hidden")
endif()
if(BUILD_FOR_NATIVE_CPU AND CC_HAS_ARCH_NATIVE)
target_compile_options(${TARGET} PUBLIC "-march=native")
target_compile_options(${TARGET} PRIVATE "-march=native")
endif()
endmacro()
macro(libmdbx_setup_libs TARGET MODE)
target_link_libraries(${TARGET} ${MODE} Threads::Threads)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
target_link_libraries(${TARGET} ${MODE} ntdll.lib)
target_link_libraries(${TARGET} ${MODE} ntdll)
if(MDBX_NTDLL_EXTRA_IMPLIB AND MDBX_WITHOUT_MSVC_CRT)
target_link_libraries(${TARGET} ${MODE} ntdll_extra)
endif()
@@ -567,7 +606,7 @@ macro(libmdbx_setup_libs TARGET MODE)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
target_link_libraries(${TARGET} ${MODE} log)
endif()
if(LIBCXX_FILESYSTEM AND MDBX_BUILD_CXX)
if(MDBX_CXX_STANDARD GREATER_EQUAL 17 AND LIBCXX_FILESYSTEM AND MDBX_BUILD_CXX)
target_link_libraries(${TARGET} ${MODE} ${LIBCXX_FILESYSTEM})
endif()
endmacro()
@@ -664,34 +703,34 @@ endif()
# mdbx-shared-lib installation
if(NOT DEFINED MDBX_DLL_INSTALL_DESTINATION)
if(WIN32)
set(MDBX_DLL_INSTALL_DESTINATION bin)
set(MDBX_DLL_INSTALL_DESTINATION ${CMAKE_INSTALL_BINDIR})
else()
set(MDBX_DLL_INSTALL_DESTINATION lib)
set(MDBX_DLL_INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
endif()
if(MDBX_BUILD_SHARED_LIBRARY)
if(CMAKE_VERSION VERSION_LESS 3.12)
install(TARGETS mdbx EXPORT libmdbx
LIBRARY DESTINATION ${MDBX_DLL_INSTALL_DESTINATION} COMPONENT runtime
OBJECTS DESTINATION lib COMPONENT devel
ARCHIVE DESTINATION lib COMPONENT devel
PUBLIC_HEADER DESTINATION include COMPONENT devel
INCLUDES DESTINATION include COMPONENT devel)
OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel)
else()
install(TARGETS mdbx EXPORT libmdbx
LIBRARY DESTINATION ${MDBX_DLL_INSTALL_DESTINATION} COMPONENT runtime
NAMELINK_COMPONENT devel
OBJECTS DESTINATION lib COMPONENT devel
ARCHIVE DESTINATION lib COMPONENT devel
PUBLIC_HEADER DESTINATION include COMPONENT devel
INCLUDES DESTINATION include COMPONENT devel)
OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel)
endif()
endif(MDBX_BUILD_SHARED_LIBRARY)
# mdbx-tools installation
if(MDBX_BUILD_TOOLS)
if(NOT DEFINED MDBX_TOOLS_INSTALL_DESTINATION)
set(MDBX_TOOLS_INSTALL_DESTINATION bin)
set(MDBX_TOOLS_INSTALL_DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
install(
TARGETS
@@ -706,7 +745,7 @@ if(MDBX_BUILD_TOOLS)
COMPONENT runtime)
if(MDBX_INSTALL_MANPAGES)
if(NOT DEFINED MDBX_MAN_INSTALL_DESTINATION)
set(MDBX_MAN_INSTALL_DESTINATION man/man1)
set(MDBX_MAN_INSTALL_DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
endif()
install(
FILES
@@ -725,26 +764,28 @@ endif(MDBX_BUILD_TOOLS)
if(MDBX_INSTALL_STATIC)
if(CMAKE_VERSION VERSION_LESS 3.12)
install(TARGETS mdbx-static EXPORT libmdbx
LIBRARY DESTINATION lib COMPONENT devel
OBJECTS DESTINATION lib COMPONENT devel
ARCHIVE DESTINATION lib COMPONENT devel
PUBLIC_HEADER DESTINATION include COMPONENT devel
INCLUDES DESTINATION include COMPONENT devel)
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel)
else()
install(TARGETS mdbx-static EXPORT libmdbx
LIBRARY DESTINATION lib COMPONENT devel
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
NAMELINK_COMPONENT devel
OBJECTS DESTINATION lib COMPONENT devel
ARCHIVE DESTINATION lib COMPONENT devel
PUBLIC_HEADER DESTINATION include COMPONENT devel
INCLUDES DESTINATION include COMPONENT devel)
OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel)
endif()
endif(MDBX_INSTALL_STATIC)
################################################################################
# collect options & build info
string(TIMESTAMP MDBX_BUILD_TIMESTAMP UTC)
if(NOT DEFINED MDBX_BUILD_TIMESTAMP)
string(TIMESTAMP MDBX_BUILD_TIMESTAMP UTC)
endif()
set(MDBX_BUILD_FLAGS ${CMAKE_C_FLAGS})
if(MDBX_BUILD_CXX)
set(MDBX_BUILD_FLAGS ${CMAKE_CXX_FLAGS})

26
CMakeSettings.json Normal file
View File

@@ -0,0 +1,26 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\libmdbx\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\libmdbx\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
},
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "Release",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\libmdbx\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\libmdbx\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
}
]
}

View File

@@ -1,19 +1,211 @@
ChangeLog
---------
## v0.10.1 (in development)
TODO:
### TODO
- [Engage an "overlapped I/O" on Windows](https://github.com/erthink/libmdbx/issues/224).
- [Simple careful mode for working with corrupted DB](https://github.com/erthink/libmdbx/issues/223).
- [Move most of `mdbx_chk` functional to the library API](https://github.com/erthink/libmdbx/issues/204).
- [Replace SRW-lock on Windows to allow shrink DB with `MDBX_NOTLS` option](https://github.com/erthink/libmdbx/issues/210).
- [More flexible support of asynchronous runtime/framework(s)](https://github.com/erthink/libmdbx/issues/200).
- [Migration guide from LMDB to MDBX](https://github.com/erthink/libmdbx/issues/199).
- [Get rid of dirty-pages list in MDBX_WRITEMAP mode](https://github.com/erthink/libmdbx/issues/193).
- [Large/Overflow pages accounting for dirty-room](https://github.com/erthink/libmdbx/issues/192).
- [C++ Buffer issue](https://github.com/erthink/libmdbx/issues/191).
- Finalize C++ API (few typos and trivia bugs are still likely for now).
- [Support for RAW devices](https://github.com/erthink/libmdbx/issues/124).
- [Test framework issue](https://github.com/erthink/libmdbx/issues/127).
- [Support MessagePack for Keys & Values](https://github.com/erthink/libmdbx/issues/115).
- [Engage new terminology](https://github.com/erthink/libmdbx/issues/137).
- Packages for [Astra Linux](https://astralinux.ru/), [ALT Linux](https://www.altlinux.org/), [ROSA Linux](https://www.rosalinux.ru/), Fedora/RHEL, Debian/Ubuntu.
- Finalize C++ API (there is still a small chance for a few typos and bugs).
- Packages for [Astra Linux](https://astralinux.ru/), [ALT Linux](https://www.altlinux.org/), [ROSA Linux](https://www.rosalinux.ru/), etc.
## v0.11.2 at 2021-12-02
Acknowledgements:
- [장세연 (Чан Се Ен)](https://github.com/sasgas) for contributing to C++ API.
- [Alain Picard](https://github.com/castortech) for [Java bindings](https://github.com/castortech/mdbxjni).
- [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
- [Kris Zyp](https://github.com/kriszyp) for reporting and testing.
- [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs).
Fixes:
- [Fixed compilation](https://github.com/erthink/libmdbx/pull/239) with `devtoolset-9` on CentOS/RHEL 7.
- [Fixed unexpected `MDBX_PROBLEM` error](https://github.com/erthink/libmdbx/issues/242) because of update an obsolete meta-page.
- [Fixed returning `MDBX_NOTFOUND` error](https://github.com/erthink/libmdbx/issues/243) in case an inexact value found for `MDBX_GET_BOTH` operation.
- [Fixed compilation](https://github.com/erthink/libmdbx/issues/245) without kernel/libc-devel headers.
Minors:
- Fixed `constexpr`-related macros for legacy compilers.
- Allowed to define 'CMAKE_CXX_STANDARD` using an environment variable.
- Simplified collection statistics of page operation .
- Added `MDBX_FORCE_BUILD_AS_MAIN_PROJECT` cmake option.
- Remove unneeded `#undef P_DIRTY`.
## v0.11.1 at 2021-10-23
### Backward compatibility break:
The database format signature has been changed to prevent
forward-interoperability with an previous releases, which may lead to a
[false positive diagnosis of database corruption](https://github.com/erthink/libmdbx/issues/238)
due to flaws of an old library versions.
This change is mostly invisible:
- previously versions are unable to read/write a new DBs;
- but the new release is able to handle an old DBs and will silently upgrade ones.
Acknowledgements:
- [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
## v0.10.5 at 2021-10-13 (obsolete, please use v0.11.1)
Unfortunately, the `v0.10.5` accidentally comes not full-compatible with previous releases:
- `v0.10.5` can read/processing DBs created by previous releases, i.e. the backward-compatibility is provided;
- however, previous releases may lead to false-corrupted state with DB that was touched by `v0.10.5`, i.e. the forward-compatibility is broken for `v0.10.4` and earlier.
This cannot be fixed, as it requires fixing past versions, which as a result we will just get a current version.
Therefore, it is recommended to use `v0.11.1` instead of `v0.10.5`.
Acknowledgements:
- [Noel Kuntze](https://github.com/Thermi) for immediately bug reporting.
Fixes:
- Fixed unaligned access regression after the `#pragma pack` fix for modern compilers.
- Added UBSAN-test to CI to avoid a regression(s) similar to lately fixed.
- Fixed possibility of meta-pages clashing after manually turn to a particular meta-page using `mdbx_chk` utility.
Minors:
- Refined handling of weak or invalid meta-pages while a DB opening.
- Refined providing information for the @MAIN and @GC sub-databases of a last committed modification transaction's ID.
## v0.10.4 at 2021-10-10
Acknowledgements:
- [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs).
- [Andrew Ashikhmin](https://github.com/yperbasis) for contributing to C++ API.
Fixes:
- Fixed possibility of looping update GC during transaction commit (no public issue since the problem was discovered inside [Positive Technologies](https://www.ptsecurity.ru)).
- Fixed `#pragma pack` to avoid provoking some compilers to generate code with [unaligned access](https://github.com/erthink/libmdbx/issues/235).
- Fixed `noexcept` for potentially throwing `txn::put()` of C++ API.
Minors:
- Added stochastic test script for checking small transactions cases.
- Removed extra transaction commit/restart inside test framework.
- In debugging builds fixed a too small (single page) by default DB shrink threshold.
## v0.10.3 at 2021-08-27
Acknowledgements:
- [Francisco Vallarino](https://github.com/fjvallarino) for [Haskell bindings for libmdbx](https://hackage.haskell.org/package/libmdbx).
- [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
- [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for contributing.
Extensions and improvements:
- Added `cursor::erase()` overloads for `key` and for `key-value`.
- Resolve minor Coverity Scan issues (no fixes but some hint/comment were added).
- Resolve minor UndefinedBehaviorSanitizer issues (no fixes but some workaround were added).
Fixes:
- Always setup `madvise` while opening DB (fixes https://github.com/erthink/libmdbx/issues/231).
- Fixed checking legacy `P_DIRTY` flag (`0x10`) for nested/sub-pages.
Minors:
- Fixed getting revision number from middle of history during amalgamation (GNU Makefile).
- Fixed search GCC tools for LTO (CMake scripts).
- Fixed/reorder dirs list for search CLANG tools for LTO (CMake scripts).
- Fixed/workarounds for CLANG < 9.x
- Fixed CMake warning about compatibility with 3.8.2
## v0.10.2 at 2021-07-26
Acknowledgements:
- [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing.
- [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for reporting bugs.
- [Lionel Debroux](https://github.com/debrouxl) for fuzzing tests and reporting bugs.
- [Sergey Fedotov](https://github.com/SergeyFromHell/) for [`node-mdbx` NodeJS bindings](https://www.npmjs.com/package/node-mdbx).
- [Kris Zyp](https://github.com/kriszyp) for [`lmdbx-store` NodeJS bindings](https://github.com/kriszyp/lmdbx-store).
- [Noel Kuntze](https://github.com/Thermi) for [draft Python bindings](https://github.com/erthink/libmdbx/commits/python-bindings).
New features, extensions and improvements:
- [Allow to predefine/override `MDBX_BUILD_TIMESTAMP` for builds reproducibility](https://github.com/erthink/libmdbx/issues/201).
- Added options support for `long-stochastic` script.
- Avoided `MDBX_TXN_FULL` error for large transactions when possible.
- The `MDBX_READERS_LIMIT` increased to `32767`.
- Raise `MDBX_TOO_LARGE` under Valgrind/ASAN if being opened DB is 100 larger than RAM (to avoid hangs and OOM).
- Minimized the size of poisoned/unpoisoned regions to avoid Valgrind/ASAN stuck.
- Added more workarounds for QEMU for testing builds for 32-bit platforms, Alpha and Sparc architectures.
- `mdbx_chk` now skips iteration & checking of DB' records if corresponding page-tree is corrupted (to avoid `SIGSEGV`, ASAN failures, etc).
- Added more checks for [rare/fuzzing corruption cases](https://github.com/erthink/libmdbx/issues/217).
Backward compatibility break:
- Use file `VERSION.txt` for version information instead of `VERSION` to avoid collision with `#include <version>`.
- Rename `slice::from/to_FOO_bytes()` to `slice::envisage_from/to_FOO_length()'.
- Rename `MDBX_TEST_EXTRA` make's variable to `MDBX_SMOKE_EXTRA`.
- Some details of the C++ API have been changed for subsequent freezing.
Fixes:
- Fixed excess meta-pages checks in case `mdbx_chk` is called to check the DB for a specific meta page and thus could prevent switching to the selected meta page, even if the check passed without errors.
- Fixed [recursive use of SRW-lock on Windows cause by `MDBX_NOTLS` option](https://github.com/erthink/libmdbx/issues/203).
- Fixed [log a warning during a new DB creation](https://github.com/erthink/libmdbx/issues/205).
- Fixed [false-negative `mdbx_cursor_eof()` result](https://github.com/erthink/libmdbx/issues/207).
- Fixed [`make install` with non-GNU `install` utility (OSX, BSD)](https://github.com/erthink/libmdbx/issues/208).
- Fixed [installation by `CMake` in special cases by complete use `GNUInstallDirs`'s variables](https://github.com/erthink/libmdbx/issues/209).
- Fixed [C++ Buffer issue with `std::string` and alignment](https://github.com/erthink/libmdbx/issues/191).
- Fixed `safe64_reset()` for platforms without atomic 64-bit compare-and-swap.
- Fixed hang/shutdown on big-endian platforms without `__cxa_thread_atexit()`.
- Fixed [using bad meta-pages if DB was partially/recoverable corrupted](https://github.com/erthink/libmdbx/issues/217).
- Fixed extra `noexcept` for `buffer::&assign_reference()`.
- Fixed `bootid` generation on Windows for case of change system' time.
- Fixed [test framework keygen-related issue](https://github.com/erthink/libmdbx/issues/127).
## v0.10.1 at 2021-06-01
Acknowledgements:
- [Alexey Akhunov](https://github.com/AlexeyAkhunov) and [Alex Sharov](https://github.com/AskAlexSharov) for bug reporting and testing.
- [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for bug reporting and testing related to WSL2.
New features:
- Added `-p` option to `mdbx_stat` utility for printing page operations statistic.
- Added explicit checking for and warning about using unfit github's archives.
- Added fallback from [OFD locking](https://bit.ly/3yFRtYC) to legacy non-OFD POSIX file locks on an `EINVAL` error.
- Added [Plan 9](https://en.wikipedia.org/wiki/9P_(protocol)) network file system to the whitelist for an ability to open a DB in exclusive mode.
- Support for opening from WSL2 environment a DB hosted on Windows drive and mounted via [DrvFs](https://docs.microsoft.com/it-it/archive/blogs/wsl/wsl-file-system-support#drvfs) (i.e by Plan 9 noted above).
Fixes:
- Fixed minor "foo not used" warnings from modern C++ compilers when building the C++ part of the library.
- Fixed confusing/messy errors when build library from unfit github's archives (https://github.com/erthink/libmdbx/issues/197).
- Fixed `#elsif` typo.
- Fixed rare unexpected `MDBX_PROBLEM` error during altering data in huge transactions due to wrong spilling/oust of dirty pages (https://github.com/erthink/libmdbx/issues/195).
- Re-Fixed WSL1/WSL2 detection with distinguishing (https://github.com/erthink/libmdbx/issues/97).
## v0.10.0 at 2021-05-09

View File

@@ -29,18 +29,19 @@ INSTALL ?= install
CC ?= gcc
CFLAGS_EXTRA ?=
LD ?= ld
MDBX_BUILD_OPTIONS ?= -DNDEBUG=1
MDBX_BUILD_OPTIONS ?=-DNDEBUG=1
MDBX_BUILD_TIMESTAMP ?=$(shell date +%Y-%m-%dT%H:%M:%S%z)
CFLAGS ?= -std=gnu11 -O2 -g -Wall -Werror -Wextra -Wpedantic -ffunction-sections -fPIC -fvisibility=hidden -pthread -Wno-error=attributes $(CFLAGS_EXTRA)
# -Wno-tautological-compare
CXX ?= g++
# Choosing C++ standard with deferred simple variable expansion trick
CXXSTD ?= $(eval CXXSTD := $$(shell PROBE=$$$$([ -f mdbx.c++ ] && echo mdbx.c++ || echo src/mdbx.c++); for std in gnu++20 c++20 gnu++2a c++2a gnu++17 c++17 gnu++14 c++14 gnu+11 c++11; do $(CXX) -std=$$$${std} -c $$$${PROBE} -o /dev/null 2>/dev/null >/dev/null && echo "-std=$$$${std}" && exit; done))$(CXXSTD)
CXXSTD ?= $(eval CXXSTD := $$(shell PROBE=$$$$([ -f mdbx.c++ ] && echo mdbx.c++ || echo src/mdbx.c++); for std in gnu++23 c++23 gnu++2b c++2b gnu++20 c++20 gnu++2a c++2a gnu++17 c++17 gnu++1z c++1z gnu++14 c++14 gnu++1y c++1y gnu+11 c++11 gnu++0x c++0x; do $(CXX) -std=$$$${std} -c $$$${PROBE} -o /dev/null 2>std-$$$${std}.err >/dev/null && echo "-std=$$$${std}" && exit; done))$(CXXSTD)
CXXFLAGS = $(CXXSTD) $(filter-out -std=gnu11,$(CFLAGS))
# HINT: Try append '--no-as-needed,-lrt' for ability to built with modern glibc, but then run with the old.
LIBS ?= $(shell uname | grep -qi SunOS && echo "-lkstat") $(shell uname | grep -qi -e Darwin -e OpenBSD || echo "-lrt") $(shell uname | grep -qi Windows && echo "-lntdll")
# TIP: Try append '--no-as-needed,-lrt' for ability to built with modern glibc, but then use with the old.
LIBS ?= $(strip -lm $(shell uname | grep -qi SunOS && echo "-lkstat") $(shell uname | grep -qi -e Darwin -e OpenBSD || echo "-lrt") $(shell uname | grep -qi Windows && echo "-lntdll"))
LDFLAGS ?= $(shell $(LD) --help 2>/dev/null | grep -q -- --gc-sections && echo '-Wl,--gc-sections,-z,relro,-O1')$(shell $(LD) --help 2>/dev/null | grep -q -- -dead_strip && echo '-Wl,-dead_strip')
LDFLAGS ?= $(strip $(shell $(LD) --help 2>/dev/null | grep -q -- --gc-sections && echo '-Wl,--gc-sections,-z,relro,-O1')$(shell $(LD) --help 2>/dev/null | grep -q -- -dead_strip && echo '-Wl,-dead_strip'))
EXE_LDFLAGS ?= -pthread
################################################################################
@@ -58,8 +59,9 @@ HEADERS := mdbx.h mdbx.h++
LIBRARIES := libmdbx.a libmdbx.$(SO_SUFFIX)
TOOLS := mdbx_stat mdbx_copy mdbx_dump mdbx_load mdbx_chk mdbx_drop
MANPAGES := mdbx_stat.1 mdbx_copy.1 mdbx_dump.1 mdbx_load.1 mdbx_chk.1 mdbx_drop.1
TIP := // TIP:
.PHONY: all help options lib tools clean install uninstall
.PHONY: all help options lib tools clean install uninstall check_buildflags_tag
.PHONY: install-strip install-no-strip strip libmdbx mdbx show-options
ifeq ("$(origin V)", "command line")
@@ -72,11 +74,11 @@ endif
ifeq ($(MDBX_BUILD_VERBOSE),1)
QUIET :=
HUSH :=
$(info ## TIP: Use `make V=0` for quiet.)
$(info $(TIP) Use `make V=0` for quiet.)
else
QUIET := @
HUSH := >/dev/null
$(info ## TIP: Use `make V=1` for verbose.)
$(info $(TIP) Use `make V=1` for verbose.)
endif
all: show-options $(LIBRARIES) $(TOOLS)
@@ -102,19 +104,22 @@ help:
@echo " make bench-clean - remove temp database(s) after benchmark"
#> dist-cutoff-begin
@echo ""
@echo " make smoke - fast smoke test"
@echo " make test - basic test"
@echo " make check - basic test"
@echo " make memcheck - build with Valgrind's and test with memcheck tool"
@echo " make test-valgrind - build with Valgrind's and test with memcheck tool"
@echo " make test-asan - build with AddressSanitizer and test"
@echo " make test-leak - build with LeakSanitizer and test"
@echo " make test-ubsan - build with UndefinedBehaviourSanitizer and test"
@echo " make cross-gcc - run cross-compilation testset"
@echo " make cross-qemu - run cross-compilation and execution testset with QEMU"
@echo " make check - smoke test with amalgamation and installation checking"
@echo " make long-test - execute long test which runs for several weeks, or until you interrupt it"
@echo " make memcheck - build with Valgrind's and smoke test with memcheck tool"
@echo " make test-valgrind - build with Valgrind's and basic test with memcheck tool"
@echo " make test-asan - build with AddressSanitizer and basic test"
@echo " make test-leak - build with LeakSanitizer and basic test"
@echo " make test-ubsan - build with UndefinedBehaviourSanitizer and basic test"
@echo " make cross-gcc - check cross-compilation without test execution"
@echo " make cross-qemu - run cross-compilation and execution basic test with QEMU"
@echo " make gcc-analyzer - run gcc-analyzer (mostly useless for now)"
@echo " make build-test - build test executable(s)"
@echo " make test-fault - run transaction owner failure testcase"
@echo " make test-singleprocess - run single-process test (used by make cross-qemu)"
@echo " make smoke-fault - execute transaction owner failure smoke testcase"
@echo " make smoke-singleprocess - execute single-process smoke test"
@echo " make test-singleprocess - execute single-process basic test (also used by make cross-qemu)"
@echo ""
@echo " make dist - build amalgamated source code"
@echo " make doxygen - build HTML documentation"
@@ -123,12 +128,14 @@ help:
#< dist-cutoff-end
show-options:
@echo " MDBX_BUILD_OPTIONS =$(MDBX_BUILD_OPTIONS)"
@echo '## TIP: Use `make options` to listing available build options.'
@echo " MDBX_BUILD_OPTIONS = $(MDBX_BUILD_OPTIONS)"
@echo " MDBX_BUILD_TIMESTAMP = $(MDBX_BUILD_TIMESTAMP)"
@echo '$(TIP) Use `make options` to listing available build options.'
@echo " CC =`which $(CC)` | `$(CC) --version | head -1`"
@echo " CFLAGS =$(CFLAGS)"
@echo " CXXFLAGS =$(CXXFLAGS)"
@echo " LDFLAGS =$(LDFLAGS) $(LIBS) $(EXE_LDFLAGS)"
@echo '## TIP: Use `make help` to listing available targets.'
@echo '$(TIP) Use `make help` to listing available targets.'
options:
@echo " INSTALL =$(INSTALL)"
@@ -149,7 +156,8 @@ options:
@echo " EXE_LDFLAGS =$(EXE_LDFLAGS)"
@echo " LIBS =$(LIBS)"
@echo ""
@echo " MDBX_BUILD_OPTIONS =$(MDBX_BUILD_OPTIONS)"
@echo " MDBX_BUILD_OPTIONS = $(MDBX_BUILD_OPTIONS)"
@echo " MDBX_BUILD_TIMESTAMP = $(MDBX_BUILD_TIMESTAMP)"
@echo ""
@echo "## Assortment items for MDBX_BUILD_OPTIONS:"
@echo "## Note that the defaults should already be correct for most platforms;"
@@ -178,7 +186,17 @@ clean:
@echo ' REMOVE ...'
$(QUIET)rm -rf $(TOOLS) mdbx_test @* *.[ao] *.[ls]o *.$(SO_SUFFIX) *.dSYM *~ tmp.db/* \
*.gcov *.log *.err src/*.o test/*.o mdbx_example dist \
config.h src/config.h src/version.c *.tar*
config.h src/config.h src/version.c *.tar* buildflags.tag
MDBX_BUILD_FLAGS =$(strip $(MDBX_BUILD_OPTIONS) $(CXXSTD) $(CFLAGS) $(LDFLAGS) $(LIBS))
check_buildflags_tag:
$(QUIET)if [ "$(MDBX_BUILD_FLAGS)" != "$$(cat buildflags.tag 2>&1)" ]; then \
echo -n " CLEAN for build with specified flags..." && \
$(MAKE) IOARENA=false CXXSTD= -s clean >/dev/null && echo " Ok" && \
echo '$(MDBX_BUILD_FLAGS)' > buildflags.tag; \
fi
buildflags.tag: check_buildflags_tag
libmdbx.a: mdbx-static.o mdbx++-static.o
@echo ' AR $@'
@@ -196,13 +214,13 @@ ifeq ($(wildcard mdbx.c),mdbx.c)
# Amalgamated source code, i.e. distributed after `make dist`
MAN_SRCDIR := man1/
config.h: mdbx.c $(lastword $(MAKEFILE_LIST))
config.h: buildflags.tag mdbx.c $(lastword $(MAKEFILE_LIST))
@echo ' MAKE $@'
$(QUIET)(echo '#define MDBX_BUILD_TIMESTAMP "$(shell date +%Y-%m-%dT%H:%M:%S%z)"' \
&& echo '#define MDBX_BUILD_FLAGS "$(CXXSTD) $(CFLAGS) $(LDFLAGS) $(LIBS)"' \
$(QUIET)(echo '#define MDBX_BUILD_TIMESTAMP "$(MDBX_BUILD_TIMESTAMP)"' \
&& echo "#define MDBX_BUILD_FLAGS \"$$(cat buildflags.tag)\"" \
&& echo '#define MDBX_BUILD_COMPILER "$(shell (LC_ALL=C $(CC) --version || echo 'Please use GCC or CLANG compatible compiler') | head -1)"' \
&& echo '#define MDBX_BUILD_TARGET "$(shell set -o pipefail; (LC_ALL=C $(CC) -v 2>&1 | grep -i '^Target:' | cut -d ' ' -f 2- || (LC_ALL=C $(CC) --version | grep -qi e2k && echo E2K) || echo 'Please use GCC or CLANG compatible compiler') | head -1)"' \
) > $@
) >$@
mdbx-dylib.o: config.h mdbx.c mdbx.h $(lastword $(MAKEFILE_LIST))
@echo ' CC $@'
@@ -229,9 +247,9 @@ else
################################################################################
# Plain (non-amalgamated) sources with test
.PHONY: build-test check cross-gcc cross-qemu dist doxygen gcc-analyzer
.PHONY: reformat release-assets tags test test-asan test-fault test-leak
.PHONY: test-singleprocess test-ubsan test-valgrind memcheck
.PHONY: build-test build-test-with-valgrind check cross-gcc cross-qemu dist doxygen gcc-analyzer long-test
.PHONY: reformat release-assets tags smoke test test-asan smoke-fault test-leak
.PHONY: smoke-singleprocess test-singleprocess test-ubsan test-valgrind memcheck
define uname2osal
case "$(UNAME)" in
@@ -247,7 +265,7 @@ define uname2titer
esac
endef
DIST_EXTRA := LICENSE README.md CMakeLists.txt GNUmakefile Makefile ChangeLog.md VERSION config.h.in ntdll.def \
DIST_EXTRA := LICENSE README.md CMakeLists.txt GNUmakefile Makefile ChangeLog.md VERSION.txt config.h.in ntdll.def \
$(addprefix man1/, $(MANPAGES)) cmake/compiler.cmake cmake/profile.cmake cmake/utils.cmake
DIST_SRC := mdbx.h mdbx.h++ mdbx.c mdbx.c++ $(addsuffix .c, $(TOOLS))
@@ -271,71 +289,90 @@ reformat:
fi
MAN_SRCDIR := src/man1/
ALLOY_DEPS := $(wildcard src/*)
MDBX_GIT_VERSION = $(shell set -o pipefail; git describe --tags | sed -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)|\1|p' || echo 'Please fetch tags and/or use non-obsolete git version')
MDBX_GIT_REVISION = $(shell set -o pipefail; git rev-list --count HEAD ^`git tag --sort=-version:refname | sed -n '/^\(v[0-9]\+\.[0-9]\+\.[0-9]\+\)*/p;q' || echo 'failed_git_tag_with_sort'` || echo 'Please use non-obsolete git version')
MDBX_GIT_TIMESTAMP = $(shell git show --no-patch --format=%cI HEAD || echo 'Please install latest get version')
MDBX_GIT_DESCRIBE = $(shell git describe --tags --long --dirty=-dirty || echo 'Please fetch tags and/or install non-obsolete git version')
ALLOY_DEPS := $(shell git ls-files src/)
git_DIR := $(shell if [ -d .git ]; then echo .git; elif [ -s .git -a -f .git ]; then grep '^gitdir: ' .git | cut -d ':' -f 2; else echo git_directory_is_absent; fi)
MDBX_GIT_VERSION = $(shell set -o pipefail; git describe --tags 2>&- | sed -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)|\1|p' || echo 'Please fetch tags and/or use non-obsolete git version')
MDBX_GIT_REVISION = $(shell set -o pipefail; git rev-list `git describe --tags --abbrev=0`..HEAD --count 2>&- || echo 'Please fetch tags and/or use non-obsolete git version')
MDBX_GIT_TIMESTAMP = $(shell git show --no-patch --format=%cI HEAD 2>&- || echo 'Please install latest get version')
MDBX_GIT_DESCRIBE = $(shell git describe --tags --long --dirty=-dirty 2>&- || echo 'Please fetch tags and/or install non-obsolete git version')
MDBX_VERSION_SUFFIX = $(shell set -o pipefail; echo -n '$(MDBX_GIT_DESCRIBE)' | tr -c -s '[a-zA-Z0-9]' _)
MDBX_BUILD_SOURCERY = $(shell set -o pipefail; $(MAKE) CXXSTD= -s src/version.c >/dev/null && (openssl dgst -r -sha256 src/version.c || sha256sum src/version.c || shasum -a 256 src/version.c) 2>/dev/null | cut -d ' ' -f 1 || echo 'Please install openssl or sha256sum or shasum')_$(MDBX_VERSION_SUFFIX)
MDBX_BUILD_SOURCERY = $(shell set -o pipefail; $(MAKE) IOARENA=false CXXSTD= -s src/version.c >/dev/null && (openssl dgst -r -sha256 src/version.c || sha256sum src/version.c || shasum -a 256 src/version.c) 2>/dev/null | cut -d ' ' -f 1 || (echo 'Please install openssl or sha256sum or shasum' >&2 && echo sha256sum_is_no_available))_$(MDBX_VERSION_SUFFIX)
MDBX_DIST_DIR = libmdbx-$(MDBX_VERSION_SUFFIX)
# Extra options mdbx_test utility
MDBX_TEST_EXTRA ?=
MDBX_SMOKE_EXTRA ?=
check: test dist
check: DESTDIR = $(shell pwd)/@check-install
check: test dist install
test: build-test
@echo ' RUNNING `mdbx_test basic`...'
smoke: build-test
@echo ' SMOKE `mdbx_test basic`...'
$(QUIET)rm -f $(TEST_DB) $(TEST_LOG).gz && (set -o pipefail; \
(./mdbx_test --table=+data.integer --keygen.split=29 --datalen.min=min --datalen.max=max --progress --console=no --repeat=$(TEST_ITER) --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_TEST_EXTRA) basic && \
./mdbx_test --mode=-writemap,-nosync-safe,-lifo --progress --console=no --repeat=12 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_TEST_EXTRA) basic) \
| tee >(gzip --stdout > $(TEST_LOG).gz) | tail -n 42) \
(./mdbx_test --table=+data.integer --keygen.split=29 --datalen.min=min --datalen.max=max --progress --console=no --repeat=$(TEST_ITER) --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_SMOKE_EXTRA) basic && \
./mdbx_test --mode=-writemap,-nosync-safe,-lifo --progress --console=no --repeat=12 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_SMOKE_EXTRA) basic) \
| tee >(gzip --stdout >$(TEST_LOG).gz) | tail -n 42) \
&& ./mdbx_chk -vvn $(TEST_DB) && ./mdbx_chk -vvn $(TEST_DB)-copy
test-singleprocess: all mdbx_test
@echo ' RUNNING `mdbx_test --nested`...'
smoke-singleprocess: build-test
@echo ' SMOKE `mdbx_test --nested`...'
$(QUIET)rm -f $(TEST_DB) $(TEST_LOG).gz && (set -o pipefail; \
(./mdbx_test --table=+data.integer --keygen.split=29 --datalen.min=min --datalen.max=max --progress --console=no --repeat=42 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_TEST_EXTRA) --hill && \
(./mdbx_test --table=+data.integer --keygen.split=29 --datalen.min=min --datalen.max=max --progress --console=no --repeat=42 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_SMOKE_EXTRA) --hill && \
./mdbx_test --progress --console=no --repeat=2 --pathname=$(TEST_DB) --dont-cleanup-before --dont-cleanup-after --copy && \
./mdbx_test --mode=-writemap,-nosync-safe,-lifo --progress --console=no --repeat=42 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_TEST_EXTRA) --nested) \
| tee >(gzip --stdout > $(TEST_LOG).gz) | tail -n 42) \
./mdbx_test --mode=-writemap,-nosync-safe,-lifo --progress --console=no --repeat=42 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_SMOKE_EXTRA) --nested) \
| tee >(gzip --stdout >$(TEST_LOG).gz) | tail -n 42) \
&& ./mdbx_chk -vvn $(TEST_DB) && ./mdbx_chk -vvn $(TEST_DB)-copy
test-fault: all mdbx_test
@echo ' RUNNING `mdbx_test --inject-writefault=42 basic`...'
$(QUIET)rm -f $(TEST_DB) $(TEST_LOG).gz && (set -o pipefail; ./mdbx_test --progress --console=no --pathname=$(TEST_DB) --inject-writefault=42 --dump-config --dont-cleanup-after $(MDBX_TEST_EXTRA) basic \
| tee >(gzip --stdout > $(TEST_LOG).gz) | tail -n 42) \
smoke-fault: build-test
@echo ' SMOKE `mdbx_test --inject-writefault=42 basic`...'
$(QUIET)rm -f $(TEST_DB) $(TEST_LOG).gz && (set -o pipefail; ./mdbx_test --progress --console=no --pathname=$(TEST_DB) --inject-writefault=42 --dump-config --dont-cleanup-after $(MDBX_SMOKE_EXTRA) basic \
| tee >(gzip --stdout >$(TEST_LOG).gz) | tail -n 42) \
; ./mdbx_chk -vvnw $(TEST_DB) && ([ ! -e $(TEST_DB)-copy ] || ./mdbx_chk -vvn $(TEST_DB)-copy)
VALGRIND=valgrind --trace-children=yes --log-file=valgrind-%p.log --leak-check=full --track-origins=yes --error-exitcode=42 --suppressions=test/valgrind_suppress.txt
memcheck test-valgrind:
@echo " RUNNING \`mdbx_test basic\` under Valgrind's memcheck..."
$(QUIET)$(MAKE) CXXSTD= clean && $(MAKE) CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-Ofast -DMDBX_USE_VALGRIND" build-test && \
rm -f valgrind-*.log $(TEST_DB) $(TEST_LOG).gz && (set -o pipefail; ( \
$(VALGRIND) ./mdbx_test --table=+data.integer --keygen.split=29 --datalen.min=min --datalen.max=max --progress --console=no --repeat=2 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_TEST_EXTRA) basic && \
test: build-test
@echo ' RUNNING `test/long_stochastic.sh --loops 2`...'
$(QUIET)test/long_stochastic.sh --loops 2 --db-upto-mb 256 --skip-make >$(TEST_LOG)
long-test: build-test
@echo ' RUNNING `test/long_stochastic.sh --loops 42`...'
$(QUIET)test/long_stochastic.sh --loops 42 --db-upto-mb 1024 --skip-make
test-singleprocess: build-test
@echo ' RUNNING `test/long_stochastic.sh --single --loops 2`...'
$(QUIET)test/long_stochastic.sh --single --loops 2 --db-upto-mb 256 --skip-make >$(TEST_LOG)
test-valgrind: CFLAGS_EXTRA=-Ofast -DMDBX_USE_VALGRIND
test-valgrind: build-test
@echo ' RUNNING `test/long_stochastic.sh --with-valgrind --loops 2`...'
$(QUIET)test/long_stochastic.sh --with-valgrind --loops 2 --db-upto-mb 256 --skip-make >$(TEST_LOG)
memcheck: VALGRIND=valgrind --trace-children=yes --log-file=valgrind-%p.log --leak-check=full --track-origins=yes --error-exitcode=42 --suppressions=test/valgrind_suppress.txt
memcheck: CFLAGS_EXTRA=-Ofast -DMDBX_USE_VALGRIND
memcheck: build-test
@echo " SMOKE \`mdbx_test basic\` under Valgrind's memcheck..."
$(QUIET)rm -f valgrind-*.log $(TEST_DB) $(TEST_LOG).gz && (set -o pipefail; ( \
$(VALGRIND) ./mdbx_test --table=+data.integer --keygen.split=29 --datalen.min=min --datalen.max=max --progress --console=no --repeat=2 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_SMOKE_EXTRA) basic && \
$(VALGRIND) ./mdbx_test --progress --console=no --pathname=$(TEST_DB) --dont-cleanup-before --dont-cleanup-after --copy && \
$(VALGRIND) ./mdbx_test --mode=-writemap,-nosync-safe,-lifo --progress --console=no --repeat=4 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_TEST_EXTRA) basic && \
$(VALGRIND) ./mdbx_test --mode=-writemap,-nosync-safe,-lifo --progress --console=no --repeat=4 --pathname=$(TEST_DB) --dont-cleanup-after $(MDBX_SMOKE_EXTRA) basic && \
$(VALGRIND) ./mdbx_chk -vvn $(TEST_DB) && \
$(VALGRIND) ./mdbx_chk -vvn $(TEST_DB)-copy \
) | tee >(gzip --stdout > $(TEST_LOG).gz) | tail -n 42)
) | tee >(gzip --stdout >$(TEST_LOG).gz) | tail -n 42)
gcc-analyzer:
@echo ' RE-BUILD with `-fanalyzer` option...'
@echo "NOTE: There a lot of false-positive warnings at 2020-05-01 by pre-release GCC-10 (20200328, Red Hat 10.0.1-0.11)"
$(QUIET)$(MAKE) CXXSTD=$(CXXSTD) --always-make CFLAGS_EXTRA="-Og -fanalyzer -Wno-error" build-test
$(QUIET)$(MAKE) IOARENA=false CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-Og -fanalyzer -Wno-error" build-test
test-ubsan:
@echo ' RE-CHECK with `-fsanitize=undefined` option...'
$(QUIET)$(MAKE) CXXSTD= clean && $(MAKE) CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-Ofast -fsanitize=undefined -fsanitize-undefined-trap-on-error" check
@echo ' RE-TEST with `-fsanitize=undefined` option...'
$(QUIET)$(MAKE) IOARENA=false CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-Ofast -fsanitize=undefined -fsanitize-undefined-trap-on-error" test
test-asan:
@echo ' RE-CHECK with `-fsanitize=address` option...'
$(QUIET)$(MAKE) CXXSTD= clean && $(MAKE) CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-Os -fsanitize=address" check
@echo ' RE-TEST with `-fsanitize=address` option...'
$(QUIET)$(MAKE) IOARENA=false CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-Os -fsanitize=address" test
test-leak:
@echo ' RE-CHECK with `-fsanitize=leak` option...'
$(QUIET)$(MAKE) CXXSTD= clean && $(MAKE) CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-fsanitize=leak" check
@echo ' RE-TEST with `-fsanitize=leak` option...'
$(QUIET)$(MAKE) IOARENA=false CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-fsanitize=leak" test
mdbx_example: mdbx.h example/example-mdbx.c libmdbx.$(SO_SUFFIX)
@echo ' CC+LD $@'
@@ -344,7 +381,7 @@ mdbx_example: mdbx.h example/example-mdbx.c libmdbx.$(SO_SUFFIX)
build-test: all mdbx_example mdbx_test
define test-rule
$(patsubst %.cc,%.o,$(1)): $(1) $(TEST_INC) mdbx.h $(lastword $(MAKEFILE_LIST))
$(patsubst %.cc,%.o,$(1)): $(1) $(TEST_INC) $(HEADERS) $(lastword $(MAKEFILE_LIST))
@echo ' CC $$@'
$(QUIET)$$(CXX) $$(CXXFLAGS) $$(MDBX_BUILD_OPTIONS) -c $(1) -o $$@
@@ -359,7 +396,18 @@ mdbx_test: $(TEST_OBJ) libmdbx.$(SO_SUFFIX)
@echo ' LD $@'
$(QUIET)$(CXX) $(CXXFLAGS) $(TEST_OBJ) -Wl,-rpath . -L . -l mdbx $(EXE_LDFLAGS) $(LIBS) -o $@
git_DIR := $(shell if [ -d .git ]; then echo .git; elif [ -s .git -a -f .git ]; then grep '^gitdir: ' .git | cut -d ':' -f 2; else echo "Please use libmdbx as a git-submodule or the amalgamated source code" >&2 && echo git_directory; fi)
$(git_DIR)/HEAD $(git_DIR)/index $(git_DIR)/refs/tags:
@echo '*** ' >&2
@echo '*** Please don''t use tarballs nor zips which are automatically provided by Github !' >&2
@echo '*** These archives do not contain version information and thus are unfit to build libmdbx.' >&2
@echo '*** You can vote for ability of disabling auto-creation such unsuitable archives at https://github.community/t/disable-tarball' >&2
@echo '*** ' >&2
@echo '*** Instead of above, just clone the git repository, either download a tarball or zip with the properly amalgamated source core.' >&2
@echo '*** For embedding libmdbx use a git-submodule or the amalgamated source code.' >&2
@echo '*** ' >&2
@echo '*** Please, avoid using any other techniques.' >&2
@echo '*** ' >&2
@false
src/version.c: src/version.c.in $(lastword $(MAKEFILE_LIST)) $(git_DIR)/HEAD $(git_DIR)/index $(git_DIR)/refs/tags
@echo ' MAKE $@'
@@ -372,16 +420,16 @@ src/version.c: src/version.c.in $(lastword $(MAKEFILE_LIST)) $(git_DIR)/HEAD $(g
-e "s|\$${MDBX_VERSION_MINOR}|$(shell echo '$(MDBX_GIT_VERSION)' | cut -d . -f 2)|" \
-e "s|\$${MDBX_VERSION_RELEASE}|$(shell echo '$(MDBX_GIT_VERSION)' | cut -d . -f 3)|" \
-e "s|\$${MDBX_VERSION_REVISION}|$(MDBX_GIT_REVISION)|" \
src/version.c.in > $@
src/version.c.in >$@
src/config.h: src/version.c $(lastword $(MAKEFILE_LIST))
src/config.h: buildflags.tag src/version.c $(lastword $(MAKEFILE_LIST))
@echo ' MAKE $@'
$(QUIET)(echo '#define MDBX_BUILD_TIMESTAMP "$(shell date +%Y-%m-%dT%H:%M:%S%z)"' \
&& echo '#define MDBX_BUILD_FLAGS "$(CXXSTD) $(CFLAGS) $(LDFLAGS) $(LIBS)"' \
$(QUIET)(echo '#define MDBX_BUILD_TIMESTAMP "$(MDBX_BUILD_TIMESTAMP)"' \
&& echo "#define MDBX_BUILD_FLAGS \"$$(cat buildflags.tag)\"" \
&& echo '#define MDBX_BUILD_COMPILER "$(shell (LC_ALL=C $(CC) --version || echo 'Please use GCC or CLANG compatible compiler') | head -1)"' \
&& echo '#define MDBX_BUILD_TARGET "$(shell set -o pipefail; (LC_ALL=C $(CC) -v 2>&1 | grep -i '^Target:' | cut -d ' ' -f 2- || (LC_ALL=C $(CC) --version | grep -qi e2k && echo E2K) || echo 'Please use GCC or CLANG compatible compiler') | head -1)"' \
&& echo '#define MDBX_BUILD_SOURCERY $(MDBX_BUILD_SOURCERY)' \
) > $@
) >$@
mdbx-dylib.o: src/config.h src/version.c src/alloy.c $(ALLOY_DEPS) $(lastword $(MAKEFILE_LIST))
@echo ' CC $@'
@@ -402,32 +450,32 @@ docs/Doxyfile: docs/Doxyfile.in src/version.c
-e "s|\$${MDBX_VERSION_MINOR}|$(shell echo '$(MDBX_GIT_VERSION)' | cut -d . -f 2)|" \
-e "s|\$${MDBX_VERSION_RELEASE}|$(shell echo '$(MDBX_GIT_VERSION)' | cut -d . -f 3)|" \
-e "s|\$${MDBX_VERSION_REVISION}|$(MDBX_GIT_REVISION)|" \
docs/Doxyfile.in > $@
docs/Doxyfile.in >$@
define md-extract-section
docs/__$(1).md: $(2)
@echo ' EXTRACT $1'
$(QUIET)sed -n '/<!-- section-begin $(1) -->/,/<!-- section-end -->/p' $$< > $$@ && test -s $$@
$(QUIET)sed -n '/<!-- section-begin $(1) -->/,/<!-- section-end -->/p' $$< >$$@ && test -s $$@
endef
$(foreach section,overview mithril characteristics improvements history usage performance bindings,$(eval $(call md-extract-section,$(section),README.md)))
docs/overall.md: docs/__overview.md docs/_toc.md docs/__mithril.md docs/__history.md AUTHORS LICENSE
@echo ' MAKE $@'
$(QUIET)echo -e "\\mainpage Overall\n\\section brief Brief" | cat - $(filter %.md, $^) > $@ && echo -e "\n\n\nLicense\n=======\n" | cat AUTHORS - LICENSE >> $@
$(QUIET)echo -e "\\mainpage Overall\n\\section brief Brief" | cat - $(filter %.md, $^) >$@ && echo -e "\n\n\nLicense\n=======\n" | cat AUTHORS - LICENSE >>$@
docs/intro.md: docs/_preface.md docs/__characteristics.md docs/__improvements.md docs/_restrictions.md docs/__performance.md
@echo ' MAKE $@'
$(QUIET)cat $^ | sed 's/^Performance comparison$$/Performance comparison {#performance}/' > $@
$(QUIET)cat $^ | sed 's/^Performance comparison$$/Performance comparison {#performance}/' >$@
docs/usage.md: docs/__usage.md docs/_starting.md docs/__bindings.md
@echo ' MAKE $@'
$(QUIET)echo -e "\\page usage Usage\n\\section getting Building & Embedding" | cat - $^ | sed 's/^Bindings$$/Bindings {#bindings}/' > $@
$(QUIET)echo -e "\\page usage Usage\n\\section getting Building & Embedding" | cat - $^ | sed 's/^Bindings$$/Bindings {#bindings}/' >$@
doxygen: docs/Doxyfile docs/overall.md docs/intro.md docs/usage.md mdbx.h mdbx.h++ src/options.h ChangeLog.md AUTHORS LICENSE
@echo ' RUNNING doxygen...'
$(QUIET)rm -rf docs/html && \
cat mdbx.h | tr '\n' '\r' | sed -e 's/LIBMDBX_INLINE_API\s*(\s*\([^,]\+\),\s*\([^,]\+\),\s*(\s*\([^)]\+\)\s*)\s*)\s*{/inline \1 \2(\3) {/g' | tr '\r' '\n' > docs/mdbx.h && \
cat mdbx.h | tr '\n' '\r' | sed -e 's/LIBMDBX_INLINE_API\s*(\s*\([^,]\+\),\s*\([^,]\+\),\s*(\s*\([^)]\+\)\s*)\s*)\s*{/inline \1 \2(\3) {/g' | tr '\r' '\n' >docs/mdbx.h && \
cp mdbx.h++ src/options.h ChangeLog.md docs/ && (cd docs && doxygen Doxyfile $(HUSH)) && cp AUTHORS LICENSE docs/html/
mdbx++-dylib.o: src/config.h src/mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST))
@@ -450,15 +498,14 @@ release-assets: libmdbx-sources-$(MDBX_VERSION_SUFFIX).tar.gz libmdbx-sources-$(
dist-checked.tag: $(addprefix dist/, $(DIST_SRC) $(DIST_EXTRA))
@echo -n ' VERIFY amalgamated sources...'
$(QUIET)rm -rf $@ \
$(QUIET)rm -rf $@ dist/@tmp-shared_internals.inc \
&& if grep -R "define xMDBX_ALLOY" dist | grep -q MDBX_BUILD_SOURCERY; then echo "sed output is WRONG!" >&2; exit 2; fi \
&& rm -rf dist-check && cp -r -p dist dist-check && ($(MAKE) -C dist-check > dist-check/build.log 2> dist-check/build.err || (cat dist-check/build.err && exit 1)) \
&& touch $@ || (echo " FAILED! See dist-check/build.err" >&2; exit 2) && echo " Ok" \
&& rm dist/@tmp-shared_internals.inc
&& rm -rf dist-check && cp -r -p dist dist-check && ($(MAKE) IOARENA=false CXXSTD=$(CXXSTD) -C dist-check >dist-check.log 2>dist-check.err || (cat dist-check.err && exit 1)) \
&& touch $@ || (echo " FAILED! See dist-check.log and dist-check.err" >&2; exit 2) && echo " Ok"
libmdbx-sources-$(MDBX_VERSION_SUFFIX).tar.gz: dist-checked.tag
@echo ' CREATE $@'
$(QUIET)$(TAR) -c $(shell LC_ALL=C $(TAR) --help | grep -q -- '--owner' && echo '--owner=0 --group=0') -f - -C dist $(DIST_SRC) $(DIST_EXTRA) | gzip -c -9 > $@
$(QUIET)$(TAR) -c $(shell LC_ALL=C $(TAR) --help | grep -q -- '--owner' && echo '--owner=0 --group=0') -f - -C dist $(DIST_SRC) $(DIST_EXTRA) | gzip -c -9 >$@
libmdbx-sources-$(MDBX_VERSION_SUFFIX).zip: dist-checked.tag
@echo ' CREATE $@'
@@ -475,26 +522,26 @@ dist/mdbx.h++: mdbx.h++ src/version.c $(lastword $(MAKEFILE_LIST))
dist/@tmp-shared_internals.inc: src/version.c $(ALLOY_DEPS) $(lastword $(MAKEFILE_LIST))
@echo ' ALLOYING...'
$(QUIET)mkdir -p dist \
&& echo '#define xMDBX_ALLOY 1' > dist/@tmp-sed.inc && echo '#define MDBX_BUILD_SOURCERY $(MDBX_BUILD_SOURCERY)' >> dist/@tmp-sed.inc \
&& echo '#define xMDBX_ALLOY 1' >dist/@tmp-sed.inc && echo '#define MDBX_BUILD_SOURCERY $(MDBX_BUILD_SOURCERY)' >>dist/@tmp-sed.inc \
&& sed \
-e '/#pragma once/r dist/@tmp-sed.inc' \
-e 's|#include "../mdbx.h"|@INCLUDE "mdbx.h"|' \
-e '/#include "defs.h"/r src/defs.h' \
-e '/#include "osal.h"/r src/osal.h' \
-e '/#include "options.h"/r src/options.h' \
src/internals.h > $@ \
src/internals.h >$@ \
&& rm -rf dist/@tmp-sed.inc
dist/mdbx.c: dist/@tmp-shared_internals.inc $(lastword $(MAKEFILE_LIST))
@echo ' MAKE $@'
$(QUIET)mkdir -p dist && (cat dist/@tmp-shared_internals.inc \
&& cat src/core.c src/osal.c src/version.c src/lck-windows.c src/lck-posix.c \
) | grep -v -e '#include "' -e '#pragma once' | sed 's|@INCLUDE|#include|' > $@
) | grep -v -e '#include "' -e '#pragma once' | sed 's|@INCLUDE|#include|' >$@
dist/mdbx.c++: dist/@tmp-shared_internals.inc src/mdbx.c++ $(lastword $(MAKEFILE_LIST))
@echo ' MAKE $@'
$(QUIET)mkdir -p dist && (cat dist/@tmp-shared_internals.inc && cat src/mdbx.c++) \
| grep -v -e '#include "' -e '#pragma once' | sed 's|@INCLUDE|#include|;s|"mdbx.h"|"mdbx.h++"|' > $@
| grep -v -e '#include "' -e '#pragma once' | sed 's|@INCLUDE|#include|;s|"mdbx.h"|"mdbx.h++"|' >$@
define dist-tool-rule
dist/$(1).c: src/$(1).c src/wingetopt.h src/wingetopt.c \
@@ -505,7 +552,7 @@ dist/$(1).c: src/$(1).c src/wingetopt.h src/wingetopt.c \
-e '/#include "wingetopt.h"/r src/wingetopt.c' \
src/$(1).c \
| grep -v -e '#include "' -e '#pragma once' -e '#define xMDBX_ALLOY' \
| sed 's|@INCLUDE|#include|' > $$@
| sed 's|@INCLUDE|#include|' >$$@
endef
$(foreach file,$(TOOLS),$(eval $(call dist-tool-rule,$(file))))
@@ -513,14 +560,14 @@ $(foreach file,$(TOOLS),$(eval $(call dist-tool-rule,$(file))))
define dist-extra-rule
dist/$(1): $(1)
@echo ' REFINE $$@'
$(QUIET)mkdir -p $$(dir $$@) && sed -e '/^#> dist-cutoff-begin/,/^#< dist-cutoff-end/d' $$< > $$@
$(QUIET)mkdir -p $$(dir $$@) && sed -e '/^#> dist-cutoff-begin/,/^#< dist-cutoff-end/d' $$< >$$@
endef
$(foreach file,$(filter-out man1/% VERSION %.in ntdll.def,$(DIST_EXTRA)),$(eval $(call dist-extra-rule,$(file))))
$(foreach file,$(filter-out man1/% VERSION.txt %.in ntdll.def,$(DIST_EXTRA)),$(eval $(call dist-extra-rule,$(file))))
dist/VERSION: src/version.c
dist/VERSION.txt: src/version.c
@echo ' MAKE $@'
$(QUIET)mkdir -p dist/ && echo "$(MDBX_GIT_VERSION).$(MDBX_GIT_REVISION)" > $@
$(QUIET)mkdir -p dist/ && echo "$(MDBX_GIT_VERSION).$(MDBX_GIT_REVISION)" >$@
dist/ntdll.def: src/ntdll.def
@echo ' COPY $@'
@@ -539,7 +586,7 @@ endif
################################################################################
# Cross-compilation simple test
CROSS_LIST = sparc64-linux-gnu-gcc alpha-linux-gnu-gcc mips-linux-gnu-gcc \
CROSS_LIST = mips-linux-gnu-gcc \
powerpc64-linux-gnu-gcc powerpc-linux-gnu-gcc \
arm-linux-gnueabihf-gcc aarch64-linux-gnu-gcc \
sh4-linux-gnu-gcc mips64-linux-gnuabi64-gcc \
@@ -550,7 +597,7 @@ CROSS_LIST = sparc64-linux-gnu-gcc alpha-linux-gnu-gcc mips-linux-gnu-gcc \
# s390x-linux-gnu-gcc - works (previously: qemu hang/abort)
# sparc64-linux-gnu-gcc - coredump (qemu mmap-troubles, previously: qemu fails fcntl for F_SETLK/F_GETLK)
# alpha-linux-gnu-gcc - coredump (qemu mmap-troubles)
CROSS_LIST_NOQEMU =
CROSS_LIST_NOQEMU = sparc64-linux-gnu-gcc alpha-linux-gnu-gcc
cross-gcc:
@echo ' Re-building by cross-compiler for: $(CROSS_LIST_NOQEMU) $(CROSS_LIST)'
@@ -558,7 +605,7 @@ cross-gcc:
@echo "FOR INSTANCE: apt install g++-aarch64-linux-gnu g++-alpha-linux-gnu g++-arm-linux-gnueabihf g++-hppa-linux-gnu g++-mips-linux-gnu g++-mips64-linux-gnuabi64 g++-powerpc-linux-gnu g++-powerpc64-linux-gnu g++-s390x-linux-gnu g++-sh4-linux-gnu g++-sparc64-linux-gnu"
$(QUIET)for CC in $(CROSS_LIST_NOQEMU) $(CROSS_LIST); do \
echo "===================== $$CC"; \
$(MAKE) CXXSTD= clean && CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) all || exit $$?; \
$(MAKE) IOARENA=false CXXSTD= clean && CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) IOARENA=false all || exit $$?; \
done
# Unfortunately qemu don't provide robust support for futexes.
@@ -571,21 +618,25 @@ cross-qemu:
@echo " 2) apt install binfmt-support qemu-user-static qemu-user qemu-system-arm qemu-system-mips qemu-system-misc qemu-system-ppc qemu-system-sparc"
$(QUIET)for CC in $(CROSS_LIST); do \
echo "===================== $$CC + qemu"; \
$(MAKE) CXXSTD= clean && \
MDBX_TEST_EXTRA="$(MDBX_TEST_EXTRA)$$(echo $$CC | grep -q -e alpha -e sparc && echo ' --size-upper=64M --size-lower=64M')" \
$(MAKE) IOARENA=false CXXSTD= clean && \
CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_BUILD_OPTIONS="-DMDBX_SAFE4QEMU $(MDBX_BUILD_OPTIONS)" \
$(MAKE) test-singleprocess || exit $$?; \
$(MAKE) IOARENA=false smoke-singleprocess test-singleprocess || exit $$?; \
done
#< dist-cutoff-end
install: $(LIBRARIES) $(TOOLS) $(HEADERS)
@echo ' INSTALLING...'
$(INSTALL) -D -p $(EXE_INSTALL_FLAGS) -t $(DESTDIR)$(prefix)/bin$(suffix) $(TOOLS) && \
$(INSTALL) -D -p $(EXE_INSTALL_FLAGS) -t $(DESTDIR)$(prefix)/lib$(suffix) $(filter-out libmdbx.a,$(LIBRARIES)) && \
$(INSTALL) -D -p -t $(DESTDIR)$(prefix)/lib$(suffix) libmdbx.a && \
$(INSTALL) -D -p -m 444 -t $(DESTDIR)$(prefix)/include $(HEADERS) && \
$(INSTALL) -D -p -m 444 -t $(DESTDIR)$(mandir)/man1 $(addprefix $(MAN_SRCDIR), $(MANPAGES))
$(QUIET)mkdir -p $(DESTDIR)$(prefix)/bin$(suffix) && \
$(INSTALL) -p $(EXE_INSTALL_FLAGS) $(TOOLS) $(DESTDIR)$(prefix)/bin$(suffix)/ && \
mkdir -p $(DESTDIR)$(prefix)/lib$(suffix)/ && \
$(INSTALL) -p $(EXE_INSTALL_FLAGS) $(filter-out libmdbx.a,$(LIBRARIES)) $(DESTDIR)$(prefix)/lib$(suffix)/ && \
mkdir -p $(DESTDIR)$(prefix)/lib$(suffix)/ && \
$(INSTALL) -p libmdbx.a $(DESTDIR)$(prefix)/lib$(suffix)/ && \
mkdir -p $(DESTDIR)$(prefix)/include/ && \
$(INSTALL) -p -m 444 $(HEADERS) $(DESTDIR)$(prefix)/include/ && \
mkdir -p $(DESTDIR)$(mandir)/man1/ && \
$(INSTALL) -p -m 444 $(addprefix $(MAN_SRCDIR), $(MANPAGES)) $(DESTDIR)$(mandir)/man1/
install-strip: EXE_INSTALL_FLAGS = -s
install-strip: install
@@ -603,23 +654,32 @@ uninstall:
################################################################################
# Benchmarking by ioarena
IOARENA ?= $(shell \
ifeq ($(origin IOARENA),undefined)
IOARENA := $(shell \
(test -x ../ioarena/@BUILD/src/ioarena && echo ../ioarena/@BUILD/src/ioarena) || \
(test -x ../../@BUILD/src/ioarena && echo ../../@BUILD/src/ioarena) || \
(test -x ../../src/ioarena && echo ../../src/ioarena) || which ioarena)
(test -x ../../src/ioarena && echo ../../src/ioarena) || which ioarena 2>&- || \
(echo false && echo '$(TIP) Clone and build the https://github.com/pmwkaa/ioarena.git within a neighbouring directory for availability of benchmarking.' >&2))
endif
NN ?= 25000000
BENCH_CRUD_MODE ?= nosync
ifneq ($(wildcard $(IOARENA)),)
.PHONY: bench bench-clean bench-couple re-bench bench-quartet bench-triplet
bench-clean:
@echo ' REMOVE bench-*.txt _ioarena/*'
$(QUIET)rm -rf bench-*.txt _ioarena/*
re-bench: bench-clean bench
ifeq ($(or $(IOARENA),false),false)
bench bench-quartet bench-triplet bench-couple:
$(QUIET)echo 'The `ioarena` benchmark is required.' >&2 && \
echo 'Please clone and build the https://github.com/pmwkaa/ioarena.git within a neighbouring `ioarena` directory.' >&2 && \
false
else
.PHONY: bench bench-clean bench-couple re-bench bench-quartet bench-triplet
define bench-rule
bench-$(1)_$(2).txt: $(3) $(IOARENA) $(lastword $(MAKEFILE_LIST))
@echo ' RUNNING ioarena for $1/$2...'

View File

@@ -5,8 +5,8 @@ clean install install-no-strip install-strip strip tools uninstall \
bench bench-clean bench-couple bench-quartet bench-triplet re-bench \
lib libmdbx mdbx mdbx_chk mdbx_copy mdbx_drop mdbx_dump mdbx_load mdbx_stat \
check dist memcheck cross-gcc cross-qemu doxygen gcc-analyzer reformat \
release-assets tags test build-test mdbx_test \
test-asan test-fault test-leak test-singleprocess test-ubsan test-valgrind:
release-assets tags test build-test mdbx_test smoke smoke-fault smoke-singleprocess \
test-asan test-leak test-singleprocess test-ubsan test-valgrind:
@CC=$(CC) \
CXX=`if test -n "$(CXX)" && which "$(CXX)" > /dev/null; then echo "$(CXX)"; elif test -n "$(CCC)" && which "$(CCC)" > /dev/null; then echo "$(CCC)"; else echo "c++"; fi` \
`which gmake || which gnumake || echo 'echo "GNU Make 3.80 or above is required"; exit 2;'` \

107
README.md
View File

@@ -91,7 +91,7 @@ _MithrilDB_ is a rightly relevant name.
- [Improvements beyond LMDB](#improvements-beyond-lmdb)
- [History & Acknowledgments](#history)
- [Usage](#usage)
- [Building](#building)
- [Building and Testing](#building-and-testing)
- [API description](#api-description)
- [Bindings](#bindings)
- [Performance comparison](#performance-comparison)
@@ -154,8 +154,8 @@ transaction journal. No crash recovery needed. No maintenance is required.
## Limitations
- **Page size**: a power of 2, minimum `256` (mostly for testing), maximum `65536` bytes, default `4096` bytes.
- **Key size**: minimum `0`, maximum ≈¼ pagesize (`1348` bytes for default 4K pagesize, `21828` bytes for 64K pagesize).
- **Value size**: minimum `0`, maximum `2146435072` (`0x7FF00000`) bytes for maps, ≈¼ pagesize for multimaps (`1348` bytes for default 4K pagesize, `21828` bytes for 64K pagesize).
- **Key size**: minimum `0`, maximum ≈½ pagesize (`2022` bytes for default 4K pagesize, `32742` bytes for 64K pagesize).
- **Value size**: minimum `0`, maximum `2146435072` (`0x7FF00000`) bytes for maps, ≈½ pagesize for multimaps (`2022` bytes for default 4K pagesize, `32742` bytes for 64K pagesize).
- **Write transaction size**: up to `1327217884` pages (`4.944272` TiB for default 4K pagesize, `79.108351` TiB for 64K pagesize).
- **Database size**: up to `2147483648` pages (≈`8.0` TiB for default 4K pagesize, ≈`128.0` TiB for 64K pagesize).
- **Maximum sub-databases**: `32765`.
@@ -167,9 +167,11 @@ transaction journal. No crash recovery needed. No maintenance is required.
2. _libmdbx_ is based on [B+ tree](https://en.wikipedia.org/wiki/B%2B_tree), so access to database pages is mostly random.
Thus SSDs provide a significant performance boost over spinning disks for large databases.
3. _libmdbx_ uses [shadow paging](https://en.wikipedia.org/wiki/Shadow_paging) instead of [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging). Thus syncing data to disk might be a bottleneck for write intensive workload.
3. _libmdbx_ uses [shadow paging](https://en.wikipedia.org/wiki/Shadow_paging) instead of [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging).
Thus syncing data to disk might be a bottleneck for write intensive workload.
4. _libmdbx_ uses [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write) for [snapshot isolation](https://en.wikipedia.org/wiki/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
4. _libmdbx_ uses [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write) for [snapshot isolation](https://en.wikipedia.org/wiki/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.
@@ -200,8 +202,8 @@ the user's point of view.
## Added Features
1. Keys could be more than 2 times longer than _LMDB_.
> For DB with default page size _libmdbx_ support keys up to 1300 bytes
> and up to 21780 bytes for 64K page size. _LMDB_ allows key size up to
> For DB with default page size _libmdbx_ support keys up to 2022 bytes
> and up to 32742 bytes for 64K page size. _LMDB_ allows key size up to
> 511 bytes and may silently loses data with large values.
2. Up to 30% faster than _LMDB_ in [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) benchmarks.
@@ -343,6 +345,13 @@ Currently, libmdbx is only available in a
Packages support for common Linux distributions is planned in the future,
since release the version 1.0.
## Never use tarballs nor zips automatically provided by Github !
Please don't use tarballs nor zips which are automatically provided by Github.
These archives do not contain version information and thus are unfit to build _libmdbx_.
Instead of ones just clone the git repository, either download a tarball or zip with the properly amalgamated source core.
Moreover, please vote for [ability of disabling auto-creation such unsuitable archives](https://github.community/t/disable-tarball).
## Source code embedding
_libmdbx_ provides two official ways for integration in source code form:
@@ -362,7 +371,7 @@ The amalgamated source code could be created from the original clone of git
repository on Linux by executing `make dist`. As a result, the desired
set of files will be formed in the `dist` subdirectory.
## Building
## Building and Testing
Both amalgamated and original source code provides build through the use
[CMake](https://cmake.org/) or [GNU
@@ -376,10 +385,76 @@ target platform. Obviously you need building tools itself, i.e. `git`,
and `make options` are also available for listing existing targets
and build options respectively.
The only significant specificity is that git' tags are required
to build from complete (not amalgamated) source codes.
Executing **`git fetch --tags --force --prune`** is enough to get ones,
or `git fetch --unshallow --tags --prune --force` after the Github's
[`actions/checkout@v2`](https://github.com/actions/checkout) either set **`fetch-depth: 0`** for it.
So just using CMake or GNU Make in your habitual manner and feel free to
fill an issue or make pull request in the case something will be
unexpected or broken down.
### Testing
The amalgamated source code does not contain any tests for or several reasons.
Please read [the explanation](https://github.com/erthink/libmdbx/issues/214#issuecomment-870717981) and don't ask to alter this.
So for testing _libmdbx_ itself you need a full source code, i.e. the clone of a git repository, there is no option.
The full source code of _libmdbx_ has a [`test` subdirectory](https://github.com/erthink/libmdbx/tree/master/test) with minimalistic test "framework".
Actually yonder is a source code of the `mdbx_test` console utility which has a set of command-line options that allow construct and run a reasonable enough test scenarios.
This test utility is intended for _libmdbx_'s developers for testing library itself, but not for use by users.
Therefore, only basic information is provided:
- There are few CRUD-based test cases (hill, TTL, nested, append, jitter, etc),
which can be combined to test the concurrent operations within shared database in a multi-processes environment.
This is the `basic` test scenario.
- The `Makefile` provide several self-described targets for testing: `smoke`, `test`, `check`, `memcheck`, `test-valgrind`,
`test-asan`, `test-leak`, `test-ubsan`, `cross-gcc`, `cross-qemu`, `gcc-analyzer`, `smoke-fault`, `smoke-singleprocess`,
`test-singleprocess`, 'long-test'. Please run `make --help` if doubt.
- In addition to the `mdbx_test` utility, there is the script [`long_stochastic.sh`](https://github.com/erthink/libmdbx/blob/master/test/long_stochastic.sh),
which calls `mdbx_test` by going through set of modes and options, with gradually increasing the number of operations and the size of transactions.
This script is used for mostly of all automatic testing, including `Makefile` targets and Continuous Integration.
- Brief information of available command-line options is available by `--help`.
However, you should dive into source code to get all, there is no option.
Anyway, no matter how thoroughly the _libmdbx_ is tested, you should rely only on your own tests for a few reasons:
1. Mostly of all use cases are unique.
So it is no warranty that your use case was properly tested, even the _libmdbx_'s tests engages stochastic approach.
2. If there are problems, then your test on the one hand will help to verify whether you are using _libmdbx_ correctly,
on the other hand it will allow to reproduce the problem and insure against regression in a future.
3. Actually you should rely on than you checked by yourself or take a risk.
### Common important details
#### Build reproducibility
By default _libmdbx_ track build time via `MDBX_BUILD_TIMESTAMP` build option and macro.
So for a [reproducible builds](https://en.wikipedia.org/wiki/Reproducible_builds) you should predefine/override it to known fixed string value.
For instance:
- for reproducible build with make: `make MDBX_BUILD_TIMESTAMP=unknown ` ...
- or during configure by CMake: `cmake -DMDBX_BUILD_TIMESTAMP:STRING=unknown ` ...
Of course, in addition to this, your toolchain must ensure the reproducibility of builds.
For more information please refer to [reproducible-builds.org](https://reproducible-builds.org/).
#### Containers
There are no special traits nor quirks if you use libmdbx ONLY inside the single container.
But in a cross-container cases or with a host-container(s) mix the two major things MUST be
guaranteed:
1. Coherence of memory mapping content and unified page cache inside OS kernel for host and all container(s) operated with a some DB.
Basically this means must be only a single physical copy of each memory mapped DB' page in the system memory.
2. Uniqueness of PID values and/or a common space for ones:
- for POSIX systems: PID uniqueness for all processes operated with a DB.
I.e. the `--pid=host` is required for run DB-aware processes inside Docker,
either without host interaction a `--pid=container:<name|id>` with the same name/id.
- for non-POSIX (i.e. Windows) systems: inter-visibility of processes handles.
I.e. the `OpenProcess(SYNCHRONIZE, ..., PID)` must return reasonable error,
including `ERROR_ACCESS_DENIED`,
but not the `ERROR_INVALID_PARAMETER` as for an invalid/non-existent PID.
#### DSO/DLL unloading and destructors of Thread-Local-Storage objects
When building _libmdbx_ as a shared library or use static _libmdbx_ as a
part of another dynamic library, it is advisable to make sure that your
@@ -472,7 +547,7 @@ Please refer to the [official guide](https://developer.android.com/studio/projec
### iOS
To build _libmdbx_ for iOS, we recommend using CMake with the
"[toolchain file](https://cmake.org/cmake/help/latest/variable/CMAKE_TOOLCHAIN_FILE.html)"
["toolchain file"](https://cmake.org/cmake/help/latest/variable/CMAKE_TOOLCHAIN_FILE.html)
from the [ios-cmake](https://github.com/leetal/ios-cmake) project.
<!-- section-end -->
@@ -489,12 +564,16 @@ Bindings
| Runtime | Repo | Author |
| ------- | ------ | ------ |
| Haskell | [libmdbx-hs](https://hackage.haskell.org/package/libmdbx) | [Francisco Vallarino](https://github.com/fjvallarino) |
| Python (draft) | [python-bindings](https://github.com/erthink/libmdbx/commits/python-bindings) branch | [Noel Kuntze](https://github.com/Thermi)
| NodeJS | [lmdbx-js](https://github.com/kriszyp/lmdbx-js) | [Kris Zyp](https://github.com/kriszyp/)
| NodeJS | [node-mdbx](https://www.npmjs.com/package/node-mdbx/) | [Сергей Федотов](mailto:sergey.fedotov@corp.mail.ru) |
| Ruby | [ruby-mdbx](https://rubygems.org/gems/mdbx/) | [Mahlon E. Smith](https://github.com/mahlonsmith) |
| Go | [mdbx-go](https://github.com/torquem-ch/mdbx-go) | [Alex Sharov](https://github.com/AskAlexSharov) |
| [Nim](https://en.wikipedia.org/wiki/Nim_(programming_language)) | [NimDBX](https://github.com/snej/nimdbx) | [Jens Alfke](https://github.com/snej)
| Rust | [heed](https://github.com/Kerollmops/heed), [mdbx-rs](https://github.com/Kerollmops/mdbx-rs) | [Clément Renault](https://github.com/Kerollmops) |
| Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) |
| .NET | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) |
| Rust | [libmdbx-rs](https://github.com/vorot93/libmdbx-rs) | [Artem Vorotnikov](https://github.com/vorot93) |
| Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) |
| .NET (obsolete) | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) |
<!-- section-end -->
@@ -603,7 +682,9 @@ records.
execution time of transactions. Each interval shows minimal and maximum
execution time, cross marks standard deviation.
**1,000,000 transactions in async-write mode**. In case of a crash all data is consistent and conforms to the one of last successful transactions, but lost transaction count is much higher than in
**1,000,000 transactions in async-write mode**.
In case of a crash all data is consistent and conforms to the one of last successful transactions,
but lost transaction count is much higher than in
lazy-write mode. All DB engines in this mode do as little writes as
possible on persistent storage. _libmdbx_ uses
[msync(MS_ASYNC)](https://linux.die.net/man/2/msync) in this mode.

View File

@@ -1,4 +1,4 @@
version: 0.10.0.{build}
version: 0.11.2.{build}
environment:
matrix:
@@ -52,8 +52,8 @@ matrix:
configuration: Release
# Enable RDP for troubleshooting
init:
- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
#init:
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
before_build:
- git clean -x -f -d

View File

@@ -13,9 +13,14 @@
## limitations under the License.
##
cmake_minimum_required(VERSION 3.8.2)
if(CMAKE_VERSION VERSION_LESS 3.12)
cmake_minimum_required(VERSION 3.8.2)
else()
cmake_minimum_required(VERSION 3.12)
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 3.8.2)
cmake_policy(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
if(CMAKE_VERSION MATCHES ".*MSVC.*" AND CMAKE_VERSION VERSION_LESS 3.16)
message(FATAL_ERROR "CMake from MSVC kit is unfit! "
@@ -286,21 +291,21 @@ if(CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG})
set(gcc_suffix "")
if(gcc_collect_valid AND gcc_collect)
string(REGEX MATCH "^(.*cc)(-.+)$" gcc_suffix_valid ${gcc_collect})
string(REGEX MATCH "^(.*(cc|\\+\\+))(-.+)$" gcc_suffix_valid ${gcc_collect})
if(gcc_suffix_valid)
string(REGEX MATCH "^(.*cc)(-.+)$" "\\2" gcc_suffix ${gcc_collect})
string(REGEX REPLACE "^(.*(cc|\\+\\+))(-.+)$" "\\3" gcc_suffix ${gcc_collect})
endif()
endif()
get_filename_component(gcc_dir ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} DIRECTORY)
if(NOT CMAKE_GCC_AR)
find_program(CMAKE_GCC_AR NAMES gcc${gcc_suffix}-ar gcc-ar${gcc_suffix} PATHS ${gcc_dir} NO_DEFAULT_PATH)
find_program(CMAKE_GCC_AR NAMES "gcc${gcc_suffix}-ar" "gcc-ar${gcc_suffix}" PATHS "${gcc_dir}" NO_DEFAULT_PATH)
endif()
if(NOT CMAKE_GCC_NM)
find_program(CMAKE_GCC_NM NAMES gcc${gcc_suffix}-nm gcc-nm${gcc_suffix} PATHS ${gcc_dir} NO_DEFAULT_PATH)
find_program(CMAKE_GCC_NM NAMES "gcc${gcc_suffix}-nm" "gcc-nm${gcc_suffix}" PATHS "${gcc_dir}" NO_DEFAULT_PATH)
endif()
if(NOT CMAKE_GCC_RANLIB)
find_program(CMAKE_GCC_RANLIB NAMES gcc${gcc_suffix}-ranlib gcc-ranlib${gcc_suffix} PATHS ${gcc_dir} NO_DEFAULT_PATH)
find_program(CMAKE_GCC_RANLIB NAMES "gcc${gcc_suffix}-ranlib" "gcc-ranlib${gcc_suffix}" PATHS "${gcc_dir}" NO_DEFAULT_PATH)
endif()
unset(gcc_dir)
@@ -342,30 +347,40 @@ if(CMAKE_COMPILER_IS_CLANG)
OUTPUT_VARIABLE clang_search_dirs RESULT_VARIABLE clang_probe_result ERROR_QUIET)
unset(clang_bindirs)
unset(clang_bindirs_x)
unset(clang_libdirs)
unset(clang_libdirs_x)
if(clang_probe_result EQUAL 0)
string(REGEX MATCH "(^|\n.*)(.*programs: =)([^\n]+)((\n.*)|$)" regexp_valid ${clang_search_dirs})
if(regexp_valid)
string(REGEX REPLACE "(^|\n.*)(.*programs: =)([^\n]+)((\n.*)|$)" "\\3" list ${clang_search_dirs})
string(REPLACE ":" ";" list "${list}")
#set(clang_bindirs "")
foreach(dir IN LISTS list)
get_filename_component(dir "${dir}" REALPATH)
string(REGEX MATCH "(^|\n.*)(.*programs: =)([^\n]+)((\n.*)|$)" regexp_valid ${clang_search_dirs})
if(regexp_valid)
string(REGEX REPLACE "(^|\n.*)(.*programs: =)([^\n]+)((\n.*)|$)" "\\3" list ${clang_search_dirs})
string(REPLACE ":" ";" list "${list}")
foreach(dir IN LISTS list)
get_filename_component(dir "${dir}" REALPATH)
if(dir MATCHES ".*llvm.*" OR dir MATCHES ".*clang.*")
list(APPEND clang_bindirs "${dir}")
endforeach()
list(REMOVE_DUPLICATES clang_bindirs)
endif()
string(REGEX MATCH "(^|\n.*)(.*libraries: =)([^\n]+)((\n.*)|$)" regexp_valid ${clang_search_dirs})
if(regexp_valid)
string(REGEX REPLACE "(^|\n.*)(.*libraries: =)([^\n]+)((\n.*)|$)" "\\3" list ${clang_search_dirs})
string(REPLACE ":" ";" list "${list}")
#set(clang_libdirs "")
foreach(dir IN LISTS list)
get_filename_component(dir "${dir}" REALPATH)
else()
list(APPEND clang_bindirs_x "${dir}")
endif()
endforeach()
list(APPEND clang_bindirs "${clang_bindirs_x}")
list(REMOVE_DUPLICATES clang_bindirs)
endif()
string(REGEX MATCH "(^|\n.*)(.*libraries: =)([^\n]+)((\n.*)|$)" regexp_valid ${clang_search_dirs})
if(regexp_valid)
string(REGEX REPLACE "(^|\n.*)(.*libraries: =)([^\n]+)((\n.*)|$)" "\\3" list ${clang_search_dirs})
string(REPLACE ":" ";" list "${list}")
foreach(dir IN LISTS list)
get_filename_component(dir "${dir}" REALPATH)
if(dir MATCHES ".*llvm.*" OR dir MATCHES ".*clang.*")
list(APPEND clang_libdirs "${dir}")
endforeach()
list(REMOVE_DUPLICATES clang_libdirs)
endif()
else()
list(APPEND clang_libdirs_x "${dir}")
endif()
endforeach()
list(APPEND clang_libdirs "${clang_libdirs_x}")
list(REMOVE_DUPLICATES clang_libdirs)
endif()
else()
get_filename_component(clang_bindirs ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} DIRECTORY)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")

View File

@@ -13,9 +13,14 @@
## limitations under the License.
##
cmake_minimum_required(VERSION 3.8.2)
if(CMAKE_VERSION VERSION_LESS 3.12)
cmake_minimum_required(VERSION 3.8.2)
else()
cmake_minimum_required(VERSION 3.12)
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 3.8.2)
cmake_policy(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
include(CheckLibraryExists)
check_library_exists(gcov __gcov_flush "" HAVE_GCOV)

View File

@@ -13,9 +13,14 @@
## limitations under the License.
##
cmake_minimum_required(VERSION 3.8.2)
if(CMAKE_VERSION VERSION_LESS 3.12)
cmake_minimum_required(VERSION 3.8.2)
else()
cmake_minimum_required(VERSION 3.12)
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 3.8.2)
cmake_policy(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
macro(add_compile_flags languages)
foreach(_lang ${languages})
@@ -173,7 +178,10 @@ macro(fetch_version name source_root_directory parent_scope)
set(${name}_GIT_REVISION 0)
# Try to get version from VERSION file
set(version_file "${source_root_directory}/VERSION")
set(version_file "${source_root_directory}/VERSION.txt")
if(NOT EXISTS "${version_file}")
set(version_file "${source_root_directory}/VERSION")
endif()
if(EXISTS "${version_file}")
file(STRINGS "${version_file}" ${name}_VERSION LIMIT_COUNT 1 LIMIT_INPUT 42)
endif()

146
mdbx.h
View File

@@ -361,6 +361,12 @@ typedef mode_t mdbx_mode_t;
#define LIBMDBX_INLINE_API(TYPE, NAME, ARGS) static __inline TYPE NAME ARGS
#endif /* LIBMDBX_INLINE_API */
/** \brief Converts a macro argument into a string constant. */
#ifndef MDBX_STRINGIFY
#define MDBX_STRINGIFY_HELPER(x) #x
#define MDBX_STRINGIFY(x) MDBX_STRINGIFY_HELPER(x)
#endif /* MDBX_STRINGIFY */
/*----------------------------------------------------------------------------*/
#ifndef __cplusplus
@@ -387,7 +393,8 @@ typedef mode_t mdbx_mode_t;
#define MDBX_CXX01_CONSTEXPR __inline
#define MDBX_CXX01_CONSTEXPR_VAR const
#elif !defined(DOXYGEN) && \
(!defined(__cpp_constexpr) || __cpp_constexpr < 200704L || \
((__cplusplus < 201103L && defined(__cpp_constexpr) && \
__cpp_constexpr < 200704L) || \
(defined(__LCC__) && __LCC__ < 124) || \
(defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 407) && \
!defined(__clang__) && !defined(__LCC__)) || \
@@ -404,7 +411,7 @@ typedef mode_t mdbx_mode_t;
#define MDBX_CXX11_CONSTEXPR __inline
#define MDBX_CXX11_CONSTEXPR_VAR const
#elif !defined(DOXYGEN) && \
(!defined(__cpp_constexpr) || __cpp_constexpr < 201304 || \
(!defined(__cpp_constexpr) || __cpp_constexpr < 201304L || \
(defined(__LCC__) && __LCC__ < 124) || \
(defined(__GNUC__) && __GNUC__ < 6 && !defined(__clang__) && \
!defined(__LCC__)) || \
@@ -454,6 +461,25 @@ typedef mode_t mdbx_mode_t;
#endif
#endif /* MDBX_PRINTF_ARGS */
#if defined(DOXYGEN) || \
(defined(__cplusplus) && __cplusplus >= 201603 && \
__has_cpp_attribute(maybe_unused) && \
__has_cpp_attribute(maybe_unused) >= 201603) || \
(!defined(__cplusplus) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ > 202005L)
#define MDBX_MAYBE_UNUSED [[maybe_unused]]
#elif defined(__GNUC__) || __has_attribute(__unused__)
#define MDBX_MAYBE_UNUSED __attribute__((__unused__))
#else
#define MDBX_MAYBE_UNUSED
#endif /* MDBX_MAYBE_UNUSED */
#if __has_attribute(no_sanitize)
#define MDBX_NOSANITIZE_ENUM __attribute((__no_sanitize__("enum")))
#else
#define MDBX_NOSANITIZE_ENUM
#endif /* MDBX_NOSANITIZE_ENUM */
/* 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
@@ -479,28 +505,40 @@ typedef mode_t mdbx_mode_t;
/// used to define flags (based on Microsoft's DEFINE_ENUM_FLAG_OPERATORS).
#define DEFINE_ENUM_FLAG_OPERATORS(ENUM) \
extern "C++" { \
MDBX_CXX01_CONSTEXPR ENUM operator|(ENUM a, ENUM b) { \
MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator|(ENUM a, ENUM b) { \
return ENUM(unsigned(a) | unsigned(b)); \
} \
MDBX_CXX14_CONSTEXPR ENUM &operator|=(ENUM &a, ENUM b) { return a = a | b; } \
MDBX_CXX01_CONSTEXPR ENUM operator&(ENUM a, ENUM b) { \
MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator|=(ENUM &a, \
ENUM b) { \
return a = a | b; \
} \
MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator&(ENUM a, ENUM b) { \
return ENUM(unsigned(a) & unsigned(b)); \
} \
MDBX_CXX01_CONSTEXPR ENUM operator&(ENUM a, unsigned b) { \
MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator&(ENUM a, \
unsigned b) { \
return ENUM(unsigned(a) & b); \
} \
MDBX_CXX01_CONSTEXPR ENUM operator&(unsigned a, ENUM b) { \
MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator&(unsigned a, \
ENUM b) { \
return ENUM(a & unsigned(b)); \
} \
MDBX_CXX14_CONSTEXPR ENUM &operator&=(ENUM &a, ENUM b) { return a = a & b; } \
MDBX_CXX14_CONSTEXPR ENUM &operator&=(ENUM &a, unsigned b) { \
MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator&=(ENUM &a, \
ENUM b) { \
return a = a & b; \
} \
MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator&=(ENUM &a, \
unsigned b) { \
return a = a & b; \
} \
MDBX_CXX01_CONSTEXPR unsigned operator~(ENUM a) { return ~unsigned(a); } \
MDBX_CXX01_CONSTEXPR ENUM operator^(ENUM a, ENUM b) { \
MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator^(ENUM a, ENUM b) { \
return ENUM(unsigned(a) ^ unsigned(b)); \
} \
MDBX_CXX14_CONSTEXPR ENUM &operator^=(ENUM &a, ENUM b) { return a = a ^ b; } \
MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator^=(ENUM &a, \
ENUM b) { \
return a = a ^ b; \
} \
}
#else /* __cplusplus */
/* nope for C since it always allows these operators for enums */
@@ -531,9 +569,9 @@ typedef mode_t mdbx_mode_t;
extern "C" {
#endif
/* MDBX version 0.10.x */
/* MDBX version 0.11.x */
#define MDBX_VERSION_MAJOR 0
#define MDBX_VERSION_MINOR 10
#define MDBX_VERSION_MINOR 11
#ifndef LIBMDBX_API
#if defined(LIBMDBX_EXPORTS)
@@ -772,6 +810,10 @@ enum MDBX_log_level_t {
and all other log-messages */
MDBX_LOG_EXTRA = 7,
#ifdef ENABLE_UBSAN
MDBX_LOG_MAX = 7 /* avoid UBSAN false-positive trap by a tests */,
#endif /* ENABLE_UBSAN */
/** for \ref mdbx_setup_debug() only: Don't change current settings */
MDBX_LOG_DONTCHANGE = -1
};
@@ -785,6 +827,8 @@ typedef enum MDBX_log_level_t MDBX_log_level_t;
* effect, but `MDBX_DBG_ASSERT`, `MDBX_DBG_AUDIT` and `MDBX_DBG_JITTER` only if
* libmdbx builded with \ref MDBX_DEBUG. */
enum MDBX_debug_flags_t {
MDBX_DBG_NONE = 0,
/** Enable assertion checks.
* Requires build with \ref MDBX_DEBUG > 0 */
MDBX_DBG_ASSERT = 1,
@@ -807,6 +851,11 @@ enum MDBX_debug_flags_t {
/** Allow read and write transactions overlapping for the same thread */
MDBX_DBG_LEGACY_OVERLAP = 32,
#ifdef ENABLE_UBSAN
MDBX_DBG_MAX = ((unsigned)MDBX_LOG_MAX) << 16 |
63 /* avoid UBSAN false-positive trap by a tests */,
#endif /* ENABLE_UBSAN */
/** for mdbx_setup_debug() only: Don't change current settings */
MDBX_DBG_DONTCHANGE = -1
};
@@ -1334,10 +1383,10 @@ DEFINE_ENUM_FLAG_OPERATORS(MDBX_txn_flags_t)
enum MDBX_db_flags_t {
MDBX_DB_DEFAULTS = 0,
/** Use reverse string keys */
/** Use reverse string comparison for keys. */
MDBX_REVERSEKEY = UINT32_C(0x02),
/** Use sorted duplicates, i.e. allow multi-values */
/** Use sorted duplicates, i.e. allow multi-values for a keys. */
MDBX_DUPSORT = UINT32_C(0x04),
/** Numeric keys in native byte order either uint32_t or uint64_t. The keys
@@ -1345,18 +1394,19 @@ enum MDBX_db_flags_t {
* arguments. */
MDBX_INTEGERKEY = UINT32_C(0x08),
/** With \ref MDBX_DUPSORT; sorted dup items have fixed size */
/** With \ref MDBX_DUPSORT; sorted dup items have fixed size. The data values
* must all be of the same size. */
MDBX_DUPFIXED = UINT32_C(0x10),
/** With \ref MDBX_DUPSORT and with \ref MDBX_DUPFIXED; dups are fixed size
* \ref MDBX_INTEGERKEY -style integers. The data values must all be of the
* same size and must be aligned while passing as arguments. */
* like \ref MDBX_INTEGERKEY -style integers. The data values must all be of
* the same size and must be aligned while passing as arguments. */
MDBX_INTEGERDUP = UINT32_C(0x20),
/** With \ref MDBX_DUPSORT; use reverse string comparison */
/** With \ref MDBX_DUPSORT; use reverse string comparison for data values. */
MDBX_REVERSEDUP = UINT32_C(0x40),
/** Create DB if not already existing */
/** Create DB if not already existing. */
MDBX_CREATE = UINT32_C(0x40000),
/** Opens an existing sub-database created with unknown flags.
@@ -1687,7 +1737,7 @@ enum MDBX_error_t {
#ifdef ENODATA
MDBX_ENODATA = ENODATA,
#else
MDBX_ENODATA = -1,
MDBX_ENODATA = 9919 /* for compatibility with LLVM's C++ libraries/headers */,
#endif /* ENODATA */
MDBX_EINVAL = EINVAL,
MDBX_EACCESS = EACCES,
@@ -2275,7 +2325,8 @@ struct MDBX_envinfo {
/** Statistics of page operations.
* \details Overall statistics of page operations of all (running, completed
* and aborted) transactions in the current multi-process session (since the
* first process opened the database). */
* first process opened the database after everyone had previously closed it).
*/
struct {
uint64_t newly; /**< Quantity of a new pages added */
uint64_t cow; /**< Quantity of pages copied for update */
@@ -3235,9 +3286,11 @@ struct MDBX_commit_latency {
uint32_t gc;
/** \brief Duration of internal audit if enabled. */
uint32_t audit;
/** \brief Duration of writing dirty/modified data pages. */
/** \brief Duration of writing dirty/modified data pages to a filesystem,
* i.e. the summary duration of a `write()` syscalls during commit. */
uint32_t write;
/** \brief Duration of syncing written data to the dist/storage. */
/** \brief Duration of syncing written data to the disk/storage, i.e.
* the duration of a `fdatasync()` or a `msync()` syscall during commit. */
uint32_t sync;
/** \brief Duration of transaction ending (releasing resources). */
uint32_t ending;
@@ -3451,7 +3504,23 @@ LIBMDBX_API int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary);
/** \brief A callback function used to compare two keys in a database
* \ingroup c_crud
* \see mdbx_cmp() \see mdbx_get_keycmp()
* \see mdbx_get_datacmp \see mdbx_dcmp() */
* \see mdbx_get_datacmp \see mdbx_dcmp()
*
* \anchor avoid_custom_comparators
* It is recommend not using custom comparison functions, but instead
* converting the keys to one of the forms that are suitable for built-in
* comparators (for instance take look to the \ref value2key).
* The reasons to not using custom comparators are:
* - The order of records could not be validated without your code.
* So `mdbx_chk` utility will reports "wrong order" errors
* and the `-i` option is required to suppress ones.
* - A records could not be ordered or sorted without your code.
* So `mdbx_load` utility should be used with `-a` option to preserve
* input data order.
* - However, the custom comparators feature will never be removed.
* You have been warned but still can use custom comparators knowing
* about the issues noted above. In this case you should ignore `deprecated`
* warnings or define `MDBX_DEPRECATED` macro to empty to avoid ones. */
typedef int(MDBX_cmp_func)(const MDBX_val *a,
const MDBX_val *b) MDBX_CXX17_NOEXCEPT;
@@ -3528,16 +3597,7 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a,
*
* For \ref mdbx_dbi_open_ex() additional arguments allow you to set custom
* comparison functions for keys and values (for multimaps).
* However, I recommend not using custom comparison functions, but instead
* converting the keys to one of the forms that are suitable for built-in
* comparators (for instance take look to the \ref value2key).
* The reasons to not using custom comparators are:
* - The order of records could not be validated without your code.
* So `mdbx_chk` utility will reports "wrong order" errors
* and the `-i` option is required to ignore ones.
* - A records could not be ordered or sorted without your code.
* So mdbx_load utility should be used with `-a` option to preserve
* input data order.
* \see avoid_custom_comparators
*
* \returns A non-zero error value on failure and 0 on success,
* some possible errors are:
@@ -3554,8 +3614,10 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a,
LIBMDBX_API int mdbx_dbi_open(MDBX_txn *txn, const char *name,
MDBX_db_flags_t flags, MDBX_dbi *dbi);
/** \deprecated Please avoid using custom comparators
* and use mdbx_dbi_open() instead.
/** \deprecated Please
* \ref avoid_custom_comparators "avoid using custom comparators" and use
* \ref mdbx_dbi_open() instead.
*
* \ingroup c_dbi
*
* \param [in] txn transaction handle returned by \ref mdbx_txn_begin().
@@ -3571,7 +3633,9 @@ MDBX_DEPRECATED LIBMDBX_API int
mdbx_dbi_open_ex(MDBX_txn *txn, const char *name, MDBX_db_flags_t flags,
MDBX_dbi *dbi, MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp);
/** \defgroup value2key Value-to-Key functions to avoid custom comparators
/** \defgroup value2key Value-to-Key functions
* \brief Value-to-Key functions to
* \ref avoid_custom_comparators "avoid using custom comparators"
* \see key2value
* @{
*
@@ -3606,7 +3670,9 @@ MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_INLINE_API(uint32_t, mdbx_key_from_int32,
}
/** @} */
/** \defgroup key2value Key-to-Value functions to avoid custom comparators
/** \defgroup key2value Key-to-Value functions
* \brief Key-to-Value functions to
* \ref avoid_custom_comparators "avoid using custom comparators"
* \see value2key
* @{ */
MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int64_t
@@ -4542,6 +4608,7 @@ LIBMDBX_API int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
/** \brief Compare two keys according to a particular database.
* \ingroup c_crud
* \see MDBX_cmp_func
*
* This returns a comparison as if the two data items were keys in the
* specified database.
@@ -4566,6 +4633,7 @@ mdbx_get_keycmp(MDBX_db_flags_t flags);
/** \brief Compare two data items according to a particular database.
* \ingroup c_crud
* \see MDBX_cmp_func
*
* This returns a comparison as if the two items were data items of the
* specified database.

2618
mdbx.h++

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,9 @@
From 7834ae8fc834f5f7b98d45703079cd94e5402ed6 Mon Sep 17 00:00:00 2001
From f732fc79456f3b296543ab2625d35eeef2655618 Mon Sep 17 00:00:00 2001
From: Leonid Yuriev <leo@yuriev.ru>
Date: Fri, 27 Nov 2020 16:31:12 +0300
Cc: Heiko Thiery <heiko.thiery@gmail.com>, Thomas Petazzoni <thomas.petazzoni@bootlin.com>, Leonid Yuriev <leo@yuriev.ru
Subject: [PATCH v5 1/1] package/libmdbx: new package (library/database).
Date: Sun, 24 Oct 2021 20:13:33 +0300
Subject: [PATCH] package/libmdbx: new package (library/database).
This patch adds libmdbx v0.9.2:
This patch adds libmdbx v0.11.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.
@@ -13,44 +12,14 @@ This patch adds libmdbx v0.9.2:
- https://github.com/erthink/libmdbx
Signed-off-by: Leonid Yuriev <leo@yuriev.ru>
---
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.
Changes v4 -> v5:
- libmdbx version v0.9.1 -> v0.9.2 (released 2020-11-27)
- dropped all patch since not needed.
- cosmetic changes (suggested by Thomas Petazzoni <thomas.petazzoni@bootlin.com>).
- added dependence of BR2_TOOLCHAIN_HAS_SYNC_4 (suggested by Thomas Petazzoni <thomas.petazzoni@bootlin.com>).
- added dependence of !BR2_TOOLCHAIN_HAS_GCC_BUG_64735 (suggested by Thomas Petazzoni <thomas.petazzoni@bootlin.com>).
- take in account the BR2_SHARED_STATIC_LIBS (suggested by Thomas Petazzoni <thomas.petazzoni@bootlin.com>).
Signed-off-by: Leonid Yuriev <leo@yuriev.ru>
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
---
DEVELOPERS | 3 +++
package/Config.in | 1 +
package/libmdbx/Config.in | 45 ++++++++++++++++++++++++++++++++++++
package/libmdbx/libmdbx.hash | 5 ++++
package/libmdbx/libmdbx.mk | 33 ++++++++++++++++++++++++++
5 files changed, 87 insertions(+)
package/libmdbx/libmdbx.mk | 42 +++++++++++++++++++++++++++++++++
5 files changed, 96 insertions(+)
create mode 100644 package/libmdbx/Config.in
create mode 100644 package/libmdbx/libmdbx.hash
create mode 100644 package/libmdbx/libmdbx.mk
@@ -134,28 +103,28 @@ index 0000000000..d13f73938f
+ !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..0d3501f1d9
index 0000000000..c8b50f9ac3
--- /dev/null
+++ b/package/libmdbx/libmdbx.hash
@@ -0,0 +1,5 @@
+# Hashes from: https://github.com/erthink/libmdbx/releases/
+sha256 c35cc53d66d74ebfc86e39441ba26276541ac7892bf91dba1e70c83665a02767 libmdbx-amalgamated-0.9.2.tar.gz
+sha256 f954ba8c9768914a92c2b46aac0d66bec674dbb4d7b0f01e362ea2921746ddaa libmdbx-amalgamated-0.11.1.tar.gz
+
+# Locally calculated
+sha256 310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569 LICENSE
diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk
new file mode 100644
index 0000000000..f3720130ec
index 0000000000..02d00b1a5a
--- /dev/null
+++ b/package/libmdbx/libmdbx.mk
@@ -0,0 +1,33 @@
@@ -0,0 +1,42 @@
+################################################################################
+#
+# libmdbx
+#
+################################################################################
+
+LIBMDBX_VERSION = 0.9.2
+LIBMDBX_VERSION = 0.11.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
@@ -165,7 +134,12 @@ index 0000000000..f3720130ec
+LIBMDBX_STRIP_COMPONENTS = 0
+LIBMDBX_INSTALL_STAGING = YES
+
+LIBMDBX_CONF_OPTS = -DMDBX_INSTALL_MANPAGES=OFF -DBUILD_FOR_NATIVE_CPU=OFF \
+# Set CMAKE_BUILD_TYPE to Release to remove -Werror and avoid a build failure
+# with glibc < 2.12
+LIBMDBX_CONF_OPTS = \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DMDBX_INSTALL_MANPAGES=OFF \
+ -DBUILD_FOR_NATIVE_CPU=OFF \
+ -DMDBX_BUILD_CXX=$(if $(BR2_PACKAGE_LIBMDBX_CXX),ON,OFF) \
+ -DMDBX_BUILD_TOOLS=$(if $(BR2_PACKAGE_LIBMDBX_TOOLS),ON,OFF)
+
@@ -176,12 +150,16 @@ index 0000000000..f3720130ec
+endif
+
+ifeq ($(BR2_SHARED_LIBS)$(BR2_SHARED_STATIC_LIBS),y)
+LIBMDBX_CONF_OPTS += -DMDBX_BUILD_SHARED_LIBRARY=ON -DMDBX_LINK_TOOLS_NONSTATIC=ON
+LIBMDBX_CONF_OPTS += \
+ -DMDBX_BUILD_SHARED_LIBRARY=ON \
+ -DMDBX_LINK_TOOLS_NONSTATIC=ON
+else
+LIBMDBX_CONF_OPTS += -DMDBX_BUILD_SHARED_LIBRARY=OFF -DMDBX_LINK_TOOLS_NONSTATIC=OFF
+LIBMDBX_CONF_OPTS += \
+ -DMDBX_BUILD_SHARED_LIBRARY=OFF \
+ -DMDBX_LINK_TOOLS_NONSTATIC=OFF
+endif
+
+$(eval $(cmake-package))
--
2.29.2
2.33.1

View File

@@ -1,219 +0,0 @@
From 0bf9d06e8b090e2d9783d03074f3752ed708f6cf Mon Sep 17 00:00:00 2001
From: Leonid Yuriev <leo@yuriev.ru>
Date: Fri, 27 Nov 2020 16:31:12 +0300
Cc: Heiko Thiery <heiko.thiery@gmail.com>
Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Subject: [PATCH v5 0/1] cover letter for package/libmdbx: new package (library/database)
This patch adds libmdbx v0.9.2 and below is a brief overview of libmdbx.
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 +
package/libmdbx/Config.in | 45 ++++++++++++++++++++++++++++++++++++
package/libmdbx/libmdbx.hash | 5 ++++
package/libmdbx/libmdbx.mk | 33 ++++++++++++++++++++++++++
5 files changed, 87 insertions(+)
create mode 100644 package/libmdbx/Config.in
create mode 100644 package/libmdbx/libmdbx.hash
create mode 100644 package/libmdbx/libmdbx.mk
--
2.29.2

View File

@@ -1,34 +1,34 @@
N | MASK | ENV | TXN | DB | PUT | DBI | NODE | PAGE |
--|---------|-----------|--------------|----------|-----------|------------|---------|----------|
0 |0000 0001|ALLOC_CACHE|TXN_FINISHED | | |DBI_DIRTY |F_BIGDATA|P_BRANCH
1 |0000 0002|ALLOC_GC |TXN_ERROR |REVERSEKEY|F_SUBDATA |DBI_STALE |F_SUBDATA|P_LEAF
2 |0000 0004|ALLOC_NEW |TXN_DIRTY |DUPSORT | |DBI_FRESH |F_DUPDATA|P_OVERFLOW
3 |0000 0008|ALLOC_SLOT |TXN_SPILLS |INTEGERKEY| |DBI_CREAT | |P_META
4 |0000 0010| |TXN_HAS_CHILD |DUPFIXED |NOOVERWRITE|DBI_VALID | |P_BAD
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| | | | | | |P_SPILLED
14|0000 4000|NOSUBDIR | | | | | |P_LOOSE
15|0000 8000| | |DB_VALID |NOSPILL | | |P_FROZEN
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| |
N | MASK | ENV | TXN | DB | PUT | DBI | NODE | PAGE | MRESIZE |
--|---------|-----------|--------------|----------|-----------|------------|---------|----------|---------|
0 |0000 0001|ALLOC_CACHE|TXN_FINISHED | | |DBI_DIRTY |F_BIGDATA|P_BRANCH | |
1 |0000 0002|ALLOC_GC |TXN_ERROR |REVERSEKEY|F_SUBDATA |DBI_STALE |F_SUBDATA|P_LEAF | |
2 |0000 0004|ALLOC_NEW |TXN_DIRTY |DUPSORT | |DBI_FRESH |F_DUPDATA|P_OVERFLOW| |
3 |0000 0008|ALLOC_SLOT |TXN_SPILLS |INTEGERKEY| |DBI_CREAT | |P_META | |
4 |0000 0010| |TXN_HAS_CHILD |DUPFIXED |NOOVERWRITE|DBI_VALID | |P_BAD | |
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| _MAY_MOVE | | | | | | | <= |
9 |0000 0200| _MAY_UNMAP| | | | | | | <= |
10|0000 0400| | | | | | | | |
11|0000 0800| | | | | | | | |
12|0000 1000| | | | | | | | |
13|0000 2000| | | | | | |P_SPILLED | |
14|0000 4000|NOSUBDIR | | | | | |P_LOOSE | |
15|0000 8000| | |DB_VALID |NOSPILL | | |P_FROZEN | |
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| | | | | | | |

1958
src/core.c

File diff suppressed because it is too large Load Diff

View File

@@ -103,14 +103,6 @@
# endif
#endif /* __must_check_result */
#ifndef __maybe_unused
# if defined(__GNUC__) || __has_attribute(__unused__)
# define __maybe_unused __attribute__((__unused__))
# else
# define __maybe_unused
# endif
#endif /* __maybe_unused */
#if !defined(__noop) && !defined(_MSC_VER)
# define __noop(...) do {} while(0)
#endif /* __noop */
@@ -198,7 +190,7 @@
# elif defined(__GNUC__) || __has_attribute(__hot__)
# define __hot __attribute__((__hot__)) __optimize("O3")
# else
# define __hot __optimize("O3")
# define __hot __optimize("O3")
# endif
# else
# define __hot
@@ -256,7 +248,7 @@
#endif /* __anonymous_struct_extension__ */
#ifndef __Wpedantic_format_voidptr
static __inline __maybe_unused const void* MDBX_PURE_FUNCTION
MDBX_MAYBE_UNUSED MDBX_PURE_FUNCTION static __inline const void*
__Wpedantic_format_voidptr(const void* ptr) {return ptr;}
# define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
#endif /* __Wpedantic_format_voidptr */
@@ -312,11 +304,6 @@
# define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
#endif /* ARRAY_END */
#ifndef STRINGIFY
# define STRINGIFY_HELPER(x) #x
# define STRINGIFY(x) STRINGIFY_HELPER(x)
#endif /* STRINGIFY */
#define CONCAT(a,b) a##b
#define XCONCAT(a,b) CONCAT(a,b)
@@ -334,7 +321,7 @@
#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
#define FIXME "FIXME: " __FILE__ ", " STRINGIFY(__LINE__)
#define FIXME "FIXME: " __FILE__ ", " MDBX_STRINGIFY(__LINE__)
#ifndef STATIC_ASSERT_MSG
# if defined(static_assert)

View File

@@ -61,13 +61,26 @@
* Studio 2015 Update 3). But you could remove this #error and try to continue
* at your own risk. In such case please don't rise up an issues related ONLY to
* old compilers.
*
* NOTE:
* Unfortunately, there are several different builds of "Visual Studio" that
* are called "Visual Studio 2015 Update 3".
*
* The 190024234 is used here because it is minimal version of Visual Studio
* that was used for build and testing libmdbx in recent years. Soon this
* value will be increased to 19.0.24241.7, since build and testing using
* "Visual Studio 2015" will be performed only at https://ci.appveyor.com.
*
* Please ask Microsoft (but not us) for information about version differences
* and how to and where you can obtain the latest "Visual Studio 2015" build
* with all fixes.
*/
#error \
"At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#endif /* _CRT_SECURE_NO_WARNINGS */
#if _MSC_VER > 1800
#pragma warning(disable : 4464) /* relative include path contains '..' */
#endif
@@ -264,9 +277,7 @@ static __always_inline memory_order mo_c11_load(enum MDBX_memory_order fence) {
#ifndef __cplusplus
static __inline void mdbx_jitter4testing(bool tiny);
static __maybe_unused __always_inline void
MDBX_MAYBE_UNUSED static __always_inline void
mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
#ifdef MDBX_HAVE_C11ATOMICS
atomic_thread_fence(write ? mo_c11_store(order) : mo_c11_load(order));
@@ -278,7 +289,7 @@ mdbx_memory_fence(enum MDBX_memory_order order, bool write) {
#endif /* MDBX_HAVE_C11ATOMICS */
}
static __maybe_unused __always_inline uint32_t
MDBX_MAYBE_UNUSED static __always_inline uint32_t
atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
enum MDBX_memory_order order) {
STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
@@ -294,7 +305,7 @@ atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value,
return value;
}
static __maybe_unused __always_inline uint32_t
MDBX_MAYBE_UNUSED static __always_inline uint32_t
atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4);
#ifdef MDBX_HAVE_C11ATOMICS
@@ -309,70 +320,6 @@ atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) {
#endif /* MDBX_HAVE_C11ATOMICS */
}
static __maybe_unused __always_inline uint64_t
atomic_store64(MDBX_atomic_uint64_t *p, const uint64_t value,
enum MDBX_memory_order order) {
STATIC_ASSERT(sizeof(MDBX_atomic_uint64_t) == 8);
#if MDBX_64BIT_ATOMIC
#ifdef MDBX_HAVE_C11ATOMICS
assert(atomic_is_lock_free(MDBX_c11a_rw(uint64_t, p)));
atomic_store_explicit(MDBX_c11a_rw(uint64_t, p), value, mo_c11_store(order));
#else /* MDBX_HAVE_C11ATOMICS */
if (order != mo_Relaxed)
mdbx_compiler_barrier();
p->weak = value;
mdbx_memory_fence(order, true);
#endif /* MDBX_HAVE_C11ATOMICS */
#else /* !MDBX_64BIT_ATOMIC */
mdbx_compiler_barrier();
atomic_store32(&p->low, (uint32_t)value, mo_Relaxed);
mdbx_jitter4testing(true);
atomic_store32(&p->high, (uint32_t)(value >> 32), order);
mdbx_jitter4testing(true);
#endif /* !MDBX_64BIT_ATOMIC */
return value;
}
static __maybe_unused
#if MDBX_64BIT_ATOMIC
__always_inline
#endif /* MDBX_64BIT_ATOMIC */
uint64_t
atomic_load64(const MDBX_atomic_uint64_t *p,
enum MDBX_memory_order order) {
STATIC_ASSERT(sizeof(MDBX_atomic_uint64_t) == 8);
#if MDBX_64BIT_ATOMIC
#ifdef MDBX_HAVE_C11ATOMICS
assert(atomic_is_lock_free(MDBX_c11a_ro(uint64_t, p)));
return atomic_load_explicit(MDBX_c11a_ro(uint64_t, p), mo_c11_load(order));
#else /* MDBX_HAVE_C11ATOMICS */
mdbx_memory_fence(order, false);
const uint64_t value = p->weak;
if (order != mo_Relaxed)
mdbx_compiler_barrier();
return value;
#endif /* MDBX_HAVE_C11ATOMICS */
#else /* !MDBX_64BIT_ATOMIC */
mdbx_compiler_barrier();
uint64_t value = (uint64_t)atomic_load32(&p->high, order) << 32;
mdbx_jitter4testing(true);
value |= atomic_load32(&p->low, (order == mo_Relaxed) ? mo_Relaxed
: mo_AcquireRelease);
mdbx_jitter4testing(true);
for (;;) {
mdbx_compiler_barrier();
uint64_t again = (uint64_t)atomic_load32(&p->high, order) << 32;
mdbx_jitter4testing(true);
again |= atomic_load32(&p->low, (order == mo_Relaxed) ? mo_Relaxed
: mo_AcquireRelease);
mdbx_jitter4testing(true);
if (likely(value == again))
return value;
value = again;
}
#endif /* !MDBX_64BIT_ATOMIC */
}
#endif /* !__cplusplus */
/*----------------------------------------------------------------------------*/
@@ -384,7 +331,7 @@ static __maybe_unused
#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
/* FROZEN: The version number for a database's datafile format. */
#define MDBX_DATA_VERSION 2
#define MDBX_DATA_VERSION 3
/* The version number for a database's lockfile format. */
#define MDBX_LOCK_VERSION 4
@@ -437,7 +384,7 @@ typedef uint16_t indx_t;
/*----------------------------------------------------------------------------*/
/* Core structures for database and shared memory (i.e. format definition) */
#pragma pack(push, 1)
#pragma pack(push, 4)
/* Information about a single database in the environment. */
typedef struct MDBX_db {
@@ -488,8 +435,6 @@ typedef struct MDBX_meta {
MDBX_db mm_dbs[CORE_DBS]; /* first is free space, 2nd is main db */
/* The size of pages used in this DB */
#define mm_psize mm_dbs[FREE_DBI].md_xsize
/* Any persistent environment flags, see mdbx_env */
#define mm_flags mm_dbs[FREE_DBI].md_flags
MDBX_canary mm_canary;
#define MDBX_DATASIGN_NONE 0u
@@ -517,6 +462,8 @@ typedef struct MDBX_meta {
} MDBX_meta;
#pragma pack(1)
/* Common header for all page types. The page type depends on mp_flags.
*
* P_BRANCH and P_LEAF pages have unsorted 'MDBX_node's at the end, with
@@ -787,7 +734,11 @@ typedef struct MDBX_lockinfo {
#define MDBX_DATA_MAGIC \
((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + MDBX_DATA_VERSION)
#define MDBX_DATA_MAGIC_DEVEL ((MDBX_MAGIC << 8) + 255)
#define MDBX_DATA_MAGIC_LEGACY_COMPAT \
((MDBX_MAGIC << 8) + MDBX_PNL_ASCENDING * 64 + 2)
#define MDBX_DATA_MAGIC_LEGACY_DEVEL ((MDBX_MAGIC << 8) + 255)
#define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION)
@@ -818,15 +769,13 @@ typedef struct MDBX_lockinfo {
#if MDBX_WORDBITS >= 64
#define MAX_MAPSIZE MAX_MAPSIZE64
#define MDBX_READERS_LIMIT \
((MAX_PAGESIZE - sizeof(MDBX_lockinfo)) / sizeof(MDBX_reader))
#define MDBX_PGL_LIMIT ((size_t)MAX_PAGENO)
#else
#define MDBX_READERS_LIMIT 1024
#define MAX_MAPSIZE MAX_MAPSIZE32
#define MDBX_PGL_LIMIT (MAX_MAPSIZE32 / MIN_PAGESIZE)
#endif /* MDBX_WORDBITS */
#define MDBX_READERS_LIMIT 32767
#define MDBX_RADIXSORT_THRESHOLD 333
/*----------------------------------------------------------------------------*/
@@ -921,15 +870,7 @@ typedef struct MDBX_dbx {
* Every operation requires a transaction handle. */
struct MDBX_txn {
#define MDBX_MT_SIGNATURE UINT32_C(0x93D53A31)
size_t mt_signature;
MDBX_txn *mt_parent; /* parent of a nested txn */
/* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
MDBX_txn *mt_child;
MDBX_geo mt_geo;
/* next unallocated page */
#define mt_next_pgno mt_geo.next
/* corresponding to the current size of datafile */
#define mt_end_pgno mt_geo.now
uint32_t mt_signature;
/* Transaction Flags */
/* mdbx_txn_begin() flags */
@@ -958,8 +899,17 @@ struct MDBX_txn {
MDBX_SHRINK_ALLOWED)
#error "Oops, some flags overlapped or wrong"
#endif
uint32_t mt_flags;
MDBX_txn *mt_parent; /* parent of a nested txn */
/* Nested txn under this txn, set together with flag MDBX_TXN_HAS_CHILD */
MDBX_txn *mt_child;
MDBX_geo mt_geo;
/* next unallocated page */
#define mt_next_pgno mt_geo.next
/* corresponding to the current size of datafile */
#define mt_end_pgno mt_geo.now
unsigned mt_flags;
/* The ID of this transaction. IDs are integers incrementing from 1.
* Only committed write transactions increment the ID. If a transaction
* aborts, the ID may be re-used by the next writer. */
@@ -1147,7 +1097,7 @@ struct MDBX_env {
mdbx_thread_key_t me_txkey; /* thread-key for readers */
char *me_pathname; /* path to the DB files */
void *me_pbuf; /* scratch area for DUPSORT put() */
MDBX_txn *me_txn0; /* prealloc'd write transaction */
MDBX_txn *me_txn0; /* preallocated write transaction */
MDBX_dbx *me_dbxs; /* array of static DB info */
uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
@@ -1252,6 +1202,15 @@ extern uint8_t mdbx_runtime_flags;
extern uint8_t mdbx_loglevel;
extern MDBX_debug_func *mdbx_debug_logger;
MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) {
#if MDBX_DEBUG
if (MDBX_DBG_JITTER & mdbx_runtime_flags)
mdbx_osal_jitter(tiny);
#else
(void)tiny;
#endif
}
MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
mdbx_debug_log(int level, const char *function, int line, const char *fmt,
...) MDBX_PRINTF_ARGS(4, 5);
@@ -1379,7 +1338,7 @@ void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier()
#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
static __maybe_unused __inline void
MDBX_MAYBE_UNUSED static __inline void
mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
#if MDBX_MMAP_INCOHERENT_FILE_WRITE
char *const begin = (char *)(-pagesize & (intptr_t)addr);
@@ -1421,15 +1380,6 @@ MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void);
MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void);
MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
static __maybe_unused __inline void mdbx_jitter4testing(bool tiny) {
#if MDBX_DEBUG
if (MDBX_DBG_JITTER & mdbx_runtime_flags)
mdbx_osal_jitter(tiny);
#else
(void)tiny;
#endif
}
#endif /* !__cplusplus */
#define MDBX_IS_ERROR(rc) \
@@ -1564,45 +1514,46 @@ typedef struct MDBX_node {
* | 1, a > b
* \
*/
#if 1
#ifndef __e2k__
/* LY: fast enough on most systems */
#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
#else
/* LY: more parallelable on VLIW Elbrus */
#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
#endif
/* Do not spill pages to disk if txn is getting full, may fail instead */
#define MDBX_NOSPILL 0x8000
MDBX_NOTHROW_CONST_FUNCTION static __maybe_unused __inline pgno_t
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
pgno_add(pgno_t base, pgno_t augend) {
assert(base <= MAX_PAGENO);
return (augend < MAX_PAGENO - base) ? base + augend : MAX_PAGENO;
}
MDBX_NOTHROW_CONST_FUNCTION static __maybe_unused __inline pgno_t
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
pgno_sub(pgno_t base, pgno_t subtrahend) {
assert(base >= MIN_PAGENO);
return (subtrahend < base - MIN_PAGENO) ? base - subtrahend : MIN_PAGENO;
}
MDBX_NOTHROW_CONST_FUNCTION static __always_inline __maybe_unused bool
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
is_powerof2(size_t x) {
return (x & (x - 1)) == 0;
}
MDBX_NOTHROW_CONST_FUNCTION static __always_inline __maybe_unused size_t
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
floor_powerof2(size_t value, size_t granularity) {
assert(is_powerof2(granularity));
return value & ~(granularity - 1);
}
MDBX_NOTHROW_CONST_FUNCTION static __always_inline __maybe_unused size_t
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline size_t
ceil_powerof2(size_t value, size_t granularity) {
return floor_powerof2(value + granularity - 1, granularity);
}
MDBX_NOTHROW_CONST_FUNCTION static __maybe_unused unsigned
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned
log2n_powerof2(size_t value) {
assert(value > 0 && value < INT32_MAX && is_powerof2(value));
assert((value & -(int32_t)value) == value);
@@ -1632,7 +1583,7 @@ log2n_powerof2(size_t value) {
#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
#if !defined(__cplusplus) || CONSTEXPR_ENUM_FLAGS_OPERATIONS
static __maybe_unused void static_checks(void) {
MDBX_MAYBE_UNUSED static void static_checks(void) {
STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
"Oops, MDBX_MAX_DBI or CORE_DBS?");
STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
@@ -1647,3 +1598,17 @@ static __maybe_unused void static_checks(void) {
#ifdef __cplusplus
}
#endif
#define MDBX_ASAN_POISON_MEMORY_REGION(addr, size) \
do { \
mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr), \
(size_t)(size), __LINE__); \
ASAN_POISON_MEMORY_REGION(addr, size); \
} while (0)
#define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size) \
do { \
mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr), \
(size_t)(size), __LINE__); \
ASAN_UNPOISON_MEMORY_REGION(addr, size); \
} while (0)

View File

@@ -29,33 +29,27 @@ uint32_t mdbx_linux_kernel_version;
bool mdbx_RunningOnWSL1;
#endif /* xMDBX_ALLOY */
static __cold uint8_t probe_for_WSL(const char *tag) {
__cold static uint8_t probe_for_WSL(const char *tag) {
const char *const WSL = strstr(tag, "WSL");
if (WSL && WSL[3] >= '2' && WSL[3] <= '9')
return WSL[3] - '0';
const char *const wsl = strstr(tag, "wsl");
if (wsl && wsl[3] >= '2' && wsl[3] <= '9')
return wsl[3] - '0';
return (WSL || wsl || strcasestr(tag, "Microsoft")) ? 1 : 0;
if (WSL || wsl || strcasestr(tag, "Microsoft"))
/* Expecting no new kernel within WSL1, either it will explicitly
* marked by an appropriate WSL-version hint. */
return (mdbx_linux_kernel_version < /* 4.19.x */ 0x04130000) ? 1 : 2;
return 0;
}
#endif /* Linux */
static __cold __attribute__((__constructor__)) void
__cold static __attribute__((__constructor__)) void
mdbx_global_constructor(void) {
#if defined(__linux__) || defined(__gnu_linux__)
struct utsname buffer;
if (uname(&buffer) == 0) {
/* "Official" way of detecting WSL1 but not WSL2
* https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
*
* WARNING: False negative detection of WSL1 will result in DATA LOSS!
* So, the REQUIREMENTS for this code:
* 1. MUST detect WSL1 without false-negatives.
* 2. DESIRABLE detect WSL2 but without the risk of violating the first. */
mdbx_RunningOnWSL1 = probe_for_WSL(buffer.version) == 1 ||
probe_for_WSL(buffer.sysname) == 1 ||
probe_for_WSL(buffer.release) == 1;
int i = 0;
char *p = buffer.release;
while (*p && i < 4) {
@@ -71,13 +65,23 @@ mdbx_global_constructor(void) {
++p;
}
}
/* "Official" way of detecting WSL1 but not WSL2
* https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
*
* WARNING: False negative detection of WSL1 will result in DATA LOSS!
* So, the REQUIREMENTS for this code:
* 1. MUST detect WSL1 without false-negatives.
* 2. DESIRABLE detect WSL2 but without the risk of violating the first. */
mdbx_RunningOnWSL1 = probe_for_WSL(buffer.version) == 1 ||
probe_for_WSL(buffer.sysname) == 1 ||
probe_for_WSL(buffer.release) == 1;
}
#endif /* Linux */
mdbx_rthc_global_init();
}
static __cold __attribute__((__destructor__)) void
__cold static __attribute__((__destructor__)) void
mdbx_global_destructor(void) {
mdbx_rthc_global_dtor();
}
@@ -141,7 +145,7 @@ mdbx_global_destructor(void) {
#if MDBX_USE_OFDLOCKS
static int op_setlk, op_setlkw, op_getlk;
static void __cold choice_fcntl() {
__cold static void choice_fcntl() {
assert(!op_setlk && !op_setlkw && !op_getlk);
if ((mdbx_runtime_flags & MDBX_DBG_LEGACY_MULTIOPEN) == 0
#if defined(__linux__) || defined(__gnu_linux__)
@@ -194,6 +198,22 @@ static int lck_op(mdbx_filehandle_t fd, int cmd, int lck, off_t offset,
return MDBX_SUCCESS;
}
rc = errno;
#if MDBX_USE_OFDLOCKS
if (rc == EINVAL &&
(cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW || cmd == F_OFD_GETLK)) {
/* fallback to non-OFD locks */
if (cmd == F_OFD_SETLK)
cmd = F_SETLK;
else if (cmd == F_OFD_SETLKW)
cmd = F_SETLKW;
else
cmd = F_GETLK;
op_setlk = F_SETLK;
op_setlkw = F_SETLKW;
op_getlk = F_GETLK;
continue;
}
#endif /* MDBX_USE_OFDLOCKS */
if (rc != EINTR || cmd == op_setlkw) {
mdbx_assert(nullptr, MDBX_IS_ERROR(rc));
return rc;
@@ -314,7 +334,7 @@ static int check_fstat(MDBX_env *env) {
return rc;
}
MDBX_INTERNAL_FUNC int __cold mdbx_lck_seize(MDBX_env *env) {
__cold MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env) {
assert(env->me_lazy_fd != INVALID_HANDLE_VALUE);
if (unlikely(mdbx_getpid() != env->me_pid))
return MDBX_PANIC;
@@ -467,7 +487,7 @@ MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env) {
return rc;
}
MDBX_INTERNAL_FUNC int __cold mdbx_lck_destroy(MDBX_env *env,
__cold MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
MDBX_env *inprocess_neighbor) {
if (unlikely(mdbx_getpid() != env->me_pid))
return MDBX_PANIC;
@@ -554,7 +574,7 @@ MDBX_INTERNAL_FUNC int __cold mdbx_lck_destroy(MDBX_env *env,
/*---------------------------------------------------------------------------*/
MDBX_INTERNAL_FUNC int __cold mdbx_lck_init(MDBX_env *env,
__cold MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
MDBX_env *inprocess_neighbor,
int global_uniqueness_flag) {
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
@@ -701,7 +721,7 @@ bailout:
#endif /* MDBX_LOCKING > 0 */
}
static int __cold mdbx_ipclock_failed(MDBX_env *env, mdbx_ipclock_t *ipc,
__cold static int mdbx_ipclock_failed(MDBX_env *env, mdbx_ipclock_t *ipc,
const int err) {
int rc = err;
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2008 || MDBX_LOCKING == MDBX_LOCKING_SYSV

View File

@@ -260,6 +260,7 @@ static int suspend_and_append(mdbx_handle_array_t **array,
MDBX_INTERNAL_FUNC int
mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
mdbx_assert(env, (env->me_flags & MDBX_NOTLS) == 0);
const uintptr_t CurrentTid = GetCurrentThreadId();
int rc;
if (env->me_lck_mmap.lck) {
@@ -277,12 +278,6 @@ mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
if (reader->mr_tid.weak == CurrentTid ||
reader->mr_tid.weak == WriteTxnOwner)
goto skip_lck;
if (env->me_flags & MDBX_NOTLS) {
/* Skip duplicates in no-tls mode */
for (const MDBX_reader *scan = reader; --scan >= begin;)
if (scan->mr_tid.weak == reader->mr_tid.weak)
goto skip_lck;
}
rc = suspend_and_append(array, (mdbx_tid_t)reader->mr_tid.weak);
if (rc != MDBX_SUCCESS) {

View File

@@ -12,6 +12,8 @@ mdbx_stat \- MDBX environment status tool
[\c
.BR \-q ]
[\c
.BR \-p ]
[\c
.BR \-e ]
[\c
.BR \-f [ f [ f ]]]
@@ -35,13 +37,18 @@ Write the library version number to the standard output, and exit.
.BR \-q
Be quiet.
.TP
.BR \-p
Display overall statistics of page operations of all (running, completed
and aborted) transactions in the current multi-process session (since the
first process opened the database after everyone had previously closed it).
.TP
.BR \-e
Display information about the database environment.
.TP
.BR \-f
Display information about the environment freelist.
If \fB\-ff\fP is given, summarize each freelist entry.
If \fB\-fff\fP is given, display the full list of page IDs in the freelist.
Display information about the environment GC.
If \fB\-ff\fP is given, summarize each GC/freelist entry.
If \fB\-fff\fP is given, display the full list of page IDs in the GC/freelist.
.TP
.BR \-r
Display information about the environment reader table.

View File

@@ -5,9 +5,9 @@
// Non-inline part of the libmdbx C++ API (preliminary)
//
#ifdef _MSC_VER
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#endif /* _CRT_SECURE_NO_WARNINGS */
#include "../mdbx.h++"
@@ -124,7 +124,7 @@ public:
//------------------------------------------------------------------------------
__cold std::string format_va(const char *fmt, va_list ap) {
__cold std::string format_va(const char *fmt, va_list ap) {
va_list ones;
va_copy(ones, ap);
#ifdef _MSC_VER
@@ -145,7 +145,7 @@ __cold std::string format_va(const char *fmt, va_list ap) {
return result;
}
__cold std::string format(const char *fmt, ...) {
__cold std::string format(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
std::string result = format_va(fmt, ap);
@@ -166,15 +166,15 @@ public:
virtual ~bug() noexcept;
};
__cold bug::bug(const trouble_location &location) noexcept
__cold bug::bug(const trouble_location &location) noexcept
: std::runtime_error(format("mdbx.bug: %s.%s at %s:%u", location.function(),
location.condition(), location.filename(),
location.line())),
location_(location) {}
__cold bug::~bug() noexcept {}
__cold bug::~bug() noexcept {}
[[noreturn]] __cold void raise_bug(const trouble_location &what_and_where) {
[[noreturn]] __cold void raise_bug(const trouble_location &what_and_where) {
throw bug(what_and_where);
}
@@ -188,7 +188,7 @@ __cold bug::~bug() noexcept {}
#define ENSURE(condition) \
do \
if (MDBX_UNLIKELY(!(condition))) \
RAISE_BUG(__LINE__, #condition, __func__, __FILE__); \
MDBX_CXX20_UNLIKELY RAISE_BUG(__LINE__, #condition, __func__, __FILE__); \
while (0)
#define NOT_IMPLEMENTED() \
@@ -204,7 +204,8 @@ template <typename PATH> struct path_to_pchar {
operator const char *() const { return str.c_str(); }
};
template <typename PATH> PATH pchar_to_path(const char *c_str) {
template <typename PATH>
MDBX_MAYBE_UNUSED PATH pchar_to_path(const char *c_str) {
return PATH(c_str);
}
@@ -241,7 +242,8 @@ template <> struct path_to_pchar<std::wstring> {
operator const char *() const { return str.c_str(); }
};
template <> std::wstring pchar_to_path<std::wstring>(const char *c_str) {
template <>
MDBX_MAYBE_UNUSED std::wstring pchar_to_path<std::wstring>(const char *c_str) {
std::wstring wstr;
if (c_str && *c_str) {
const int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str,
@@ -266,16 +268,22 @@ namespace mdbx {
[[noreturn]] __cold void throw_max_length_exceeded() {
throw std::length_error(
"mdbx:: exceeded the maximal length of data/slice/buffer");
"mdbx:: Exceeded the maximal length of data/slice/buffer.");
}
[[noreturn]] __cold void throw_too_small_target_buffer() {
throw std::length_error("mdbx:: the target buffer is too small");
throw std::length_error("mdbx:: The target buffer is too small.");
}
[[noreturn]] __cold void throw_out_range() {
throw std::out_of_range("mdbx:: slice or buffer method was called with "
"an argument that exceeds the length");
throw std::out_of_range("mdbx:: Slice or buffer method was called with "
"an argument that exceeds the length.");
}
[[noreturn]] __cold void throw_allocators_mismatch() {
throw std::logic_error(
"mdbx:: An allocators mismatch, so an object could not be transferred "
"into an incompatible memory allocation scheme.");
}
__cold exception::exception(const ::mdbx::error &error) noexcept
@@ -336,7 +344,7 @@ __cold const char *error::what() const noexcept {
switch (code()) {
#define ERROR_CASE(CODE) \
case CODE: \
return STRINGIFY(CODE)
return MDBX_STRINGIFY(CODE)
ERROR_CASE(MDBX_ENODATA);
ERROR_CASE(MDBX_EINVAL);
ERROR_CASE(MDBX_EACCESS);
@@ -472,15 +480,15 @@ bool slice::is_printable(bool disable_utf8) const noexcept {
F0, F1, F1, F1, F4, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_ // f0
};
if (length() < 1)
return false;
if (MDBX_UNLIKELY(length() < 1))
MDBX_CXX20_UNLIKELY return false;
auto src = byte_ptr();
const auto end = src + length();
if (MDBX_UNLIKELY(disable_utf8)) {
do
if (MDBX_UNLIKELY((P_ & map[*src]) == 0))
return false;
MDBX_CXX20_UNLIKELY return false;
while (++src < end);
return true;
}
@@ -491,35 +499,35 @@ bool slice::is_printable(bool disable_utf8) const noexcept {
const auto second_to = range_to[bits & second_range_mask];
switch (bits >> LS) {
default:
return false;
MDBX_CXX20_UNLIKELY return false;
case 1:
src += 1;
continue;
case 2:
if (unlikely(src + 1 >= end))
return false;
if (unlikely(src[1] < second_from || src[1] > second_to))
return false;
if (MDBX_UNLIKELY(src + 1 >= end))
MDBX_CXX20_UNLIKELY return false;
if (MDBX_UNLIKELY(src[1] < second_from || src[1] > second_to))
MDBX_CXX20_UNLIKELY return false;
src += 2;
continue;
case 3:
if (unlikely(src + 3 >= end))
return false;
if (unlikely(src[1] < second_from || src[1] > second_to))
return false;
if (unlikely(src[2] < 0x80 || src[2] > 0xBF))
return false;
if (MDBX_UNLIKELY(src + 3 >= end))
MDBX_CXX20_UNLIKELY return false;
if (MDBX_UNLIKELY(src[1] < second_from || src[1] > second_to))
MDBX_CXX20_UNLIKELY return false;
if (MDBX_UNLIKELY(src[2] < 0x80 || src[2] > 0xBF))
MDBX_CXX20_UNLIKELY return false;
src += 3;
continue;
case 4:
if (unlikely(src + 4 >= end))
return false;
if (unlikely(src[1] < second_from || src[1] > second_to))
return false;
if (unlikely(src[2] < 0x80 || src[2] > 0xBF))
return false;
if (unlikely(src[3] < 0x80 || src[3] > 0xBF))
return false;
if (MDBX_UNLIKELY(src + 4 >= end))
MDBX_CXX20_UNLIKELY return false;
if (MDBX_UNLIKELY(src[1] < second_from || src[1] > second_to))
MDBX_CXX20_UNLIKELY return false;
if (MDBX_UNLIKELY(src[2] < 0x80 || src[2] > 0xBF))
MDBX_CXX20_UNLIKELY return false;
if (MDBX_UNLIKELY(src[3] < 0x80 || src[3] > 0xBF))
MDBX_CXX20_UNLIKELY return false;
src += 4;
continue;
}
@@ -530,15 +538,14 @@ bool slice::is_printable(bool disable_utf8) const noexcept {
//------------------------------------------------------------------------------
char *slice::to_hex(char *__restrict dest, size_t dest_size, bool uppercase,
unsigned wrap_width) const {
if (MDBX_UNLIKELY(to_hex_bytes(wrap_width) > dest_size))
throw_too_small_target_buffer();
char *to_hex::write_bytes(char *__restrict dest, size_t dest_size) const {
if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
auto src = byte_ptr();
auto src = source.byte_ptr();
const char alphabase = (uppercase ? 'A' : 'a') - 10;
auto line = dest;
for (const auto end = src + length(); src != end; ++src) {
for (const auto end = source.end_byte_ptr(); src != end; ++src) {
const int8_t hi = *src >> 4;
const int8_t lo = *src & 15;
dest[0] = char(alphabase + hi + (((hi - 10) >> 7) & -7));
@@ -552,16 +559,15 @@ char *slice::to_hex(char *__restrict dest, size_t dest_size, bool uppercase,
return dest;
}
byte *slice::from_hex(byte *__restrict dest, size_t dest_size,
bool ignore_spaces) const {
if (MDBX_UNLIKELY(length() % 2 && !ignore_spaces))
throw std::domain_error(
char *from_hex::write_bytes(char *__restrict dest, size_t dest_size) const {
if (MDBX_UNLIKELY(source.length() % 2 && !ignore_spaces))
MDBX_CXX20_UNLIKELY throw std::domain_error(
"mdbx::from_hex:: odd length of hexadecimal string");
if (MDBX_UNLIKELY(from_hex_bytes() > dest_size))
throw_too_small_target_buffer();
if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
auto src = byte_ptr();
for (auto left = length(); left > 0;) {
auto src = source.byte_ptr();
for (auto left = source.length(); left > 0;) {
if (MDBX_UNLIKELY(*src <= ' ') &&
MDBX_LIKELY(ignore_spaces && isspace(*src))) {
++src;
@@ -570,7 +576,8 @@ byte *slice::from_hex(byte *__restrict dest, size_t dest_size,
}
if (MDBX_UNLIKELY(left < 1 || !isxdigit(src[0]) || !isxdigit(src[1])))
throw std::domain_error("mdbx::from_hex:: invalid hexadecimal string");
MDBX_CXX20_UNLIKELY throw std::domain_error(
"mdbx::from_hex:: invalid hexadecimal string");
int8_t hi = src[0];
hi = (hi | 0x20) - 'a';
@@ -587,13 +594,13 @@ byte *slice::from_hex(byte *__restrict dest, size_t dest_size,
return dest;
}
bool slice::is_hex(bool ignore_spaces) const noexcept {
if (MDBX_UNLIKELY(length() % 2 && !ignore_spaces))
return false;
bool from_hex::is_erroneous() const noexcept {
if (MDBX_UNLIKELY(source.length() % 2 && !ignore_spaces))
MDBX_CXX20_UNLIKELY return true;
bool got = false;
auto src = byte_ptr();
for (auto left = length(); left > 0;) {
auto src = source.byte_ptr();
for (auto left = source.length(); left > 0;) {
if (MDBX_UNLIKELY(*src <= ' ') &&
MDBX_LIKELY(ignore_spaces && isspace(*src))) {
++src;
@@ -602,13 +609,13 @@ bool slice::is_hex(bool ignore_spaces) const noexcept {
}
if (MDBX_UNLIKELY(left < 1 || !isxdigit(src[0]) || !isxdigit(src[1])))
return false;
MDBX_CXX20_UNLIKELY return true;
got = true;
src += 2;
left -= 2;
}
return got;
return !got;
}
//------------------------------------------------------------------------------
@@ -656,13 +663,12 @@ static inline char b58_8to11(uint64_t &v) noexcept {
return b58_alphabet[i];
}
char *slice::to_base58(char *__restrict dest, size_t dest_size,
unsigned wrap_width) const {
if (MDBX_UNLIKELY(to_base58_bytes(wrap_width) > dest_size))
throw_too_small_target_buffer();
char *to_base58::write_bytes(char *__restrict dest, size_t dest_size) const {
if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
auto src = byte_ptr();
size_t left = length();
auto src = source.byte_ptr();
size_t left = source.length();
auto line = dest;
while (MDBX_LIKELY(left > 7)) {
left -= 8;
@@ -739,13 +745,12 @@ static inline signed char b58_11to8(uint64_t &v, const byte c) noexcept {
return m;
}
byte *slice::from_base58(byte *__restrict dest, size_t dest_size,
bool ignore_spaces) const {
if (MDBX_UNLIKELY(from_base58_bytes() > dest_size))
throw_too_small_target_buffer();
char *from_base58::write_bytes(char *__restrict dest, size_t dest_size) const {
if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
auto src = byte_ptr();
for (auto left = length(); left > 0;) {
auto src = source.byte_ptr();
for (auto left = source.length(); left > 0;) {
if (MDBX_UNLIKELY(isspace(*src)) && ignore_spaces) {
++src;
--left;
@@ -760,7 +765,7 @@ byte *slice::from_base58(byte *__restrict dest, size_t dest_size,
b58_11to8(v, src[6]) | b58_11to8(v, src[7]) |
b58_11to8(v, src[8]) | b58_11to8(v, src[9]) |
b58_11to8(v, src[10])) < 0))
goto bailout;
MDBX_CXX20_UNLIKELY goto bailout;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
v = bswap64(v);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
@@ -775,14 +780,14 @@ byte *slice::from_base58(byte *__restrict dest, size_t dest_size,
}
constexpr unsigned invalid_length_mask = 1 << 1 | 1 << 4 | 1 << 8;
if (invalid_length_mask & (1 << left))
goto bailout;
if (MDBX_UNLIKELY(invalid_length_mask & (1 << left)))
MDBX_CXX20_UNLIKELY goto bailout;
uint64_t v = 1;
unsigned parrots = 0;
do {
if (MDBX_UNLIKELY(b58_11to8(v, *src++) < 0))
goto bailout;
MDBX_CXX20_UNLIKELY goto bailout;
parrots += 32;
} while (--left);
@@ -799,10 +804,10 @@ bailout:
throw std::domain_error("mdbx::from_base58:: invalid base58 string");
}
bool slice::is_base58(bool ignore_spaces) const noexcept {
bool from_base58::is_erroneous() const noexcept {
bool got = false;
auto src = byte_ptr();
for (auto left = length(); left > 0;) {
auto src = source.byte_ptr();
for (auto left = source.length(); left > 0;) {
if (MDBX_UNLIKELY(*src <= ' ') &&
MDBX_LIKELY(ignore_spaces && isspace(*src))) {
++src;
@@ -815,7 +820,7 @@ bool slice::is_base58(bool ignore_spaces) const noexcept {
b58_map[src[3]] | b58_map[src[4]] | b58_map[src[5]] |
b58_map[src[6]] | b58_map[src[7]] | b58_map[src[8]] |
b58_map[src[9]] | b58_map[src[10]]) < 0))
return false;
MDBX_CXX20_UNLIKELY return true;
src += 11;
left -= 11;
got = true;
@@ -828,12 +833,12 @@ bool slice::is_base58(bool ignore_spaces) const noexcept {
do
if (MDBX_UNLIKELY(b58_map[*src++] < 0))
return false;
MDBX_CXX20_UNLIKELY return true;
while (--left);
got = true;
break;
}
return got;
return !got;
}
//------------------------------------------------------------------------------
@@ -852,13 +857,12 @@ static inline void b64_3to4(const byte x, const byte y, const byte z,
dest[3] = alphabet[z & 0x3f];
}
char *slice::to_base64(char *__restrict dest, size_t dest_size,
unsigned wrap_width) const {
if (MDBX_UNLIKELY(to_base64_bytes(wrap_width) > dest_size))
throw_too_small_target_buffer();
char *to_base64::write_bytes(char *__restrict dest, size_t dest_size) const {
if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
auto src = byte_ptr();
size_t left = length();
auto src = source.byte_ptr();
size_t left = source.length();
auto line = dest;
while (true) {
switch (left) {
@@ -908,22 +912,22 @@ static const signed char b64_map[256] = {
static inline signed char b64_4to3(signed char a, signed char b, signed char c,
signed char d,
byte *__restrict dest) noexcept {
char *__restrict dest) noexcept {
dest[0] = byte((a << 2) + ((b & 0x30) >> 4));
dest[1] = byte(((b & 0xf) << 4) + ((c & 0x3c) >> 2));
dest[2] = byte(((c & 0x3) << 6) + d);
return a | b | c | d;
}
byte *slice::from_base64(byte *__restrict dest, size_t dest_size,
bool ignore_spaces) const {
if (MDBX_UNLIKELY(length() % 4 && !ignore_spaces))
throw std::domain_error("mdbx::from_base64:: odd length of base64 string");
if (MDBX_UNLIKELY(from_base64_bytes() > dest_size))
throw_too_small_target_buffer();
char *from_base64::write_bytes(char *__restrict dest, size_t dest_size) const {
if (MDBX_UNLIKELY(source.length() % 4 && !ignore_spaces))
MDBX_CXX20_UNLIKELY throw std::domain_error(
"mdbx::from_base64:: odd length of base64 string");
if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
auto src = byte_ptr();
for (auto left = length(); left > 0;) {
auto src = source.byte_ptr();
for (auto left = source.length(); left > 0;) {
if (MDBX_UNLIKELY(*src <= ' ') &&
MDBX_LIKELY(ignore_spaces && isspace(*src))) {
++src;
@@ -931,10 +935,11 @@ byte *slice::from_base64(byte *__restrict dest, size_t dest_size,
continue;
}
if (MDBX_UNLIKELY(left < 3)) {
bailout:
throw std::domain_error("mdbx::from_base64:: invalid base64 string");
}
if (MDBX_UNLIKELY(left < 3))
MDBX_CXX20_UNLIKELY {
bailout:
throw std::domain_error("mdbx::from_base64:: invalid base64 string");
}
const signed char a = b64_map[src[0]], b = b64_map[src[1]],
c = b64_map[src[2]], d = b64_map[src[3]];
if (MDBX_UNLIKELY(b64_4to3(a, b, c, d, dest) < 0)) {
@@ -944,7 +949,7 @@ byte *slice::from_base64(byte *__restrict dest, size_t dest_size,
if (c == d)
return dest + 1;
}
goto bailout;
MDBX_CXX20_UNLIKELY goto bailout;
}
src += 4;
left -= 4;
@@ -952,13 +957,13 @@ byte *slice::from_base64(byte *__restrict dest, size_t dest_size,
return dest;
}
bool slice::is_base64(bool ignore_spaces) const noexcept {
if (MDBX_UNLIKELY(length() % 4 && !ignore_spaces))
return false;
bool from_base64::is_erroneous() const noexcept {
if (MDBX_UNLIKELY(source.length() % 4 && !ignore_spaces))
MDBX_CXX20_UNLIKELY return true;
bool got = false;
auto src = byte_ptr();
for (auto left = length(); left > 0;) {
auto src = source.byte_ptr();
for (auto left = source.length(); left > 0;) {
if (MDBX_UNLIKELY(*src <= ' ') &&
MDBX_LIKELY(ignore_spaces && isspace(*src))) {
++src;
@@ -967,26 +972,28 @@ bool slice::is_base64(bool ignore_spaces) const noexcept {
}
if (MDBX_UNLIKELY(left < 3))
return false;
MDBX_CXX20_UNLIKELY return false;
const signed char a = b64_map[src[0]], b = b64_map[src[1]],
c = b64_map[src[2]], d = b64_map[src[3]];
if (MDBX_UNLIKELY((a | b | c | d) < 0)) {
if (left == 4 && (a | b) >= 0 && d == EQ && (c >= 0 || c == d))
if (MDBX_UNLIKELY((a | b | c | d) < 0))
MDBX_CXX20_UNLIKELY {
if (left == 4 && (a | b) >= 0 && d == EQ && (c >= 0 || c == d))
return false;
return true;
return false;
}
}
got = true;
src += 4;
left -= 4;
}
return got;
return !got;
}
//------------------------------------------------------------------------------
template class LIBMDBX_API_TYPE buffer<legacy_allocator>;
#if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L
#if defined(__cpp_lib_memory_resource) && \
__cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI
template class LIBMDBX_API_TYPE buffer<polymorphic_allocator>;
#endif /* __cpp_lib_memory_resource >= 201603L */
@@ -1183,9 +1190,9 @@ static inline MDBX_env *create_env() {
}
env_managed::~env_managed() noexcept {
if (handle_)
error::success_or_panic(::mdbx_env_close(handle_), "mdbx::~env()",
"mdbx_env_close");
if (MDBX_UNLIKELY(handle_))
MDBX_CXX20_UNLIKELY error::success_or_panic(
::mdbx_env_close(handle_), "mdbx::~env()", "mdbx_env_close");
}
void env_managed::close(bool dont_sync) {
@@ -1193,12 +1200,12 @@ void env_managed::close(bool dont_sync) {
static_cast<MDBX_error_t>(::mdbx_env_close_ex(handle_, dont_sync));
switch (rc.code()) {
case MDBX_EBADSIGN:
handle_ = nullptr;
MDBX_CXX20_UNLIKELY handle_ = nullptr;
__fallthrough /* fall through */;
default:
rc.throw_exception();
MDBX_CXX20_UNLIKELY rc.throw_exception();
case MDBX_SUCCESS:
handle_ = nullptr;
MDBX_CXX20_LIKELY handle_ = nullptr;
}
}
@@ -1220,7 +1227,7 @@ __cold env_managed::env_managed(const ::std::filesystem::path &pathname,
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
error::throw_exception(MDBX_INCOMPATIBLE);
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
__cold env_managed::env_managed(const ::std::filesystem::path &pathname,
@@ -1236,7 +1243,7 @@ __cold env_managed::env_managed(const ::std::filesystem::path &pathname,
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
error::throw_exception(MDBX_INCOMPATIBLE);
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
#endif /* MDBX_STD_FILESYSTEM_PATH */
@@ -1251,7 +1258,7 @@ __cold env_managed::env_managed(const ::std::wstring &pathname,
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
error::throw_exception(MDBX_INCOMPATIBLE);
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
__cold env_managed::env_managed(const ::std::wstring &pathname,
@@ -1267,7 +1274,7 @@ __cold env_managed::env_managed(const ::std::wstring &pathname,
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
error::throw_exception(MDBX_INCOMPATIBLE);
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
#endif /* Windows */
@@ -1281,7 +1288,7 @@ __cold env_managed::env_managed(const ::std::string &pathname,
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
error::throw_exception(MDBX_INCOMPATIBLE);
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
__cold env_managed::env_managed(const ::std::string &pathname,
@@ -1297,7 +1304,7 @@ __cold env_managed::env_managed(const ::std::string &pathname,
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
error::throw_exception(MDBX_INCOMPATIBLE);
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
//------------------------------------------------------------------------------
@@ -1312,25 +1319,25 @@ txn_managed txn::start_nested() {
}
txn_managed::~txn_managed() noexcept {
if (handle_)
error::success_or_panic(::mdbx_txn_abort(handle_), "mdbx::~txn",
"mdbx_txn_abort");
if (MDBX_UNLIKELY(handle_))
MDBX_CXX20_UNLIKELY error::success_or_panic(::mdbx_txn_abort(handle_),
"mdbx::~txn", "mdbx_txn_abort");
}
void txn_managed::abort() {
const error err = static_cast<MDBX_error_t>(::mdbx_txn_abort(handle_));
if (MDBX_LIKELY(err.code() != MDBX_THREAD_MISMATCH))
handle_ = nullptr;
MDBX_CXX20_LIKELY handle_ = nullptr;
if (MDBX_UNLIKELY(err.code() != MDBX_SUCCESS))
err.throw_exception();
MDBX_CXX20_UNLIKELY err.throw_exception();
}
void txn_managed::commit() {
const error err = static_cast<MDBX_error_t>(::mdbx_txn_commit(handle_));
if (MDBX_LIKELY(err.code() != MDBX_THREAD_MISMATCH))
handle_ = nullptr;
MDBX_CXX20_LIKELY handle_ = nullptr;
if (MDBX_UNLIKELY(err.code() != MDBX_SUCCESS))
err.throw_exception();
MDBX_CXX20_UNLIKELY err.throw_exception();
}
//------------------------------------------------------------------------------
@@ -1394,7 +1401,7 @@ __cold ::std::ostream &operator<<(::std::ostream &out, const slice &it) {
if (root.is_printable())
(out << "\"").write(root.char_ptr(), root.length()) << "\"";
else
out << root.base58_encode();
out << root.encode_base58();
if (root.length() < it.length())
out << "...";
}
@@ -1422,7 +1429,7 @@ __cold ::std::ostream &operator<<(::std::ostream &out,
}
const auto bytes = (it.bytes < 0) ? out << "-",
size_t(-it.bytes) : size_t(it.bytes);
size_t(-it.bytes) : size_t(it.bytes);
struct {
size_t one;
const char *suffix;

View File

@@ -112,7 +112,7 @@ struct problem {
};
struct problem *problems_list;
uint64_t total_problems;
unsigned total_problems, data_tree_problems, gc_tree_problems;
static void MDBX_PRINTF_ARGS(1, 2) print(const char *msg, ...) {
if (!quiet) {
@@ -299,14 +299,20 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
const size_t nentries, const size_t payload_bytes,
const size_t header_bytes, const size_t unused_bytes) {
(void)ctx;
const bool is_gc_tree = dbi_name_or_tag == MDBX_PGWALK_GC;
if (deep > 42) {
problem_add("deep", deep, "too large", nullptr);
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
return MDBX_CORRUPTED /* avoid infinite loop/recursion */;
}
walk_dbi_t *dbi = pagemap_lookup_dbi(dbi_name_or_tag, false);
if (!dbi)
if (!dbi) {
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
return MDBX_ENOMEM;
}
const size_t page_bytes = payload_bytes + header_bytes + unused_bytes;
walk.pgcount += pgnumber;
@@ -319,13 +325,19 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
(unsigned)pagetype, deep);
pagetype_caption = "unknown";
dbi->pages.other += pgnumber;
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
break;
case MDBX_page_broken:
pagetype_caption = "broken";
dbi->pages.other += pgnumber;
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
break;
case MDBX_subpage_broken:
pagetype_caption = "broken-subpage";
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
break;
case MDBX_page_meta:
pagetype_caption = "meta";
@@ -375,17 +387,21 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
bool already_used = false;
for (unsigned n = 0; n < pgnumber; ++n) {
uint64_t spanpgno = pgno + n;
if (spanpgno >= alloc_pages)
if (spanpgno >= alloc_pages) {
problem_add("page", spanpgno, "wrong page-no",
"%s-page: %" PRIu64 " > %" PRIu64 ", deep %i",
pagetype_caption, spanpgno, alloc_pages, deep);
else if (walk.pagemap[spanpgno]) {
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
} else if (walk.pagemap[spanpgno]) {
walk_dbi_t *coll_dbi = &walk.dbi[walk.pagemap[spanpgno] - 1];
problem_add("page", spanpgno,
(branch && coll_dbi == dbi) ? "loop" : "already used",
"%s-page: by %s, deep %i", pagetype_caption, coll_dbi->name,
deep);
already_used = true;
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
} else {
walk.pagemap[spanpgno] = (short)(dbi - walk.dbi + 1);
dbi->pages.total += 1;
@@ -399,18 +415,26 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
if (MDBX_IS_ERROR(err)) {
problem_add("page", pgno, "invalid/corrupted", "%s-page", pagetype_caption);
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
} else {
if (unused_bytes > page_size)
if (unused_bytes > page_size) {
problem_add("page", pgno, "illegal unused-bytes",
"%s-page: %u < %" PRIuPTR " < %u", pagetype_caption, 0,
unused_bytes, envinfo.mi_dxb_pagesize);
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
}
if (header_bytes < (int)sizeof(long) ||
(size_t)header_bytes >= envinfo.mi_dxb_pagesize - sizeof(long))
(size_t)header_bytes >= envinfo.mi_dxb_pagesize - sizeof(long)) {
problem_add("page", pgno, "illegal header-length",
"%s-page: %" PRIuPTR " < %" PRIuPTR " < %" PRIuPTR,
pagetype_caption, sizeof(long), header_bytes,
envinfo.mi_dxb_pagesize - sizeof(long));
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
}
if (payload_bytes < 1) {
if (nentries > 1) {
problem_add("page", pgno, "zero size-of-entry",
@@ -420,12 +444,16 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
// LY: hush a misuse error
page_bytes = page_size;
} */
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
} else {
problem_add("page", pgno, "empty",
"%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR
" entries, deep %i",
pagetype_caption, payload_bytes, nentries, deep);
dbi->pages.empty += 1;
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
}
}
@@ -438,6 +466,8 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
payload_bytes, unused_bytes, deep);
if (page_size > page_bytes)
dbi->lost_bytes += page_size - page_bytes;
data_tree_problems += !is_gc_tree;
gc_tree_problems += is_gc_tree;
} else {
dbi->payload_bytes += payload_bytes + header_bytes;
walk.total_payload_bytes += payload_bytes + header_bytes;
@@ -807,8 +837,9 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
bad_data = true;
}
if (prev_key.iov_base && !bad_data) {
if ((flags & MDBX_DUPFIXED) && prev_data.iov_len != data.iov_len) {
if (prev_key.iov_base) {
if (prev_data.iov_base && !bad_data && (flags & MDBX_DUPFIXED) &&
prev_data.iov_len != data.iov_len) {
problem_add("entry", record_count, "different data length",
"%" PRIuPTR " != %" PRIuPTR, prev_data.iov_len,
data.iov_len);
@@ -821,11 +852,11 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
++dups;
if ((flags & MDBX_DUPSORT) == 0) {
problem_add("entry", record_count, "duplicated entries", nullptr);
if (data.iov_len == prev_data.iov_len &&
if (prev_data.iov_base && data.iov_len == prev_data.iov_len &&
memcmp(data.iov_base, prev_data.iov_base, data.iov_len) == 0) {
problem_add("entry", record_count, "complete duplicate", nullptr);
}
} else if (!bad_data) {
} else if (!bad_data && prev_data.iov_base) {
cmp = mdbx_dcmp(txn, dbi_handle, &data, &prev_data);
if (cmp == 0) {
problem_add("entry", record_count, "complete duplicate", nullptr);
@@ -838,11 +869,6 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
problem_add("entry", record_count, "wrong order of entries", nullptr);
}
}
} else if (verbose) {
if (flags & MDBX_INTEGERKEY)
print(" - fixed key-size %" PRIuPTR "\n", key.iov_len);
if (flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED))
print(" - fixed data-size %" PRIuPTR "\n", data.iov_len);
}
if (handler) {
@@ -855,10 +881,17 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
key_bytes += key.iov_len;
data_bytes += data.iov_len;
if (!bad_key)
if (!bad_key) {
if (verbose && (flags & MDBX_INTEGERKEY) && !prev_key.iov_base)
print(" - fixed key-size %" PRIuPTR "\n", key.iov_len);
prev_key = key;
if (!bad_data)
}
if (!bad_data) {
if (verbose && (flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED)) &&
!prev_data.iov_base)
print(" - fixed data-size %" PRIuPTR "\n", data.iov_len);
prev_data = data;
}
rc = mdbx_cursor_get(mc, &key, &data, MDBX_NEXT);
}
if (rc != MDBX_NOTFOUND)
@@ -915,7 +948,7 @@ static __inline bool meta_ot(txnid_t txn_a, uint64_t sign_a, txnid_t txn_b,
static __inline bool meta_eq(txnid_t txn_a, uint64_t sign_a, txnid_t txn_b,
uint64_t sign_b) {
if (txn_a != txn_b)
if (!txn_a || txn_a != txn_b)
return false;
if (SIGN_IS_STEADY(sign_a) != SIGN_IS_STEADY(sign_b))
@@ -1033,7 +1066,7 @@ int main(int argc, char *argv[]) {
int rc;
char *prog = argv[0];
char *envname;
int problems_maindb = 0, problems_freedb = 0, problems_meta = 0;
unsigned problems_maindb = 0, problems_freedb = 0, problems_meta = 0;
bool write_locked = false;
bool turn_meta = false;
bool force_turn_meta = false;
@@ -1114,7 +1147,6 @@ int main(int argc, char *argv[]) {
quiet = true;
break;
case 'n':
envflags |= MDBX_NOSUBDIR;
break;
case 'w':
envflags &= ~MDBX_RDONLY;
@@ -1377,11 +1409,6 @@ int main(int argc, char *argv[]) {
"of may by large than the database itself,\n "
"until it will be closed or reopened in read-write mode.\n");
#endif
print(" - transactions: recent %" PRIu64 ", latter reader %" PRIu64
", lag %" PRIi64 "\n",
envinfo.mi_recent_txnid, envinfo.mi_latter_reader_txnid,
envinfo.mi_recent_txnid - envinfo.mi_latter_reader_txnid);
verbose_meta(0, envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign,
envinfo.mi_bootid.meta0.x, envinfo.mi_bootid.meta0.y);
verbose_meta(1, envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign,
@@ -1390,52 +1417,70 @@ int main(int argc, char *argv[]) {
envinfo.mi_bootid.meta2.x, envinfo.mi_bootid.meta2.y);
}
if (verbose > 1)
print(" - performs check for meta-pages clashes\n");
if (meta_eq(envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign,
envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign)) {
print(" ! meta-%d and meta-%d are clashed\n", 0, 1);
++problems_meta;
}
if (meta_eq(envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign,
envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign)) {
print(" ! meta-%d and meta-%d are clashed\n", 1, 2);
++problems_meta;
}
if (meta_eq(envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign,
envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign)) {
print(" ! meta-%d and meta-%d are clashed\n", 2, 0);
++problems_meta;
}
if (stuck_meta >= 0) {
if (verbose) {
print(" - skip checking meta-pages since the %u"
" is selected for verification\n",
stuck_meta);
print(" - transactions: recent %" PRIu64
", selected for verification %" PRIu64 ", lag %" PRIi64 "\n",
envinfo.mi_recent_txnid, get_meta_txnid(stuck_meta),
envinfo.mi_recent_txnid - get_meta_txnid(stuck_meta));
}
} else {
if (verbose > 1)
print(" - performs check for meta-pages clashes\n");
if (meta_eq(envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign,
envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign)) {
print(" ! meta-%d and meta-%d are clashed\n", 0, 1);
++problems_meta;
}
if (meta_eq(envinfo.mi_meta1_txnid, envinfo.mi_meta1_sign,
envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign)) {
print(" ! meta-%d and meta-%d are clashed\n", 1, 2);
++problems_meta;
}
if (meta_eq(envinfo.mi_meta2_txnid, envinfo.mi_meta2_sign,
envinfo.mi_meta0_txnid, envinfo.mi_meta0_sign)) {
print(" ! meta-%d and meta-%d are clashed\n", 2, 0);
++problems_meta;
}
const unsigned steady_meta_id = meta_recent(true);
const uint64_t steady_meta_txnid = get_meta_txnid(steady_meta_id);
const unsigned weak_meta_id = meta_recent(false);
const uint64_t weak_meta_txnid = get_meta_txnid(weak_meta_id);
if (envflags & MDBX_EXCLUSIVE) {
if (verbose > 1)
print(" - performs full check recent-txn-id with meta-pages\n");
if (steady_meta_txnid != envinfo.mi_recent_txnid) {
print(" ! steady meta-%d txn-id mismatch recent-txn-id (%" PRIi64
" != %" PRIi64 ")\n",
steady_meta_id, steady_meta_txnid, envinfo.mi_recent_txnid);
++problems_meta;
const unsigned steady_meta_id = meta_recent(true);
const uint64_t steady_meta_txnid = get_meta_txnid(steady_meta_id);
const unsigned weak_meta_id = meta_recent(false);
const uint64_t weak_meta_txnid = get_meta_txnid(weak_meta_id);
if (envflags & MDBX_EXCLUSIVE) {
if (verbose > 1)
print(" - performs full check recent-txn-id with meta-pages\n");
if (steady_meta_txnid != envinfo.mi_recent_txnid) {
print(" ! steady meta-%d txn-id mismatch recent-txn-id (%" PRIi64
" != %" PRIi64 ")\n",
steady_meta_id, steady_meta_txnid, envinfo.mi_recent_txnid);
++problems_meta;
}
} else if (write_locked) {
if (verbose > 1)
print(" - performs lite check recent-txn-id with meta-pages (not a "
"monopolistic mode)\n");
if (weak_meta_txnid != envinfo.mi_recent_txnid) {
print(" ! weak meta-%d txn-id mismatch recent-txn-id (%" PRIi64
" != %" PRIi64 ")\n",
weak_meta_id, weak_meta_txnid, envinfo.mi_recent_txnid);
++problems_meta;
}
} else if (verbose) {
print(" - skip check recent-txn-id with meta-pages (monopolistic or "
"read-write mode only)\n");
}
} else if (write_locked) {
if (verbose > 1)
print(" - performs lite check recent-txn-id with meta-pages (not a "
"monopolistic mode)\n");
if (weak_meta_txnid != envinfo.mi_recent_txnid) {
print(" ! weak meta-%d txn-id mismatch recent-txn-id (%" PRIi64
" != %" PRIi64 ")\n",
weak_meta_id, weak_meta_txnid, envinfo.mi_recent_txnid);
++problems_meta;
}
} else if (verbose) {
print(" - skip check recent-txn-id with meta-pages (monopolistic or "
"read-write mode only)\n");
total_problems += problems_meta;
if (verbose)
print(" - transactions: recent %" PRIu64 ", latter reader %" PRIu64
", lag %" PRIi64 "\n",
envinfo.mi_recent_txnid, envinfo.mi_latter_reader_txnid,
envinfo.mi_recent_txnid - envinfo.mi_latter_reader_txnid);
}
total_problems += problems_meta;
if (!dont_traversal) {
struct problem *saved_list;
@@ -1546,8 +1591,19 @@ int main(int argc, char *argv[]) {
if (!verbose)
print("Iterating DBIs...\n");
problems_maindb = process_db(~0u, /* MAIN_DBI */ nullptr, nullptr, false);
problems_freedb = process_db(FREE_DBI, "@GC", handle_freedb, false);
if (data_tree_problems) {
print("Skip processing %s since tree is corrupted (%u problems)\n", "@MAIN",
data_tree_problems);
problems_maindb = data_tree_problems;
} else
problems_maindb = process_db(~0u, /* MAIN_DBI */ nullptr, nullptr, false);
if (gc_tree_problems) {
print("Skip processing %s since tree is corrupted (%u problems)\n", "@GC",
gc_tree_problems);
problems_freedb = gc_tree_problems;
} else
problems_freedb = process_db(FREE_DBI, "@GC", handle_freedb, false);
if (verbose) {
uint64_t value = envinfo.mi_mapsize / envinfo.mi_dxb_pagesize;
@@ -1604,7 +1660,7 @@ int main(int argc, char *argv[]) {
if (rc == 0 && total_problems == 1 && problems_meta == 1 && !dont_traversal &&
(envflags & MDBX_RDONLY) == 0 && !only_subdb && stuck_meta < 0 &&
steady_meta_txnid < envinfo.mi_recent_txnid) {
get_meta_txnid(meta_recent(true)) < envinfo.mi_recent_txnid) {
print("Perform sync-to-disk for make steady checkpoint at txn-id #%" PRIi64
"\n",
envinfo.mi_recent_txnid);
@@ -1674,8 +1730,8 @@ bailout:
#endif /* !WINDOWS */
if (total_problems) {
print("Total %" PRIu64 " error%s detected, elapsed %.3f seconds.\n",
total_problems, (total_problems > 1) ? "s are" : " is", elapsed);
print("Total %u error%s detected, elapsed %.3f seconds.\n", total_problems,
(total_problems > 1) ? "s are" : " is", elapsed);
if (problems_meta || problems_maindb || problems_freedb)
return EXIT_FAILURE_CHECK_MAJOR;
return EXIT_FAILURE_CHECK_MINOR;

View File

@@ -54,7 +54,9 @@ static void usage(void) {
"usage: %s [-V] [-q] [-d] [-s name] dbpath\n"
" -V\t\tprint version and exit\n"
" -q\t\tbe quiet\n"
" -d\t\tdelete the specified database, don't just empty it\n",
" -d\t\tdelete the specified database, don't just empty it\n"
" -s name\tdrop the specified named subDB\n"
" \t\tby default empty the main DB\n",
prog);
exit(EXIT_FAILURE);
}
@@ -79,11 +81,12 @@ int main(int argc, char *argv[]) {
if (argc < 2)
usage();
/* -d: delete the db, don't just empty it
* -s: drop the named subDB
* -V: print version and exit
* (default) empty the main DB */
while ((i = getopt(argc, argv, "ds:nV")) != EOF) {
while ((i = getopt(argc, argv,
"d"
"s:"
"n"
"q"
"V")) != EOF) {
switch (i) {
case 'V':
printf("mdbx_drop version %d.%d.%d.%d\n"
@@ -99,11 +102,13 @@ int main(int argc, char *argv[]) {
mdbx_build.target, mdbx_build.compiler, mdbx_build.flags,
mdbx_build.options);
return EXIT_SUCCESS;
case 'q':
quiet = true;
break;
case 'd':
delete = true;
break;
case 'n':
envflags |= MDBX_NOSUBDIR;
break;
case 's':
subname = optarg;
@@ -130,11 +135,12 @@ int main(int argc, char *argv[]) {
#endif /* !WINDOWS */
envname = argv[optind];
if (!quiet)
if (!quiet) {
printf("mdbx_drop %s (%s, T-%s)\nRunning for %s/%s...\n",
mdbx_version.git.describe, mdbx_version.git.datetime,
mdbx_version.git.tree, envname, subname ? subname : "@MAIN");
fflush(nullptr);
fflush(nullptr);
}
rc = mdbx_env_create(&env);
if (unlikely(rc != MDBX_SUCCESS)) {

View File

@@ -101,7 +101,9 @@ static void dumpval(MDBX_val *v) {
bool quiet = false, rescue = false;
const char *prog;
static void error(const char *func, int rc) {
fprintf(stderr, "%s: %s() error %d %s\n", prog, func, rc, mdbx_strerror(rc));
if (!quiet)
fprintf(stderr, "%s: %s() error %d %s\n", prog, func, rc,
mdbx_strerror(rc));
}
/* Dump in BDB-compatible format */
@@ -216,17 +218,17 @@ static int dump_sdb(MDBX_txn *txn, MDBX_dbi dbi, char *name) {
static void usage(void) {
fprintf(stderr,
"usage: %s [-V] [-q] [-f file] [-l] [-p] [-a|-s subdb] [-r] "
"usage: %s [-V] [-q] [-f file] [-l] [-p] [-r] [-a|-s subdb] "
"dbpath\n"
" -V\t\tprint version and exit\n"
" -q\t\tbe quiet\n"
" -f\t\twrite to file instead of stdout\n"
" -l\t\tlist subDBs and exit\n"
" -p\t\tuse printable characters\n"
" -a\t\tdump main DB and all subDBs,\n"
" \t\tby default dump only the main DB\n"
" -s\t\tdump only the named subDB\n"
" -r\t\trescue mode (ignore errors to dump corrupted DB)\n",
" -r\t\trescue mode (ignore errors to dump corrupted DB)\n"
" -a\t\tdump main DB and all subDBs\n"
" -s name\tdump only the specified named subDB\n"
" \t\tby default dump only the main DB\n",
prog);
exit(EXIT_FAILURE);
}
@@ -294,7 +296,6 @@ int main(int argc, char *argv[]) {
}
break;
case 'n':
envflags |= MDBX_NOSUBDIR;
break;
case 'p':
mode |= PRINT;
@@ -431,8 +432,9 @@ int main(int argc, char *argv[]) {
if (unlikely(rc != MDBX_SUCCESS)) {
if (!rescue)
break;
fprintf(stderr, "%s: %s: ignore %s for `%s` and continue\n", prog,
envname, mdbx_strerror(rc), subname);
if (!quiet)
fprintf(stderr, "%s: %s: ignore %s for `%s` and continue\n", prog,
envname, mdbx_strerror(rc), subname);
/* Here is a hack for rescue mode, don't do that:
* - we should restart transaction in case error due
* database corruption;
@@ -466,8 +468,9 @@ int main(int argc, char *argv[]) {
if (have_raw && (!count /* || rescue */))
rc = dump_sdb(txn, MAIN_DBI, nullptr);
else if (!count) {
fprintf(stderr, "%s: %s does not contain multiple databases\n", prog,
envname);
if (!quiet)
fprintf(stderr, "%s: %s does not contain multiple databases\n", prog,
envname);
rc = MDBX_NOTFOUND;
}
} else {
@@ -480,7 +483,8 @@ int main(int argc, char *argv[]) {
case MDBX_SUCCESS:
break;
case MDBX_EINTR:
fprintf(stderr, "Interrupted by signal/user\n");
if (!quiet)
fprintf(stderr, "Interrupted by signal/user\n");
break;
default:
if (unlikely(rc != MDBX_SUCCESS))

View File

@@ -485,7 +485,7 @@ static void usage(void) {
" -a\t\tappend records in input order (required for custom "
"comparators)\n"
" -f file\tread from file instead of stdin\n"
" -s name\tload into named subDB\n"
" -s name\tload into specified named subDB\n"
" -N\t\tdon't overwrite existing records when loading, just skip "
"ones\n"
" -p\t\tpurge subDB before loading\n"

View File

@@ -54,14 +54,16 @@ static void print_stat(MDBX_stat *ms) {
static void usage(const char *prog) {
fprintf(stderr,
"usage: %s [-V] [-e] [-f[f[f]]] [-r[r]] [-a|-s name] dbpath\n"
"usage: %s [-V] [-q] [-e] [-f[f[f]]] [-r[r]] [-a|-s name] dbpath\n"
" -V\t\tprint version and exit\n"
" -q\t\tbe quiet\n"
" -p\t\tshow statistics of page operations for current session\n"
" -e\t\tshow whole DB info\n"
" -f\t\tshow GC info\n"
" -r\t\tshow readers\n"
" -a\t\tprint stat of main DB and all subDBs\n"
" \t\t(default) print stat of only the main DB\n"
" -s name\tprint stat of only the named subDB\n",
" -s name\tprint stat of only the specified named subDB\n"
" \t\tby default print stat of only the main DB\n",
prog);
exit(EXIT_FAILURE);
}
@@ -88,12 +90,15 @@ static int reader_list_func(void *ctx, int num, int slot, mdbx_pid_t pid,
}
const char *prog;
bool quiet = false;
static void error(const char *func, int rc) {
fprintf(stderr, "%s: %s() error %d %s\n", prog, func, rc, mdbx_strerror(rc));
if (!quiet)
fprintf(stderr, "%s: %s() error %d %s\n", prog, func, rc,
mdbx_strerror(rc));
}
int main(int argc, char *argv[]) {
int o, rc;
int opt, rc;
MDBX_env *env;
MDBX_txn *txn;
MDBX_dbi dbi;
@@ -101,20 +106,23 @@ int main(int argc, char *argv[]) {
prog = argv[0];
char *envname;
char *subname = nullptr;
int alldbs = 0, envinfo = 0, envflags = 0, freinfo = 0, rdrinfo = 0;
bool alldbs = false, envinfo = false, pgop = false;
int freinfo = 0, rdrinfo = 0;
if (argc < 2)
usage(prog);
while ((o = getopt(argc, argv,
"V"
"a"
"e"
"f"
"n"
"r"
"s:")) != EOF) {
switch (o) {
while ((opt = getopt(argc, argv,
"V"
"q"
"p"
"a"
"e"
"f"
"n"
"r"
"s:")) != EOF) {
switch (opt) {
case 'V':
printf("mdbx_stat version %d.%d.%d.%d\n"
" - source: %s %s, commit %s, tree %s\n"
@@ -129,22 +137,27 @@ int main(int argc, char *argv[]) {
mdbx_build.target, mdbx_build.compiler, mdbx_build.flags,
mdbx_build.options);
return EXIT_SUCCESS;
case 'q':
quiet = true;
break;
case 'p':
pgop = true;
break;
case 'a':
if (subname)
usage(prog);
alldbs++;
alldbs = true;
break;
case 'e':
envinfo++;
envinfo = true;
break;
case 'f':
freinfo++;
freinfo += 1;
break;
case 'n':
envflags |= MDBX_NOSUBDIR;
break;
case 'r':
rdrinfo++;
rdrinfo += 1;
break;
case 's':
if (alldbs)
@@ -174,10 +187,12 @@ int main(int argc, char *argv[]) {
envname = argv[optind];
envname = argv[optind];
printf("mdbx_stat %s (%s, T-%s)\nRunning for %s...\n",
mdbx_version.git.describe, mdbx_version.git.datetime,
mdbx_version.git.tree, envname);
fflush(nullptr);
if (!quiet) {
printf("mdbx_stat %s (%s, T-%s)\nRunning for %s...\n",
mdbx_version.git.describe, mdbx_version.git.datetime,
mdbx_version.git.tree, envname);
fflush(nullptr);
}
rc = mdbx_env_create(&env);
if (unlikely(rc != MDBX_SUCCESS)) {
@@ -193,7 +208,7 @@ int main(int argc, char *argv[]) {
}
}
rc = mdbx_env_open(env, envname, envflags | MDBX_RDONLY, 0);
rc = mdbx_env_open(env, envname, MDBX_RDONLY, 0);
if (unlikely(rc != MDBX_SUCCESS)) {
error("mdbx_env_open", rc);
goto env_close;
@@ -205,7 +220,7 @@ int main(int argc, char *argv[]) {
goto txn_abort;
}
if (envinfo || freinfo) {
if (envinfo || freinfo || pgop) {
rc = mdbx_env_info_ex(env, txn, &mei, sizeof(mei));
if (unlikely(rc != MDBX_SUCCESS)) {
error("mdbx_env_info_ex", rc);
@@ -216,6 +231,33 @@ int main(int argc, char *argv[]) {
memset(&mei, 0, sizeof(mei));
}
if (pgop) {
printf("Page Operations (for current session):\n");
printf(" New: %8" PRIu64 "\t// quantity of a new pages added\n",
mei.mi_pgop_stat.newly);
printf(" CoW: %8" PRIu64
"\t// quantity of pages copied for altering\n",
mei.mi_pgop_stat.cow);
printf(" Clone: %8" PRIu64 "\t// quantity of parent's dirty pages "
"clones for nested transactions\n",
mei.mi_pgop_stat.clone);
printf(" Split: %8" PRIu64
"\t// page splits during insertions or updates\n",
mei.mi_pgop_stat.split);
printf(" Merge: %8" PRIu64
"\t// page merges during deletions or updates\n",
mei.mi_pgop_stat.merge);
printf(" Spill: %8" PRIu64 "\t// quantity of spilled/ousted `dirty` "
"pages during large transactions\n",
mei.mi_pgop_stat.spill);
printf(" Unspill: %8" PRIu64 "\t// quantity of unspilled/redone `dirty` "
"pages during large transactions\n",
mei.mi_pgop_stat.unspill);
printf(" WOP: %8" PRIu64
"\t// number of explicit write operations (not a pages) to a disk\n",
mei.mi_pgop_stat.wops);
}
if (envinfo) {
printf("Environment Info\n");
printf(" Pagesize: %u\n", mei.mi_dxb_pagesize);
@@ -356,7 +398,8 @@ int main(int argc, char *argv[]) {
case MDBX_NOTFOUND:
break;
case MDBX_EINTR:
fprintf(stderr, "Interrupted by signal/user\n");
if (!quiet)
fprintf(stderr, "Interrupted by signal/user\n");
goto txn_abort;
default:
error("mdbx_cursor_get", rc);
@@ -462,7 +505,8 @@ int main(int argc, char *argv[]) {
case MDBX_NOTFOUND:
break;
case MDBX_EINTR:
fprintf(stderr, "Interrupted by signal/user\n");
if (!quiet)
fprintf(stderr, "Interrupted by signal/user\n");
break;
default:
if (unlikely(rc != MDBX_SUCCESS))

View File

@@ -39,18 +39,18 @@
#else
#define MDBX_ENV_CHECKPID 1
#endif
#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" STRINGIFY(MDBX_ENV_CHECKPID)
#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
#else
#define MDBX_ENV_CHECKPID_CONFIG STRINGIFY(MDBX_ENV_CHECKPID)
#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
#endif /* MDBX_ENV_CHECKPID */
/** Controls checking transaction owner thread against misuse transactions from
* other threads. */
#ifndef MDBX_TXN_CHECKOWNER
#define MDBX_TXN_CHECKOWNER 1
#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" STRINGIFY(MDBX_TXN_CHECKOWNER)
#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
#else
#define MDBX_TXN_CHECKOWNER_CONFIG STRINGIFY(MDBX_TXN_CHECKOWNER)
#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
#endif /* MDBX_TXN_CHECKOWNER */
/** Does a system have battery-backed Real-Time Clock or just a fake. */
@@ -61,9 +61,9 @@
#else
#define MDBX_TRUST_RTC 1
#endif
#define MDBX_TRUST_RTC_CONFIG "AUTO=" STRINGIFY(MDBX_TRUST_RTC)
#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
#else
#define MDBX_TRUST_RTC_CONFIG STRINGIFY(MDBX_TRUST_RTC)
#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
#endif /* MDBX_TRUST_RTC */
/** Controls online database auto-compactification during write-transactions. */
@@ -238,9 +238,9 @@
#else
#define MDBX_LOCKING MDBX_LOCKING_SYSV
#endif
#define MDBX_LOCKING_CONFIG "AUTO=" STRINGIFY(MDBX_LOCKING)
#define MDBX_LOCKING_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_LOCKING)
#else
#define MDBX_LOCKING_CONFIG STRINGIFY(MDBX_LOCKING)
#define MDBX_LOCKING_CONFIG MDBX_STRINGIFY(MDBX_LOCKING)
#endif /* MDBX_LOCKING */
#endif /* !Windows */
@@ -253,9 +253,9 @@
#else
#define MDBX_USE_OFDLOCKS 0
#endif
#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" STRINGIFY(MDBX_USE_OFDLOCKS)
#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
#else
#define MDBX_USE_OFDLOCKS_CONFIG STRINGIFY(MDBX_USE_OFDLOCKS)
#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
#endif /* MDBX_USE_OFDLOCKS */
/** Advanced: Using sendfile() syscall (autodetection by default). */
@@ -326,9 +326,9 @@
#else
#define MDBX_64BIT_ATOMIC 0
#endif
#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" STRINGIFY(MDBX_64BIT_ATOMIC)
#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
#else
#define MDBX_64BIT_ATOMIC_CONFIG STRINGIFY(MDBX_64BIT_ATOMIC)
#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
#endif /* MDBX_64BIT_ATOMIC */
#ifndef MDBX_64BIT_CAS
@@ -355,9 +355,9 @@
#else
#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
#endif
#define MDBX_64BIT_CAS_CONFIG "AUTO=" STRINGIFY(MDBX_64BIT_CAS)
#define MDBX_64BIT_CAS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_CAS)
#else
#define MDBX_64BIT_CAS_CONFIG STRINGIFY(MDBX_64BIT_CAS)
#define MDBX_64BIT_CAS_CONFIG MDBX_STRINGIFY(MDBX_64BIT_CAS)
#endif /* MDBX_64BIT_CAS */
#ifndef MDBX_UNALIGNED_OK

View File

@@ -217,7 +217,7 @@ __extern_C void __assert(const char *function, const char *file, int line,
#if !defined(__ANDROID_API__) || MDBX_DEBUG
void __cold mdbx_assert_fail(const MDBX_env *env, const char *msg,
__cold void mdbx_assert_fail(const MDBX_env *env, const char *msg,
const char *func, int line) {
#if MDBX_DEBUG
if (env && env->me_assert_func) {
@@ -1329,6 +1329,7 @@ static int mdbx_check_fs_local(mdbx_filehandle_t handle, int flags) {
strncasecmp("cifs", name, name_len) == 0 ||
strncasecmp("ncpfs", name, name_len) == 0 ||
strncasecmp("smbfs", name, name_len) == 0 ||
strcasecmp("9P" /* WSL2 */, name) == 0 ||
((name_len > 3 && strncasecmp("fuse", name, 4) == 0) &&
strncasecmp("fuseblk", name, name_len) != 0)) &&
!(flags & MDBX_EXCLUSIVE))
@@ -1376,6 +1377,36 @@ static int mdbx_check_fs_local(mdbx_filehandle_t handle, int flags) {
return MDBX_SUCCESS;
}
static int check_mmap_limit(const size_t limit) {
const bool should_check =
#if defined(__SANITIZE_ADDRESS__)
true;
#else
RUNNING_ON_VALGRIND;
#endif /* __SANITIZE_ADDRESS__ */
if (should_check) {
intptr_t pagesize, total_ram_pages, avail_ram_pages;
int err =
mdbx_get_sysraminfo(&pagesize, &total_ram_pages, &avail_ram_pages);
if (unlikely(err != MDBX_SUCCESS))
return err;
const int log2page = log2n_powerof2(pagesize);
if ((limit >> (log2page + 7)) > (size_t)total_ram_pages ||
(limit >> (log2page + 6)) > (size_t)avail_ram_pages) {
mdbx_error(
"%s (%zu pages) is too large for available (%zu pages) or total "
"(%zu pages) system RAM",
"database upper size limit", limit >> log2page, avail_ram_pages,
total_ram_pages);
return MDBX_TOO_LARGE;
}
}
return MDBX_SUCCESS;
}
MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
const size_t size, const size_t limit,
const unsigned options) {
@@ -1383,34 +1414,34 @@ MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
map->limit = 0;
map->current = 0;
map->address = nullptr;
map->filesize = 0;
#if defined(_WIN32) || defined(_WIN64)
map->section = NULL;
map->filesize = 0;
#endif /* Windows */
int err = mdbx_check_fs_local(map->fd, flags);
if (unlikely(err != MDBX_SUCCESS))
return err;
err = check_mmap_limit(limit);
if (unlikely(err != MDBX_SUCCESS))
return err;
if ((flags & MDBX_RDONLY) == 0 && (options & MMAP_OPTION_TRUNCATE) != 0) {
err = mdbx_ftruncate(map->fd, size);
if (err != MDBX_SUCCESS)
return err;
#if defined(_WIN32) || defined(_WIN64)
map->filesize = size;
#else
#if !(defined(_WIN32) || defined(_WIN64))
map->current = size;
#endif /* ! Windows */
#endif /* !Windows */
} else {
uint64_t filesize = 0;
err = mdbx_filesize(map->fd, &filesize);
err = mdbx_filesize(map->fd, &map->filesize);
if (err != MDBX_SUCCESS)
return err;
#if defined(_WIN32) || defined(_WIN64)
map->filesize = filesize;
#else
map->current = (filesize > limit) ? limit : (size_t)filesize;
#endif /* ! Windows */
#if !(defined(_WIN32) || defined(_WIN64))
map->current = (map->filesize > limit) ? limit : (size_t)map->filesize;
#endif /* !Windows */
}
#if defined(_WIN32) || defined(_WIN64)
@@ -1430,8 +1461,9 @@ MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
if (!NT_SUCCESS(err))
return ntstatus2errcode(err);
SIZE_T ViewSize =
(flags & MDBX_RDONLY) ? 0 : mdbx_RunningUnderWine() ? size : limit;
SIZE_T ViewSize = (flags & MDBX_RDONLY) ? 0
: mdbx_RunningUnderWine() ? size
: limit;
err = NtMapViewOfSection(
map->section, GetCurrentProcess(), &map->address,
/* ZeroBits */ 0,
@@ -1507,7 +1539,7 @@ MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
#endif /* ! Windows */
VALGRIND_MAKE_MEM_DEFINED(map->address, map->current);
ASAN_UNPOISON_MEMORY_REGION(map->address, map->current);
MDBX_ASAN_UNPOISON_MEMORY_REGION(map->address, map->current);
return MDBX_SUCCESS;
}
@@ -1516,7 +1548,10 @@ MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map) {
/* Unpoisoning is required for ASAN to avoid false-positive diagnostic
* when this memory will re-used by malloc or another mmapping.
* See https://github.com/erthink/libmdbx/pull/93#issuecomment-613687203 */
ASAN_UNPOISON_MEMORY_REGION(map->address, map->limit);
MDBX_ASAN_UNPOISON_MEMORY_REGION(map->address,
(map->filesize && map->filesize < map->limit)
? map->filesize
: map->limit);
#if defined(_WIN32) || defined(_WIN64)
if (map->section)
NtClose(map->section);
@@ -1534,8 +1569,8 @@ MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map) {
return MDBX_SUCCESS;
}
MDBX_INTERNAL_FUNC int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size,
size_t limit, const bool may_move) {
MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
size_t size, size_t limit) {
assert(size <= limit);
#if defined(_WIN32) || defined(_WIN64)
assert(size != map->current || limit != map->limit || size < map->filesize);
@@ -1558,6 +1593,10 @@ MDBX_INTERNAL_FUNC int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size,
}
if (limit > map->limit) {
err = check_mmap_limit(limit);
if (unlikely(err != MDBX_SUCCESS))
return err;
/* check ability of address space for growth before unmap */
PVOID BaseAddress = (PBYTE)map->address + map->limit;
SIZE_T RegionSize = limit - map->limit;
@@ -1579,6 +1618,13 @@ MDBX_INTERNAL_FUNC int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size,
* - change size of mapped view;
* - extend read-only mapping;
* Therefore we should unmap/map entire section. */
if ((flags & MDBX_MRESIZE_MAY_UNMAP) == 0)
return MDBX_RESULT_TRUE;
/* Unpoisoning is required for ASAN to avoid false-positive diagnostic
* when this memory will re-used by malloc or another mmapping.
* See https://github.com/erthink/libmdbx/pull/93#issuecomment-613687203 */
MDBX_ASAN_UNPOISON_MEMORY_REGION(map->address, map->limit);
status = NtUnmapViewOfSection(GetCurrentProcess(), map->address);
if (!NT_SUCCESS(status))
return ntstatus2errcode(status);
@@ -1614,7 +1660,7 @@ retry_file_and_section:
if (status != (NTSTATUS) /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018)
goto bailout_ntstatus /* no way to recovery */;
if (may_move)
if (flags & MDBX_MRESIZE_MAY_MOVE)
/* the base address could be changed */
map->address = NULL;
}
@@ -1672,7 +1718,7 @@ retry_mapview:;
if (!NT_SUCCESS(status)) {
if (status == (NTSTATUS) /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 &&
map->address && may_move) {
map->address && (flags & MDBX_MRESIZE_MAY_MOVE) != 0) {
/* try remap at another base address */
map->address = NULL;
goto retry_mapview;
@@ -1683,7 +1729,7 @@ retry_mapview:;
if (map->address && (size != map->current || limit != map->limit)) {
/* try remap with previously size and limit,
* but will return MDBX_UNABLE_EXTEND_MAPSIZE on success */
rc = MDBX_UNABLE_EXTEND_MAPSIZE;
rc = (limit > map->limit) ? MDBX_UNABLE_EXTEND_MAPSIZE : MDBX_RESULT_TRUE;
size = map->current;
ReservedSize = limit = map->limit;
goto retry_file_and_section;
@@ -1699,40 +1745,62 @@ retry_mapview:;
#else /* Windows */
uint64_t filesize = 0;
int rc = mdbx_filesize(map->fd, &filesize);
map->filesize = 0;
int rc = mdbx_filesize(map->fd, &map->filesize);
if (rc != MDBX_SUCCESS)
return rc;
if (flags & MDBX_RDONLY) {
map->current = (filesize > limit) ? limit : (size_t)filesize;
map->current = (map->filesize > limit) ? limit : (size_t)map->filesize;
if (map->current != size)
rc = MDBX_UNABLE_EXTEND_MAPSIZE;
} else if (filesize != size) {
rc = mdbx_ftruncate(map->fd, size);
if (rc != MDBX_SUCCESS)
return rc;
rc =
(size > map->current) ? MDBX_UNABLE_EXTEND_MAPSIZE : MDBX_RESULT_TRUE;
} else {
if (map->filesize != size) {
rc = mdbx_ftruncate(map->fd, size);
if (rc != MDBX_SUCCESS)
return rc;
map->filesize = size;
}
if (map->current > size) {
/* Clearing asan's bitmask for the region which released in shrinking,
* since:
* - after the shrinking we will get an exception when accessing
* this region and (therefore) do not need the help of ASAN.
* - this allows us to clear the mask only within the file size
* when closing the mapping. */
MDBX_ASAN_UNPOISON_MEMORY_REGION(
(char *)map->address + size,
((map->current < map->limit) ? map->current : map->limit) - size);
}
map->current = size;
}
if (limit == map->limit)
return MDBX_SUCCESS;
return rc;
if (limit < map->limit) {
/* unmap an excess at end of mapping. */
// coverity[offset_free : FALSE]
if (unlikely(munmap(map->dxb + limit, map->limit - limit)))
return errno;
map->limit = limit;
return MDBX_SUCCESS;
return rc;
}
int err = check_mmap_limit(limit);
if (unlikely(err != MDBX_SUCCESS))
return err;
assert(limit > map->limit);
uint8_t *ptr = MAP_FAILED;
#if defined(MREMAP_MAYMOVE)
ptr = mremap(map->address, map->limit, limit, may_move ? MREMAP_MAYMOVE : 0);
ptr = mremap(map->address, map->limit, limit,
(flags & MDBX_MRESIZE_MAY_MOVE) ? MREMAP_MAYMOVE : 0);
if (ptr == MAP_FAILED) {
const int err = errno;
err = errno;
switch (err) {
default:
return err;
@@ -1763,7 +1831,7 @@ retry_mapview:;
return errno;
ptr = MAP_FAILED;
} else {
const int err = errno;
err = errno;
switch (err) {
default:
return err;
@@ -1779,7 +1847,7 @@ retry_mapview:;
if (ptr == MAP_FAILED) {
/* unmap and map again whole region */
if (!may_move) {
if ((flags & MDBX_MRESIZE_MAY_UNMAP) == 0) {
/* TODO: Perhaps here it is worth to implement suspend/resume threads
* and perform unmap/map as like for Windows. */
return MDBX_UNABLE_EXTEND_MAPSIZE;
@@ -1788,16 +1856,44 @@ retry_mapview:;
if (unlikely(munmap(map->address, map->limit)))
return errno;
ptr = mmap(map->address, limit, mmap_prot, mmap_flags, map->fd, 0);
// coverity[pass_freed_arg : FALSE]
ptr = mmap(map->address, limit, mmap_prot,
(flags & MDBX_MRESIZE_MAY_MOVE)
? mmap_flags
: mmap_flags | (MAP_FIXED_NOREPLACE ? MAP_FIXED_NOREPLACE
: MAP_FIXED),
map->fd, 0);
if (MAP_FIXED_NOREPLACE != 0 && MAP_FIXED_NOREPLACE != MAP_FIXED &&
unlikely(ptr == MAP_FAILED) && !(flags & MDBX_MRESIZE_MAY_MOVE) &&
errno == /* kernel don't support MAP_FIXED_NOREPLACE */ EINVAL)
// coverity[pass_freed_arg : FALSE]
ptr = mmap(map->address, limit, mmap_prot, mmap_flags | MAP_FIXED,
map->fd, 0);
if (unlikely(ptr == MAP_FAILED)) {
ptr = mmap(map->address, map->limit, mmap_prot, mmap_flags, map->fd, 0);
/* try to restore prev mapping */
// coverity[pass_freed_arg : FALSE]
ptr = mmap(map->address, map->limit, mmap_prot,
(flags & MDBX_MRESIZE_MAY_MOVE)
? mmap_flags
: mmap_flags | (MAP_FIXED_NOREPLACE ? MAP_FIXED_NOREPLACE
: MAP_FIXED),
map->fd, 0);
if (MAP_FIXED_NOREPLACE != 0 && MAP_FIXED_NOREPLACE != MAP_FIXED &&
unlikely(ptr == MAP_FAILED) && !(flags & MDBX_MRESIZE_MAY_MOVE) &&
errno == /* kernel don't support MAP_FIXED_NOREPLACE */ EINVAL)
// coverity[pass_freed_arg : FALSE]
ptr = mmap(map->address, map->limit, mmap_prot, mmap_flags | MAP_FIXED,
map->fd, 0);
if (unlikely(ptr == MAP_FAILED)) {
VALGRIND_MAKE_MEM_NOACCESS(map->address, map->current);
/* Unpoisoning is required for ASAN to avoid false-positive diagnostic
* when this memory will re-used by malloc or another mmapping.
* See https://github.com/erthink/libmdbx/pull/93#issuecomment-613687203
*/
ASAN_UNPOISON_MEMORY_REGION(map->address, map->limit);
MDBX_ASAN_UNPOISON_MEMORY_REGION(
map->address,
(map->current < map->limit) ? map->current : map->limit);
map->limit = 0;
map->current = 0;
map->address = nullptr;
@@ -1813,12 +1909,12 @@ retry_mapview:;
VALGRIND_MAKE_MEM_NOACCESS(map->address, map->current);
/* Unpoisoning is required for ASAN to avoid false-positive diagnostic
* when this memory will re-used by malloc or another mmapping.
* See https://github.com/erthink/libmdbx/pull/93#issuecomment-613687203
*/
ASAN_UNPOISON_MEMORY_REGION(map->address, map->limit);
* See https://github.com/erthink/libmdbx/pull/93#issuecomment-613687203 */
MDBX_ASAN_UNPOISON_MEMORY_REGION(
map->address, (map->current < map->limit) ? map->current : map->limit);
VALGRIND_MAKE_MEM_DEFINED(ptr, map->current);
ASAN_UNPOISON_MEMORY_REGION(ptr, map->current);
MDBX_ASAN_UNPOISON_MEMORY_REGION(ptr, map->current);
map->address = ptr;
}
map->limit = limit;
@@ -1840,7 +1936,7 @@ retry_mapview:;
/*----------------------------------------------------------------------------*/
MDBX_INTERNAL_FUNC __cold void mdbx_osal_jitter(bool tiny) {
__cold MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny) {
for (;;) {
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
defined(__x86_64__)
@@ -1868,7 +1964,7 @@ MDBX_INTERNAL_FUNC __cold void mdbx_osal_jitter(bool tiny) {
#elif defined(__APPLE__) || defined(__MACH__)
#include <mach/mach_time.h>
#elif defined(__linux__) || defined(__gnu_linux__)
static __cold clockid_t choice_monoclock(void) {
__cold static clockid_t choice_monoclock(void) {
struct timespec probe;
#if defined(CLOCK_BOOTTIME)
if (clock_gettime(CLOCK_BOOTTIME, &probe) == 0)
@@ -1908,7 +2004,8 @@ mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16) {
#else
const uint64_t ratio = UINT64_C(1000000000);
#endif
return (ratio * seconds_16dot16 + 32768) >> 16;
const uint64_t ret = (ratio * seconds_16dot16 + 32768) >> 16;
return likely(ret || seconds_16dot16 == 0) ? ret : /* fix underflow */ 1;
}
MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime) {
@@ -1920,13 +2017,15 @@ MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime) {
if (monotime > limit)
return UINT32_MAX;
}
const uint32_t ret =
#if defined(_WIN32) || defined(_WIN64)
return (uint32_t)((monotime << 16) / performance_frequency.QuadPart);
(uint32_t)((monotime << 16) / performance_frequency.QuadPart);
#elif defined(__APPLE__) || defined(__MACH__)
return (uint32_t)((monotime << 16) / ratio_16dot16_to_monotine);
(uint32_t)((monotime << 16) / ratio_16dot16_to_monotine);
#else
return (uint32_t)(monotime * 128 / 1953125);
(uint32_t)(monotime * 128 / 1953125);
#endif
return likely(ret || monotime == 0) ? ret : /* fix underflow */ 1;
}
MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void) {
@@ -2057,8 +2156,8 @@ static LSTATUS mdbx_RegGetValue(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpValue,
}
#endif
static __cold __maybe_unused bool bootid_parse_uuid(bin128_t *s, const void *p,
const size_t n) {
__cold MDBX_MAYBE_UNUSED static bool
bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) {
if (n > 31) {
unsigned bits = 0;
for (unsigned i = 0; i < n; ++i) /* try parse an UUID in text form */ {
@@ -2173,7 +2272,7 @@ __cold MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void) {
if (mdbx_RegGetValue(HKEY_LOCAL_MACHINE, HKLM_MicrosoftCryptography,
"MachineGuid", &buf.MachineGuid,
&len) == ERROR_SUCCESS &&
len > 42 && len < sizeof(buf))
len < sizeof(buf))
got_machineid = bootid_parse_uuid(&bin, &buf.MachineGuid, len);
if (!got_machineid) {
@@ -2237,12 +2336,16 @@ __cold MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void) {
0x03 /* SystemTmeOfDayInformation */, &buf.SysTimeOfDayInfo,
sizeof(buf.SysTimeOfDayInfo), &len);
if (NT_SUCCESS(status) &&
len >= offsetof(union buf, SysTimeOfDayInfoHacked.BootTime) +
sizeof(buf.SysTimeOfDayInfoHacked.BootTime) &&
len >= offsetof(union buf, SysTimeOfDayInfoHacked.BootTimeBias) +
sizeof(buf.SysTimeOfDayInfoHacked.BootTimeBias) &&
buf.SysTimeOfDayInfoHacked.BootTime.QuadPart) {
bootid_collect(&bin, &buf.SysTimeOfDayInfoHacked.BootTime,
sizeof(buf.SysTimeOfDayInfoHacked.BootTime));
got_boottime = true;
const uint64_t UnbiasedBootTime =
buf.SysTimeOfDayInfoHacked.BootTime.QuadPart -
buf.SysTimeOfDayInfoHacked.BootTimeBias;
if (UnbiasedBootTime) {
bootid_collect(&bin, &UnbiasedBootTime, sizeof(UnbiasedBootTime));
got_boottime = true;
}
}
if (!got_boottime) {
@@ -2413,7 +2516,7 @@ __cold int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages,
if (unlikely(pagesize < MIN_PAGESIZE || !is_powerof2(pagesize)))
return MDBX_INCOMPATIBLE;
__maybe_unused const int log2page = log2n_powerof2(pagesize);
MDBX_MAYBE_UNUSED const int log2page = log2n_powerof2(pagesize);
assert(pagesize == (INT64_C(1) << log2page));
(void)log2page;

View File

@@ -33,7 +33,7 @@
#if defined(_WIN32) || defined(_WIN64)
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#endif /* _CRT_SECURE_NO_WARNINGS */
#if !defined(_NO_CRT_STDIO_INLINE) && MDBX_BUILD_SHARED_LIBRARY && \
!defined(xMDBX_TOOLS) && MDBX_WITHOUT_MSVC_CRT
#define _NO_CRT_STDIO_INLINE
@@ -114,11 +114,9 @@
#include <mach/mach_host.h>
#include <mach/mach_port.h>
#include <uuid/uuid.h>
#undef P_DIRTY
#endif
#if defined(__linux__) || defined(__gnu_linux__)
#include <linux/sysctl.h>
#include <sched.h>
#include <sys/sendfile.h>
#include <sys/statfs.h>
@@ -440,7 +438,7 @@ typedef pthread_mutex_t mdbx_fastmutex_t;
/* Get the size of a memory page for the system.
* This is the basic size that the platform's memory manager uses, and is
* fundamental to the use of memory-mapped files. */
MDBX_NOTHROW_CONST_FUNCTION static __maybe_unused __inline size_t
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
mdbx_syspagesize(void) {
#if defined(_WIN32) || defined(_WIN64)
SYSTEM_INFO si;
@@ -460,8 +458,8 @@ typedef struct mdbx_mmap_param {
mdbx_filehandle_t fd;
size_t limit; /* mapping length, but NOT a size of file nor DB */
size_t current; /* mapped region size, i.e. the size of file and DB */
#if defined(_WIN32) || defined(_WIN64)
uint64_t filesize /* in-process cache of a file size */;
#if defined(_WIN32) || defined(_WIN64)
HANDLE section; /* memory-mapped section handle */
#endif
} mdbx_mmap_t;
@@ -481,9 +479,10 @@ typedef union MDBX_srwlock {
} MDBX_srwlock;
#endif /* Windows */
#ifdef __cplusplus
extern void mdbx_osal_jitter(bool tiny);
#else
#ifndef __cplusplus
MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
/*----------------------------------------------------------------------------*/
/* Atomics */
@@ -527,7 +526,7 @@ extern void mdbx_osal_jitter(bool tiny);
#include <sys/cachectl.h>
#endif
static __maybe_unused __inline void mdbx_compiler_barrier(void) {
MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
#if defined(__clang__) || defined(__GNUC__)
__asm__ __volatile__("" ::: "memory");
#elif defined(_MSC_VER)
@@ -547,7 +546,7 @@ static __maybe_unused __inline void mdbx_compiler_barrier(void) {
#endif
}
static __maybe_unused __inline void mdbx_memory_barrier(void) {
MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
#ifdef MDBX_HAVE_C11ATOMICS
atomic_thread_fence(memory_order_seq_cst);
#elif defined(__ATOMIC_SEQ_CST)
@@ -587,8 +586,8 @@ static __maybe_unused __inline void mdbx_memory_barrier(void) {
#define mdbx_asprintf asprintf
#define mdbx_vasprintf vasprintf
#else
MDBX_INTERNAL_FUNC MDBX_PRINTF_ARGS(2, 3) int __maybe_unused
mdbx_asprintf(char **strp, const char *fmt, ...);
MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
#endif
@@ -611,7 +610,7 @@ MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
LIBMDBX_API char *mdbx_strdup(const char *str);
#endif
static __maybe_unused __inline int mdbx_get_errno(void) {
MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
#if defined(_WIN32) || defined(_WIN64)
DWORD rc = GetLastError();
#else
@@ -695,8 +694,10 @@ MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
const size_t must, const size_t limit,
const unsigned options);
MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
MDBX_INTERNAL_FUNC int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t current,
size_t wanna, const bool may_move);
#define MDBX_MRESIZE_MAY_MOVE 0x00000100
#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
size_t size, size_t limit);
#if defined(_WIN32) || defined(_WIN64)
typedef struct {
unsigned limit, count;
@@ -713,7 +714,7 @@ MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
const char *pathname, int err);
static __maybe_unused __inline uint32_t mdbx_getpid(void) {
MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
#if defined(_WIN32) || defined(_WIN64)
return GetCurrentProcessId();
@@ -722,7 +723,7 @@ static __maybe_unused __inline uint32_t mdbx_getpid(void) {
#endif
}
static __maybe_unused __inline uintptr_t mdbx_thread_self(void) {
MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
mdbx_tid_t thunk;
STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
#if defined(_WIN32) || defined(_WIN64)
@@ -733,7 +734,6 @@ static __maybe_unused __inline uintptr_t mdbx_thread_self(void) {
return (uintptr_t)thunk;
}
MDBX_INTERNAL_FUNC void __maybe_unused mdbx_osal_jitter(bool tiny);
MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
MDBX_INTERNAL_FUNC uint64_t
mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);

View File

@@ -8,7 +8,7 @@
#error "API version mismatch! Had `git fetch --tags` done?"
#endif
static const char sourcery[] = STRINGIFY(MDBX_BUILD_SOURCERY);
static const char sourcery[] = MDBX_STRINGIFY(MDBX_BUILD_SOURCERY);
__dll_export
#ifdef __attribute_used__

View File

@@ -1,7 +1,7 @@
enable_language(CXX)
include(../cmake/compiler.cmake)
add_executable(mdbx_test
set(LIBMDBX_TEST_SOURCES
base.h
cases.cc
chrono.cc
@@ -30,6 +30,12 @@ add_executable(mdbx_test
nested.cc
)
if(NOT MDBX_BUILD_CXX)
list(APPEND LIBMDBX_TEST_SOURCES "${MDBX_SOURCE_DIR}/mdbx.c++" ../mdbx.h++)
endif()
add_executable(mdbx_test ${LIBMDBX_TEST_SOURCES})
if(MDBX_CXX_STANDARD)
set_target_properties(mdbx_test PROPERTIES
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)

View File

@@ -23,7 +23,9 @@
#define _WIN32_WINNT 0x0601 /* Windows 7 */
#endif
#ifdef _MSC_VER
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif /* _CRT_SECURE_NO_WARNINGS */
#pragma warning(push, 1)
#pragma warning(disable : 4548) /* expression before comma has no effect; \
expected expression with side - effect */
@@ -86,7 +88,7 @@
#define MDBX_INTERNAL_FUNC
#define MDBX_INTERNAL_VAR extern
#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
#include "../mdbx.h"
#include "../mdbx.h++"
#include "../src/defs.h"
#include "../src/osal.h"

View File

@@ -19,7 +19,7 @@
namespace chrono {
#pragma pack(push, 1)
#pragma pack(push, 4)
typedef union time {
uint64_t fixedpoint;

View File

@@ -310,6 +310,7 @@ const struct option_verb mode_bits[] = {
{"lifo", unsigned(MDBX_LIFORECLAIM)},
{"perturb", unsigned(MDBX_PAGEPERTURB)},
{"accede", unsigned(MDBX_ACCEDE)},
{"exclusive", unsigned(MDBX_EXCLUSIVE)},
{nullptr, 0}};
const struct option_verb table_bits[] = {

View File

@@ -135,8 +135,6 @@ inline bool parse_option_intptr(int argc, char *const argv[], int &narg,
//-----------------------------------------------------------------------------
#pragma pack(push, 1)
struct keygen_params_pod {
/* Параметры генератора пар key-value. Также может быть полезным описание
* алгоритма генерации в keygen.h
@@ -307,8 +305,6 @@ struct actor_config_pod {
wait4id(wait4id) {}
};
#pragma pack(pop)
extern const struct option_verb mode_bits[];
extern const struct option_verb table_bits[];
void dump(const char *title = "config-dump: ");

View File

@@ -73,7 +73,12 @@ bool testcase_hill::run() {
uint64_t committed_serial = serial_count;
unsigned txn_nops = 0;
bool rc = false;
bool rc = speculum_verify();
if (!rc) {
log_notice("uphill: bailout before main loop");
goto bailout;
}
while (should_continue()) {
const keygen::serial_t a_serial = serial_count;
if (unlikely(!keyvalue_maker.increment(serial_count, 1))) {

View File

@@ -243,23 +243,25 @@ void maker::seek2end(serial_t &serial) const {
serial = actor_params::serial_mask(mapping.width) - 1;
}
bool maker::increment(serial_t &serial, int delta) const {
bool maker::increment(serial_t &serial, int64_t delta) const {
if (serial > actor_params::serial_mask(mapping.width)) {
log_extra("keygen-increment: %" PRIu64 " > %" PRIu64 ", overflow", serial,
actor_params::serial_mask(mapping.width));
return false;
}
serial_t target = serial + (int64_t)delta;
serial_t target = serial + delta;
if (target > actor_params::serial_mask(mapping.width) ||
((delta > 0) ? target < serial : target > serial)) {
log_extra("keygen-increment: %" PRIu64 "%-d => %" PRIu64 ", overflow",
log_extra("keygen-increment: %" PRIu64 "%-" PRId64 " => %" PRIu64
", overflow",
serial, delta, target);
return false;
}
log_extra("keygen-increment: %" PRIu64 "%-d => %" PRIu64 ", continue", serial,
delta, target);
log_extra("keygen-increment: %" PRIu64 "%-" PRId64 " => %" PRIu64
", continue",
serial, delta, target);
serial = target;
return true;
}

View File

@@ -130,8 +130,8 @@ public:
bool is_unordered() const;
void seek2end(serial_t &serial) const;
bool increment(serial_t &serial, int delta) const;
bool increment_key_part(serial_t &serial, int delta,
bool increment(serial_t &serial, int64_t delta) const;
bool increment_key_part(serial_t &serial, int64_t delta,
bool reset_value_part = true) const {
if (reset_value_part) {
serial_t value_part_bits = ((serial_t(1) << mapping.split) - 1);
@@ -139,7 +139,7 @@ public:
if (delta >= 0)
serial &= ~value_part_bits;
}
return increment(serial, delta << mapping.split);
return increment(serial, int64_t(uint64_t(delta) << mapping.split));
}
};

View File

@@ -1,36 +1,121 @@
#!/usr/bin/env bash
if ! which make cc c++ tee lz4 >/dev/null; then
echo "Please install the following prerequisites: make cc c++ tee lz4 banner" >&2
if ! which make cc c++ tee >/dev/null; then
echo "Please install the following prerequisites: make cc c++ tee banner" >&2
exit 1
fi
LIST=basic
FROM=1
UPTO=9999999
MONITOR=
LOOPS=
SKIP_MAKE=no
BANNER="$(which banner 2>/dev/null | echo echo)"
UNAME="$(uname -s 2>/dev/null || echo Unknown)"
set -euo pipefail
DB_UPTO_MB=17408
## NOTE: Valgrind could produce some false-positive warnings
## in multi-process environment with shared memory.
## For instance, when the process "A" explicitly marks a memory
## region as "undefined", the process "B" fill it,
## and after this process "A" read such region, etc.
#VALGRIND="valgrind --trace-children=yes --log-file=valgrind-%p.log --leak-check=full --track-origins=yes --error-exitcode=42 --suppressions=test/valgrind_suppress.txt"
while [ -n "$1" ]
do
case "$1" in
--help)
echo "--multi Engage multi-process test scenario (default)"
echo "--single Execute series of single-process tests (for QEMU, etc)"
echo "--with-valgrind Run tests under Valgrind's memcheck tool"
echo "--skip-make Don't (re)build libmdbx and test's executable"
echo "--from NN Start iterating from the NN ops per test case"
echo "--upto NN Don't run tests with more than NN ops per test case"
echo "--loops NN Stop after the NN loops"
echo "--dir PATH Specifies directory for test DB and other files (it will be cleared)"
echo "--db-upto-mb NN Limits upper size of test DB to the NN megabytes"
echo "--help Print this usage help and exit"
exit -2
;;
--multi)
LIST=basic
;;
--single)
LIST="--nested --hill --append --ttl --copy"
;;
--with-valgrind)
echo " NOTE: Valgrind could produce some false-positive warnings"
echo " in multi-process environment with shared memory."
echo " For instance, when the process 'A' explicitly marks a memory"
echo " region as 'undefined', the process 'B' fill it,"
echo " and after this process 'A' read such region, etc."
MONITOR="valgrind --trace-children=yes --log-file=valgrind-%p.log --leak-check=full --track-origins=yes --error-exitcode=42 --suppressions=test/valgrind_suppress.txt"
rm -f valgrind-*.log
;;
--skip-make)
SKIP_MAKE=yes
;;
--from)
FROM=$(($2))
if [ -z "$FROM" -o "$FROM" -lt 1 ]; then
echo "Invalid value '$FROM' for --from option"
exit -2
fi
shift
;;
--upto)
UPTO=$(($2))
if [ -z "$UPTO" -o "$UPTO" -lt 1 ]; then
echo "Invalid value '$UPTO' for --upto option"
exit -2
fi
shift
;;
--loops)
LOOPS=$(($2))
if [ -z "$LOOPS" -o "$LOOPS" -lt 1 -o "$LOOPS" -gt 99 ]; then
echo "Invalid value '$LOOPS' for --loops option"
exit -2
fi
shift
;;
--dir)
TESTDB_DIR="$2"
if [ -z "$TESTDB_DIR" ]; then
echo "Invalid value '$TESTDB_DIR' for --dir option"
exit -2
fi
shift
;;
--db-upto-mb)
DB_UPTO_MB=$(($2))
if [ -z "$DB_UPTO_MB" -o "$DB_UPTO_MB" -lt 1 -o "$DB_UPTO_MB" -gt 4194304 ]; then
echo "Invalid value '$DB_UPTO_MB' for --db-upto-mb option"
exit -2
fi
shift
;;
*)
echo "Unknown option '$1'"
exit -2
;;
esac
shift
done
set -euo pipefail
if [ -z "$MONITOR" ]; then
if which time >/dev/null 2>/dev/null; then
MONITOR=$(which time)
if $MONITOR -o /dev/stdout true >/dev/null 2>/dev/null; then
MONITOR="$MONITOR -o /dev/stdout"
fi
fi
export MALLOC_CHECK_=7 MALLOC_PERTURB_=42
fi
###############################################################################
# 1. clean data from prev runs and examine available RAM
if [[ -v VALGRIND && ! -z "$VALGRIND" ]]; then
rm -f valgrind-*.log
else
VALGRIND=time
export MALLOC_CHECK_=7 MALLOC_PERTURB_=42
fi
WANNA_MOUNT=0
case ${UNAME} in
Linux)
MAKE=make
if [[ ! -v TESTDB_DIR || -z "$TESTDB_DIR" ]]; then
for old_test_dir in $(ls -d /dev/shm/mdbx-test.[0-9]*); do
if [ -z "${TESTDB_DIR:-}" ]; then
for old_test_dir in $(ls -d /dev/shm/mdbx-test.[0-9]* 2>/dev/null); do
rm -rf $old_test_dir
done
TESTDB_DIR="/dev/shm/mdbx-test.$$"
@@ -46,8 +131,8 @@ case ${UNAME} in
FreeBSD)
MAKE=gmake
if [[ ! -v TESTDB_DIR || -z "$TESTDB_DIR" ]]; then
for old_test_dir in $(ls -d /tmp/mdbx-test.[0-9]*); do
if [ -z "${TESTDB_DIR:-}" ]; then
for old_test_dir in $(ls -d /tmp/mdbx-test.[0-9]* 2>/dev/null); do
umount $old_test_dir && rm -r $old_test_dir
done
TESTDB_DIR="/tmp/mdbx-test.$$"
@@ -56,14 +141,13 @@ case ${UNAME} in
else
mkdir -p $TESTDB_DIR && rm -f $TESTDB_DIR/*
fi
ram_avail_mb=$(($(LC_ALL=C vmstat -s | grep -ie '[0-9] pages free$' | cut -d p -f 1) * ($(LC_ALL=C vmstat -s | grep -ie '[0-9] bytes per page$' | cut -d b -f 1) / 1024) / 1024))
;;
Darwin)
MAKE=make
if [[ ! -v TESTDB_DIR || -z "$TESTDB_DIR" ]]; then
for vol in $(ls -d /Volumes/mdx[0-9]*[0-9]tst); do
if [ -z "${TESTDB_DIR:-}" ]; then
for vol in $(ls -d /Volumes/mdx[0-9]*[0-9]tst 2>/dev/null); do
disk=$(mount | grep $vol | cut -d ' ' -f 1)
echo "umount: volume $vol disk $disk"
hdiutil unmount $vol -force
@@ -74,12 +158,10 @@ case ${UNAME} in
else
mkdir -p $TESTDB_DIR && rm -f $TESTDB_DIR/*
fi
pagesize=$(($(LC_ALL=C vm_stat | grep -o 'page size of [0-9]\+ bytes' | cut -d' ' -f 4) / 1024))
freepages=$(LC_ALL=C vm_stat | grep '^Pages free:' | grep -o '[0-9]\+\.$' | cut -d'.' -f 1)
ram_avail_mb=$((pagesize * freepages / 1024))
echo "pagesize ${pagesize}K, freepages ${freepages}, ram_avail_mb ${ram_avail_mb}"
;;
*)
@@ -88,6 +170,8 @@ case ${UNAME} in
;;
esac
rm -f ${TESTDB_DIR}/*
###############################################################################
# 2. estimate reasonable RAM space for test-db
@@ -117,8 +201,8 @@ fi
# system immediately, as well some space is required for logs.
#
db_size_mb=$(((ram_avail_mb - ram_reserve4logs_mb) / 4))
if [ $db_size_mb -gt 17408 ]; then
db_size_mb=17408
if [ $db_size_mb -gt $DB_UPTO_MB ]; then
db_size_mb=$DB_UPTO_MB
fi
echo "=== use ${db_size_mb}M for DB"
@@ -150,48 +234,80 @@ case ${UNAME} in
esac
###############################################################################
# 4. Run basic test, i.e. `make check`
# 4. build the test executables
${MAKE} -j2 all mdbx_test
#${MAKE} TEST_DB=${TESTDB_DIR}/smoke.db TEST_LOG=${TESTDB_DIR}/smoke.log check
rm -f ${TESTDB_DIR}/*
if [ "$SKIP_MAKE" != "yes" ]; then
${MAKE} -j$(which nproc >/dev/null 2>/dev/null && nproc || echo 2) build-test
fi
###############################################################################
# 5. run stochastic iterations
function join { local IFS="$1"; shift; echo "$*"; }
function bit2option { local -n arr=$1; (( ($2&(1<<$3)) != 0 )) && echo -n '+' || echo -n '-'; echo "${arr[$3]}"; }
if which lz4 >/dev/null; then
function logger {
lz4 > ${TESTDB_DIR}/long.log.lz4
}
elif which gzip >/dev/null; then
function logger {
gzip > ${TESTDB_DIR}/long.log.gz
}
else
function logger {
cat > ${TESTDB_DIR}/long.log
}
fi
syncmodes=("" ,+nosync-safe ,+nosync-utterly)
options=(writemap coalesce lifo notls perturb)
function bits2list {
local -n arr=$1
function join { local IFS="$1"; shift; echo "$*"; }
function bits2options {
local bits=$1
local i
local list=()
for ((i=0; i<${#arr[@]}; ++i)) do
list[$i]=$(bit2option $1 $2 $i)
for ((i = 0; i < ${#options[@]}; ++i)); do
list[$i]=$( (( (bits & (1 << i)) != 0 )) && echo -n '+' || echo -n '-'; echo ${options[$i]})
done
join , "${list[@]}"
join , ${list[@]}
}
function failed {
echo "FAILED" >&2
exit 1
}
function check_deep {
if [ "$case" = "basic" -o "$case" = "--hill" ]; then
tee >(logger) | grep -e reach -e achieve
else
logger
fi
}
function probe {
echo "----------------------------------------------- $(date)"
echo "${caption}: $*"
rm -f ${TESTDB_DIR}/* \
&& ${VALGRIND} ./mdbx_test ${speculum} --random-writemap=no --ignore-dbfull --repeat=11 --pathname=${TESTDB_DIR}/long.db --cleanup-after=no "$@" \
| tee >(lz4 > ${TESTDB_DIR}/long.log.lz4) | grep -e reach -e achieve \
&& ${VALGRIND} ./mdbx_chk ${TESTDB_DIR}/long.db | tee ${TESTDB_DIR}/long-chk.log \
&& ([ ! -e ${TESTDB_DIR}/long.db-copy ] || ${VALGRIND} ./mdbx_chk ${TESTDB_DIR}/long.db-copy | tee ${TESTDB_DIR}/long-chk-copy.log) \
|| (echo "FAILED"; exit 1)
echo "${caption}"
rm -f ${TESTDB_DIR}/* || failed
for case in $LIST
do
echo "Run ./mdbx_test ${speculum} --random-writemap=no --ignore-dbfull --repeat=11 --pathname=${TESTDB_DIR}/long.db --cleanup-after=no $@ $case"
${MONITOR} ./mdbx_test ${speculum} --random-writemap=no --ignore-dbfull --repeat=11 --pathname=${TESTDB_DIR}/long.db --cleanup-after=no "$@" $case | check_deep \
&& ${MONITOR} ./mdbx_chk ${TESTDB_DIR}/long.db | tee ${TESTDB_DIR}/long-chk.log \
&& ([ ! -e ${TESTDB_DIR}/long.db-copy ] || ${MONITOR} ./mdbx_chk ${TESTDB_DIR}/long.db-copy | tee ${TESTDB_DIR}/long-chk-copy.log) \
|| failed
done
}
#------------------------------------------------------------------------------
count=0
loop=0
cases='?'
for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10000000 33333333 100000000 333333333 1000000000; do
if [ $nops -lt $FROM ]; then continue; fi
if [ $nops -gt $UPTO ]; then echo "The '--upto $UPTO' limit reached"; break; fi
if [ -n "$LOOPS" ] && [ $loop -ge "$LOOPS" ]; then echo "The '--loops $LOOPS' limit reached"; break; fi
echo "======================================================================="
wbatch=$((nops / 7 + 1))
speculum=$([ $nops -le 1000 ] && echo '--speculum' || true)
@@ -204,68 +320,70 @@ for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10
split=30
caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
split=24
caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
split=16
caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
split=4
caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=min --size-upper=${db_size_mb}M --table=-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed} basic
--pagesize=min --size-upper-upto=${db_size_mb}M --table=-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
done # options
loop=$((loop + 1))
if [ -n "$LOOPS" ] && [ $loop -ge "$LOOPS" ]; then break; fi
cases="${subcase}"
wbatch=$(((wbatch > 7) ? wbatch / 7 : 1))
if [ $wbatch -eq 1 -o $((nops / wbatch)) -gt 1000 ]; then break; fi

View File

@@ -92,6 +92,8 @@ MDBX_NORETURN void usage(void) {
" --mode={[+-]FLAG}[,[+-]FLAG]...\n"
" nosubdir == MDBX_NOSUBDIR\n"
" rdonly == MDBX_RDONLY\n"
" exclusive == MDBX_EXCLUSIVE\n"
" accede == MDBX_ACCEDE\n"
" nometasync == MDBX_NOMETASYNC\n"
" lifo == MDBX_LIFORECLAIM\n"
" coalesce == MDBX_COALESCE\n"
@@ -222,6 +224,43 @@ void cleanup() {
log_trace("<< cleanup");
}
static void fixup4qemu(actor_params &params) {
#ifdef MDBX_SAFE4QEMU
#if MDBX_WORDBITS == 32
intptr_t safe4qemu_limit = size_t(512) << 20 /* 512 megabytes */;
#if defined(__SANITIZE_ADDRESS__)
safe4qemu_limit >>= 1;
#else
if (RUNNING_ON_VALGRIND)
safe4qemu_limit >>= 1;
#endif /* __SANITIZE_ADDRESS__ */
if (params.size_lower > safe4qemu_limit ||
params.size_now > safe4qemu_limit ||
params.size_upper > safe4qemu_limit) {
params.size_upper = std::min(params.size_upper, safe4qemu_limit);
params.size_now = std::min(params.size_now, params.size_upper);
params.size_lower = std::min(params.size_lower, params.size_now);
log_notice("workaround: for conformance 32-bit build with "
"QEMU/ASAN/Valgrind database size reduced to %zu megabytes",
safe4qemu_limit >> 20);
}
#endif /* MDBX_WORDBITS == 32 */
#if defined(__alpha__) || defined(__alpha) || defined(__sparc__) || \
defined(__sparc) || defined(__sparc64__) || defined(__sparc64)
if (params.size_lower != params.size_upper) {
log_notice(
"workaround: for conformance Alpha/Sparc build with QEMU/ASAN/Valgrind "
"enforce fixed database size %zu megabytes",
params.size_upper >> 20);
params.size_lower = params.size_now = params.size_upper;
}
#endif /* Alpha || Sparc */
#endif /* MDBX_SAFE4QEMU */
(void)params;
}
int main(int argc, char *const argv[]) {
#ifdef _DEBUG
@@ -254,6 +293,7 @@ int main(int argc, char *const argv[]) {
const char *value = nullptr;
if (config::parse_option(argc, argv, narg, "case", &value)) {
fixup4qemu(params);
testcase_setup(value, params, last_space_id);
continue;
}
@@ -327,6 +367,15 @@ int main(int argc, char *const argv[]) {
mdbx_limits_dbsize_min(params.pagesize),
mdbx_limits_dbsize_max(params.pagesize)))
continue;
int64_t i64 = params.size_upper;
if (config::parse_option(argc, argv, narg, "size-upper-upto", i64,
int64_t(mdbx_limits_dbsize_min(params.pagesize)),
INT64_MAX, -1)) {
if (i64 > mdbx_limits_dbsize_max(params.pagesize))
i64 = mdbx_limits_dbsize_max(params.pagesize);
params.size_upper = intptr_t(i64);
continue;
}
if (config::parse_option_intptr(argc, argv, narg, "size-upper",
params.size_upper,
mdbx_limits_dbsize_min(params.pagesize),
@@ -477,38 +526,47 @@ int main(int argc, char *const argv[]) {
continue;
}
if (config::parse_option(argc, argv, narg, "hill", &value, "auto")) {
fixup4qemu(params);
configure_actor(last_space_id, ac_hill, value, params);
continue;
}
if (config::parse_option(argc, argv, narg, "jitter", nullptr)) {
fixup4qemu(params);
configure_actor(last_space_id, ac_jitter, value, params);
continue;
}
if (config::parse_option(argc, argv, narg, "dead.reader", nullptr)) {
fixup4qemu(params);
configure_actor(last_space_id, ac_deadread, value, params);
continue;
}
if (config::parse_option(argc, argv, narg, "dead.writer", nullptr)) {
fixup4qemu(params);
configure_actor(last_space_id, ac_deadwrite, value, params);
continue;
}
if (config::parse_option(argc, argv, narg, "try", nullptr)) {
fixup4qemu(params);
configure_actor(last_space_id, ac_try, value, params);
continue;
}
if (config::parse_option(argc, argv, narg, "copy", nullptr)) {
fixup4qemu(params);
configure_actor(last_space_id, ac_copy, value, params);
continue;
}
if (config::parse_option(argc, argv, narg, "append", nullptr)) {
fixup4qemu(params);
configure_actor(last_space_id, ac_append, value, params);
continue;
}
if (config::parse_option(argc, argv, narg, "ttl", nullptr)) {
fixup4qemu(params);
configure_actor(last_space_id, ac_ttl, value, params);
continue;
}
if (config::parse_option(argc, argv, narg, "nested", nullptr)) {
fixup4qemu(params);
configure_actor(last_space_id, ac_nested, value, params);
continue;
}
@@ -522,9 +580,10 @@ int main(int argc, char *const argv[]) {
global::config::console_mode))
continue;
if (*argv[narg] != '-')
if (*argv[narg] != '-') {
fixup4qemu(params);
testcase_setup(argv[narg], params, last_space_id);
else
} else
failure("Unknown option '%s'. Try --help\n", argv[narg]);
}
@@ -550,10 +609,6 @@ int main(int argc, char *const argv[]) {
if (global::config::cleanup_before)
cleanup();
log_trace(">> probe entropy_ticks()");
entropy_ticks();
log_trace("<< probe entropy_ticks()");
if (global::actors.size() == 1) {
logging::setup("main");
global::singlemode = true;

View File

@@ -110,16 +110,26 @@ bool testcase_nested::teardown() {
}
void testcase_nested::push_txn() {
MDBX_txn *txn;
MDBX_txn *nested_txn;
MDBX_txn_flags_t flags = MDBX_txn_flags_t(
prng32() & uint32_t(MDBX_TXN_NOSYNC | MDBX_TXN_NOMETASYNC));
int err = mdbx_txn_begin(db_guard.get(), txn_guard.get(), flags, &txn);
int err = mdbx_txn_begin(db_guard.get(), txn_guard.get(), flags, &nested_txn);
if (unlikely(err != MDBX_SUCCESS))
failure_perror("mdbx_txn_begin(nested)", err);
stack.emplace(scoped_txn_guard(txn), serial, fifo, speculum);
std::swap(txn_guard, std::get<0>(stack.top()));
/* CLANG/LLVM C++ library could stupidly copy std::set<> item-by-item,
* i.e. with insertion(s) & comparison(s), which will cause null dereference
* during call mdbx_cmp() with zero txn. So it is the workaround for this:
* - explicitly set txn_guard with the new nested txn;
* - explicitly copy the `speculum` (an instance of std::set<>). */
scoped_txn_guard nested_txn_guard(nested_txn);
txn_guard.swap(nested_txn_guard);
SET speculum_snapshot(speculum);
stack.emplace(std::move(nested_txn_guard), serial, fifo,
std::move(speculum_snapshot));
log_verbose("begin level#%zu txn #%" PRIu64 ", flags 0x%x, serial %" PRIu64,
stack.size(), mdbx_txn_id(txn), flags, serial);
stack.size(), mdbx_txn_id(nested_txn), flags, serial);
if (!dbi && stack.size() == 1)
dbi = db_table_open(true);
}
bool testcase_nested::pop_txn(bool abort) {
@@ -131,6 +141,9 @@ bool testcase_nested::pop_txn(bool abort) {
log_verbose(
"abort level#%zu txn #%" PRIu64 ", undo serial %" PRIu64 " <- %" PRIu64,
stack.size(), mdbx_txn_id(txn), serial, std::get<1>(stack.top()));
if (dbi > 0 && stack.size() == 1 &&
is_handle_created_in_current_txn(dbi, txn))
dbi = 0;
int err = mdbx_txn_abort(txn);
if (unlikely(err != MDBX_SUCCESS))
failure_perror("mdbx_txn_abort()", err);
@@ -192,7 +205,7 @@ bool testcase_nested::trim_tail(unsigned window_width) {
while (fifo.size() > window_width) {
uint64_t tail_serial = fifo.back().first;
const unsigned tail_count = fifo.back().second;
log_verbose("nested: pop-tail (serial %" PRIu64 ", count %u)",
log_verbose("nested: trim-tail (serial %" PRIu64 ", count %u)",
tail_serial, tail_count);
fifo.pop_back();
for (unsigned n = 0; n < tail_count; ++n) {

View File

@@ -45,11 +45,11 @@
#if __cplusplus >= 201103L
#include <atomic>
static __inline __maybe_unused int atomic_decrement(std::atomic_int *p) {
MDBX_MAYBE_UNUSED static __inline int atomic_decrement(std::atomic_int *p) {
return std::atomic_fetch_sub(p, 1) - 1;
}
#else
static __inline __maybe_unused int atomic_decrement(volatile int *p) {
MDBX_MAYBE_UNUSED static __inline int atomic_decrement(volatile int *p) {
#if defined(__GNUC__) || defined(__clang__)
return __sync_sub_and_fetch(p, 1);
#elif defined(_MSC_VER)

365
test/stochastic_small.sh Executable file
View File

@@ -0,0 +1,365 @@
#!/usr/bin/env bash
if ! which make cc c++ tee >/dev/null; then
echo "Please install the following prerequisites: make cc c++ tee banner" >&2
exit 1
fi
LIST=--hill
FROM=1
UPTO=9999
MONITOR=
LOOPS=
SKIP_MAKE=no
BANNER="$(which banner 2>/dev/null | echo echo)"
UNAME="$(uname -s 2>/dev/null || echo Unknown)"
DB_UPTO_MB=17408
while [ -n "$1" ]
do
case "$1" in
--help)
echo "--multi Engage multi-process test scenario (default)"
echo "--single Execute series of single-process tests (for QEMU, etc)"
echo "--with-valgrind Run tests under Valgrind's memcheck tool"
echo "--skip-make Don't (re)build libmdbx and test's executable"
echo "--from NN Start iterating from the NN ops per test case"
echo "--upto NN Don't run tests with more than NN ops per test case"
echo "--loops NN Stop after the NN loops"
echo "--dir PATH Specifies directory for test DB and other files (it will be cleared)"
echo "--db-upto-mb NN Limits upper size of test DB to the NN megabytes"
echo "--help Print this usage help and exit"
exit -2
;;
--multi)
LIST=basic
;;
--single)
LIST="--nested --hill --append --ttl --copy"
;;
--with-valgrind)
echo " NOTE: Valgrind could produce some false-positive warnings"
echo " in multi-process environment with shared memory."
echo " For instance, when the process 'A' explicitly marks a memory"
echo " region as 'undefined', the process 'B' fill it,"
echo " and after this process 'A' read such region, etc."
MONITOR="valgrind --trace-children=yes --log-file=valgrind-%p.log --leak-check=full --track-origins=yes --error-exitcode=42 --suppressions=test/valgrind_suppress.txt"
rm -f valgrind-*.log
;;
--skip-make)
SKIP_MAKE=yes
;;
--from)
FROM=$(($2))
if [ -z "$FROM" -o "$FROM" -lt 1 ]; then
echo "Invalid value '$FROM' for --from option"
exit -2
fi
shift
;;
--upto)
UPTO=$(($2))
if [ -z "$UPTO" -o "$UPTO" -lt 1 ]; then
echo "Invalid value '$UPTO' for --upto option"
exit -2
fi
shift
;;
--loops)
LOOPS=$(($2))
if [ -z "$LOOPS" -o "$LOOPS" -lt 1 -o "$LOOPS" -gt 99 ]; then
echo "Invalid value '$LOOPS' for --loops option"
exit -2
fi
shift
;;
--dir)
TESTDB_DIR="$2"
if [ -z "$TESTDB_DIR" ]; then
echo "Invalid value '$TESTDB_DIR' for --dir option"
exit -2
fi
shift
;;
--db-upto-mb)
DB_UPTO_MB=$(($2))
if [ -z "$DB_UPTO_MB" -o "$DB_UPTO_MB" -lt 1 -o "$DB_UPTO_MB" -gt 4194304 ]; then
echo "Invalid value '$DB_UPTO_MB' for --db-upto-mb option"
exit -2
fi
shift
;;
*)
echo "Unknown option '$1'"
exit -2
;;
esac
shift
done
set -euo pipefail
if [ -z "$MONITOR" ]; then
if which time >/dev/null 2>/dev/null; then
MONITOR=$(which time)
if $MONITOR -o /dev/stdout true >/dev/null 2>/dev/null; then
MONITOR="$MONITOR -o /dev/stdout"
fi
fi
export MALLOC_CHECK_=7 MALLOC_PERTURB_=42
fi
###############################################################################
# 1. clean data from prev runs and examine available RAM
WANNA_MOUNT=0
case ${UNAME} in
Linux)
MAKE=make
if [ -z "${TESTDB_DIR:-}" ]; then
for old_test_dir in $(ls -d /dev/shm/mdbx-test.[0-9]* 2>/dev/null); do
rm -rf $old_test_dir
done
TESTDB_DIR="/dev/shm/mdbx-test.$$"
fi
mkdir -p $TESTDB_DIR && rm -f $TESTDB_DIR/*
if LC_ALL=C free | grep -q -i available; then
ram_avail_mb=$(($(LC_ALL=C free | grep -i Mem: | tr -s [:blank:] ' ' | cut -d ' ' -f 7) / 1024))
else
ram_avail_mb=$(($(LC_ALL=C free | grep -i Mem: | tr -s [:blank:] ' ' | cut -d ' ' -f 4) / 1024))
fi
;;
FreeBSD)
MAKE=gmake
if [ -z "${TESTDB_DIR:-}" ]; then
for old_test_dir in $(ls -d /tmp/mdbx-test.[0-9]* 2>/dev/null); do
umount $old_test_dir && rm -r $old_test_dir
done
TESTDB_DIR="/tmp/mdbx-test.$$"
rm -rf $TESTDB_DIR && mkdir -p $TESTDB_DIR
WANNA_MOUNT=1
else
mkdir -p $TESTDB_DIR && rm -f $TESTDB_DIR/*
fi
ram_avail_mb=$(($(LC_ALL=C vmstat -s | grep -ie '[0-9] pages free$' | cut -d p -f 1) * ($(LC_ALL=C vmstat -s | grep -ie '[0-9] bytes per page$' | cut -d b -f 1) / 1024) / 1024))
;;
Darwin)
MAKE=make
if [ -z "${TESTDB_DIR:-}" ]; then
for vol in $(ls -d /Volumes/mdx[0-9]*[0-9]tst 2>/dev/null); do
disk=$(mount | grep $vol | cut -d ' ' -f 1)
echo "umount: volume $vol disk $disk"
hdiutil unmount $vol -force
hdiutil detach $disk
done
TESTDB_DIR="/Volumes/mdx$$tst"
WANNA_MOUNT=1
else
mkdir -p $TESTDB_DIR && rm -f $TESTDB_DIR/*
fi
pagesize=$(($(LC_ALL=C vm_stat | grep -o 'page size of [0-9]\+ bytes' | cut -d' ' -f 4) / 1024))
freepages=$(LC_ALL=C vm_stat | grep '^Pages free:' | grep -o '[0-9]\+\.$' | cut -d'.' -f 1)
ram_avail_mb=$((pagesize * freepages / 1024))
echo "pagesize ${pagesize}K, freepages ${freepages}, ram_avail_mb ${ram_avail_mb}"
;;
*)
echo "FIXME: ${UNAME} not supported by this script"
exit 2
;;
esac
rm -f ${TESTDB_DIR}/*
###############################################################################
# 2. estimate reasonable RAM space for test-db
echo "=== ${ram_avail_mb}M RAM available"
ram_reserve4logs_mb=1234
if [ $ram_avail_mb -lt $ram_reserve4logs_mb ]; then
echo "=== At least ${ram_reserve4logs_mb}Mb RAM required"
exit 3
fi
#
# В режимах отличных от MDBX_WRITEMAP изменения до записи в файл
# будут накапливаться в памяти, что может потребовать свободной
# памяти размером с БД. Кроме этого, в тест входит сценарий
# создания копия БД на ходу. Поэтому БД не может быть больше 1/3
# от доступной памяти. Однако, следует учесть что malloc() будет
# не сразу возвращать выделенную память системе, а также
# предусмотреть места для логов.
#
# In non-MDBX_WRITEMAP modes, updates (dirty pages) will
# accumulate in memory before writing to the disk, which may
# require a free memory up to the size of a whole database. In
# addition, the test includes a script create a copy of the
# database on the go. Therefore, the database cannot be more 1/3
# of available memory. Moreover, should be taken into account
# that malloc() will not return the allocated memory to the
# system immediately, as well some space is required for logs.
#
db_size_mb=$(((ram_avail_mb - ram_reserve4logs_mb) / 4))
if [ $db_size_mb -gt $DB_UPTO_MB ]; then
db_size_mb=$DB_UPTO_MB
fi
echo "=== use ${db_size_mb}M for DB"
###############################################################################
# 3. Create test-directory in ramfs/tmpfs, i.e. create/format/mount if required
case ${UNAME} in
Linux)
;;
FreeBSD)
if [[ WANNA_MOUNT ]]; then
mount -t tmpfs tmpfs $TESTDB_DIR
fi
;;
Darwin)
if [[ WANNA_MOUNT ]]; then
ramdisk_size_mb=$((42 + db_size_mb * 2 + ram_reserve4logs_mb))
number_of_sectors=$((ramdisk_size_mb * 2048))
ramdev=$(hdiutil attach -nomount ram://${number_of_sectors})
diskutil erasevolume ExFAT "mdx$$tst" ${ramdev}
fi
;;
*)
echo "FIXME: ${UNAME} not supported by this script"
exit 2
;;
esac
###############################################################################
# 4. build the test executables
if [ "$SKIP_MAKE" != "yes" ]; then
${MAKE} -j$(which nproc >/dev/null 2>/dev/null && nproc || echo 2) build-test
fi
###############################################################################
# 5. run stochastic iterations
if which lz4 >/dev/null; then
function logger {
lz4 > ${TESTDB_DIR}/long.log.lz4
}
elif which gzip >/dev/null; then
function logger {
gzip > ${TESTDB_DIR}/long.log.gz
}
else
function logger {
cat > ${TESTDB_DIR}/long.log
}
fi
syncmodes=("" ,+nosync-safe ,+nosync-utterly)
options=(writemap coalesce lifo notls perturb)
function join { local IFS="$1"; shift; echo "$*"; }
function bits2options {
local bits=$1
local i
local list=()
for ((i = 0; i < ${#options[@]}; ++i)); do
list[$i]=$( (( (bits & (1 << i)) != 0 )) && echo -n '+' || echo -n '-'; echo ${options[$i]})
done
join , ${list[@]}
}
function failed {
echo "FAILED" >&2
exit 1
}
function check_deep {
if [ "$case" = "basic" -o "$case" = "--hill" ]; then
tee >(logger) | grep -e reach -e achieve
else
logger
fi
}
function probe {
echo "----------------------------------------------- $(date)"
echo "${caption}"
rm -f ${TESTDB_DIR}/* || failed
for case in $LIST
do
echo "Run ./mdbx_test ${speculum} --random-writemap=no --ignore-dbfull --repeat=1 --pathname=${TESTDB_DIR}/long.db --cleanup-after=no $@ $case"
${MONITOR} ./mdbx_test ${speculum} --random-writemap=no --ignore-dbfull --repeat=1 --pathname=${TESTDB_DIR}/long.db --cleanup-before=yes --cleanup-after=no "$@" $case | check_deep \
&& ${MONITOR} ./mdbx_chk ${TESTDB_DIR}/long.db | tee ${TESTDB_DIR}/long-chk.log \
&& ([ ! -e ${TESTDB_DIR}/long.db-copy ] || ${MONITOR} ./mdbx_chk ${TESTDB_DIR}/long.db-copy | tee ${TESTDB_DIR}/long-chk-copy.log) \
|| failed
done
}
#------------------------------------------------------------------------------
count=0
loop=0
cases='?'
for ((wbatch=FROM; wbatch<=UPTO; ++wbatch)); do
if [ -n "$LOOPS" ] && [ $loop -ge "$LOOPS" ]; then echo "The '--loops $LOOPS' limit reached"; break; fi
echo "======================================================================="
speculum=$([ $wbatch -le 1000 ] && echo '--speculum' || true)
nops=$((wbatch/7 + 1))
for ((rep=1; rep < 11; ++rep)); do
echo "======================================================================="
${BANNER} "$nops / $wbatch, repeat $rep"
subcase=0
for ((bits=2**${#options[@]}; --bits >= 0; )); do
seed=$(($(date +%s) + RANDOM))
split=30
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=4K --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
split=24
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=4K --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
split=16
caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=4K --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=4K --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=4K --size-upper-upto=${db_size_mb}M --table=-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
split=4
caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=4K --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=4K --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
caption="Probe #$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
--pagesize=4K --size-upper-upto=${db_size_mb}M --table=-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%3]} \
--keygen.seed=${seed}
done # options
cases="${subcase}"
done # repeats
loop=$((loop + 1))
if [ -n "$LOOPS" ] && [ $loop -ge "$LOOPS" ]; then break; fi
done # wbatch
echo "=== ALL DONE ====================== $(date)"

View File

@@ -197,6 +197,18 @@ int testcase::breakable_commit() {
log_trace(">> txn_commit");
assert(txn_guard);
/* CLANG/LLVM C++ library could stupidly copy std::set<> item-by-item,
* i.e. with insertion(s) & comparison(s), which will cause null dereference
* during call mdbx_cmp() with zero txn. So it is the workaround for this:
* - explicitly make copies of the `speculums`;
* - explicitly move relevant copy after transaction commit. */
SET speculum_committed_copy(ItemCompare(this)),
speculum_copy(ItemCompare(this));
if (need_speculum_assign) {
speculum_committed_copy = speculum_committed;
speculum_copy = speculum;
}
MDBX_txn *txn = txn_guard.release();
txn_inject_writefault(txn);
int rc = mdbx_txn_commit(txn);
@@ -207,9 +219,9 @@ int testcase::breakable_commit() {
if (need_speculum_assign) {
need_speculum_assign = false;
if (unlikely(rc != MDBX_SUCCESS))
speculum = speculum_committed;
speculum = std::move(speculum_committed_copy);
else
speculum_committed = speculum;
speculum_committed = std::move(speculum_copy);
}
log_trace("<< txn_commit: %s", rc ? "failed" : "Ok");
@@ -465,6 +477,15 @@ void testcase::update_canary(uint64_t increment) {
log_trace("<< update_canary: sequence = %" PRIu64, canary_now.y);
}
bool testcase::is_handle_created_in_current_txn(const MDBX_dbi handle,
MDBX_txn *txn) {
unsigned flags, state;
int err = mdbx_dbi_flags_ex(txn, handle, &flags, &state);
if (unlikely(err != MDBX_SUCCESS))
failure_perror("mdbx_dbi_flags_ex()", err);
return (state & MDBX_DBI_CREAT) != 0;
}
int testcase::db_open__begin__table_create_open_clean(MDBX_dbi &handle) {
db_open();
@@ -472,6 +493,9 @@ int testcase::db_open__begin__table_create_open_clean(MDBX_dbi &handle) {
for (;;) {
txn_begin(false);
handle = db_table_open(true);
if (is_handle_created_in_current_txn(handle, txn_guard.get()))
return MDBX_SUCCESS;
db_table_clear(handle);
err = breakable_commit();
if (likely(err == MDBX_SUCCESS)) {
@@ -617,7 +641,8 @@ enum speculum_cursors : int {
prev = 1,
prev_prev = 2,
next = 3,
next_next = 4
next_next = 4,
seek_check = 5
};
bool testcase::is_same(const Item &a, const Item &b) const {
@@ -691,7 +716,7 @@ void testcase::speculum_check_cursor(const char *where, const char *stage,
// verbose(where, stage, cursor_key, cursor_data, cursor_err);
// verbose(where, stage, it);
if (cursor_err != MDBX_SUCCESS && cursor_err != MDBX_NOTFOUND &&
cursor_err != MDBX_RESULT_TRUE)
cursor_err != MDBX_RESULT_TRUE && cursor_err != MDBX_ENODATA)
failure("speculum-%s: %s %s %d %s", where, stage, "cursor-get", cursor_err,
mdbx_strerror(cursor_err));
@@ -714,8 +739,8 @@ void testcase::speculum_check_cursor(const char *where, const char *stage,
const testcase::SET::const_iterator &it,
MDBX_cursor *cursor,
const MDBX_cursor_op op) const {
MDBX_val cursor_key = {};
MDBX_val cursor_data = {};
MDBX_val cursor_key = {0, 0};
MDBX_val cursor_data = {0, 0};
int err;
if (it != speculum.end() && std::next(it) == speculum.end() &&
op == MDBX_PREV && (config.params.table_flags & MDBX_DUPSORT)) {
@@ -828,11 +853,26 @@ int testcase::insert(const keygen::buffer &akey, const keygen::buffer &adata,
int err;
bool rc = true;
Item item;
#if SPECULUM_CURSORS
MDBX_cursor *check_seek_cursor = nullptr;
MDBX_val seek_check_key, seek_check_data;
int seek_check_err = 42;
#endif /* SPECULUM_CURSORS */
if (config.params.speculum) {
item.first = iov2dataview(akey);
item.second = iov2dataview(adata);
#if SPECULUM_CURSORS
speculum_prepare_cursors(item);
check_seek_cursor = speculum_cursors[seek_check].get();
seek_check_key = akey->value;
seek_check_data = adata->value;
seek_check_err = mdbx_cursor_get(
check_seek_cursor, &seek_check_key, &seek_check_data,
(config.params.table_flags & MDBX_DUPSORT) ? MDBX_GET_BOTH
: MDBX_SET_KEY);
if (seek_check_err != MDBX_SUCCESS && seek_check_err != MDBX_NOTFOUND)
failure("speculum-%s: %s pre-insert %d %s", "insert", "seek",
seek_check_err, mdbx_strerror(seek_check_err));
#endif /* SPECULUM_CURSORS */
}
@@ -857,6 +897,26 @@ int testcase::insert(const keygen::buffer &akey, const keygen::buffer &adata,
}
#if SPECULUM_CURSORS
if (insertion_result.second) {
if (seek_check_err != MDBX_NOTFOUND) {
log_error(
"speculum.pre-insert-seek: unexpected %d {%s, %s}", seek_check_err,
mdbx_dump_val(&seek_check_key, dump_key, sizeof(dump_key)),
mdbx_dump_val(&seek_check_data, dump_value, sizeof(dump_value)));
rc = false;
}
} else {
if (seek_check_err != MDBX_SUCCESS) {
log_error(
"speculum.pre-insert-seek: unexpected %d {%s, %s}", seek_check_err,
mdbx_dump_val(&seek_check_key, dump_key, sizeof(dump_key)),
mdbx_dump_val(&seek_check_data, dump_value, sizeof(dump_value)));
speculum_check_iterator("insert", "pre-seek", insertion_result.first,
seek_check_key, seek_check_data);
rc = false;
}
}
if (insertion_result.first != speculum.begin()) {
const auto cursor_prev = speculum_cursors[prev].get();
auto it_prev = insertion_result.first;
@@ -1018,7 +1078,7 @@ bool testcase::speculum_verify() {
char dump_mkey[128], dump_mvalue[128];
MDBX_cursor *cursor;
int err = mdbx_cursor_open(txn_guard.get(), dbi, &cursor);
int eof, err = mdbx_cursor_open(txn_guard.get(), dbi, &cursor);
if (err != MDBX_SUCCESS)
failure_perror("mdbx_cursor_open()", err);
@@ -1026,6 +1086,15 @@ bool testcase::speculum_verify() {
MDBX_val akey, avalue;
MDBX_val mkey, mvalue;
err = mdbx_cursor_get(cursor, &akey, &avalue, MDBX_FIRST);
if (err == MDBX_NOTFOUND) {
err = mdbx_cursor_get(cursor, &akey, &avalue, MDBX_GET_CURRENT);
if (err == MDBX_ENODATA)
err = MDBX_NOTFOUND;
else {
log_error("unexpected %d for MDBX_GET_CURRENT on empty DB", err);
rc = false;
}
}
unsigned extra = 0, lost = 0, n = 0;
assert(std::is_sorted(speculum.cbegin(), speculum.cend(), ItemCompare(this)));
@@ -1034,14 +1103,20 @@ bool testcase::speculum_verify() {
if (err != MDBX_SUCCESS) {
akey.iov_len = avalue.iov_len = 0;
akey.iov_base = avalue.iov_base = nullptr;
} else {
eof = mdbx_cursor_eof(cursor);
if (eof != MDBX_RESULT_FALSE) {
log_error("false-positive cursor-eof %u/%u: db{%s, %s}, rc %i", n,
extra, mdbx_dump_val(&akey, dump_key, sizeof(dump_key)),
mdbx_dump_val(&avalue, dump_value, sizeof(dump_value)), eof);
rc = false;
}
}
const auto S_key = iov2dataview(akey);
const auto S_data = iov2dataview(avalue);
if (it != speculum.cend()) {
mkey.iov_base = (void *)it->first.c_str();
mkey.iov_len = it->first.size();
mvalue.iov_base = (void *)it->second.c_str();
mvalue.iov_len = it->second.size();
mkey = it->first;
mvalue = it->second;
}
if (err == MDBX_SUCCESS && it != speculum.cend() && S_key == it->first &&
S_data == it->second) {
@@ -1091,6 +1166,21 @@ bool testcase::speculum_verify() {
n += 1;
}
if (err == MDBX_NOTFOUND) {
eof = mdbx_cursor_eof(cursor);
if (eof != MDBX_RESULT_TRUE) {
eof = mdbx_cursor_eof(cursor);
log_error("false-negative cursor-eof: %u, rc %i", n, eof);
rc = false;
}
err = mdbx_cursor_get(cursor, &akey, &avalue, MDBX_GET_CURRENT);
if (err == MDBX_SUCCESS)
err = mdbx_cursor_get(cursor, &akey, &avalue, MDBX_NEXT);
if (err != MDBX_ENODATA) {
log_error("unexpected %d for MDBX_GET_CURRENT at EOF", err);
rc = false;
}
}
mdbx_cursor_close(cursor);
return rc;
}

View File

@@ -130,16 +130,12 @@ public:
};
#define REGISTER_TESTCASE(NAME) \
static registry::factory<testcase_##NAME> gRegister_##NAME(ac_##NAME, \
STRINGIFY(NAME))
static registry::factory<testcase_##NAME> gRegister_##NAME( \
ac_##NAME, MDBX_STRINGIFY(NAME))
class testcase {
protected:
#if HAVE_cxx17_std_string_view
using data_view = std::string_view;
#else
using data_view = std::string;
#endif
using data_view = mdbx::slice;
static inline data_view iov2dataview(const MDBX_val &v) {
return (v.iov_base && v.iov_len)
? data_view(static_cast<const char *>(v.iov_base), v.iov_len)
@@ -149,7 +145,8 @@ protected:
return iov2dataview(b->value);
}
using Item = std::pair<std::string, std::string>;
using Item = std::pair<::mdbx::buffer<>, ::mdbx::buffer<>>;
static MDBX_val dataview2iov(const data_view &v) {
MDBX_val r;
r.iov_base = (void *)v.data();
@@ -158,10 +155,13 @@ protected:
}
struct ItemCompare {
const testcase *context;
ItemCompare(const testcase *owner) : context(owner) {}
ItemCompare(const testcase *owner) : context(owner) {
/* The context->txn_guard may be empty/null here */
}
bool operator()(const Item &a, const Item &b) const {
MDBX_val va = dataview2iov(a.first), vb = dataview2iov(b.first);
assert(context->txn_guard.get() != nullptr);
int cmp = mdbx_cmp(context->txn_guard.get(), context->dbi, &va, &vb);
if (cmp == 0 &&
(context->config.params.table_flags & MDBX_DUPSORT) != 0) {
@@ -202,7 +202,7 @@ protected:
#define SPECULUM_CURSORS 1
#endif /* SPECULUM_CURSORS */
#if SPECULUM_CURSORS
scoped_cursor_guard speculum_cursors[5];
scoped_cursor_guard speculum_cursors[5 + 1];
void speculum_prepare_cursors(const Item &item);
void speculum_check_cursor(const char *where, const char *stage,
const testcase::SET::const_iterator &it,
@@ -268,6 +268,7 @@ protected:
void db_table_clear(MDBX_dbi handle, MDBX_txn *txn = nullptr);
void db_table_close(MDBX_dbi handle);
int db_open__begin__table_create_open_clean(MDBX_dbi &handle);
bool is_handle_created_in_current_txn(const MDBX_dbi handle, MDBX_txn *txn);
bool wait4start();
void report(size_t nops_done);

View File

@@ -101,164 +101,6 @@ bool is_samedata(const MDBX_val *a, const MDBX_val *b) {
//-----------------------------------------------------------------------------
/* TODO: replace my 'libmera' from t1ha. */
uint64_t entropy_ticks(void) {
#if defined(EMSCRIPTEN)
return (uint64_t)emscripten_get_now();
#endif /* EMSCRIPTEN */
#if defined(__APPLE__) || defined(__MACH__)
return mach_absolute_time();
#endif /* defined(__APPLE__) || defined(__MACH__) */
#if defined(__sun__) || defined(__sun)
return gethrtime();
#endif /* __sun__ */
#if defined(__GNUC__) || defined(__clang__)
#if defined(__ia64__)
uint64_t ticks;
__asm __volatile("mov %0=ar.itc" : "=r"(ticks));
return ticks;
#elif defined(__hppa__)
uint64_t ticks;
__asm __volatile("mfctl 16, %0" : "=r"(ticks));
return ticks;
#elif defined(__s390__)
uint64_t ticks;
__asm __volatile("stck 0(%0)" : : "a"(&(ticks)) : "memory", "cc");
return ticks;
#elif defined(__alpha__)
uint64_t ticks;
__asm __volatile("rpcc %0" : "=r"(ticks));
return ticks;
#elif defined(__sparc__) || defined(__sparc) || defined(__sparc64__) || \
defined(__sparc64) || defined(__sparc_v8plus__) || \
defined(__sparc_v8plus) || defined(__sparc_v8plusa__) || \
defined(__sparc_v8plusa) || defined(__sparc_v9__) || defined(__sparc_v9)
union {
uint64_t u64;
struct {
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
uint32_t h, l;
#else
uint32_t l, h;
#endif
} u32;
} cycles;
#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || \
defined(__sparc_v9__) || defined(__sparc_v8plus) || \
defined(__sparc_v8plusa) || defined(__sparc_v9)
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul || \
defined(__sparc64__) || defined(__sparc64)
__asm __volatile("rd %%tick, %0" : "=r"(cycles.u64));
#else
__asm __volatile("rd %%tick, %1; srlx %1, 32, %0"
: "=r"(cycles.u32.h), "=r"(cycles.u32.l));
#endif /* __sparc64__ */
#else
__asm __volatile(".byte 0x83, 0x41, 0x00, 0x00; mov %%g1, %0"
: "=r"(cycles.u64)
:
: "%g1");
#endif /* __sparc8plus__ || __sparc_v9__ */
return cycles.u64;
#elif (defined(__powerpc64__) || defined(__ppc64__) || defined(__ppc64) || \
defined(__powerpc64))
uint64_t ticks;
__asm __volatile("mfspr %0, 268" : "=r"(ticks));
return ticks;
#elif (defined(__powerpc__) || defined(__ppc__) || defined(__powerpc) || \
defined(__ppc))
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
uint64_t ticks;
__asm __volatile("mftb %0" : "=r"(ticks));
*now = ticks;
#else
uint64_t ticks;
uint32_t low, high_before, high_after;
__asm __volatile("mftbu %0; mftb %1; mftbu %2"
: "=r"(high_before), "=r"(low), "=r"(high_after));
ticks = (uint64_t)high_after << 32;
ticks |= low & /* zeroes if high part has changed */
~(high_before - high_after);
#endif
#elif (defined(__aarch64__) || (defined(__ARM_ARCH) && __ARM_ARCH > 7)) && \
!defined(MDBX_SAFE4QEMU)
uint64_t virtual_timer;
__asm __volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer));
return virtual_timer;
#elif (defined(__ARM_ARCH) && __ARM_ARCH > 5 && __ARM_ARCH < 8) || \
defined(_M_ARM)
static uint32_t pmcntenset = 0x00425B00;
if (unlikely(pmcntenset == 0x00425B00)) {
uint32_t pmuseren;
#ifdef _M_ARM
pmuseren = _MoveFromCoprocessor(15, 0, 9, 14, 0);
#else
__asm("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren));
#endif
if (1 & pmuseren /* Is it allowed for user mode code? */) {
#ifdef _M_ARM
pmcntenset = _MoveFromCoprocessor(15, 0, 9, 12, 1);
#else
__asm("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset));
#endif
} else
pmcntenset = 0;
}
if (pmcntenset & 0x80000000ul /* Is it counting? */) {
#ifdef _M_ARM
return __rdpmccntr64();
#else
uint32_t pmccntr;
__asm __volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr));
return pmccntr;
#endif
}
#elif ((defined(_MIPS_ISA) && defined(_MIPS_ISA_MIPS2) && \
_MIPS_ISA >= _MIPS_ISA_MIPS2) || \
(defined(__mips) && __mips >= 2) || defined(_R4000)) && \
!defined(MDBX_SAFE4QEMU) /* QEMU may not emulate the CC register \
(High-resolution cycle counter) */
unsigned count;
__asm __volatile("rdhwr %0, $2" : "=r"(count));
return count;
#endif /* arch selector */
#endif /* __GNUC__ || __clang__ */
#if defined(__e2k__) || defined(__ia32__)
return __rdtsc();
#elif defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
LARGE_INTEGER PerformanceCount;
if (QueryPerformanceCounter(&PerformanceCount))
return PerformanceCount.QuadPart;
return GetTickCount64();
#else
struct timespec ts;
#if defined(CLOCK_MONOTONIC_COARSE)
clockid_t clk_id = CLOCK_MONOTONIC_COARSE;
#elif defined(CLOCK_MONOTONIC_RAW)
clockid_t clk_id = CLOCK_MONOTONIC_RAW;
#else
clockid_t clk_id = CLOCK_MONOTONIC;
#endif
int rc = clock_gettime(clk_id, &ts);
if (unlikely(rc))
failure_perror("clock_gettime()", rc);
return (((uint64_t)ts.tv_sec) << 32) + ts.tv_nsec;
#endif
}
//-----------------------------------------------------------------------------
uint64_t prng64_white(uint64_t &state) {
state = prng64_map2_careless(state);
return bleach64(state);
@@ -303,8 +145,6 @@ uint64_t prng64(void) { return prng64_white(prng_state); }
void prng_fill(void *ptr, size_t bytes) { prng_fill(prng_state, ptr, bytes); }
uint64_t entropy_white() { return bleach64(entropy_ticks()); }
double double_from_lower(uint64_t salt) {
#ifdef IEEE754_DOUBLE_BIAS
ieee754_double r;
@@ -336,25 +176,25 @@ double double_from_upper(uint64_t salt) {
#endif
}
bool flipcoin() { return bleach32((uint32_t)entropy_ticks()) & 1; }
bool flipcoin_x2() { return (bleach32((uint32_t)entropy_ticks()) & 3) == 0; }
bool flipcoin_x3() { return (bleach32((uint32_t)entropy_ticks()) & 7) == 0; }
bool flipcoin_x4() { return (bleach32((uint32_t)entropy_ticks()) & 15) == 0; }
bool flipcoin() { return prng32() & 1; }
bool flipcoin_x2() { return (prng32() & 3) == 0; }
bool flipcoin_x3() { return (prng32() & 7) == 0; }
bool flipcoin_x4() { return (prng32() & 15) == 0; }
bool flipcoin_n(unsigned n) {
return (bleach64(entropy_ticks()) & ((UINT64_C(1) << n) - 1)) == 0;
return (prng64() & ((UINT64_C(1) << n) - 1)) == 0;
}
bool jitter(unsigned probability_percent) {
const uint32_t top = UINT32_MAX - UINT32_MAX % 100;
uint32_t dice, edge = (top) / 100 * probability_percent;
do
dice = bleach32((uint32_t)entropy_ticks());
dice = prng32();
while (dice >= top);
return dice < edge;
}
void jitter_delay(bool extra) {
unsigned dice = entropy_white() & 3;
unsigned dice = prng32() & 3;
if (dice == 0) {
log_trace("== jitter.no-delay");
} else {
@@ -367,8 +207,8 @@ void jitter_delay(bool extra) {
osal_yield();
cpu_relax();
if (dice > 2) {
unsigned us = entropy_white() &
(extra ? 0xffff /* 656 ms */ : 0x3ff /* 1 ms */);
unsigned us =
prng32() & (extra ? 0xffff /* 656 ms */ : 0x3ff /* 1 ms */);
log_trace("== jitter.delay: %0.6f", us / 1000000.0);
osal_udelay(us);
}

View File

@@ -292,8 +292,6 @@ inline bool is_samedata(const MDBX_val &a, const MDBX_val &b) {
}
std::string format(const char *fmt, ...);
uint64_t entropy_ticks(void);
uint64_t entropy_white(void);
static inline uint64_t bleach64(uint64_t v) {
// Tommy Ettinger, https://www.blogger.com/profile/04953541827437796598
// http://mostlymangling.blogspot.com/2019/01/better-stronger-mixer-and-test-procedure.html

View File

@@ -22,6 +22,14 @@
...
fun:mdbx_mapresize
}
{
msync-wipe-steady
Memcheck:Param
msync(start)
fun:msync
...
fun:mdbx_wipe_steady
}
# single-page flush by pwrite()
{
@@ -42,16 +50,15 @@
}
# modern Valgrind don't support the `vector[...]` pattern
#{
# pwritev-page-flush
# Memcheck:Param
# pwritev(vector[...])
# fun:pwritev
# ...
# fun:mdbx_iov_write*
#}
# for((i=0;i<64;++i)); do echo -e "{\n pwritev-page-flush-$i\n Memcheck:Param\n pwritev(vector[$i])\n fun:pwritev\n ...\n fun:mdbx_iov_write*\n}"; done >> valgrind_suppress.txt
{
pwritev-page-flush
Memcheck:Param
pwritev(vector[...])
fun:pwritev
...
fun:mdbx_iov_write*
}
{
pwritev-page-flush-0
Memcheck:Param