mdbxmou 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +32 -0
- package/.github/workflows/publish.yml +27 -0
- package/.gitmodules +3 -0
- package/CMakeLists.txt +53 -0
- package/LICENSE +201 -0
- package/README.md +639 -0
- package/build.js +11 -0
- package/deps/libmdbx/.clang-format +3 -0
- package/deps/libmdbx/.cmake-format.yaml +3 -0
- package/deps/libmdbx/.le.ini +40 -0
- package/deps/libmdbx/CMakeLists.txt +1269 -0
- package/deps/libmdbx/COPYRIGHT +159 -0
- package/deps/libmdbx/ChangeLog.md +2786 -0
- package/deps/libmdbx/GNUmakefile +950 -0
- package/deps/libmdbx/LICENSE +177 -0
- package/deps/libmdbx/Makefile +16 -0
- package/deps/libmdbx/NOTICE +39 -0
- package/deps/libmdbx/README.md +863 -0
- package/deps/libmdbx/TODO.md +43 -0
- package/deps/libmdbx/cmake/compiler.cmake +1221 -0
- package/deps/libmdbx/cmake/profile.cmake +58 -0
- package/deps/libmdbx/cmake/utils.cmake +524 -0
- package/deps/libmdbx/conanfile.py +323 -0
- package/deps/libmdbx/docs/Doxyfile.in +2734 -0
- package/deps/libmdbx/docs/_preface.md +47 -0
- package/deps/libmdbx/docs/_restrictions.md +248 -0
- package/deps/libmdbx/docs/_starting.md +245 -0
- package/deps/libmdbx/docs/_toc.md +34 -0
- package/deps/libmdbx/docs/header.html +96 -0
- package/deps/libmdbx/example/CMakeLists.txt +6 -0
- package/deps/libmdbx/example/README.md +1 -0
- package/deps/libmdbx/example/example-mdbx.c +154 -0
- package/deps/libmdbx/example/sample-bdb.txt +77 -0
- package/deps/libmdbx/mdbx.h +6655 -0
- package/deps/libmdbx/mdbx.h++ +6428 -0
- package/deps/libmdbx/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +173 -0
- package/deps/libmdbx/src/alloy.c +54 -0
- package/deps/libmdbx/src/api-cold.c +543 -0
- package/deps/libmdbx/src/api-copy.c +912 -0
- package/deps/libmdbx/src/api-cursor.c +754 -0
- package/deps/libmdbx/src/api-dbi.c +315 -0
- package/deps/libmdbx/src/api-env.c +1434 -0
- package/deps/libmdbx/src/api-extra.c +165 -0
- package/deps/libmdbx/src/api-key-transform.c +197 -0
- package/deps/libmdbx/src/api-misc.c +286 -0
- package/deps/libmdbx/src/api-opts.c +575 -0
- package/deps/libmdbx/src/api-range-estimate.c +365 -0
- package/deps/libmdbx/src/api-txn-data.c +454 -0
- package/deps/libmdbx/src/api-txn.c +921 -0
- package/deps/libmdbx/src/atomics-ops.h +364 -0
- package/deps/libmdbx/src/atomics-types.h +97 -0
- package/deps/libmdbx/src/audit.c +109 -0
- package/deps/libmdbx/src/bits.md +34 -0
- package/deps/libmdbx/src/chk.c +1796 -0
- package/deps/libmdbx/src/cogs.c +309 -0
- package/deps/libmdbx/src/cogs.h +506 -0
- package/deps/libmdbx/src/coherency.c +170 -0
- package/deps/libmdbx/src/config.h.in +88 -0
- package/deps/libmdbx/src/cursor.c +2396 -0
- package/deps/libmdbx/src/cursor.h +391 -0
- package/deps/libmdbx/src/dbi.c +717 -0
- package/deps/libmdbx/src/dbi.h +142 -0
- package/deps/libmdbx/src/debug_begin.h +36 -0
- package/deps/libmdbx/src/debug_end.h +15 -0
- package/deps/libmdbx/src/dpl.c +486 -0
- package/deps/libmdbx/src/dpl.h +134 -0
- package/deps/libmdbx/src/dxb.c +1335 -0
- package/deps/libmdbx/src/env.c +607 -0
- package/deps/libmdbx/src/essentials.h +125 -0
- package/deps/libmdbx/src/gc-get.c +1345 -0
- package/deps/libmdbx/src/gc-put.c +970 -0
- package/deps/libmdbx/src/gc.h +40 -0
- package/deps/libmdbx/src/global.c +474 -0
- package/deps/libmdbx/src/internals.h +585 -0
- package/deps/libmdbx/src/layout-dxb.h +288 -0
- package/deps/libmdbx/src/layout-lck.h +289 -0
- package/deps/libmdbx/src/lck-posix.c +859 -0
- package/deps/libmdbx/src/lck-windows.c +607 -0
- package/deps/libmdbx/src/lck.c +174 -0
- package/deps/libmdbx/src/lck.h +110 -0
- package/deps/libmdbx/src/logging_and_debug.c +250 -0
- package/deps/libmdbx/src/logging_and_debug.h +159 -0
- package/deps/libmdbx/src/man1/mdbx_chk.1 +106 -0
- package/deps/libmdbx/src/man1/mdbx_copy.1 +95 -0
- package/deps/libmdbx/src/man1/mdbx_drop.1 +48 -0
- package/deps/libmdbx/src/man1/mdbx_dump.1 +101 -0
- package/deps/libmdbx/src/man1/mdbx_load.1 +105 -0
- package/deps/libmdbx/src/man1/mdbx_stat.1 +86 -0
- package/deps/libmdbx/src/mdbx.c++ +1837 -0
- package/deps/libmdbx/src/meta.c +656 -0
- package/deps/libmdbx/src/meta.h +168 -0
- package/deps/libmdbx/src/mvcc-readers.c +414 -0
- package/deps/libmdbx/src/node.c +365 -0
- package/deps/libmdbx/src/node.h +102 -0
- package/deps/libmdbx/src/ntdll.def +1246 -0
- package/deps/libmdbx/src/options.h +534 -0
- package/deps/libmdbx/src/osal.c +3485 -0
- package/deps/libmdbx/src/osal.h +587 -0
- package/deps/libmdbx/src/page-get.c +483 -0
- package/deps/libmdbx/src/page-iov.c +185 -0
- package/deps/libmdbx/src/page-iov.h +34 -0
- package/deps/libmdbx/src/page-ops.c +744 -0
- package/deps/libmdbx/src/page-ops.h +142 -0
- package/deps/libmdbx/src/pnl.c +236 -0
- package/deps/libmdbx/src/pnl.h +146 -0
- package/deps/libmdbx/src/preface.h +990 -0
- package/deps/libmdbx/src/proto.h +105 -0
- package/deps/libmdbx/src/refund.c +212 -0
- package/deps/libmdbx/src/sort.h +484 -0
- package/deps/libmdbx/src/spill.c +431 -0
- package/deps/libmdbx/src/spill.h +74 -0
- package/deps/libmdbx/src/table.c +107 -0
- package/deps/libmdbx/src/tls.c +551 -0
- package/deps/libmdbx/src/tls.h +43 -0
- package/deps/libmdbx/src/tools/chk.c +673 -0
- package/deps/libmdbx/src/tools/copy.c +166 -0
- package/deps/libmdbx/src/tools/drop.c +199 -0
- package/deps/libmdbx/src/tools/dump.c +515 -0
- package/deps/libmdbx/src/tools/load.c +831 -0
- package/deps/libmdbx/src/tools/stat.c +516 -0
- package/deps/libmdbx/src/tools/wingetopt.c +87 -0
- package/deps/libmdbx/src/tools/wingetopt.h +30 -0
- package/deps/libmdbx/src/tree-ops.c +1554 -0
- package/deps/libmdbx/src/tree-search.c +140 -0
- package/deps/libmdbx/src/txl.c +99 -0
- package/deps/libmdbx/src/txl.h +26 -0
- package/deps/libmdbx/src/txn.c +1083 -0
- package/deps/libmdbx/src/unaligned.h +205 -0
- package/deps/libmdbx/src/utils.c +32 -0
- package/deps/libmdbx/src/utils.h +76 -0
- package/deps/libmdbx/src/version.c.in +44 -0
- package/deps/libmdbx/src/walk.c +290 -0
- package/deps/libmdbx/src/walk.h +20 -0
- package/deps/libmdbx/src/windows-import.c +152 -0
- package/deps/libmdbx/src/windows-import.h +128 -0
- package/deps/libmdbx/test/CMakeLists.txt +317 -0
- package/deps/libmdbx/test/append.c++ +237 -0
- package/deps/libmdbx/test/base.h++ +92 -0
- package/deps/libmdbx/test/battery-tmux.sh +64 -0
- package/deps/libmdbx/test/cases.c++ +118 -0
- package/deps/libmdbx/test/chrono.c++ +134 -0
- package/deps/libmdbx/test/chrono.h++ +85 -0
- package/deps/libmdbx/test/config.c++ +643 -0
- package/deps/libmdbx/test/config.h++ +334 -0
- package/deps/libmdbx/test/copy.c++ +62 -0
- package/deps/libmdbx/test/dead.c++ +39 -0
- package/deps/libmdbx/test/dump-load.sh +40 -0
- package/deps/libmdbx/test/extra/crunched_delete.c++ +409 -0
- package/deps/libmdbx/test/extra/cursor_closing.c++ +410 -0
- package/deps/libmdbx/test/extra/dbi.c++ +229 -0
- package/deps/libmdbx/test/extra/doubtless_positioning.c++ +253 -0
- package/deps/libmdbx/test/extra/dupfix_addodd.c +94 -0
- package/deps/libmdbx/test/extra/dupfix_multiple.c++ +311 -0
- package/deps/libmdbx/test/extra/early_close_dbi.c++ +137 -0
- package/deps/libmdbx/test/extra/hex_base64_base58.c++ +118 -0
- package/deps/libmdbx/test/extra/maindb_ordinal.c++ +61 -0
- package/deps/libmdbx/test/extra/open.c++ +96 -0
- package/deps/libmdbx/test/extra/pcrf/README.md +2 -0
- package/deps/libmdbx/test/extra/pcrf/pcrf_test.c +380 -0
- package/deps/libmdbx/test/extra/probe.c++ +10 -0
- package/deps/libmdbx/test/extra/txn.c++ +407 -0
- package/deps/libmdbx/test/extra/upsert_alldups.c +193 -0
- package/deps/libmdbx/test/fork.c++ +263 -0
- package/deps/libmdbx/test/hill.c++ +447 -0
- package/deps/libmdbx/test/jitter.c++ +197 -0
- package/deps/libmdbx/test/keygen.c++ +393 -0
- package/deps/libmdbx/test/keygen.h++ +130 -0
- package/deps/libmdbx/test/log.c++ +358 -0
- package/deps/libmdbx/test/log.h++ +91 -0
- package/deps/libmdbx/test/main.c++ +706 -0
- package/deps/libmdbx/test/nested.c++ +318 -0
- package/deps/libmdbx/test/osal-unix.c++ +647 -0
- package/deps/libmdbx/test/osal-windows.c++ +440 -0
- package/deps/libmdbx/test/osal.h++ +41 -0
- package/deps/libmdbx/test/stochastic.sh +690 -0
- package/deps/libmdbx/test/stub/LICENSE +24 -0
- package/deps/libmdbx/test/stub/README.md +8 -0
- package/deps/libmdbx/test/stub/pthread_barrier.c +104 -0
- package/deps/libmdbx/test/stub/pthread_barrier.h +77 -0
- package/deps/libmdbx/test/test.c++ +1551 -0
- package/deps/libmdbx/test/test.h++ +298 -0
- package/deps/libmdbx/test/tmux.conf +3 -0
- package/deps/libmdbx/test/try.c++ +30 -0
- package/deps/libmdbx/test/ttl.c++ +240 -0
- package/deps/libmdbx/test/utils.c++ +203 -0
- package/deps/libmdbx/test/utils.h++ +326 -0
- package/deps/libmdbx/test/valgrind_suppress.txt +536 -0
- package/lib/mdbx_evn_async.js +211 -0
- package/lib/mdbx_worker.js +195 -0
- package/lib/nativemou.js +6 -0
- package/package.json +38 -0
- package/src/async/envmou_close.cpp +34 -0
- package/src/async/envmou_close.hpp +32 -0
- package/src/async/envmou_copy_to.cpp +29 -0
- package/src/async/envmou_copy_to.hpp +38 -0
- package/src/async/envmou_keys.cpp +201 -0
- package/src/async/envmou_keys.hpp +50 -0
- package/src/async/envmou_open.cpp +38 -0
- package/src/async/envmou_open.hpp +33 -0
- package/src/async/envmou_query.cpp +167 -0
- package/src/async/envmou_query.hpp +53 -0
- package/src/dbimou.cpp +522 -0
- package/src/dbimou.hpp +82 -0
- package/src/env_arg0.hpp +24 -0
- package/src/envmou.cpp +445 -0
- package/src/envmou.hpp +116 -0
- package/src/modulemou.cpp +113 -0
- package/src/querymou.cpp +177 -0
- package/src/querymou.hpp +93 -0
- package/src/txnmou.cpp +254 -0
- package/src/txnmou.hpp +122 -0
- package/src/typemou.hpp +239 -0
- package/src/valuemou.hpp +194 -0
- package/test/async.js +67 -0
- package/test/e3.js +38 -0
- package/test/e4.js +89 -0
- package/test/e5.js +162 -0
- package/test/test-batch-ops.js +243 -0
- package/test/test-cursor-mode.js +84 -0
- package/test/test-multi-mode.js +87 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
\page intro Introduction
|
|
2
|
+
\section characteristics Characteristics
|
|
3
|
+
|
|
4
|
+
Preface {#preface}
|
|
5
|
+
------------------
|
|
6
|
+
|
|
7
|
+
> For the most part, this section is a copy of the corresponding text
|
|
8
|
+
> from LMDB description, but with some edits reflecting the improvements
|
|
9
|
+
> and enhancements were made in MDBX.
|
|
10
|
+
|
|
11
|
+
MDBX is a Btree-based database management library modeled loosely on the
|
|
12
|
+
BerkeleyDB API, but much simplified. The entire database (aka "environment")
|
|
13
|
+
is exposed in a memory map, and all data fetches return data directly from
|
|
14
|
+
the mapped memory, so no malloc's or memcpy's occur during data fetches.
|
|
15
|
+
As such, the library is extremely simple because it requires no page caching
|
|
16
|
+
layer of its own, and it is extremely high performance and memory-efficient.
|
|
17
|
+
It is also fully transactional with full ACID semantics, and when the memory
|
|
18
|
+
map is read-only, the database integrity cannot be corrupted by stray pointer
|
|
19
|
+
writes from application code.
|
|
20
|
+
|
|
21
|
+
The library is fully thread-aware and supports concurrent read/write access
|
|
22
|
+
from multiple processes and threads. Data pages use a copy-on-write strategy
|
|
23
|
+
so no active data pages are ever overwritten, which also provides resistance
|
|
24
|
+
to corruption and eliminates the need of any special recovery procedures
|
|
25
|
+
after a system crash. Writes are fully serialized; only one write transaction
|
|
26
|
+
may be active at a time, which guarantees that writers can never deadlock.
|
|
27
|
+
The database structure is multi-versioned so readers run with no locks;
|
|
28
|
+
writers cannot block readers, and readers don't block writers.
|
|
29
|
+
|
|
30
|
+
Unlike other well-known database mechanisms which use either write-ahead
|
|
31
|
+
transaction logs or append-only data writes, MDBX requires no maintenance
|
|
32
|
+
during operation. Both write-ahead loggers and append-only databases require
|
|
33
|
+
periodic checkpointing and/or compaction of their log or database files
|
|
34
|
+
otherwise they grow without bound. MDBX tracks retired/freed pages within the
|
|
35
|
+
database and re-uses them for new write operations, so the database size does
|
|
36
|
+
not grow without bound in normal use. It is worth noting that the "next"
|
|
37
|
+
version libmdbx (\ref MithrilDB) will solve this problem.
|
|
38
|
+
|
|
39
|
+
The memory map can be used as a read-only or read-write map. It is read-only
|
|
40
|
+
by default as this provides total immunity to corruption. Using read-write
|
|
41
|
+
mode offers much higher write performance, but adds the possibility for stray
|
|
42
|
+
application writes thru pointers to silently corrupt the database.
|
|
43
|
+
Of course if your application code is known to be bug-free (...) then this is
|
|
44
|
+
not an issue.
|
|
45
|
+
|
|
46
|
+
If this is your first time using a transactional embedded key-value store,
|
|
47
|
+
you may find the \ref starting section below to be helpful.
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
Restrictions & Caveats {#restrictions}
|
|
2
|
+
======================
|
|
3
|
+
In addition to those listed for some functions.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Long-lived read transactions {#long-lived-read}
|
|
7
|
+
Avoid long-lived read transactions, especially in the scenarios with a
|
|
8
|
+
high rate of write transactions. Long-lived read transactions prevents
|
|
9
|
+
recycling pages retired/freed by newer write transactions, thus the
|
|
10
|
+
database can grow quickly.
|
|
11
|
+
|
|
12
|
+
Understanding the problem of long-lived read transactions requires some
|
|
13
|
+
explanation, but can be difficult for quick perception. So is is
|
|
14
|
+
reasonable to simplify this as follows:
|
|
15
|
+
1. Garbage collection problem exists in all databases one way or
|
|
16
|
+
another, e.g. VACUUM in PostgreSQL. But in MDBX it's even more
|
|
17
|
+
discernible because of high transaction rate and intentional
|
|
18
|
+
internals simplification in favor of performance.
|
|
19
|
+
|
|
20
|
+
2. MDBX employs [Multiversion concurrency control](https://en.wikipedia.org/wiki/Multiversion_concurrency_control)
|
|
21
|
+
on the [Copy-on-Write](https://en.wikipedia.org/wiki/Copy-on-write)
|
|
22
|
+
basis, that allows multiple readers runs in parallel with a write
|
|
23
|
+
transaction without blocking. An each write transaction needs free
|
|
24
|
+
pages to put the changed data, that pages will be placed in the new
|
|
25
|
+
b-tree snapshot at commit. MDBX efficiently recycling pages from
|
|
26
|
+
previous created unused snapshots, BUT this is impossible if anyone
|
|
27
|
+
a read transaction use such snapshot.
|
|
28
|
+
|
|
29
|
+
3. Thus massive altering of data during a parallel long read operation
|
|
30
|
+
will increase the process's work set and may exhaust entire free
|
|
31
|
+
database space.
|
|
32
|
+
|
|
33
|
+
A good example of long readers is a hot backup to the slow destination
|
|
34
|
+
or debugging of a client application while retaining an active read
|
|
35
|
+
transaction. LMDB this results in `MDB_MAP_FULL` error and subsequent write
|
|
36
|
+
performance degradation.
|
|
37
|
+
|
|
38
|
+
MDBX mostly solve "long-lived" readers issue by offering to use a
|
|
39
|
+
transaction parking-and-ousting approach by \ref mdbx_txn_park(),
|
|
40
|
+
Handle-Slow-Readers \ref MDBX_hsr_func callback which allows to abort
|
|
41
|
+
long-lived read transactions, and using the \ref MDBX_LIFORECLAIM mode
|
|
42
|
+
which addresses subsequent performance degradation. The "next" version
|
|
43
|
+
of libmdbx (aka \ref MithrilDB) will completely solve this.
|
|
44
|
+
|
|
45
|
+
Nonetheless, situations that encourage lengthy read transactions while
|
|
46
|
+
intensively updating data should be avoided. For example, you should
|
|
47
|
+
avoid suspending/blocking processes/threads performing read
|
|
48
|
+
transactions, including during debugging, and use transaction parking if
|
|
49
|
+
necessary.
|
|
50
|
+
|
|
51
|
+
You should also beware of aborting processes that perform reading
|
|
52
|
+
transactions. Despite the fact that libmdbx automatically checks and
|
|
53
|
+
cleans readers, as an a process aborting (especially with core dump) can
|
|
54
|
+
take a long time, and checking readers cannot be performed too often due
|
|
55
|
+
to performance degradation.
|
|
56
|
+
|
|
57
|
+
This issue will be addressed in MithrlDB and one of libmdbx releases,
|
|
58
|
+
presumably in 2025. To do this, nonlinear GC recycling will be
|
|
59
|
+
implemented, without stopping garbage recycling on the old MVCC snapshot
|
|
60
|
+
used by a long read transaction.
|
|
61
|
+
|
|
62
|
+
After the planned implementation, any long-term reading transaction will
|
|
63
|
+
still keep the used MVCC-snapshot (all the database pages forming it)
|
|
64
|
+
from being recycled, but it will allow all unused MVCC snapshots to be
|
|
65
|
+
recycled, both before and after the readable one. This will eliminate
|
|
66
|
+
one of the main architectural flaws inherited from LMDB and caused the
|
|
67
|
+
growth of a database in proportion to a volume of data changes made
|
|
68
|
+
concurrently with a long-running read transaction.
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
## Large data items
|
|
72
|
+
|
|
73
|
+
MDBX allows you to store values up to 1 gigabyte in size, but this is
|
|
74
|
+
not the main functionality for a key-value storage, but an additional
|
|
75
|
+
feature that should not be abused. Such long values are stored in
|
|
76
|
+
consecutive/adjacent DB pages, which has both pros and cons. This allows
|
|
77
|
+
you to read long values directly without copying and without any
|
|
78
|
+
overhead from a linear section of memory.
|
|
79
|
+
|
|
80
|
+
On the other hand, when putting such values in the database, it is
|
|
81
|
+
required to find a sufficient number of free consecutive/adjacent
|
|
82
|
+
database pages, which can be very difficult and expensive, moreover
|
|
83
|
+
sometimes impossible since b-tree tends to fragmentation. So, when
|
|
84
|
+
placing very long values, the engine may need to process the entire GC,
|
|
85
|
+
and in the absence of a sufficient sequence of free pages, increase the
|
|
86
|
+
DB file. Thus, for long values, MDBX provides maximum read performance
|
|
87
|
+
at the expense of write performance.
|
|
88
|
+
|
|
89
|
+
Some aspects related to GC have been refined and improved in 2022 within
|
|
90
|
+
the first releases of the 0.12.x series. In particular the search for
|
|
91
|
+
free consecutive/adjacent pages through GC has been significantly
|
|
92
|
+
speeded, including acceleration using NOEN/SSE2/AVX2/AVX512
|
|
93
|
+
instructions.
|
|
94
|
+
|
|
95
|
+
This issue will be addressed in MithrlDB and refined within one of
|
|
96
|
+
0.15.x libmdbx releases, presumably at end of 2025.
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
### Huge transactions
|
|
100
|
+
|
|
101
|
+
A similar situation can be with huge transactions, in which a lot of
|
|
102
|
+
database pages are retired. The retired pages should be put into GC as a
|
|
103
|
+
list of page numbers for future reuse. But in huge transactions, such a
|
|
104
|
+
list of retired page numbers can also be huge, i.e. it is a very long
|
|
105
|
+
value and requires a long sequence of free pages to be saved. Thus, if
|
|
106
|
+
you delete large amounts of information from the database in a single
|
|
107
|
+
transaction, MDBX may need to increase the database file to save the
|
|
108
|
+
list of pages to be retired.
|
|
109
|
+
|
|
110
|
+
This issue was fixed in 2022 within the first releases of the 0.12.x
|
|
111
|
+
series by `Big Foot` feature, which now is enabled by default.
|
|
112
|
+
See \ref MDBX_ENABLE_BIGFOOT build-time option.
|
|
113
|
+
|
|
114
|
+
The `Big Foot` feature which significantly reduces GC overhead for
|
|
115
|
+
processing large lists of retired pages from huge transactions. Now
|
|
116
|
+
libmdbx avoid creating large chunks of PNLs (page number lists) which
|
|
117
|
+
required a long sequences of free pages, aka large/overflow pages. Thus
|
|
118
|
+
avoiding searching, allocating and storing such sequences inside GC.
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
## Space reservation
|
|
122
|
+
An MDBX database configuration will often reserve considerable unused
|
|
123
|
+
memory address space and maybe file size for future growth. This does
|
|
124
|
+
not use actual memory or disk space, but users may need to understand
|
|
125
|
+
the difference so they won't be scared off.
|
|
126
|
+
|
|
127
|
+
However, on 64-bit systems with a relative small amount of RAM, such
|
|
128
|
+
reservation can deplete system resources (trigger ENOMEM error, etc)
|
|
129
|
+
when setting an inadequately large upper DB size using \ref
|
|
130
|
+
mdbx_env_set_geometry() or \ref mdbx::env::geometry. So just avoid this.
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
## Remote filesystems
|
|
134
|
+
Do not use MDBX databases on remote filesystems, even between processes
|
|
135
|
+
on the same host. This breaks file locks on some platforms, possibly
|
|
136
|
+
memory map sync, and certainly sync between programs on different hosts.
|
|
137
|
+
|
|
138
|
+
On the other hand, MDBX support the exclusive database operation over
|
|
139
|
+
a network, and cooperative read-only access to the database placed on
|
|
140
|
+
a read-only network shares.
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
## Child processes
|
|
144
|
+
Do not use opened \ref MDBX_env instance(s) in a child processes after `fork()`.
|
|
145
|
+
It would be insane to call fork() and any MDBX-functions simultaneously
|
|
146
|
+
from multiple threads. The best way is to prevent the presence of open
|
|
147
|
+
MDBX-instances during `fork()`.
|
|
148
|
+
|
|
149
|
+
The \ref MDBX_ENV_CHECKPID build-time option, which is ON by default on
|
|
150
|
+
non-Windows platforms (i.e. where `fork()` is available), enables PID
|
|
151
|
+
checking at a few critical points. But this does not give any guarantees,
|
|
152
|
+
but only allows you to detect such errors a little sooner. Depending on
|
|
153
|
+
the platform, you should expect an application crash and/or database
|
|
154
|
+
corruption in such cases.
|
|
155
|
+
|
|
156
|
+
On the other hand, MDBX allow calling \ref mdbx_env_close() in such cases to
|
|
157
|
+
release resources, but no more and in general this is a wrong way.
|
|
158
|
+
|
|
159
|
+
#### Since v0.13.1 and later
|
|
160
|
+
|
|
161
|
+
Starting from the v0.13.1 release, the \ref mdbx_env_resurrect_after_fork()
|
|
162
|
+
is available, which allows you to reuse an already open database
|
|
163
|
+
environment in child processes, but strictly without inheriting any
|
|
164
|
+
transactions from a parent process.
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
## Read-only mode
|
|
168
|
+
There is no pure read-only mode in a normal explicitly way, since
|
|
169
|
+
readers need write access to LCK-file to be ones visible for writer.
|
|
170
|
+
|
|
171
|
+
So MDBX always tries to open/create LCK-file for read-write, but switches
|
|
172
|
+
to without-LCK mode on appropriate errors (`EROFS`, `EACCESS`, `EPERM`)
|
|
173
|
+
if the read-only mode was requested by the \ref MDBX_RDONLY flag which is
|
|
174
|
+
described below.
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
## Troubleshooting the LCK-file
|
|
178
|
+
1. A broken LCK-file can cause sync issues, including appearance of
|
|
179
|
+
wrong/inconsistent data for readers. When database opened in the
|
|
180
|
+
cooperative read-write mode the LCK-file requires to be mapped to
|
|
181
|
+
memory in read-write access. In this case it is always possible for
|
|
182
|
+
stray/malfunctioned application could writes thru pointers to
|
|
183
|
+
silently corrupt the LCK-file.
|
|
184
|
+
|
|
185
|
+
Unfortunately, there is no any portable way to prevent such
|
|
186
|
+
corruption, since the LCK-file is updated concurrently by
|
|
187
|
+
multiple processes in a lock-free manner and any locking is
|
|
188
|
+
unwise due to a large overhead.
|
|
189
|
+
|
|
190
|
+
\note Workaround: Just make all programs using the database close it;
|
|
191
|
+
the LCK-file is always reset on first open.
|
|
192
|
+
|
|
193
|
+
2. Stale reader transactions left behind by an aborted program cause
|
|
194
|
+
further writes to grow the database quickly, and stale locks can
|
|
195
|
+
block further operation.
|
|
196
|
+
MDBX checks for stale readers while opening environment and before
|
|
197
|
+
growth the database. But in some cases, this may not be enough.
|
|
198
|
+
|
|
199
|
+
\note Workaround: Check for stale readers periodically, using the
|
|
200
|
+
\ref mdbx_reader_check() function or the mdbx_stat tool.
|
|
201
|
+
|
|
202
|
+
3. Stale writers will be cleared automatically by MDBX on supported
|
|
203
|
+
platforms. But this is platform-specific, especially of
|
|
204
|
+
implementation of shared POSIX-mutexes and support for robust
|
|
205
|
+
mutexes. For instance there are no known issues on Linux, OSX,
|
|
206
|
+
Windows and FreeBSD.
|
|
207
|
+
|
|
208
|
+
\note Workaround: Otherwise just make all programs using the database
|
|
209
|
+
close it; the LCK-file is always reset on first open of the environment.
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
## One thread - One transaction
|
|
213
|
+
A thread can only use one transaction at a time, plus any nested
|
|
214
|
+
read-write transactions in the non-writemap mode. Each transaction
|
|
215
|
+
belongs to one thread. The \ref MDBX_NOSTICKYTHREADS flag changes this,
|
|
216
|
+
see below.
|
|
217
|
+
|
|
218
|
+
Do not start more than one transaction for a one thread. If you think
|
|
219
|
+
about this, it's really strange to do something with two data snapshots
|
|
220
|
+
at once, which may be different. MDBX checks and preventing this by
|
|
221
|
+
returning corresponding error code (\ref MDBX_TXN_OVERLAPPING,
|
|
222
|
+
\ref MDBX_BAD_RSLOT, \ref MDBX_BUSY) unless you using
|
|
223
|
+
\ref MDBX_NOSTICKYTHREADS option on the environment.
|
|
224
|
+
Nonetheless, with the `MDBX_NOSTICKYTHREADS` option, you must know
|
|
225
|
+
exactly what you are doing, otherwise you will get deadlocks or reading
|
|
226
|
+
an alien data.
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
## Do not open twice
|
|
230
|
+
Do not have open an MDBX database twice in the same process at the same
|
|
231
|
+
time. By default MDBX prevent this in most cases by tracking databases
|
|
232
|
+
opening and return \ref MDBX_BUSY if anyone LCK-file is already open.
|
|
233
|
+
|
|
234
|
+
The reason for this is that when the "Open file description" locks (aka
|
|
235
|
+
OFD-locks) are not available, MDBX uses POSIX locks on files, and these
|
|
236
|
+
locks have issues if one process opens a file multiple times. If a single
|
|
237
|
+
process opens the same environment multiple times, closing it once will
|
|
238
|
+
remove all the locks held on it, and the other instances will be
|
|
239
|
+
vulnerable to corruption from other processes.
|
|
240
|
+
|
|
241
|
+
For compatibility with LMDB which allows multi-opening, MDBX can be
|
|
242
|
+
configured at runtime by `mdbx_setup_debug(MDBX_DBG_LEGACY_MULTIOPEN, ...)`
|
|
243
|
+
prior to calling other MDBX functions. In this way MDBX will track
|
|
244
|
+
databases opening, detect multi-opening cases and then recover POSIX file
|
|
245
|
+
locks as necessary. However, lock recovery can cause unexpected pauses,
|
|
246
|
+
such as when another process opened the database in exclusive mode before
|
|
247
|
+
the lock was restored - we have to wait until such a process releases the
|
|
248
|
+
database, and so on.
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
Getting started {#starting}
|
|
2
|
+
===============
|
|
3
|
+
|
|
4
|
+
> This section is based on Bert Hubert's intro "LMDB Semantics", with
|
|
5
|
+
> edits reflecting the improvements and enhancements were made in MDBX.
|
|
6
|
+
> See Bert Hubert's [original](https://github.com/ahupowerdns/ahutils/blob/master/lmdb-semantics.md).
|
|
7
|
+
|
|
8
|
+
Everything starts with an environment, created by \ref mdbx_env_create().
|
|
9
|
+
Once created, this environment must also be opened with \ref mdbx_env_open(),
|
|
10
|
+
and after use be closed by \ref mdbx_env_close(). At that a non-zero value
|
|
11
|
+
of the last argument "mode" supposes MDBX will create database and directory
|
|
12
|
+
if ones does not exist. In this case the non-zero "mode" argument specifies
|
|
13
|
+
the file mode bits be applied when a new files are created by `open()` function.
|
|
14
|
+
|
|
15
|
+
Within that directory, a lock file (aka LCK-file) and a storage file (aka
|
|
16
|
+
DXB-file) will be generated. If you don't want to use a directory, you can
|
|
17
|
+
pass the \ref MDBX_NOSUBDIR option, in which case the path you provided is used
|
|
18
|
+
directly as the DXB-file, and another file with a "-lck" suffix added
|
|
19
|
+
will be used for the LCK-file.
|
|
20
|
+
|
|
21
|
+
Once the environment is open, a transaction can be created within it using
|
|
22
|
+
\ref mdbx_txn_begin(). Transactions may be read-write or read-only, and read-write
|
|
23
|
+
transactions may be nested. A transaction must only be used by one thread at
|
|
24
|
+
a time. Transactions are always required, even for read-only access. The
|
|
25
|
+
transaction provides a consistent view of the data.
|
|
26
|
+
|
|
27
|
+
Once a transaction has been created, a database (i.e. key-value space inside
|
|
28
|
+
the environment) can be opened within it using \ref mdbx_dbi_open(). If only one
|
|
29
|
+
database will ever be used in the environment, a `NULL` can be passed as the
|
|
30
|
+
database name. For named databases, the \ref MDBX_CREATE flag must be used to
|
|
31
|
+
create the database if it doesn't already exist. Also, \ref mdbx_env_set_maxdbs()
|
|
32
|
+
must be called after \ref mdbx_env_create() and before \ref mdbx_env_open() to set
|
|
33
|
+
the maximum number of named databases you want to support.
|
|
34
|
+
|
|
35
|
+
\note A single transaction can open multiple databases. Generally databases
|
|
36
|
+
should only be opened once, by the first transaction in the process.
|
|
37
|
+
|
|
38
|
+
Within a transaction, \ref mdbx_get() and \ref mdbx_put() can store single key-value
|
|
39
|
+
pairs if that is all you need to do (but see \ref Cursors below if you want to do
|
|
40
|
+
more).
|
|
41
|
+
|
|
42
|
+
A key-value pair is expressed as two \ref MDBX_val structures. This struct that is
|
|
43
|
+
exactly similar to POSIX's `struct iovec` and has two fields, `iov_len` and
|
|
44
|
+
`iov_base`. The data is a `void` pointer to an array of `iov_len` bytes.
|
|
45
|
+
\note The notable difference between MDBX and LMDB is that MDBX support zero
|
|
46
|
+
length keys.
|
|
47
|
+
|
|
48
|
+
Because MDBX is very efficient (and usually zero-copy), the data returned in
|
|
49
|
+
an \ref MDBX_val structure may be memory-mapped straight from disk. In other words
|
|
50
|
+
look but do not touch (or `free()` for that matter). Once a transaction is
|
|
51
|
+
closed, the values can no longer be used, so make a copy if you need to keep
|
|
52
|
+
them after that.
|
|
53
|
+
|
|
54
|
+
## Cursors {#Cursors}
|
|
55
|
+
To do more powerful things, we must use a cursor.
|
|
56
|
+
|
|
57
|
+
Within the transaction, a cursor can be created with \ref mdbx_cursor_open().
|
|
58
|
+
With this cursor we can store/retrieve/delete (multiple) values using
|
|
59
|
+
\ref mdbx_cursor_get(), \ref mdbx_cursor_put() and \ref mdbx_cursor_del().
|
|
60
|
+
|
|
61
|
+
The \ref mdbx_cursor_get() positions itself depending on the cursor operation
|
|
62
|
+
requested, and for some operations, on the supplied key. For example, to list
|
|
63
|
+
all key-value pairs in a database, use operation \ref MDBX_FIRST for the first
|
|
64
|
+
call to \ref mdbx_cursor_get(), and \ref MDBX_NEXT on subsequent calls, until
|
|
65
|
+
the end is hit.
|
|
66
|
+
|
|
67
|
+
To retrieve all keys starting from a specified key value, use \ref MDBX_SET. For
|
|
68
|
+
more cursor operations, see the \ref c_api reference.
|
|
69
|
+
|
|
70
|
+
When using \ref mdbx_cursor_put(), either the function will position the cursor
|
|
71
|
+
for you based on the key, or you can use operation \ref MDBX_CURRENT to use the
|
|
72
|
+
current position of the cursor. \note Note that key must then match the current
|
|
73
|
+
position's key.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## Summarizing the opening
|
|
77
|
+
|
|
78
|
+
So we have a cursor in a transaction which opened a database in an
|
|
79
|
+
environment which is opened from a filesystem after it was separately
|
|
80
|
+
created.
|
|
81
|
+
|
|
82
|
+
Or, we create an environment, open it from a filesystem, create a transaction
|
|
83
|
+
within it, open a database within that transaction, and create a cursor
|
|
84
|
+
within all of the above.
|
|
85
|
+
|
|
86
|
+
Got it?
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## Threads and processes
|
|
90
|
+
|
|
91
|
+
Do not have open an database twice in the same process at the same time, MDBX
|
|
92
|
+
will track and prevent this. Instead, share the MDBX environment that has
|
|
93
|
+
opened the file across all threads. The reason for this is:
|
|
94
|
+
- When the "Open file description" locks (aka OFD-locks) are not available,
|
|
95
|
+
MDBX uses POSIX locks on files, and these locks have issues if one process
|
|
96
|
+
opens a file multiple times.
|
|
97
|
+
- If a single process opens the same environment multiple times, closing it
|
|
98
|
+
once will remove all the locks held on it, and the other instances will be
|
|
99
|
+
vulnerable to corruption from other processes.
|
|
100
|
+
+ For compatibility with LMDB which allows multi-opening, MDBX can be
|
|
101
|
+
configured at runtime by \ref mdbx_setup_debug() with \ref MDBX_DBG_LEGACY_MULTIOPEN` option
|
|
102
|
+
prior to calling other MDBX functions. In this way MDBX will track
|
|
103
|
+
databases opening, detect multi-opening cases and then recover POSIX file
|
|
104
|
+
locks as necessary. However, lock recovery can cause unexpected pauses,
|
|
105
|
+
such as when another process opened the database in exclusive mode before
|
|
106
|
+
the lock was restored - we have to wait until such a process releases the
|
|
107
|
+
database, and so on.
|
|
108
|
+
|
|
109
|
+
Do not use opened MDBX environment(s) after `fork()` in a child process(es),
|
|
110
|
+
MDBX will check and prevent this at critical points. Instead, ensure there is
|
|
111
|
+
no open MDBX-instance(s) during fork(), or at least close it immediately after
|
|
112
|
+
`fork()` in the child process and reopen if required - for instance by using
|
|
113
|
+
`pthread_atfork()`. The reason for this is:
|
|
114
|
+
- For competitive consistent reading, MDBX assigns a slot in the shared
|
|
115
|
+
table for each process that interacts with the database. This slot is
|
|
116
|
+
populated with process attributes, including the PID.
|
|
117
|
+
- After `fork()`, in order to remain connected to a database, the child
|
|
118
|
+
process must have its own such "slot", which can't be assigned in any
|
|
119
|
+
simple and robust way another than the regular.
|
|
120
|
+
- A write transaction from a parent process cannot continue in a child
|
|
121
|
+
process for obvious reasons.
|
|
122
|
+
- Moreover, in a multithreaded process at the fork() moment any number of
|
|
123
|
+
threads could run in critical and/or intermediate sections of MDBX code
|
|
124
|
+
with interaction and/or racing conditions with threads from other
|
|
125
|
+
process(es). For instance: shrinking a database or copying it to a pipe,
|
|
126
|
+
opening or closing environment, beginning or finishing a transaction,
|
|
127
|
+
and so on.
|
|
128
|
+
= Therefore, any solution other than simply close database (and reopen if
|
|
129
|
+
necessary) in a child process would be both extreme complicated and so
|
|
130
|
+
fragile.
|
|
131
|
+
|
|
132
|
+
Do not start more than one transaction for a one thread. If you think
|
|
133
|
+
about this, it's really strange to do something with two data snapshots
|
|
134
|
+
at once, which may be different. MDBX checks and preventing this by
|
|
135
|
+
returning corresponding error code (\ref MDBX_TXN_OVERLAPPING,
|
|
136
|
+
\ref MDBX_BAD_RSLOT, \ref MDBX_BUSY) unless you using
|
|
137
|
+
\ref MDBX_NOSTICKYTHREADS option on the environment. Nonetheless,
|
|
138
|
+
with the \ref MDBX_NOSTICKYTHREADS option, you must know exactly what
|
|
139
|
+
you are doing, otherwise you will get deadlocks or reading an alien
|
|
140
|
+
data.
|
|
141
|
+
|
|
142
|
+
Also note that a transaction is tied to one thread by default using
|
|
143
|
+
Thread Local Storage. If you want to pass transactions across threads,
|
|
144
|
+
you can use the \ref MDBX_NOSTICKYTHREADS option on the environment.
|
|
145
|
+
Nevertheless, a write transaction must be committed or aborted in the
|
|
146
|
+
same thread which it was started. MDBX checks this in a reasonable
|
|
147
|
+
manner and return the \ref MDBX_THREAD_MISMATCH error in rules
|
|
148
|
+
violation.
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
## Transactions, rollbacks etc
|
|
152
|
+
|
|
153
|
+
To actually get anything done, a transaction must be committed using
|
|
154
|
+
\ref mdbx_txn_commit(). Alternatively, all of a transaction's operations
|
|
155
|
+
can be discarded using \ref mdbx_txn_abort().
|
|
156
|
+
|
|
157
|
+
\attention An important difference between MDBX and LMDB is that MDBX required
|
|
158
|
+
that any opened cursors can be reused and must be freed explicitly, regardless
|
|
159
|
+
ones was opened in a read-only or write transaction. The REASON for this is
|
|
160
|
+
eliminates ambiguity which helps to avoid errors such as: use-after-free,
|
|
161
|
+
double-free, i.e. memory corruption and segfaults.
|
|
162
|
+
|
|
163
|
+
For read-only transactions, obviously there is nothing to commit to storage.
|
|
164
|
+
\attention An another notable difference between MDBX and LMDB is that MDBX make
|
|
165
|
+
handles opened for existing databases immediately available for other
|
|
166
|
+
transactions, regardless this transaction will be aborted or reset. The
|
|
167
|
+
REASON for this is to avoiding the requirement for multiple opening a same
|
|
168
|
+
handles in concurrent read transactions, and tracking of such open but hidden
|
|
169
|
+
handles until the completion of read transactions which opened them.
|
|
170
|
+
|
|
171
|
+
In addition, as long as a transaction is open, a consistent view of the
|
|
172
|
+
database is kept alive, which requires storage. A read-only transaction that
|
|
173
|
+
no longer requires this consistent view should be terminated (committed or
|
|
174
|
+
aborted) when the view is no longer needed (but see below for an
|
|
175
|
+
optimization).
|
|
176
|
+
|
|
177
|
+
There can be multiple simultaneously active read-only transactions but only
|
|
178
|
+
one that can write. Once a single read-write transaction is opened, all
|
|
179
|
+
further attempts to begin one will block until the first one is committed or
|
|
180
|
+
aborted. This has no effect on read-only transactions, however, and they may
|
|
181
|
+
continue to be opened at any time.
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
## Duplicate keys aka Multi-values
|
|
185
|
+
|
|
186
|
+
\ref mdbx_get() and \ref mdbx_put() respectively have no and only some support or
|
|
187
|
+
multiple key-value pairs with identical keys. If there are multiple values
|
|
188
|
+
for a key, \ref mdbx_get() will only return the first value.
|
|
189
|
+
|
|
190
|
+
When multiple values for one key are required, pass the \ref MDBX_DUPSORT flag to
|
|
191
|
+
\ref mdbx_dbi_open(). In an \ref MDBX_DUPSORT database, by default \ref mdbx_put() will
|
|
192
|
+
not replace the value for a key if the key existed already. Instead it will add
|
|
193
|
+
the new value to the key. In addition, \ref mdbx_del() will pay attention to the
|
|
194
|
+
value field too, allowing for specific values of a key to be deleted.
|
|
195
|
+
|
|
196
|
+
Finally, additional cursor operations become available for traversing through
|
|
197
|
+
and retrieving duplicate values.
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
## Some optimization
|
|
201
|
+
|
|
202
|
+
If you frequently begin and abort read-only transactions, as an optimization,
|
|
203
|
+
it is possible to only reset and renew a transaction.
|
|
204
|
+
|
|
205
|
+
\ref mdbx_txn_reset() releases any old copies of data kept around for a read-only
|
|
206
|
+
transaction. To reuse this reset transaction, call \ref mdbx_txn_renew() on it.
|
|
207
|
+
Any cursors in this transaction can also be renewed using \ref mdbx_cursor_renew()
|
|
208
|
+
or freed by \ref mdbx_cursor_close().
|
|
209
|
+
|
|
210
|
+
To permanently free a transaction, reset or not, use \ref mdbx_txn_abort().
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
## Cleaning up
|
|
214
|
+
|
|
215
|
+
Any created cursors must be closed using \ref mdbx_cursor_close(). It is advisable
|
|
216
|
+
to repeat:
|
|
217
|
+
\note An important difference between MDBX and LMDB is that MDBX required that
|
|
218
|
+
any opened cursors can be reused and must be freed explicitly, regardless
|
|
219
|
+
ones was opened in a read-only or write transaction. The REASON for this is
|
|
220
|
+
eliminates ambiguity which helps to avoid errors such as: use-after-free,
|
|
221
|
+
double-free, i.e. memory corruption and segfaults.
|
|
222
|
+
|
|
223
|
+
It is very rarely necessary to close a database handle, and in general they
|
|
224
|
+
should just be left open. When you close a handle, it immediately becomes
|
|
225
|
+
unavailable for all transactions in the environment. Therefore, you should
|
|
226
|
+
avoid closing the handle while at least one transaction is using it.
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
## Now read up on the full API!
|
|
230
|
+
|
|
231
|
+
The full \ref c_api documentation lists further details below, like how to:
|
|
232
|
+
|
|
233
|
+
- Configure database size and automatic size management: \ref mdbx_env_set_geometry().
|
|
234
|
+
- Drop and clean a database: \ref mdbx_drop().
|
|
235
|
+
- Detect and report errors: \ref c_err.
|
|
236
|
+
- Optimize (bulk) loading speed: \ref MDBX_MULTIPLE, \ref MDBX_APPEND.
|
|
237
|
+
- Reduce (temporarily) robustness to gain even more speed: \ref sync_modes.
|
|
238
|
+
- Gather statistics about the database: \ref c_statinfo.
|
|
239
|
+
- Sstimate size of range query result: \ref c_rqest.
|
|
240
|
+
- Double performance by LIFO reclaiming on storages with write-back: \ref MDBX_LIFORECLAIM.
|
|
241
|
+
- Use sequences and canary markers: \ref mdbx_dbi_sequence(), \ref MDBX_canary.
|
|
242
|
+
- Use Handle-Slow-Readers callback to resolve a database full/overflow issues
|
|
243
|
+
due to long-lived read transactions: \ref mdbx_env_set_hsr().
|
|
244
|
+
- Use exclusive mode: \ref MDBX_EXCLUSIVE.
|
|
245
|
+
- Define custom sort orders (but this is recommended to be avoided).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
The source code is availale on [Gitflic](https://gitflic.ru/project/erthink/libmdbx) and mirrors on [abf.io](https://abf.io/erthink/libmdbx), [hub.mos.ru](https://hub.mos.ru/leo/libmdbx) and [Github](https://github.com/erthink/libmdbx).
|
|
2
|
+
Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
|
3
|
+
Всё будет хорошо!
|
|
4
|
+
|
|
5
|
+
> Questions, feedback and suggestions are welcome to the [Telegram' group](https://t.me/libmdbx).
|
|
6
|
+
|
|
7
|
+
\section toc Table of Contents
|
|
8
|
+
|
|
9
|
+
This manual is divided into parts,
|
|
10
|
+
each of which is divided into several sections.
|
|
11
|
+
|
|
12
|
+
1. The \ref intro
|
|
13
|
+
- \ref characteristics
|
|
14
|
+
- \ref improvements
|
|
15
|
+
- \ref restrictions
|
|
16
|
+
- \ref performance
|
|
17
|
+
2. \ref usage
|
|
18
|
+
- \ref getting
|
|
19
|
+
- \ref starting
|
|
20
|
+
- \ref bindings
|
|
21
|
+
|
|
22
|
+
3. The `C/C++` API manual:
|
|
23
|
+
- The \ref c_api reference
|
|
24
|
+
- \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
|
|
25
|
+
- The \ref mdbx.h header file reference
|
|
26
|
+
- The \ref cxx_api reference
|
|
27
|
+
- The \ref mdbx.h++ header file reference
|
|
28
|
+
|
|
29
|
+
Please do not hesitate to point out errors in the documentation,
|
|
30
|
+
including creating [merge-request](https://gitflic.ru/project/erthink/libmdbx/merge-request) with corrections and improvements.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
\section MithrilDB MithrilDB and Future
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
|
|
3
|
+
<head>
|
|
4
|
+
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
|
|
6
|
+
<meta name="generator" content="Doxygen $doxygenversion"/>
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
8
|
+
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
|
9
|
+
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
|
10
|
+
<!--BEGIN PROJECT_ICON-->
|
|
11
|
+
<link rel="icon" href="$relpath^$projecticon" type="image/x-icon" />
|
|
12
|
+
<!--END PROJECT_ICON-->
|
|
13
|
+
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
|
14
|
+
<!--BEGIN DISABLE_INDEX-->
|
|
15
|
+
<!--BEGIN FULL_SIDEBAR-->
|
|
16
|
+
<script type="text/javascript">var page_layout=1;</script>
|
|
17
|
+
<!--END FULL_SIDEBAR-->
|
|
18
|
+
<!--END DISABLE_INDEX-->
|
|
19
|
+
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
|
20
|
+
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
|
21
|
+
<!--BEGIN COPY_CLIPBOARD-->
|
|
22
|
+
<script type="text/javascript" src="$relpath^clipboard.js"></script>
|
|
23
|
+
<!--END COPY_CLIPBOARD-->
|
|
24
|
+
$treeview
|
|
25
|
+
$search
|
|
26
|
+
$mathjax
|
|
27
|
+
$darkmode
|
|
28
|
+
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
|
29
|
+
$extrastylesheet
|
|
30
|
+
</head>
|
|
31
|
+
<body>
|
|
32
|
+
<!--BEGIN DISABLE_INDEX-->
|
|
33
|
+
<!--BEGIN FULL_SIDEBAR-->
|
|
34
|
+
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
|
|
35
|
+
<!--END FULL_SIDEBAR-->
|
|
36
|
+
<!--END DISABLE_INDEX-->
|
|
37
|
+
|
|
38
|
+
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
|
39
|
+
|
|
40
|
+
<!--BEGIN TITLEAREA-->
|
|
41
|
+
<div id="titlearea">
|
|
42
|
+
<table cellspacing="0" cellpadding="0">
|
|
43
|
+
<tbody>
|
|
44
|
+
<tr id="projectrow">
|
|
45
|
+
<!--BEGIN PROJECT_LOGO-->
|
|
46
|
+
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"$logosize/></td>
|
|
47
|
+
<!--END PROJECT_LOGO-->
|
|
48
|
+
<!--BEGIN PROJECT_NAME-->
|
|
49
|
+
<td id="projectalign">
|
|
50
|
+
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber"> $projectnumber</span><!--END PROJECT_NUMBER-->
|
|
51
|
+
</div>
|
|
52
|
+
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
|
53
|
+
</td>
|
|
54
|
+
<!--END PROJECT_NAME-->
|
|
55
|
+
<!--BEGIN !PROJECT_NAME-->
|
|
56
|
+
<!--BEGIN PROJECT_BRIEF-->
|
|
57
|
+
<td>
|
|
58
|
+
<div id="projectbrief">$projectbrief</div>
|
|
59
|
+
</td>
|
|
60
|
+
<!--END PROJECT_BRIEF-->
|
|
61
|
+
<!--END !PROJECT_NAME-->
|
|
62
|
+
<!--BEGIN DISABLE_INDEX-->
|
|
63
|
+
<!--BEGIN SEARCHENGINE-->
|
|
64
|
+
<!--BEGIN !FULL_SIDEBAR-->
|
|
65
|
+
<td>$searchbox</td>
|
|
66
|
+
<!--END !FULL_SIDEBAR-->
|
|
67
|
+
<!--END SEARCHENGINE-->
|
|
68
|
+
<!--END DISABLE_INDEX-->
|
|
69
|
+
</tr>
|
|
70
|
+
<!--BEGIN SEARCHENGINE-->
|
|
71
|
+
<!--BEGIN FULL_SIDEBAR-->
|
|
72
|
+
<tr><td colspan="2">$searchbox</td></tr>
|
|
73
|
+
<!--END FULL_SIDEBAR-->
|
|
74
|
+
<!--END SEARCHENGINE-->
|
|
75
|
+
</tbody>
|
|
76
|
+
</table>
|
|
77
|
+
</div>
|
|
78
|
+
<!--END TITLEAREA-->
|
|
79
|
+
<!-- Yandex.Metrika counter -->
|
|
80
|
+
<script type="text/javascript" >
|
|
81
|
+
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
|
82
|
+
m[i].l=1*new Date();
|
|
83
|
+
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
|
84
|
+
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
|
85
|
+
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
|
|
86
|
+
|
|
87
|
+
ym(99261645, "init", {
|
|
88
|
+
clickmap:true,
|
|
89
|
+
trackLinks:true,
|
|
90
|
+
accurateTrackBounce:true,
|
|
91
|
+
webvisor:true
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
94
|
+
<noscript><div><img src="https://mc.yandex.ru/watch/99261645" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
|
95
|
+
<!-- /Yandex.Metrika counter -->
|
|
96
|
+
<!-- end header part -->
|