mirror of
https://gitflic.ru/project/erthink/libmdbx.git
synced 2026-04-10 18:32:21 +00:00
mdbx: adding packages and the minimal C++ API example.
2026-01-07 mdbx-doc: fix README typo. 2026-01-07 mdbx++: add a minimal C++ API example. 2026-01-07 mdbx++: using hex dump of slices instead of base58. 2026-01-07 mdbx++: considering extended ASCII as non-printable if UTF8 enabled. 2026-01-07 mdbx-doc: add minor doxygen-markup to C-API example. 2026-01-07 mdbx-dist: add packages-files to distribution. 2026-01-07 mdbx-pkg: add aur-package. 2026-01-07 mdbx-test: move pcrf-simulator. 2026-01-06 mdbx: re-licensing closed parts. 2026-01-06 mdbx-doc: avoid using numbered lists to prevent doxygen issues. 2026-01-06 mdbx-doc: refine "Restrictions & Caveats" section. 2026-01-05 mdbx: avoids `mdbx_txn_lock()` during copying a database.
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
mdbx.c
|
||||
mdbx.c++
|
||||
mdbx_chk.c
|
||||
mdbx_copy.c
|
||||
mdbx_drop.c
|
||||
mdbx_dump.c
|
||||
mdbx_load.c
|
||||
mdbx_stat.c
|
||||
47
.gitignore
vendored
Normal file
47
.gitignore
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
*[~#]
|
||||
@*
|
||||
*.[ao]
|
||||
*.autosave
|
||||
*.bak
|
||||
@buildflags.tag
|
||||
build.ninja
|
||||
cmake-build-*
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
CMakeLists.txt.user
|
||||
config-cmake.h
|
||||
config-gnumake.h
|
||||
CTestTestfile.cmake
|
||||
DartConfiguration.tcl
|
||||
*.dll
|
||||
*.dSYM
|
||||
*.dylib
|
||||
*.err
|
||||
*.exe
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
.idea
|
||||
libmdbx.creator.user
|
||||
*.lo
|
||||
mdbx_chk
|
||||
mdbx_copy
|
||||
mdbx_drop
|
||||
mdbx_dump
|
||||
mdbx_legacy_example
|
||||
mdbx_modern_example
|
||||
mdbx_load
|
||||
mdbx_stat
|
||||
.ninja_deps
|
||||
.ninja_log
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.tar*
|
||||
Testing/
|
||||
tmp.db
|
||||
tmp.db-lck
|
||||
valgrind.*
|
||||
.vs/
|
||||
.vscode/
|
||||
@@ -348,7 +348,8 @@ if(NOT DEFINED MDBX_CXX_STANDARD)
|
||||
elseif(CXX_FALLBACK_GNU11 OR CXX_FALLBACK_11)
|
||||
set(MDBX_CXX_STANDARD 11)
|
||||
else()
|
||||
set(MDBX_CXX_STANDARD 98)
|
||||
message(NOTICE "The C++ example will be skipped, since C++20 standard is unavailable or C++ API of libmdbx was disabled.")
|
||||
set(MDBX_CXX_STANDARD 0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -520,7 +521,6 @@ endif()
|
||||
|
||||
set(MDBX_CXX_AVAILABLE FALSE)
|
||||
if(CMAKE_CXX_COMPILER_LOADED
|
||||
AND MDBX_CXX_STANDARD LESS 83
|
||||
AND NOT MDBX_CXX_STANDARD LESS 11)
|
||||
if(NOT MDBX_WITHOUT_MSVC_CRT
|
||||
AND NOT (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
|
||||
@@ -543,7 +543,7 @@ if(CMAKE_CXX_COMPILER_LOADED
|
||||
endif()
|
||||
else()
|
||||
if(DEFINED MDBX_BUILD_CXX AND MDBX_BUILD_CXX)
|
||||
message(WARNING "MDBX_BUILD_CXX=${MDBX_BUILD_CXX}: But there is no suitable C++ compiler available.")
|
||||
message(WARNING "MDBX_BUILD_CXX=${MDBX_BUILD_CXX}: But there is no suitable C++11 compiler available.")
|
||||
endif()
|
||||
set(MDBX_ENABLE_TESTS OFF)
|
||||
set(MDBX_BUILD_CXX OFF)
|
||||
|
||||
@@ -288,7 +288,7 @@ ctest: cmake-build
|
||||
run-ut: mdbx_example
|
||||
$(QUIET)for UT in $^; do echo " Running $$UT" && ./$${UT} || exit -1; done
|
||||
|
||||
TEST_TARGETS := mdbx_example
|
||||
TEST_TARGETS := mdbx_legacy_example $(call select_by,MDBX_BUILD_CXX,mdbx_modern_example,)
|
||||
TEST_BUILD_TARGETS := build-test
|
||||
ifneq ($(CMAKE),"")
|
||||
TEST_TARGETS += ctest
|
||||
@@ -314,10 +314,14 @@ test-leak:
|
||||
@echo ' RE-TEST with `-fsanitize=leak` option...'
|
||||
$(QUIET)$(MAKE) IOARENA=false CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-fsanitize=leak" test
|
||||
|
||||
mdbx_example: mdbx.h ut_and_examples/example-mdbx.c libmdbx.$(SO_SUFFIX)
|
||||
mdbx_legacy_example: mdbx.h ut_and_examples/example-mdbx.c libmdbx.$(SO_SUFFIX)
|
||||
@echo ' CC+LD $@'
|
||||
$(QUIET)$(CC) $(CFLAGS) -I. ut_and_examples/example-mdbx.c ./libmdbx.$(SO_SUFFIX) -o $@
|
||||
|
||||
mdbx_modern_example: mdbx.h ut_and_examples/example-mdbx.c++ libmdbx.$(SO_SUFFIX)
|
||||
@echo ' CC+LD $@'
|
||||
$(QUIET)$(CXX) $(CXXFLAGS) -I. ut_and_examples/example-mdbx.c++ ./libmdbx.$(SO_SUFFIX) -o $@
|
||||
|
||||
################################################################################
|
||||
# Amalgamated source code, i.e. distributed after `make dist`
|
||||
MAN_SRCDIR := man1/
|
||||
|
||||
63
README.md
63
README.md
@@ -25,7 +25,7 @@ Historically, _libmdbx_ is a deeply revised and extended descendant of the legen
|
||||
|
||||
[](https://t.me/libmdbx)
|
||||
|
||||
> Please refer to the online [official libmdbx documentation site](https://libmdbx.dqdkfa.ru) with [`C` API description](https://libmdbx.dqdkfa.ru/group__c__api.html) and pay attention to the [`C++` API](https://sourcecraft.dev/dqdkfa/libmdbx/blob?file=mdbx.h%2B%2B#line-num-1).Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`,
|
||||
> Please refer to the online [official libmdbx documentation site](https://libmdbx.dqdkfa.ru) with [`C` API description](https://libmdbx.dqdkfa.ru/group__c__api.html) and pay attention to the [`C++` API](https://sourcecraft.dev/dqdkfa/libmdbx/blob?file=mdbx.h%2B%2B#line-num-1). Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`,
|
||||
BTC `bc1qzvl9uegf2ea6cwlytnanrscyv8snwsvrc0xfsu`, SOL `FTCTgbHajoLVZGr8aEFWMzx3NDMyS5wXJgfeMTmJznRi`.
|
||||
> Всё будет хорошо!
|
||||
|
||||
@@ -167,20 +167,20 @@ $ cc --version
|
||||
|
||||
## Gotchas
|
||||
|
||||
1. There cannot be more than one writer at a time, i.e. no more than one write transaction at a time.
|
||||
* There cannot be more than one writer at a time, i.e. no more than one write transaction at a time.
|
||||
|
||||
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).
|
||||
* _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.
|
||||
* _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, otherwise use [transaction parking](https://libmdbx.dqdkfa.ru/group__c__transactions.html#ga2c2c97730ff35cadcedfbd891ac9b12f)
|
||||
and/or [Handle-Slow-Readers callback](https://libmdbx.dqdkfa.ru/group__c__err.html#ga2cb11b56414c282fe06dd942ae6cade6).
|
||||
|
||||
5. _libmdbx_ is extraordinarily fast and provides minimal overhead for data access, so you should reconsider using brute force techniques and double check your code.
|
||||
* _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.
|
||||
|
||||
@@ -193,7 +193,6 @@ For now please refer to [chapter of "BoltDB comparison with other databases"](ht
|
||||
- _libmdbx_ provides more features compared to BoltDB and/or LMDB.
|
||||
|
||||
<!-- section-end -->
|
||||
|
||||
<!-- section-begin improvements -->
|
||||
|
||||
Improvements beyond LMDB
|
||||
@@ -203,78 +202,78 @@ _libmdbx_ is superior to legendary _[LMDB](https://symas.com/lmdb/)_ in terms of
|
||||
|
||||
## Some Added Features
|
||||
|
||||
1. Keys could be more than 2 times longer than _LMDB_, support of zero-length for keys and values.
|
||||
* Keys could be more than 2 times longer than _LMDB_, support of zero-length for keys and values.
|
||||
> 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.
|
||||
* Up to 30% faster than _LMDB_ in [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) benchmarks.
|
||||
> Benchmarks of the in-[tmpfs](https://en.wikipedia.org/wiki/Tmpfs) scenarios, that tests the speed of the engine itself, showned that _libmdbx_ 10-20% faster than _LMDB_, and up to 30% faster when _libmdbx_ compiled with specific build options which downgrades several runtime checks to be match with LMDB behaviour.
|
||||
>
|
||||
> However, libmdbx may be slower than LMDB on Windows, since uses native file locking API. These locks are really slow, but they prevent an inconsistent backup from being obtained by copying the DB file during an ongoing write transaction. So I think this is the right decision, and for speed, it's better to use Linux, or ask Microsoft to fix up file locks.
|
||||
>
|
||||
> Noted above and other results could be easily reproduced with [ioArena](https://abf.io/erthink/ioarena) just by `make bench-quartet` command, including comparisons with [RockDB](https://en.wikipedia.org/wiki/RocksDB) and [WiredTiger](https://en.wikipedia.org/wiki/WiredTiger).
|
||||
|
||||
3. Automatic on-the-fly database size adjustment, both increment and reduction.
|
||||
* Automatic on-the-fly database size adjustment, both increment and reduction.
|
||||
> _libmdbx_ manages the database size according to parameters specified by `mdbx_env_set_geometry()` function, ones include the growth step and the truncation threshold.
|
||||
>
|
||||
> Unfortunately, on-the-fly database size adjustment doesn't work under [Wine](https://en.wikipedia.org/wiki/Wine_(software)) due to its internal limitations and unimplemented functions, i.e. the `MDBX_UNABLE_EXTEND_MAPSIZE` error will be returned.
|
||||
|
||||
4. Automatic continuous zero-overhead database compactification.
|
||||
* Automatic continuous zero-overhead database compactification.
|
||||
> During each commit _libmdbx_ merges a freeing pages which adjacent with the unallocated area at the end of file, and then truncates unused space when a lot enough of.
|
||||
|
||||
5. The same database format for 32- and 64-bit builds.
|
||||
* The same database format for 32- and 64-bit builds.
|
||||
> _libmdbx_ database format depends only on the [endianness](https://en.wikipedia.org/wiki/Endianness) but not on the [bitness](https://en.wiktionary.org/wiki/bitness).
|
||||
|
||||
6. The "Big Foot" feature than solves speific performance issues with huge transactions and extra-large page-number-lists.
|
||||
* The "Big Foot" feature than solves speific performance issues with huge transactions and extra-large page-number-lists.
|
||||
|
||||
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.
|
||||
* 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.
|
||||
> LIFO means that for reuse will be taken the latest becomes unused pages. Therefore the loop of database pages circulation becomes as short as possible. In other words, the set of pages, that are (over)written in memory and on disk during a series of write transactions, will be as small as possible. Thus creates ideal conditions for the battery-backed or flash-backed disk cache efficiency.
|
||||
|
||||
8. Parking of read transactions with ousting and auto-restart, [Handle-Slow-Readers callback](https://libmdbx.dqdkfa.ru/group__c__err.html#ga2cb11b56414c282fe06dd942ae6cade6) to resolve an issues due to long-lived read transactions.
|
||||
* Parking of read transactions with ousting and auto-restart, [Handle-Slow-Readers callback](https://libmdbx.dqdkfa.ru/group__c__err.html#ga2cb11b56414c282fe06dd942ae6cade6) to resolve an issues due to long-lived read transactions.
|
||||
|
||||
9. Fast estimation of range query result volume, i.e. how many items can be found between a `KEY1` and a `KEY2`. This is a prerequisite for build and/or optimize query execution plans.
|
||||
* Fast estimation of range query result volume, i.e. how many items can be found between a `KEY1` and a `KEY2`. This is a prerequisite for build and/or optimize query execution plans.
|
||||
> _libmdbx_ performs a rough estimate based on common B-tree pages of the paths from root to corresponding keys.
|
||||
|
||||
10. Database integrity check API both with standalone `mdbx_chk` utility.
|
||||
* Database integrity check API both with standalone `mdbx_chk` utility.
|
||||
|
||||
11. Support for opening databases in the exclusive mode, including on a network share.
|
||||
* Support for opening databases in the exclusive mode, including on a network share.
|
||||
|
||||
12. Extended information of whole-database, tables/sub-databases, transactions, readers enumeration.
|
||||
* Extended information of whole-database, tables/sub-databases, transactions, readers enumeration.
|
||||
> _libmdbx_ provides a lot of information, including dirty and leftover pages for a write transaction, reading lag and holdover space for read transactions.
|
||||
|
||||
13. The ["get-cached" feature](https://libmdbx.dqdkfa.ru/group__c__crud.html#ga5bfb583bf2c5d5676ffddb466e789353) with lightweight transparent cache that could provides dramatic acceleration in many cases.
|
||||
* The ["get-cached" feature](https://libmdbx.dqdkfa.ru/group__c__crud.html#ga5bfb583bf2c5d5676ffddb466e789353) with lightweight transparent cache that could provides dramatic acceleration in many cases.
|
||||
|
||||
14. [Cloning a read transactions](https://libmdbx.dqdkfa.ru/group__c__transactions.html#ga28d3db2426df24b16c0bc40cd0af8187) and [resurrect after fork](https://libmdbx.dqdkfa.ru/group__c__extra.html#gab7d13c1dbf074bc23ebda2d886add02a) feature.
|
||||
* [Cloning a read transactions](https://libmdbx.dqdkfa.ru/group__c__transactions.html#ga28d3db2426df24b16c0bc40cd0af8187) and [resurrect after fork](https://libmdbx.dqdkfa.ru/group__c__extra.html#gab7d13c1dbf074bc23ebda2d886add02a) feature.
|
||||
|
||||
15. Automated steady sync-to-disk upon several thresholds and/or timeout via cheap polling.
|
||||
* Automated steady sync-to-disk upon several thresholds and/or timeout via cheap polling.
|
||||
|
||||
16. Extended update and quick delete operations.
|
||||
* Extended update and quick delete operations.
|
||||
> _libmdbx_ allows one _at once_ with [getting previous value](https://libmdbx.dqdkfa.ru/group__c__crud.html#gaad688c4b0fbbcff676f181dc0437befa) and addressing the particular item from multi-value with the same key.
|
||||
> _libmdbx_ support [massive deletion by bunches](https://libmdbx.dqdkfa.ru/group__c__crud.html#gac986d35a3b6b27ac43af881c471a6878) of adjacent elements much faster by cutting off entire pages and branches from a B-tree.
|
||||
|
||||
17. Ability to determine whether the particular data is on a dirty page or not, that allows to avoid copy-out before updates.
|
||||
* Ability to determine whether the particular data is on a dirty page or not, that allows to avoid copy-out before updates.
|
||||
|
||||
18. Sequence generation and three persistent 64-bit vector-clock like markers.
|
||||
* Sequence generation and three persistent 64-bit vector-clock like markers.
|
||||
|
||||
19. Useful runtime options for tuning engine to application's requirements and use cases specific.
|
||||
* Useful runtime options for tuning engine to application's requirements and use cases specific.
|
||||
|
||||
## Other fixes and specifics
|
||||
|
||||
1. Fixed more than 10 significant errors, in particular: page leaks, wrong table/sub-database statistics, segfault in several conditions,
|
||||
* Fixed more than 10 significant errors, in particular: page leaks, wrong table/sub-database statistics, segfault in several conditions,
|
||||
nonoptimal page merge strategy, updating an existing record with a change in data size (including for multimap), etc.
|
||||
|
||||
2. All cursors can be reused and should be closed explicitly, regardless ones were opened within a write or read transaction.
|
||||
* All cursors can be reused and should be closed explicitly, regardless ones were opened within a write or read transaction.
|
||||
|
||||
3. Opening database handles are spared from race conditions and pre-opening is not needed.
|
||||
* Opening database handles are spared from race conditions and pre-opening is not needed.
|
||||
|
||||
4. Returning `MDBX_EMULTIVAL` error in case of ambiguous update or delete.
|
||||
* Returning `MDBX_EMULTIVAL` error in case of ambiguous update or delete.
|
||||
|
||||
5. Guarantee of database integrity even in asynchronous unordered write-to-disk mode.
|
||||
* Guarantee of database integrity even in asynchronous unordered write-to-disk mode.
|
||||
> _libmdbx_ propose additional trade-off by `MDBX_SAFE_NOSYNC` with append-like manner for updates, that avoids database corruption after a system crash contrary to LMDB.
|
||||
> Nevertheless, the `MDBX_UTTERLY_NOSYNC` mode is available to match LMDB's behaviour for `MDB_NOSYNC`.
|
||||
|
||||
6. On **MacOS & iOS** the `fcntl(F_FULLFSYNC)` syscall is used _by default_ to synchronize data with the disk, as this is [the only way to guarantee data durability](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html) in case of power failure. Unfortunately, in scenarios with high write intensity, the use of `F_FULLFSYNC` significantly degrades performance compared to LMDB, where the `fsync()` syscall is used. Therefore, _libmdbx_ allows you to override this behavior by defining the `MDBX_OSX_SPEED_INSTEADOF_DURABILITY=1` option while build the library.
|
||||
* On **MacOS & iOS** the `fcntl(F_FULLFSYNC)` syscall is used _by default_ to synchronize data with the disk, as this is [the only way to guarantee data durability](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html) in case of power failure. Unfortunately, in scenarios with high write intensity, the use of `F_FULLFSYNC` significantly degrades performance compared to LMDB, where the `fsync()` syscall is used. Therefore, _libmdbx_ allows you to override this behavior by defining the `MDBX_OSX_SPEED_INSTEADOF_DURABILITY=1` option while build the library.
|
||||
|
||||
7. On **Windows** the `LockFileEx()` syscall is used for locking, since it allows place the database on network drives, and provides protection against incompetent user actions (aka [poka-yoke](https://en.wikipedia.org/wiki/Poka-yoke)). Therefore _libmdbx_ may be a little lag in performance tests from LMDB where the named mutexes are used.
|
||||
* On **Windows** the `LockFileEx()` syscall is used for locking, since it allows place the database on network drives, and provides protection against incompetent user actions (aka [poka-yoke](https://en.wikipedia.org/wiki/Poka-yoke)). Therefore _libmdbx_ may be a little lag in performance tests from LMDB where the named mutexes are used.
|
||||
|
||||
<!-- section-end -->
|
||||
<!-- section-begin history -->
|
||||
|
||||
@@ -1 +1 @@
|
||||
{ "git_describe": "v0.14.1-243-g0cabae85", "git_timestamp": "2026-01-05T21:40:57+03:00", "git_tree": "3a6b8a387c7d429efc2398f19b8921514c125887", "git_commit": "0cabae85663f3f8ea2c6c4595df68bc461153e06", "semver": "0.14.1.243" }
|
||||
{ "git_describe": "v0.14.1-256-g6e4093ad", "git_timestamp": "2026-01-07T15:15:51+03:00", "git_tree": "62e44b0432d3caeb13be585a6e41c2243e35fcaf", "git_commit": "6e4093ad3749c0d46f3585ef38c3a7260e5b2dd8", "semver": "0.14.1.256" }
|
||||
|
||||
118
mdbx.c
118
mdbx.c
@@ -4,7 +4,7 @@
|
||||
|
||||
#define xMDBX_ALLOY 1 /* alloyed build */
|
||||
|
||||
#define MDBX_BUILD_SOURCERY dede3aaf8e972a64ffbdc3195e53aa2ac55e0ea238548ac61e27a28a18e2f7dd_v0_14_1_243_g0cabae85
|
||||
#define MDBX_BUILD_SOURCERY 3d0786aca27f270572b5c0bfe28f74832e60f52ff9ca5510d3449b4e443d594b_v0_14_1_256_g6e4093ad
|
||||
|
||||
#define LIBMDBX_INTERNALS
|
||||
#define MDBX_DEPRECATED
|
||||
@@ -8175,76 +8175,36 @@ __cold static int copy_with_compacting(MDBX_env *env, MDBX_txn *txn, mdbx_fileha
|
||||
|
||||
__cold static int copy_asis(MDBX_env *env, MDBX_txn *txn, mdbx_filehandle_t fd, uint8_t *buffer,
|
||||
const bool dest_is_pipe, const MDBX_copy_flags_t flags) {
|
||||
bool should_unlock = false;
|
||||
if ((txn->flags & MDBX_TXN_RDONLY) != 0 && (flags & MDBX_CP_RENEW_TXN) != 0) {
|
||||
/* Try temporarily block writers until we snapshot the meta pages */
|
||||
int err = lck_txn_lock(env, true);
|
||||
if (likely(err == MDBX_SUCCESS))
|
||||
should_unlock = true;
|
||||
else if (unlikely(err != MDBX_BUSY))
|
||||
return err;
|
||||
}
|
||||
|
||||
jitter4testing(false);
|
||||
int rc = MDBX_SUCCESS;
|
||||
const size_t meta_bytes = pgno2bytes(env, NUM_METAS);
|
||||
troika_t troika = meta_tap(env);
|
||||
/* Make a snapshot of meta-pages,
|
||||
* but writing ones after the data was flushed */
|
||||
retry_snap_meta:
|
||||
memcpy(buffer, env->dxb_mmap.base, meta_bytes);
|
||||
const meta_ptr_t recent = meta_recent(env, &troika);
|
||||
meta_t *headcopy = /* LY: get pointer to the snapshot copy */
|
||||
ptr_disp(buffer, ptr_dist(recent.ptr_c, env->dxb_mmap.base));
|
||||
jitter4testing(false);
|
||||
if (txn->flags & MDBX_TXN_RDONLY) {
|
||||
if (recent.txnid != txn->txnid) {
|
||||
if (flags & MDBX_CP_RENEW_TXN)
|
||||
rc = mdbx_txn_renew(txn);
|
||||
else {
|
||||
rc = MDBX_MVCC_RETARDED;
|
||||
for (size_t n = 0; n < NUM_METAS; ++n) {
|
||||
meta_t *const meta = page_meta(ptr_disp(buffer, pgno2bytes(env, n)));
|
||||
if (troika.txnid[n] == txn->txnid && ((/* is_steady */ (troika.fsm >> n) & 1) || rc != MDBX_SUCCESS)) {
|
||||
rc = MDBX_SUCCESS;
|
||||
headcopy = meta;
|
||||
} else if (troika.txnid[n] > txn->txnid)
|
||||
meta_set_txnid(env, meta, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (should_unlock)
|
||||
lck_txn_unlock(env);
|
||||
else {
|
||||
troika_t snap = meta_tap(env);
|
||||
if (memcmp(&troika, &snap, sizeof(troika_t)) && rc == MDBX_SUCCESS) {
|
||||
troika = snap;
|
||||
goto retry_snap_meta;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (txn->flags & MDBX_TXN_RDONLY)
|
||||
eASSERT(env, meta_txnid(headcopy) == txn->txnid);
|
||||
if (flags & MDBX_CP_FORCE_DYNAMIC_SIZE)
|
||||
meta_make_sizeable(headcopy);
|
||||
/* Update signature to steady */
|
||||
meta_sign_as_steady(headcopy);
|
||||
|
||||
/* Copy the data */
|
||||
const size_t whole_size = pgno_ceil2sp_bytes(env, txn->geo.end_pgno);
|
||||
const size_t used_size = pgno2bytes(env, txn->geo.first_unallocated);
|
||||
jitter4testing(false);
|
||||
|
||||
if (flags & MDBX_CP_THROTTLE_MVCC)
|
||||
mdbx_txn_park(txn, false);
|
||||
|
||||
if (dest_is_pipe)
|
||||
rc = osal_write(fd, buffer, meta_bytes);
|
||||
|
||||
uint8_t *const data_buffer = buffer + ceil_powerof2(meta_bytes, globals.sys_pagesize);
|
||||
meta_t *const meta = meta_init_triplet(env, buffer);
|
||||
meta_set_txnid(env, meta, txn->txnid);
|
||||
|
||||
if (flags & MDBX_CP_FORCE_DYNAMIC_SIZE)
|
||||
meta_make_sizeable(meta);
|
||||
|
||||
/* copy canary sequences if present */
|
||||
if (txn->canary.v) {
|
||||
meta->canary = txn->canary;
|
||||
meta->canary.v = constmeta_txnid(meta);
|
||||
}
|
||||
|
||||
int rc = MDBX_SUCCESS;
|
||||
if (flags & MDBX_CP_THROTTLE_MVCC) {
|
||||
rc = mdbx_txn_park(txn, false);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
}
|
||||
|
||||
jitter4testing(false);
|
||||
size_t offset = meta_bytes;
|
||||
if (dest_is_pipe) {
|
||||
rc = osal_write(fd, buffer, meta_bytes);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
#if MDBX_USE_COPYFILERANGE
|
||||
static bool copyfilerange_unavailable;
|
||||
#if (defined(__linux__) || defined(__gnu_linux__))
|
||||
@@ -8260,7 +8220,10 @@ retry_snap_meta:
|
||||
}
|
||||
#endif /* MDBX_USE_COPYFILERANGE */
|
||||
|
||||
for (size_t offset = meta_bytes; rc == MDBX_SUCCESS && offset < used_size;) {
|
||||
/* Copy the data */
|
||||
const size_t whole_size = pgno_ceil2sp_bytes(env, txn->geo.end_pgno);
|
||||
const size_t used_size = pgno2bytes(env, txn->geo.first_unallocated);
|
||||
while (rc == MDBX_SUCCESS && offset < used_size) {
|
||||
if (flags & MDBX_CP_THROTTLE_MVCC) {
|
||||
rc = mdbx_txn_unpark(txn, false);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
@@ -8315,8 +8278,11 @@ retry_snap_meta:
|
||||
((size_t)MDBX_ENVCOPY_WRITEBUF < used_size - offset) ? (size_t)MDBX_ENVCOPY_WRITEBUF : used_size - offset;
|
||||
/* copy to avoid EFAULT in case swapped-out */
|
||||
memcpy(data_buffer, ptr_disp(env->dxb_mmap.base, offset), chunk);
|
||||
if (flags & MDBX_CP_THROTTLE_MVCC)
|
||||
mdbx_txn_park(txn, false);
|
||||
if (flags & MDBX_CP_THROTTLE_MVCC) {
|
||||
rc = mdbx_txn_park(txn, false);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
break;
|
||||
}
|
||||
rc = osal_write(fd, data_buffer, chunk);
|
||||
offset += chunk;
|
||||
}
|
||||
@@ -8327,7 +8293,7 @@ retry_snap_meta:
|
||||
rc = osal_fsetsize(fd, whole_size);
|
||||
else {
|
||||
memset(data_buffer, 0, (size_t)MDBX_ENVCOPY_WRITEBUF);
|
||||
for (size_t offset = used_size; rc == MDBX_SUCCESS && offset < whole_size;) {
|
||||
for (offset = used_size; rc == MDBX_SUCCESS && offset < whole_size;) {
|
||||
const size_t chunk =
|
||||
((size_t)MDBX_ENVCOPY_WRITEBUF < whole_size - offset) ? (size_t)MDBX_ENVCOPY_WRITEBUF : whole_size - offset;
|
||||
rc = osal_write(fd, data_buffer, chunk);
|
||||
@@ -40462,10 +40428,10 @@ __dll_export
|
||||
0,
|
||||
14,
|
||||
1,
|
||||
243,
|
||||
256,
|
||||
"", /* pre-release suffix of SemVer
|
||||
0.14.1.243 */
|
||||
{"2026-01-05T21:40:57+03:00", "3a6b8a387c7d429efc2398f19b8921514c125887", "0cabae85663f3f8ea2c6c4595df68bc461153e06", "v0.14.1-243-g0cabae85"},
|
||||
0.14.1.256 */
|
||||
{"2026-01-07T15:15:51+03:00", "62e44b0432d3caeb13be585a6e41c2243e35fcaf", "6e4093ad3749c0d46f3585ef38c3a7260e5b2dd8", "v0.14.1-256-g6e4093ad"},
|
||||
sourcery};
|
||||
|
||||
__dll_export
|
||||
|
||||
27
mdbx.c++
27
mdbx.c++
@@ -2,7 +2,7 @@
|
||||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
|
||||
/* clang-format off */
|
||||
|
||||
#define MDBX_BUILD_SOURCERY dede3aaf8e972a64ffbdc3195e53aa2ac55e0ea238548ac61e27a28a18e2f7dd_v0_14_1_243_g0cabae85
|
||||
#define MDBX_BUILD_SOURCERY 3d0786aca27f270572b5c0bfe28f74832e60f52ff9ca5510d3449b4e443d594b_v0_14_1_256_g6e4093ad
|
||||
|
||||
#define LIBMDBX_INTERNALS
|
||||
#define MDBX_DEPRECATED
|
||||
@@ -7565,6 +7565,7 @@ bool slice::is_printable(bool disable_utf8) const noexcept {
|
||||
enum : byte {
|
||||
LS = 4, // shift for UTF8 sequence length
|
||||
P_ = 1 << LS, // printable ASCII flag
|
||||
X_ = 1 << (LS - 1), // printable extended ASCII flag
|
||||
N_ = 0, // non-printable ASCII
|
||||
second_range_mask = P_ - 1, // mask for range flag
|
||||
r80_BF = 0, // flag for UTF8 2nd byte range
|
||||
@@ -7601,14 +7602,14 @@ bool slice::is_printable(bool disable_utf8) const noexcept {
|
||||
P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 50
|
||||
P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 60
|
||||
P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, N_, // 70
|
||||
N_, N_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, N_, P_, N_, // 80
|
||||
N_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, N_, P_, P_, // 90
|
||||
P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // a0
|
||||
P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // b0
|
||||
P_, P_, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, // c0
|
||||
N_, N_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, N_, X_, N_, // 80
|
||||
N_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, N_, X_, X_, // 90
|
||||
X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, // a0
|
||||
X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, // b0
|
||||
X_, X_, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, // c0
|
||||
C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, // df
|
||||
E0, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, ED, EE, EE, // e0
|
||||
F0, F1, F1, F1, F4, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_ // f0
|
||||
F0, F1, F1, F1, F4, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_, X_ // f0
|
||||
};
|
||||
|
||||
if (MDBX_UNLIKELY(length() < 1))
|
||||
@@ -7618,7 +7619,7 @@ bool slice::is_printable(bool disable_utf8) const noexcept {
|
||||
const auto end = src + length();
|
||||
if (MDBX_UNLIKELY(disable_utf8)) {
|
||||
do
|
||||
if (MDBX_UNLIKELY((P_ & map[*src]) == 0))
|
||||
if (MDBX_UNLIKELY(((P_ | X_) & map[*src]) == 0))
|
||||
MDBX_CXX20_UNLIKELY return false;
|
||||
while (++src < end);
|
||||
return true;
|
||||
@@ -8767,13 +8768,13 @@ __cold ::std::ostream &operator<<(::std::ostream &out, const slice &it) {
|
||||
else if (it.empty())
|
||||
out << "EMPTY->" << it.data();
|
||||
else {
|
||||
const slice root(it.head(std::min(it.length(), size_t(64))));
|
||||
const slice head(it.head(std::min(it.length(), size_t(64))));
|
||||
out << it.length() << ".";
|
||||
if (root.is_printable())
|
||||
(out << "\"").write(root.char_ptr(), root.length()) << "\"";
|
||||
if (head.is_printable())
|
||||
(out << "\"").write(head.char_ptr(), head.length()) << "\"";
|
||||
else
|
||||
out << root.encode_base58();
|
||||
if (root.length() < it.length())
|
||||
out << to_hex(head);
|
||||
if (head.length() < it.length())
|
||||
out << "...";
|
||||
}
|
||||
return out << "}";
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
|
||||
|
||||
#define MDBX_BUILD_SOURCERY dede3aaf8e972a64ffbdc3195e53aa2ac55e0ea238548ac61e27a28a18e2f7dd_v0_14_1_243_g0cabae85
|
||||
#define MDBX_BUILD_SOURCERY 3d0786aca27f270572b5c0bfe28f74832e60f52ff9ca5510d3449b4e443d594b_v0_14_1_256_g6e4093ad
|
||||
|
||||
#define LIBMDBX_INTERNALS
|
||||
#define MDBX_DEPRECATED
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
|
||||
|
||||
#define MDBX_BUILD_SOURCERY dede3aaf8e972a64ffbdc3195e53aa2ac55e0ea238548ac61e27a28a18e2f7dd_v0_14_1_243_g0cabae85
|
||||
#define MDBX_BUILD_SOURCERY 3d0786aca27f270572b5c0bfe28f74832e60f52ff9ca5510d3449b4e443d594b_v0_14_1_256_g6e4093ad
|
||||
|
||||
#define LIBMDBX_INTERNALS
|
||||
#define MDBX_DEPRECATED
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
|
||||
|
||||
#define MDBX_BUILD_SOURCERY dede3aaf8e972a64ffbdc3195e53aa2ac55e0ea238548ac61e27a28a18e2f7dd_v0_14_1_243_g0cabae85
|
||||
#define MDBX_BUILD_SOURCERY 3d0786aca27f270572b5c0bfe28f74832e60f52ff9ca5510d3449b4e443d594b_v0_14_1_256_g6e4093ad
|
||||
|
||||
#define LIBMDBX_INTERNALS
|
||||
#define MDBX_DEPRECATED
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
|
||||
|
||||
#define MDBX_BUILD_SOURCERY dede3aaf8e972a64ffbdc3195e53aa2ac55e0ea238548ac61e27a28a18e2f7dd_v0_14_1_243_g0cabae85
|
||||
#define MDBX_BUILD_SOURCERY 3d0786aca27f270572b5c0bfe28f74832e60f52ff9ca5510d3449b4e443d594b_v0_14_1_256_g6e4093ad
|
||||
|
||||
#define LIBMDBX_INTERNALS
|
||||
#define MDBX_DEPRECATED
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
|
||||
|
||||
#define MDBX_BUILD_SOURCERY dede3aaf8e972a64ffbdc3195e53aa2ac55e0ea238548ac61e27a28a18e2f7dd_v0_14_1_243_g0cabae85
|
||||
#define MDBX_BUILD_SOURCERY 3d0786aca27f270572b5c0bfe28f74832e60f52ff9ca5510d3449b4e443d594b_v0_14_1_256_g6e4093ad
|
||||
|
||||
#define LIBMDBX_INTERNALS
|
||||
#define MDBX_DEPRECATED
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2026
|
||||
|
||||
#define MDBX_BUILD_SOURCERY dede3aaf8e972a64ffbdc3195e53aa2ac55e0ea238548ac61e27a28a18e2f7dd_v0_14_1_243_g0cabae85
|
||||
#define MDBX_BUILD_SOURCERY 3d0786aca27f270572b5c0bfe28f74832e60f52ff9ca5510d3449b4e443d594b_v0_14_1_256_g6e4093ad
|
||||
|
||||
#define LIBMDBX_INTERNALS
|
||||
#define MDBX_DEPRECATED
|
||||
|
||||
16
packages/archlinux/.SRCINFO
Normal file
16
packages/archlinux/.SRCINFO
Normal file
@@ -0,0 +1,16 @@
|
||||
pkgbase = libmdbx
|
||||
pkgdesc = One of the fastest compact key-value ACID database without WAL, which surpasses the legendary LMDB in terms of reliability, features and performance. At the end of 2024 MDBX was chosen by all modern Ethereum frontiers/nodes as a storage engine.
|
||||
pkgver = 0.13.10
|
||||
pkgrel = 2
|
||||
url = https://libmdbx.dqdkfa.ru/
|
||||
arch = x86_64
|
||||
arch = i686
|
||||
arch = ARM
|
||||
arch = aarch64
|
||||
arch = powerpc64le
|
||||
license = Apache-2
|
||||
depends = glibc
|
||||
source = libmdbx-0.13.10.tar.xz::https://libmdbx.dqdkfa.ru/release/libmdbx-amalgamated-0.13.10.tar.xz
|
||||
sha256sums = e6c9af085390c41d101fce0a72794c77159e1e271e41077ea0fd4270b43cc56c
|
||||
|
||||
pkgname = libmdbx
|
||||
38
packages/archlinux/PKGBUILD
Normal file
38
packages/archlinux/PKGBUILD
Normal file
@@ -0,0 +1,38 @@
|
||||
# Maintainer: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
# Contributor: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
# Contributor: Noel Kuntze <noel.kuntze@thermi.consulting>
|
||||
pkgname=libmdbx
|
||||
pkgver=0.13.10
|
||||
pkgrel=2
|
||||
pkgdesc="One of the fastest compact key-value ACID database without WAL, which surpasses the legendary LMDB in terms of reliability, features and performance. At the end of 2024 MDBX was chosen by all modern Ethereum frontiers/nodes as a storage engine."
|
||||
url="https://libmdbx.dqdkfa.ru/"
|
||||
arch=('x86_64' 'i686' 'ARM' 'aarch64' 'powerpc64le')
|
||||
license=('Apache-2')
|
||||
depends=('glibc')
|
||||
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
|
||||
source=("$pkgname-$pkgver.tar.xz::https://libmdbx.dqdkfa.ru/release/libmdbx-amalgamated-$pkgver.tar.xz")
|
||||
sha256sums=('e6c9af085390c41d101fce0a72794c77159e1e271e41077ea0fd4270b43cc56c')
|
||||
|
||||
build() {
|
||||
make -C "$srcdir" \
|
||||
DESTDIR="$pkgdir" prefix=/usr \
|
||||
CFLAGS="$CFLAGS -std=gnu11 -ffunction-sections -fPIC -fvisibility=hidden -pthread" \
|
||||
CXXFLAGS="$CXXFLAGS -std=gnu++20 -ffunction-sections -fPIC -fvisibility=hidden -pthread" \
|
||||
lib-shared tools
|
||||
}
|
||||
|
||||
check() {
|
||||
echo " Testing a storage engine is a very voluminous and complex task that requires many hours of processor time."
|
||||
echo " Any simple tests will only verify the success of the build and create an unjustified illusion."
|
||||
echo " Therefore, full-fledged testing of libmdbx is performed during development and releasing, but the test framework used for this purpose is not included in the amalgamated source code of libmdbx releases."
|
||||
echo " The users are invited to use their own integration and functional tests, and if necessary to test libmdbx itself use a whole source code from the git repository."
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C "$srcdir" \
|
||||
DESTDIR="$pkgdir" prefix=/usr \
|
||||
CFLAGS="$CFLAGS -std=gnu11 -ffunction-sections -fPIC -fvisibility=hidden -pthread" \
|
||||
CXXFLAGS="$CXXFLAGS -std=gnu++20 -ffunction-sections -fPIC -fvisibility=hidden -pthread" \
|
||||
install-no-strip
|
||||
}
|
||||
|
||||
75
packages/buildroot/0001-package-libmdbx.patch
Normal file
75
packages/buildroot/0001-package-libmdbx.patch
Normal file
@@ -0,0 +1,75 @@
|
||||
From 13be767a0dbbb8e398ca73374728ad19d6f35d8f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?=
|
||||
=?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= <leo@yuriev.ru>
|
||||
Date: Thu, 18 Dec 2025 18:44:26 +0300
|
||||
Subject: [PATCH] package/libmdbx: new package (library/database).
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This patch adds libmdbx 0.13.10:
|
||||
- libmdbx is one of the fastest compact embeddable key-value ACID database.
|
||||
- libmdbx has a specific set of properties and capabilities,
|
||||
focused on creating unique lightweight solutions.
|
||||
- libmdbx surpasses the legendary LMDB (Lightning Memory-Mapped Database)
|
||||
in terms of reliability, features and performance.
|
||||
- more information at https://libmdbx.dqdkfa.ru
|
||||
|
||||
The 0.13.10 "Блеск Славы" (Gloss of Glory) is bugfix release of the stable branch.
|
||||
In memory of Michael Alexander Gloss, American, son of Deputy Director of the CIA,
|
||||
who died heroically in search of justice for the bright ideals of humanity
|
||||
and was posthumously awarded the Order of Courage.
|
||||
|
||||
For more information please see [ChangeLog in the `stable` branch](https://sourcecraft.dev/dqdkfa/libmdbx/browse/ChangeLog.md?rev=stable).
|
||||
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
---
|
||||
package/libmdbx/Config.in | 4 +++-
|
||||
package/libmdbx/libmdbx.hash | 4 ++--
|
||||
package/libmdbx/libmdbx.mk | 2 +-
|
||||
3 files changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/package/libmdbx/Config.in b/package/libmdbx/Config.in
|
||||
index a9a4ac45c5..1c4bc19e54 100644
|
||||
--- a/package/libmdbx/Config.in
|
||||
+++ b/package/libmdbx/Config.in
|
||||
@@ -11,7 +11,9 @@ config BR2_PACKAGE_LIBMDBX
|
||||
solutions.
|
||||
|
||||
libmdbx surpasses the legendary LMDB in terms of
|
||||
- reliability, features and performance.
|
||||
+ reliability, features and performance. At the end of 2024
|
||||
+ libmdbx was chosen by all modern Ethereum nodes
|
||||
+ as a storage engine.
|
||||
|
||||
https://libmdbx.dqdkfa.ru
|
||||
|
||||
diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash
|
||||
index ae5266716b..ad3c374988 100644
|
||||
--- a/package/libmdbx/libmdbx.hash
|
||||
+++ b/package/libmdbx/libmdbx.hash
|
||||
@@ -1,6 +1,6 @@
|
||||
# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS
|
||||
-sha256 57db987de6f7ccc66a66ae28a7bda9f9fbb48ac5fb9279bcca92fd5de13075d1 libmdbx-amalgamated-0.13.6.tar.xz
|
||||
+sha256 e6c9af085390c41d101fce0a72794c77159e1e271e41077ea0fd4270b43cc56c libmdbx-amalgamated-0.13.10.tar.xz
|
||||
|
||||
# Locally calculated
|
||||
sha256 0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594 LICENSE
|
||||
-sha256 651f71b46c6bb0046d2122df7f9def9cb24f4dc28c5b11cef059f66565cda30f NOTICE
|
||||
+sha256 1fa543d5002a28f430966acd01f231b437968421a16e8236b83938556dfddb34 NOTICE
|
||||
diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk
|
||||
index f461d98397..a1b219eb54 100644
|
||||
--- a/package/libmdbx/libmdbx.mk
|
||||
+++ b/package/libmdbx/libmdbx.mk
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
-LIBMDBX_VERSION = 0.13.6
|
||||
+LIBMDBX_VERSION = 0.13.10
|
||||
LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz
|
||||
LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release
|
||||
LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@@ -3,16 +3,34 @@
|
||||
#
|
||||
project(mdbx_ut_and_examples)
|
||||
|
||||
add_executable(mdbx_example example-mdbx.c)
|
||||
if(NOT DEFINED MDBX_LIBRARY)
|
||||
set(MDBX_LIBRARY mdbx)
|
||||
endif()
|
||||
target_link_libraries(mdbx_example ${MDBX_LIBRARY})
|
||||
|
||||
if(MDBX_BUILD_CXX AND CMAKE_CXX_COMPILER_LOADED AND NOT MDBX_CXX_STANDARD LESS 17)
|
||||
add_executable(mdbx_modern_example example-mdbx.c++)
|
||||
set_target_properties(mdbx_modern_example PROPERTIES CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
target_link_libraries(mdbx_modern_example ${MDBX_LIBRARY})
|
||||
else()
|
||||
message(NOTICE "The C++ example will be skipped, since C++17 standard is unavailable or C++ API of libmdbx was disabled.")
|
||||
set(MDBX_BUILD_CXX FALSE)
|
||||
endif()
|
||||
|
||||
add_executable(mdbx_legacy_example example-mdbx.c)
|
||||
target_link_libraries(mdbx_legacy_example ${MDBX_LIBRARY})
|
||||
|
||||
if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CROSSCOMPILING_EMULATOR)
|
||||
message(WARNING "No emulator to run cross-compiled tests")
|
||||
message(NOTICE "No emulator to run cross-compiled tests")
|
||||
add_test(NAME fake_since_no_crosscompiling_emulator COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"No emulator to run cross-compiled tests")
|
||||
else()
|
||||
add_test(NAME example_c_api COMMAND mdbx_example)
|
||||
add_test(NAME c_api COMMAND mdbx_legacy_example)
|
||||
if(MDBX_BUILD_CXX)
|
||||
add_test(NAME c++_api COMMAND mdbx_modern_example)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
add_executable(pcrf_simulator pcrf/pcrf_simulator.c)
|
||||
target_link_libraries(pcrf_simulator ${MDBX_LIBRARY})
|
||||
endif()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* The example of using the libmdbx C API.
|
||||
/** \file The example of using the libmdbx C API.
|
||||
* However, it is strongly recommended to use the modern C++ API, which requires less effort
|
||||
* and insures against many errors related to resource leaks.
|
||||
*
|
||||
* If you have already used Berkeley DB,
|
||||
* \note If you have already used Berkeley DB,
|
||||
* it will be useful to make a line-by-line comparison of this example and the sample-bdb.txt
|
||||
*/
|
||||
|
||||
|
||||
41
ut_and_examples/example-mdbx.c++
Normal file
41
ut_and_examples/example-mdbx.c++
Normal file
@@ -0,0 +1,41 @@
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2026
|
||||
/// \file The example of using the libmdbx modern C++ API.
|
||||
|
||||
#include <iostream>
|
||||
#include <mdbx.h++>
|
||||
|
||||
/* This is a minimal example now, which will be expanded soon. */
|
||||
|
||||
static bool doit(const mdbx::path &example_database_pathname) {
|
||||
using buffer = mdbx::buffer<mdbx::default_allocator, mdbx::default_capacity_policy>;
|
||||
mdbx::env::remove(example_database_pathname);
|
||||
mdbx::env_managed env(example_database_pathname, mdbx::env_managed::create_parameters(),
|
||||
mdbx::env::operate_parameters(11));
|
||||
|
||||
auto txn = env.start_write();
|
||||
auto map = txn.create_map("table-ordinals", mdbx::key_mode::ordinal, mdbx::value_mode::single);
|
||||
txn.insert(map, buffer::key_from_u64(42), "a");
|
||||
txn.insert(map, buffer::key_from_double(0.1), mdbx::slice("b"));
|
||||
txn.insert(map, buffer::key_from_jsonInteger(1), buffer("c"));
|
||||
txn.insert(map, mdbx::slice::wrap(uint64_t(0xaBad1dea)), buffer::base58("aBad1dea"));
|
||||
txn.commit_embark_read();
|
||||
|
||||
auto cursor = txn.open_cursor(map);
|
||||
cursor.to_first();
|
||||
while (!cursor.eof()) {
|
||||
std::cout << cursor.current() << std::endl;
|
||||
cursor.to_next(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, const char *[]) {
|
||||
try {
|
||||
return doit("example_database") ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
} catch (const std::exception &ex) {
|
||||
std::cerr << "Exception: " << ex.what() << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
367
ut_and_examples/pcrf/pcrf_simulator.c
Normal file
367
ut_and_examples/pcrf/pcrf_simulator.c
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright 2015 Vladimir Romanov
|
||||
* <https://www.linkedin.com/in/vladimirromanov>, Yota Lab.
|
||||
* SPDX-License-Identifier: AGPL-3.0
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "mdbx.h"
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define IP_PRINTF_ARG_HOST(addr) \
|
||||
(int)((addr) >> 24), (int)((addr) >> 16 & 0xff), (int)((addr) >> 8 & 0xff), (int)((addr) & 0xff)
|
||||
|
||||
char opt_db_path[PATH_MAX] = "./mdbx_bench2";
|
||||
static MDBX_env *env;
|
||||
#define REC_COUNT 10240000
|
||||
int64_t ids[REC_COUNT * 10];
|
||||
int32_t ids_count = 0;
|
||||
|
||||
int64_t mdbx_add_count = 0;
|
||||
int64_t mdbx_del_count = 0;
|
||||
uint64_t mdbx_add_time = 0;
|
||||
uint64_t mdbx_del_time = 0;
|
||||
int64_t obj_id = 0;
|
||||
int64_t mdbx_data_size = 0;
|
||||
int64_t mdbx_key_size = 0;
|
||||
|
||||
typedef struct {
|
||||
char session_id1[100];
|
||||
char session_id2[100];
|
||||
char ip[20];
|
||||
uint8_t fill[100];
|
||||
} session_data_t;
|
||||
|
||||
typedef struct {
|
||||
int64_t obj_id;
|
||||
int8_t event_type;
|
||||
} __attribute__((__packed__)) event_data_t;
|
||||
|
||||
static void add_id_to_pool(int64_t id) {
|
||||
ids[ids_count] = id;
|
||||
ids_count++;
|
||||
}
|
||||
|
||||
static inline int64_t getClockUs(void) {
|
||||
struct timespec val;
|
||||
#ifdef CYGWIN
|
||||
clock_gettime(CLOCK_REALTIME, &val);
|
||||
#else
|
||||
clock_gettime(CLOCK_MONOTONIC, &val);
|
||||
#endif
|
||||
return val.tv_sec * ((int64_t)1000000) + val.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
static int64_t get_id_from_pool() {
|
||||
if (ids_count == 0) {
|
||||
return -1;
|
||||
}
|
||||
int32_t index = rand() % ids_count;
|
||||
int64_t id = ids[index];
|
||||
ids[index] = ids[ids_count - 1];
|
||||
ids_count--;
|
||||
return id;
|
||||
}
|
||||
|
||||
#define MDBX_CHECK(x) \
|
||||
do { \
|
||||
const int rc = (x); \
|
||||
if (rc != MDBX_SUCCESS) { \
|
||||
printf("Error [%d] %s in %s at %s:%d\n", rc, mdbx_strerror(rc), #x, __FILE__, __LINE__); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void db_connect() {
|
||||
MDBX_dbi dbi_session;
|
||||
MDBX_dbi dbi_session_id;
|
||||
MDBX_dbi dbi_event;
|
||||
MDBX_dbi dbi_ip;
|
||||
|
||||
MDBX_CHECK(mdbx_env_create(&env));
|
||||
MDBX_CHECK(mdbx_env_set_geometry(env, 0, 0, REC_COUNT * sizeof(session_data_t) * 10, -1, -1, -1));
|
||||
MDBX_CHECK(mdbx_env_set_maxdbs(env, 30));
|
||||
MDBX_CHECK(
|
||||
mdbx_env_open(env, opt_db_path, MDBX_CREATE | MDBX_WRITEMAP | MDBX_UTTERLY_NOSYNC | MDBX_LIFORECLAIM, 0664));
|
||||
MDBX_txn *txn;
|
||||
|
||||
// transaction init
|
||||
MDBX_CHECK(mdbx_txn_begin(env, NULL, 0, &txn));
|
||||
// open database in read-write mode
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "session", MDBX_CREATE, &dbi_session));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "session_id", MDBX_CREATE, &dbi_session_id));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "event", MDBX_CREATE, &dbi_event));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "ip", MDBX_CREATE, &dbi_ip));
|
||||
// transaction commit
|
||||
MDBX_CHECK(mdbx_txn_commit(txn));
|
||||
printf("Connection open\n");
|
||||
}
|
||||
|
||||
static void create_record(uint64_t record_id) {
|
||||
MDBX_dbi dbi_session;
|
||||
MDBX_dbi dbi_session_id;
|
||||
MDBX_dbi dbi_event;
|
||||
MDBX_dbi dbi_ip;
|
||||
event_data_t event;
|
||||
MDBX_txn *txn;
|
||||
session_data_t data;
|
||||
// transaction init
|
||||
snprintf(data.session_id1, sizeof(data.session_id1), "prefix%02u_%02u.fill.fill.fill.fill.fill.fill;%" PRIu64,
|
||||
(unsigned)(record_id % 3) + 1, (unsigned)(record_id % 9) + 1, record_id);
|
||||
snprintf(data.session_id2, sizeof(data.session_id2), "dprefix%" PRIu64 ";%" PRIu64 ".fill.fill.;suffix", record_id,
|
||||
(record_id + UINT64_C(1442695040888963407)) % UINT64_C(6364136223846793005));
|
||||
snprintf(data.ip, sizeof(data.ip), "%d.%d.%d.%d", IP_PRINTF_ARG_HOST(record_id & 0xFFFFFFFF));
|
||||
event.obj_id = record_id;
|
||||
event.event_type = 1;
|
||||
|
||||
MDBX_val _session_id1_rec = {data.session_id1, strlen(data.session_id1)};
|
||||
MDBX_val _session_id2_rec = {data.session_id2, strlen(data.session_id2)};
|
||||
MDBX_val _ip_rec = {data.ip, strlen(data.ip)};
|
||||
MDBX_val _obj_id_rec = {&record_id, sizeof(record_id)};
|
||||
MDBX_val _data_rec = {&data, offsetof(session_data_t, fill) + (rand() % sizeof(data.fill))};
|
||||
MDBX_val _event_rec = {&event, sizeof(event)};
|
||||
|
||||
uint64_t start = getClockUs();
|
||||
MDBX_CHECK(mdbx_txn_begin(env, NULL, 0, &txn));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "session", MDBX_CREATE, &dbi_session));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "session_id", MDBX_CREATE, &dbi_session_id));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "event", MDBX_CREATE, &dbi_event));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "ip", MDBX_CREATE, &dbi_ip));
|
||||
MDBX_CHECK(mdbx_put(txn, dbi_session, &_obj_id_rec, &_data_rec, MDBX_NOOVERWRITE | MDBX_NODUPDATA));
|
||||
MDBX_CHECK(mdbx_put(txn, dbi_session_id, &_session_id1_rec, &_obj_id_rec, MDBX_NOOVERWRITE | MDBX_NODUPDATA));
|
||||
MDBX_CHECK(mdbx_put(txn, dbi_session_id, &_session_id2_rec, &_obj_id_rec, MDBX_NOOVERWRITE | MDBX_NODUPDATA));
|
||||
MDBX_CHECK(mdbx_put(txn, dbi_ip, &_ip_rec, &_obj_id_rec, 0));
|
||||
MDBX_CHECK(mdbx_put(txn, dbi_event, &_event_rec, &_obj_id_rec, 0));
|
||||
MDBX_CHECK(mdbx_txn_commit(txn));
|
||||
|
||||
mdbx_data_size += (_data_rec.iov_len + _obj_id_rec.iov_len * 4);
|
||||
mdbx_key_size += (_obj_id_rec.iov_len + _session_id1_rec.iov_len + _session_id2_rec.iov_len + _ip_rec.iov_len +
|
||||
_event_rec.iov_len);
|
||||
|
||||
// transaction commit
|
||||
mdbx_add_count++;
|
||||
mdbx_add_time += (getClockUs() - start);
|
||||
}
|
||||
|
||||
static void delete_record(int64_t record_id) {
|
||||
MDBX_dbi dbi_session;
|
||||
MDBX_dbi dbi_session_id;
|
||||
MDBX_dbi dbi_event;
|
||||
MDBX_dbi dbi_ip;
|
||||
event_data_t event;
|
||||
MDBX_txn *txn;
|
||||
|
||||
// transaction init
|
||||
uint64_t start = getClockUs();
|
||||
MDBX_CHECK(mdbx_txn_begin(env, NULL, 0, &txn));
|
||||
// open database in read-write mode
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "session", MDBX_CREATE, &dbi_session));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "session_id", MDBX_CREATE, &dbi_session_id));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "event", MDBX_CREATE, &dbi_event));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, "ip", MDBX_CREATE, &dbi_ip));
|
||||
// put data
|
||||
MDBX_val _obj_id_rec = {&record_id, sizeof(record_id)};
|
||||
MDBX_val _data_rec;
|
||||
// get data
|
||||
MDBX_CHECK(mdbx_get(txn, dbi_session, &_obj_id_rec, &_data_rec));
|
||||
session_data_t *data = (session_data_t *)_data_rec.iov_base;
|
||||
|
||||
MDBX_val _session_id1_rec = {data->session_id1, strlen(data->session_id1)};
|
||||
MDBX_val _session_id2_rec = {data->session_id2, strlen(data->session_id2)};
|
||||
MDBX_val _ip_rec = {data->ip, strlen(data->ip)};
|
||||
MDBX_CHECK(mdbx_del(txn, dbi_session_id, &_session_id1_rec, NULL));
|
||||
MDBX_CHECK(mdbx_del(txn, dbi_session_id, &_session_id2_rec, NULL));
|
||||
MDBX_CHECK(mdbx_del(txn, dbi_ip, &_ip_rec, NULL));
|
||||
event.obj_id = record_id;
|
||||
event.event_type = 1;
|
||||
MDBX_val _event_rec = {&event, sizeof(event)};
|
||||
MDBX_CHECK(mdbx_del(txn, dbi_event, &_event_rec, NULL));
|
||||
MDBX_CHECK(mdbx_del(txn, dbi_session, &_obj_id_rec, NULL));
|
||||
|
||||
mdbx_data_size -= (_data_rec.iov_len + _obj_id_rec.iov_len * 4);
|
||||
mdbx_key_size -= (_obj_id_rec.iov_len + _session_id1_rec.iov_len + _session_id2_rec.iov_len + _ip_rec.iov_len +
|
||||
_event_rec.iov_len);
|
||||
|
||||
// transaction commit
|
||||
MDBX_CHECK(mdbx_txn_commit(txn));
|
||||
mdbx_del_count++;
|
||||
mdbx_del_time += (getClockUs() - start);
|
||||
}
|
||||
|
||||
static void db_disconnect() {
|
||||
mdbx_env_close(env);
|
||||
printf("Connection closed\n");
|
||||
}
|
||||
|
||||
static void get_db_stat(const char *db, int64_t *ms_branch_pages, int64_t *ms_leaf_pages) {
|
||||
MDBX_txn *txn;
|
||||
MDBX_stat stat;
|
||||
MDBX_dbi dbi;
|
||||
|
||||
MDBX_CHECK(mdbx_txn_begin(env, NULL, MDBX_TXN_RDONLY, &txn));
|
||||
MDBX_CHECK(mdbx_dbi_open(txn, db, MDBX_DB_ACCEDE, &dbi));
|
||||
MDBX_CHECK(mdbx_dbi_stat(txn, dbi, &stat, sizeof(stat)));
|
||||
mdbx_txn_abort(txn);
|
||||
printf("%15s | %15" PRIu64 " | %5u | %10" PRIu64 " | %10" PRIu64 " | %11" PRIu64 " |\n", db, stat.ms_branch_pages,
|
||||
stat.ms_depth, stat.ms_entries, stat.ms_leaf_pages, stat.ms_overflow_pages);
|
||||
(*ms_branch_pages) += stat.ms_branch_pages;
|
||||
(*ms_leaf_pages) += stat.ms_leaf_pages;
|
||||
}
|
||||
|
||||
static void periodic_stat(void) {
|
||||
int64_t ms_branch_pages = 0;
|
||||
int64_t ms_leaf_pages = 0;
|
||||
MDBX_stat mst;
|
||||
MDBX_envinfo mei;
|
||||
MDBX_CHECK(mdbx_env_stat_ex(env, NULL, &mst, sizeof(mst)));
|
||||
MDBX_CHECK(mdbx_env_info_ex(env, NULL, &mei, sizeof(mei)));
|
||||
printf("Environment Info\n");
|
||||
printf(" Pagesize: %u\n", mst.ms_psize);
|
||||
if (mei.mi_geo.lower != mei.mi_geo.upper) {
|
||||
printf(" Dynamic datafile: %" PRIu64 "..%" PRIu64 " bytes (+%" PRIu64 "/-%" PRIu64 "), %" PRIu64 "..%" PRIu64
|
||||
" pages (+%" PRIu64 "/-%" PRIu64 ")\n",
|
||||
mei.mi_geo.lower, mei.mi_geo.upper, mei.mi_geo.grow, mei.mi_geo.shrink, mei.mi_geo.lower / mst.ms_psize,
|
||||
mei.mi_geo.upper / mst.ms_psize, mei.mi_geo.grow / mst.ms_psize, mei.mi_geo.shrink / mst.ms_psize);
|
||||
printf(" Current datafile: %" PRIu64 " bytes, %" PRIu64 " pages\n", mei.mi_geo.current,
|
||||
mei.mi_geo.current / mst.ms_psize);
|
||||
} else {
|
||||
printf(" Fixed datafile: %" PRIu64 " bytes, %" PRIu64 " pages\n", mei.mi_geo.current,
|
||||
mei.mi_geo.current / mst.ms_psize);
|
||||
}
|
||||
printf(" Current mapsize: %" PRIu64 " bytes, %" PRIu64 " pages \n", mei.mi_mapsize, mei.mi_mapsize / mst.ms_psize);
|
||||
printf(" Number of pages used: %" PRIu64 "\n", mei.mi_last_pgno + 1);
|
||||
printf(" Last transaction ID: %" PRIu64 "\n", mei.mi_recent_txnid);
|
||||
printf(" Tail transaction ID: %" PRIu64 " (%" PRIi64 ")\n", mei.mi_latter_reader_txnid,
|
||||
mei.mi_latter_reader_txnid - mei.mi_recent_txnid);
|
||||
printf(" Max readers: %u\n", mei.mi_maxreaders);
|
||||
printf(" Number of readers used: %u\n", mei.mi_numreaders);
|
||||
|
||||
printf(" Name | ms_branch_pages | depth | entries | leaf_pages "
|
||||
"| overf_pages |\n");
|
||||
get_db_stat("session", &ms_branch_pages, &ms_leaf_pages);
|
||||
get_db_stat("session_id", &ms_branch_pages, &ms_leaf_pages);
|
||||
get_db_stat("event", &ms_branch_pages, &ms_leaf_pages);
|
||||
get_db_stat("ip", &ms_branch_pages, &ms_leaf_pages);
|
||||
printf("%15s | %15" PRIu64 " | %5s | %10s | %10" PRIu64 " | %11s |\n", "", ms_branch_pages, "", "", ms_leaf_pages,
|
||||
"");
|
||||
|
||||
static int64_t prev_add_count;
|
||||
static int64_t prev_del_count;
|
||||
static uint64_t prev_add_time;
|
||||
static uint64_t prev_del_time;
|
||||
static int64_t t = -1;
|
||||
if (t > 0) {
|
||||
int64_t delta = (getClockUs() - t);
|
||||
printf("CPS: add %" PRIu64 ", delete %" PRIu64 ", items processed - %" PRIu64 "K data=%" PRIu64 "K key=%" PRIu64
|
||||
"K\n",
|
||||
(mdbx_add_count - prev_add_count) * 1000000 / delta, (mdbx_del_count - prev_del_count) * 1000000 / delta,
|
||||
obj_id / 1024, mdbx_data_size / 1024, mdbx_key_size / 1024);
|
||||
printf("usage data=%" PRIu64 "%%",
|
||||
((mdbx_data_size + mdbx_key_size) * 100) / ((ms_leaf_pages + ms_branch_pages) * 4096));
|
||||
if (prev_add_time != mdbx_add_time) {
|
||||
printf(" Add : %" PRIu64 " c/s", (mdbx_add_count - prev_add_count) * 1000000 / (mdbx_add_time - prev_add_time));
|
||||
}
|
||||
if (prev_del_time != mdbx_del_time) {
|
||||
printf(" Del : %" PRIu64 " c/s", (mdbx_del_count - prev_del_count) * 1000000 / (mdbx_del_time - prev_del_time));
|
||||
}
|
||||
if (mdbx_add_time) {
|
||||
printf(" tAdd : %" PRIu64 " c/s", mdbx_add_count * 1000000 / mdbx_add_time);
|
||||
}
|
||||
if (mdbx_del_time) {
|
||||
printf(" tDel : %" PRIu64 " c/s", mdbx_del_count * 1000000 / mdbx_del_time);
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
t = getClockUs();
|
||||
prev_add_count = mdbx_add_count;
|
||||
prev_del_count = mdbx_del_count;
|
||||
prev_add_time = mdbx_add_time;
|
||||
prev_del_time = mdbx_del_time;
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
static void periodic_add_rec() {
|
||||
for (int i = 0; i < 10240; i++) {
|
||||
if (ids_count <= REC_COUNT) {
|
||||
int64_t id = obj_id++;
|
||||
create_record(id);
|
||||
add_id_to_pool(id);
|
||||
}
|
||||
if (ids_count > REC_COUNT) {
|
||||
int64_t id = get_id_from_pool();
|
||||
delete_record(id);
|
||||
}
|
||||
}
|
||||
periodic_stat();
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
char filename[PATH_MAX];
|
||||
int i;
|
||||
|
||||
strcpy(filename, opt_db_path);
|
||||
strcat(filename, MDBX_DATANAME);
|
||||
remove(filename);
|
||||
|
||||
strcpy(filename, opt_db_path);
|
||||
strcat(filename, MDBX_LOCKNAME);
|
||||
remove(filename);
|
||||
|
||||
puts("Open DB...");
|
||||
db_connect();
|
||||
puts("Create data...");
|
||||
int64_t t = getClockUs();
|
||||
for (i = 0; i < REC_COUNT; i++) {
|
||||
int64_t id = obj_id++;
|
||||
create_record(id);
|
||||
add_id_to_pool(id);
|
||||
if (i % 1000 == 0) {
|
||||
int64_t now = getClockUs();
|
||||
if ((now - t) > 1000000L) {
|
||||
periodic_stat();
|
||||
t = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
periodic_stat();
|
||||
while (1) {
|
||||
int i;
|
||||
for (i = 0; i < 1000; i++) {
|
||||
int64_t id = obj_id++;
|
||||
create_record(id);
|
||||
add_id_to_pool(id);
|
||||
id = get_id_from_pool();
|
||||
delete_record(id);
|
||||
}
|
||||
for (i = 0; i < 50; i++) {
|
||||
int64_t id = obj_id++;
|
||||
create_record(id);
|
||||
add_id_to_pool(id);
|
||||
}
|
||||
int64_t id = obj_id++;
|
||||
create_record(id);
|
||||
add_id_to_pool(id);
|
||||
int64_t now = getClockUs();
|
||||
if ((now - t) > 10000000L) {
|
||||
periodic_stat();
|
||||
t = now;
|
||||
}
|
||||
}
|
||||
db_disconnect();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user