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,174 @@
|
|
|
1
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
3
|
+
|
|
4
|
+
#include "internals.h"
|
|
5
|
+
|
|
6
|
+
__cold static int lck_setup_locked(MDBX_env *env) {
|
|
7
|
+
int err = rthc_register(env);
|
|
8
|
+
if (unlikely(err != MDBX_SUCCESS))
|
|
9
|
+
return err;
|
|
10
|
+
|
|
11
|
+
int lck_seize_rc = lck_seize(env);
|
|
12
|
+
if (unlikely(MDBX_IS_ERROR(lck_seize_rc)))
|
|
13
|
+
return lck_seize_rc;
|
|
14
|
+
|
|
15
|
+
if (env->lck_mmap.fd == INVALID_HANDLE_VALUE) {
|
|
16
|
+
env->lck = lckless_stub(env);
|
|
17
|
+
env->max_readers = UINT_MAX;
|
|
18
|
+
DEBUG("lck-setup:%s%s%s", " lck-less", (env->flags & MDBX_RDONLY) ? " readonly" : "",
|
|
19
|
+
(lck_seize_rc == MDBX_RESULT_TRUE) ? " exclusive" : " cooperative");
|
|
20
|
+
return lck_seize_rc;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
DEBUG("lck-setup:%s%s%s", " with-lck", (env->flags & MDBX_RDONLY) ? " readonly" : "",
|
|
24
|
+
(lck_seize_rc == MDBX_RESULT_TRUE) ? " exclusive" : " cooperative");
|
|
25
|
+
|
|
26
|
+
MDBX_env *inprocess_neighbor = nullptr;
|
|
27
|
+
err = rthc_uniq_check(&env->lck_mmap, &inprocess_neighbor);
|
|
28
|
+
if (unlikely(MDBX_IS_ERROR(err)))
|
|
29
|
+
return err;
|
|
30
|
+
if (inprocess_neighbor) {
|
|
31
|
+
if ((globals.runtime_flags & MDBX_DBG_LEGACY_MULTIOPEN) == 0 || (inprocess_neighbor->flags & MDBX_EXCLUSIVE) != 0)
|
|
32
|
+
return MDBX_BUSY;
|
|
33
|
+
if (lck_seize_rc == MDBX_RESULT_TRUE) {
|
|
34
|
+
err = lck_downgrade(env);
|
|
35
|
+
if (unlikely(err != MDBX_SUCCESS))
|
|
36
|
+
return err;
|
|
37
|
+
lck_seize_rc = MDBX_RESULT_FALSE;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
uint64_t size = 0;
|
|
42
|
+
err = osal_filesize(env->lck_mmap.fd, &size);
|
|
43
|
+
if (unlikely(err != MDBX_SUCCESS))
|
|
44
|
+
return err;
|
|
45
|
+
|
|
46
|
+
if (lck_seize_rc == MDBX_RESULT_TRUE) {
|
|
47
|
+
size = ceil_powerof2(env->max_readers * sizeof(reader_slot_t) + sizeof(lck_t), globals.sys_pagesize);
|
|
48
|
+
jitter4testing(false);
|
|
49
|
+
} else {
|
|
50
|
+
if (env->flags & MDBX_EXCLUSIVE)
|
|
51
|
+
return MDBX_BUSY;
|
|
52
|
+
if (size > INT_MAX || (size & (globals.sys_pagesize - 1)) != 0 || size < globals.sys_pagesize) {
|
|
53
|
+
ERROR("lck-file has invalid size %" PRIu64 " bytes", size);
|
|
54
|
+
return MDBX_PROBLEM;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const size_t maxreaders = ((size_t)size - sizeof(lck_t)) / sizeof(reader_slot_t);
|
|
59
|
+
if (maxreaders < 4) {
|
|
60
|
+
ERROR("lck-size too small (up to %" PRIuPTR " readers)", maxreaders);
|
|
61
|
+
return MDBX_PROBLEM;
|
|
62
|
+
}
|
|
63
|
+
env->max_readers = (maxreaders <= MDBX_READERS_LIMIT) ? (unsigned)maxreaders : (unsigned)MDBX_READERS_LIMIT;
|
|
64
|
+
|
|
65
|
+
err =
|
|
66
|
+
osal_mmap((env->flags & MDBX_EXCLUSIVE) | MDBX_WRITEMAP, &env->lck_mmap, (size_t)size, (size_t)size,
|
|
67
|
+
lck_seize_rc ? MMAP_OPTION_TRUNCATE | MMAP_OPTION_SEMAPHORE : MMAP_OPTION_SEMAPHORE, env->pathname.lck);
|
|
68
|
+
if (unlikely(err != MDBX_SUCCESS))
|
|
69
|
+
return err;
|
|
70
|
+
|
|
71
|
+
#ifdef MADV_DODUMP
|
|
72
|
+
err = madvise(env->lck_mmap.lck, size, MADV_DODUMP) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
|
73
|
+
if (unlikely(MDBX_IS_ERROR(err)))
|
|
74
|
+
return err;
|
|
75
|
+
#endif /* MADV_DODUMP */
|
|
76
|
+
|
|
77
|
+
#ifdef MADV_WILLNEED
|
|
78
|
+
err = madvise(env->lck_mmap.lck, size, MADV_WILLNEED) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
|
79
|
+
if (unlikely(MDBX_IS_ERROR(err)))
|
|
80
|
+
return err;
|
|
81
|
+
#elif defined(POSIX_MADV_WILLNEED)
|
|
82
|
+
err = ignore_enosys(posix_madvise(env->lck_mmap.lck, size, POSIX_MADV_WILLNEED));
|
|
83
|
+
if (unlikely(MDBX_IS_ERROR(err)))
|
|
84
|
+
return err;
|
|
85
|
+
#endif /* MADV_WILLNEED */
|
|
86
|
+
|
|
87
|
+
lck_t *lck = env->lck_mmap.lck;
|
|
88
|
+
if (lck_seize_rc == MDBX_RESULT_TRUE) {
|
|
89
|
+
/* If we succeed got exclusive lock, then nobody is using the lock region
|
|
90
|
+
* and we should initialize it. */
|
|
91
|
+
memset(lck, 0, (size_t)size);
|
|
92
|
+
jitter4testing(false);
|
|
93
|
+
lck->magic_and_version = MDBX_LOCK_MAGIC;
|
|
94
|
+
lck->os_and_format = MDBX_LOCK_FORMAT;
|
|
95
|
+
#if MDBX_ENABLE_PGOP_STAT
|
|
96
|
+
lck->pgops.wops.weak = 1;
|
|
97
|
+
#endif /* MDBX_ENABLE_PGOP_STAT */
|
|
98
|
+
err = osal_msync(&env->lck_mmap, 0, (size_t)size, MDBX_SYNC_DATA | MDBX_SYNC_SIZE);
|
|
99
|
+
if (unlikely(err != MDBX_SUCCESS)) {
|
|
100
|
+
ERROR("initial-%s for lck-file failed, err %d", "msync/fsync", err);
|
|
101
|
+
eASSERT(env, MDBX_IS_ERROR(err));
|
|
102
|
+
return err;
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
if (lck->magic_and_version != MDBX_LOCK_MAGIC) {
|
|
106
|
+
const bool invalid = (lck->magic_and_version >> 8) != MDBX_MAGIC;
|
|
107
|
+
ERROR("lock region has %s", invalid ? "invalid magic"
|
|
108
|
+
: "incompatible version (only applications with nearly or the "
|
|
109
|
+
"same versions of libmdbx can share the same database)");
|
|
110
|
+
return invalid ? MDBX_INVALID : MDBX_VERSION_MISMATCH;
|
|
111
|
+
}
|
|
112
|
+
if (lck->os_and_format != MDBX_LOCK_FORMAT) {
|
|
113
|
+
ERROR("lock region has os/format signature 0x%" PRIx32 ", expected 0x%" PRIx32, lck->os_and_format,
|
|
114
|
+
MDBX_LOCK_FORMAT);
|
|
115
|
+
return MDBX_VERSION_MISMATCH;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
err = lck_init(env, inprocess_neighbor, lck_seize_rc);
|
|
120
|
+
if (unlikely(err != MDBX_SUCCESS)) {
|
|
121
|
+
eASSERT(env, MDBX_IS_ERROR(err));
|
|
122
|
+
return err;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
env->lck = lck;
|
|
126
|
+
eASSERT(env, !MDBX_IS_ERROR(lck_seize_rc));
|
|
127
|
+
return lck_seize_rc;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
__cold int lck_setup(MDBX_env *env, mdbx_mode_t mode) {
|
|
131
|
+
eASSERT(env, env->lazy_fd != INVALID_HANDLE_VALUE);
|
|
132
|
+
eASSERT(env, env->lck_mmap.fd == INVALID_HANDLE_VALUE);
|
|
133
|
+
|
|
134
|
+
int err = osal_openfile(MDBX_OPEN_LCK, env, env->pathname.lck, &env->lck_mmap.fd, mode);
|
|
135
|
+
if (err != MDBX_SUCCESS) {
|
|
136
|
+
switch (err) {
|
|
137
|
+
case MDBX_EACCESS:
|
|
138
|
+
case MDBX_EPERM:
|
|
139
|
+
if (F_ISSET(env->flags, MDBX_RDONLY | MDBX_EXCLUSIVE))
|
|
140
|
+
break;
|
|
141
|
+
__fallthrough /* fall through */;
|
|
142
|
+
case MDBX_ENOFILE:
|
|
143
|
+
case MDBX_EROFS:
|
|
144
|
+
if (env->flags & MDBX_RDONLY) {
|
|
145
|
+
/* ENSURE the file system is read-only */
|
|
146
|
+
int err_rofs = osal_check_fs_rdonly(env->lazy_fd, env->pathname.lck, err);
|
|
147
|
+
if (err_rofs == MDBX_SUCCESS ||
|
|
148
|
+
/* ignore ERROR_NOT_SUPPORTED for exclusive mode */
|
|
149
|
+
(err_rofs == MDBX_ENOSYS && (env->flags & MDBX_EXCLUSIVE)))
|
|
150
|
+
break;
|
|
151
|
+
if (err_rofs != MDBX_ENOSYS)
|
|
152
|
+
err = err_rofs;
|
|
153
|
+
}
|
|
154
|
+
__fallthrough /* fall through */;
|
|
155
|
+
default:
|
|
156
|
+
ERROR("unable to open lck-file %" MDBX_PRIsPATH ", env-flags 0x%X, err %d", env->pathname.lck, env->flags, err);
|
|
157
|
+
return err;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* LY: without-lck mode (e.g. exclusive or on read-only filesystem) */
|
|
161
|
+
env->lck_mmap.fd = INVALID_HANDLE_VALUE;
|
|
162
|
+
NOTICE("continue %" MDBX_PRIsPATH " within without-lck mode, env-flags 0x%X, lck-error %d", env->pathname.dxb,
|
|
163
|
+
env->flags, err);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
rthc_lock();
|
|
167
|
+
err = lck_setup_locked(env);
|
|
168
|
+
rthc_unlock();
|
|
169
|
+
return err;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
void mincore_clean_cache(const MDBX_env *const env) {
|
|
173
|
+
memset(env->lck->mincore_cache.begin, -1, sizeof(env->lck->mincore_cache.begin));
|
|
174
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include "essentials.h"
|
|
7
|
+
|
|
8
|
+
MDBX_INTERNAL int lck_setup(MDBX_env *env, mdbx_mode_t mode);
|
|
9
|
+
#if MDBX_LOCKING > MDBX_LOCKING_SYSV
|
|
10
|
+
MDBX_INTERNAL int lck_ipclock_stubinit(osal_ipclock_t *ipc);
|
|
11
|
+
MDBX_INTERNAL int lck_ipclock_destroy(osal_ipclock_t *ipc);
|
|
12
|
+
#endif /* MDBX_LOCKING > MDBX_LOCKING_SYSV */
|
|
13
|
+
|
|
14
|
+
/// \brief Initialization of synchronization primitives linked with MDBX_env
|
|
15
|
+
/// instance both in LCK-file and within the current process.
|
|
16
|
+
/// \param
|
|
17
|
+
/// global_uniqueness_flag = true - denotes that there are no other processes
|
|
18
|
+
/// working with DB and LCK-file. Thus the function MUST initialize
|
|
19
|
+
/// shared synchronization objects in memory-mapped LCK-file.
|
|
20
|
+
/// global_uniqueness_flag = false - denotes that at least one process is
|
|
21
|
+
/// already working with DB and LCK-file, including the case when DB
|
|
22
|
+
/// has already been opened in the current process. Thus the function
|
|
23
|
+
/// MUST NOT initialize shared synchronization objects in memory-mapped
|
|
24
|
+
/// LCK-file that are already in use.
|
|
25
|
+
/// \return Error code or zero on success.
|
|
26
|
+
MDBX_INTERNAL int lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor, int global_uniqueness_flag);
|
|
27
|
+
|
|
28
|
+
/// \brief Disconnects from shared interprocess objects and destructs
|
|
29
|
+
/// synchronization objects linked with MDBX_env instance
|
|
30
|
+
/// within the current process.
|
|
31
|
+
/// \param
|
|
32
|
+
/// inprocess_neighbor = nullptr - if the current process does not have other
|
|
33
|
+
/// instances of MDBX_env linked with the DB being closed.
|
|
34
|
+
/// Thus the function MUST check for other processes working with DB or
|
|
35
|
+
/// LCK-file, and keep or destroy shared synchronization objects in
|
|
36
|
+
/// memory-mapped LCK-file depending on the result.
|
|
37
|
+
/// inprocess_neighbor = not-nullptr - pointer to another instance of MDBX_env
|
|
38
|
+
/// (anyone of there is several) working with DB or LCK-file within the
|
|
39
|
+
/// current process. Thus the function MUST NOT try to acquire exclusive
|
|
40
|
+
/// lock and/or try to destruct shared synchronization objects linked with
|
|
41
|
+
/// DB or LCK-file. Moreover, the implementation MUST ensure correct work
|
|
42
|
+
/// of other instances of MDBX_env within the current process, e.g.
|
|
43
|
+
/// restore POSIX-fcntl locks after the closing of file descriptors.
|
|
44
|
+
/// \return Error code (MDBX_PANIC) or zero on success.
|
|
45
|
+
MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor, const uint32_t current_pid);
|
|
46
|
+
|
|
47
|
+
/// \brief Connects to shared interprocess locking objects and tries to acquire
|
|
48
|
+
/// the maximum lock level (shared if exclusive is not available)
|
|
49
|
+
/// Depending on implementation or/and platform (Windows) this function may
|
|
50
|
+
/// acquire the non-OS super-level lock (e.g. for shared synchronization
|
|
51
|
+
/// objects initialization), which will be downgraded to OS-exclusive or
|
|
52
|
+
/// shared via explicit calling of lck_downgrade().
|
|
53
|
+
/// \return
|
|
54
|
+
/// MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
|
|
55
|
+
/// the current process is the first and only after the last use of DB.
|
|
56
|
+
/// MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
|
|
57
|
+
/// DB has already been opened and now is used by other processes.
|
|
58
|
+
/// Otherwise (not 0 and not -1) - error code.
|
|
59
|
+
MDBX_INTERNAL int lck_seize(MDBX_env *env);
|
|
60
|
+
|
|
61
|
+
/// \brief Downgrades the level of initially acquired lock to
|
|
62
|
+
/// operational level specified by argument. The reason for such downgrade:
|
|
63
|
+
/// - unblocking of other processes that are waiting for access, i.e.
|
|
64
|
+
/// if (env->flags & MDBX_EXCLUSIVE) != 0, then other processes
|
|
65
|
+
/// should be made aware that access is unavailable rather than
|
|
66
|
+
/// wait for it.
|
|
67
|
+
/// - freeing locks that interfere file operation (especially for Windows)
|
|
68
|
+
/// (env->flags & MDBX_EXCLUSIVE) == 0 - downgrade to shared lock.
|
|
69
|
+
/// (env->flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
|
|
70
|
+
/// operational lock.
|
|
71
|
+
/// \return Error code or zero on success
|
|
72
|
+
MDBX_INTERNAL int lck_downgrade(MDBX_env *env);
|
|
73
|
+
|
|
74
|
+
MDBX_MAYBE_UNUSED MDBX_INTERNAL int lck_upgrade(MDBX_env *env, bool dont_wait);
|
|
75
|
+
|
|
76
|
+
/// \brief Locks LCK-file or/and table of readers for (de)registering.
|
|
77
|
+
/// \return Error code or zero on success
|
|
78
|
+
MDBX_INTERNAL int lck_rdt_lock(MDBX_env *env);
|
|
79
|
+
|
|
80
|
+
/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
|
|
81
|
+
MDBX_INTERNAL void lck_rdt_unlock(MDBX_env *env);
|
|
82
|
+
|
|
83
|
+
/// \brief Acquires write-transaction lock.
|
|
84
|
+
/// \return Error code or zero on success
|
|
85
|
+
MDBX_INTERNAL int lck_txn_lock(MDBX_env *env, bool dont_wait);
|
|
86
|
+
|
|
87
|
+
/// \brief Releases write-transaction lock..
|
|
88
|
+
MDBX_INTERNAL void lck_txn_unlock(MDBX_env *env);
|
|
89
|
+
|
|
90
|
+
/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
|
|
91
|
+
/// the current process. The function does no more than needed for
|
|
92
|
+
/// the correct working of lck_rpid_check() in other processes.
|
|
93
|
+
/// \return Error code or zero on success
|
|
94
|
+
MDBX_INTERNAL int lck_rpid_set(MDBX_env *env);
|
|
95
|
+
|
|
96
|
+
/// \brief Resets alive-flag of reader presence (indicative lock)
|
|
97
|
+
/// for PID of the current process. The function does no more than needed
|
|
98
|
+
/// for the correct working of lck_rpid_check() in other processes.
|
|
99
|
+
/// \return Error code or zero on success
|
|
100
|
+
MDBX_INTERNAL int lck_rpid_clear(MDBX_env *env);
|
|
101
|
+
|
|
102
|
+
/// \brief Checks for reading process status with the given pid with help of
|
|
103
|
+
/// alive-flag of presence (indicative lock) or using another way.
|
|
104
|
+
/// \return
|
|
105
|
+
/// MDBX_RESULT_TRUE (-1) - if the reader process with the given PID is alive
|
|
106
|
+
/// and working with DB (indicative lock is present).
|
|
107
|
+
/// MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
|
|
108
|
+
/// or not working with DB (indicative lock is not present).
|
|
109
|
+
/// Otherwise (not 0 and not -1) - error code.
|
|
110
|
+
MDBX_INTERNAL int lck_rpid_check(MDBX_env *env, uint32_t pid);
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
3
|
+
|
|
4
|
+
#include "internals.h"
|
|
5
|
+
|
|
6
|
+
__cold void debug_log_va(int level, const char *function, int line, const char *fmt, va_list args) {
|
|
7
|
+
ENSURE(nullptr, osal_fastmutex_acquire(&globals.debug_lock) == 0);
|
|
8
|
+
if (globals.logger.ptr) {
|
|
9
|
+
if (globals.logger_buffer == nullptr)
|
|
10
|
+
globals.logger.fmt(level, function, line, fmt, args);
|
|
11
|
+
else {
|
|
12
|
+
const int len = vsnprintf(globals.logger_buffer, globals.logger_buffer_size, fmt, args);
|
|
13
|
+
if (len > 0)
|
|
14
|
+
globals.logger.nofmt(level, function, line, globals.logger_buffer, len);
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
18
|
+
if (IsDebuggerPresent()) {
|
|
19
|
+
int prefix_len = 0;
|
|
20
|
+
char *prefix = nullptr;
|
|
21
|
+
if (function && line > 0)
|
|
22
|
+
prefix_len = osal_asprintf(&prefix, "%s:%d ", function, line);
|
|
23
|
+
else if (function)
|
|
24
|
+
prefix_len = osal_asprintf(&prefix, "%s: ", function);
|
|
25
|
+
else if (line > 0)
|
|
26
|
+
prefix_len = osal_asprintf(&prefix, "%d: ", line);
|
|
27
|
+
if (prefix_len > 0 && prefix) {
|
|
28
|
+
OutputDebugStringA(prefix);
|
|
29
|
+
osal_free(prefix);
|
|
30
|
+
}
|
|
31
|
+
char *msg = nullptr;
|
|
32
|
+
int msg_len = osal_vasprintf(&msg, fmt, args);
|
|
33
|
+
if (msg_len > 0 && msg) {
|
|
34
|
+
OutputDebugStringA(msg);
|
|
35
|
+
osal_free(msg);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
#else
|
|
39
|
+
if (function && line > 0)
|
|
40
|
+
fprintf(stderr, "%s:%d ", function, line);
|
|
41
|
+
else if (function)
|
|
42
|
+
fprintf(stderr, "%s: ", function);
|
|
43
|
+
else if (line > 0)
|
|
44
|
+
fprintf(stderr, "%d: ", line);
|
|
45
|
+
vfprintf(stderr, fmt, args);
|
|
46
|
+
fflush(stderr);
|
|
47
|
+
#endif
|
|
48
|
+
}
|
|
49
|
+
ENSURE(nullptr, osal_fastmutex_release(&globals.debug_lock) == 0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
__cold void debug_log(int level, const char *function, int line, const char *fmt, ...) {
|
|
53
|
+
va_list args;
|
|
54
|
+
va_start(args, fmt);
|
|
55
|
+
debug_log_va(level, function, line, fmt, args);
|
|
56
|
+
va_end(args);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
__cold void log_error(const int err, const char *func, unsigned line) {
|
|
60
|
+
assert(err != MDBX_SUCCESS);
|
|
61
|
+
if (unlikely(globals.loglevel >= MDBX_LOG_DEBUG)) {
|
|
62
|
+
const bool is_error = err != MDBX_RESULT_TRUE && err != MDBX_NOTFOUND;
|
|
63
|
+
char buf[256];
|
|
64
|
+
debug_log(is_error ? MDBX_LOG_ERROR : MDBX_LOG_VERBOSE, func, line, "%s %d (%s)\n",
|
|
65
|
+
is_error ? "error" : "condition", err, mdbx_strerror_r(err, buf, sizeof(buf)));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Dump a val in ascii or hexadecimal. */
|
|
70
|
+
__cold const char *mdbx_dump_val(const MDBX_val *val, char *const buf, const size_t bufsize) {
|
|
71
|
+
if (!val)
|
|
72
|
+
return "<null>";
|
|
73
|
+
if (!val->iov_len)
|
|
74
|
+
return "<empty>";
|
|
75
|
+
if (!buf || bufsize < 4)
|
|
76
|
+
return nullptr;
|
|
77
|
+
|
|
78
|
+
if (!val->iov_base) {
|
|
79
|
+
int len = snprintf(buf, bufsize, "<nullptr.%zu>", val->iov_len);
|
|
80
|
+
assert(len > 0 && (size_t)len < bufsize);
|
|
81
|
+
(void)len;
|
|
82
|
+
return buf;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
bool is_ascii = true;
|
|
86
|
+
const uint8_t *const data = val->iov_base;
|
|
87
|
+
for (size_t i = 0; i < val->iov_len; i++)
|
|
88
|
+
if (data[i] < ' ' || data[i] > '~') {
|
|
89
|
+
is_ascii = false;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (is_ascii) {
|
|
94
|
+
int len = snprintf(buf, bufsize, "%.*s", (val->iov_len > INT_MAX) ? INT_MAX : (int)val->iov_len, data);
|
|
95
|
+
assert(len > 0 && (size_t)len < bufsize);
|
|
96
|
+
(void)len;
|
|
97
|
+
} else {
|
|
98
|
+
char *const detent = buf + bufsize - 2;
|
|
99
|
+
char *ptr = buf;
|
|
100
|
+
*ptr++ = '<';
|
|
101
|
+
for (size_t i = 0; i < val->iov_len && ptr < detent; i++) {
|
|
102
|
+
const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
|
103
|
+
*ptr++ = hex[data[i] >> 4];
|
|
104
|
+
*ptr++ = hex[data[i] & 15];
|
|
105
|
+
}
|
|
106
|
+
if (ptr < detent)
|
|
107
|
+
*ptr++ = '>';
|
|
108
|
+
*ptr = '\0';
|
|
109
|
+
}
|
|
110
|
+
return buf;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/*------------------------------------------------------------------------------
|
|
114
|
+
LY: debug stuff */
|
|
115
|
+
|
|
116
|
+
__cold const char *pagetype_caption(const uint8_t type, char buf4unknown[16]) {
|
|
117
|
+
switch (type) {
|
|
118
|
+
case P_BRANCH:
|
|
119
|
+
return "branch";
|
|
120
|
+
case P_LEAF:
|
|
121
|
+
return "leaf";
|
|
122
|
+
case P_LEAF | P_SUBP:
|
|
123
|
+
return "subleaf";
|
|
124
|
+
case P_LEAF | P_DUPFIX:
|
|
125
|
+
return "dupfix-leaf";
|
|
126
|
+
case P_LEAF | P_DUPFIX | P_SUBP:
|
|
127
|
+
return "dupfix-subleaf";
|
|
128
|
+
case P_LEAF | P_DUPFIX | P_SUBP | P_LEGACY_DIRTY:
|
|
129
|
+
return "dupfix-subleaf.legacy-dirty";
|
|
130
|
+
case P_LARGE:
|
|
131
|
+
return "large";
|
|
132
|
+
default:
|
|
133
|
+
snprintf(buf4unknown, 16, "unknown_0x%x", type);
|
|
134
|
+
return buf4unknown;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
__cold static const char *leafnode_type(node_t *n) {
|
|
139
|
+
static const char *const tp[2][2] = {{"", ": DB"}, {": sub-page", ": sub-DB"}};
|
|
140
|
+
return (node_flags(n) & N_BIG) ? ": large page" : tp[!!(node_flags(n) & N_DUP)][!!(node_flags(n) & N_TREE)];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Display all the keys in the page. */
|
|
144
|
+
__cold void page_list(page_t *mp) {
|
|
145
|
+
pgno_t pgno = mp->pgno;
|
|
146
|
+
const char *type;
|
|
147
|
+
node_t *node;
|
|
148
|
+
size_t i, nkeys, nsize, total = 0;
|
|
149
|
+
MDBX_val key;
|
|
150
|
+
DKBUF;
|
|
151
|
+
|
|
152
|
+
switch (page_type(mp)) {
|
|
153
|
+
case P_BRANCH:
|
|
154
|
+
type = "Branch page";
|
|
155
|
+
break;
|
|
156
|
+
case P_LEAF:
|
|
157
|
+
type = "Leaf page";
|
|
158
|
+
break;
|
|
159
|
+
case P_LEAF | P_SUBP:
|
|
160
|
+
type = "Leaf sub-page";
|
|
161
|
+
break;
|
|
162
|
+
case P_LEAF | P_DUPFIX:
|
|
163
|
+
type = "Leaf2 page";
|
|
164
|
+
break;
|
|
165
|
+
case P_LEAF | P_DUPFIX | P_SUBP:
|
|
166
|
+
type = "Leaf2 sub-page";
|
|
167
|
+
break;
|
|
168
|
+
case P_LARGE:
|
|
169
|
+
VERBOSE("Overflow page %" PRIaPGNO " pages %u\n", pgno, mp->pages);
|
|
170
|
+
return;
|
|
171
|
+
case P_META:
|
|
172
|
+
VERBOSE("Meta-page %" PRIaPGNO " txnid %" PRIu64 "\n", pgno, unaligned_peek_u64(4, page_meta(mp)->txnid_a));
|
|
173
|
+
return;
|
|
174
|
+
default:
|
|
175
|
+
VERBOSE("Bad page %" PRIaPGNO " flags 0x%X\n", pgno, mp->flags);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
nkeys = page_numkeys(mp);
|
|
180
|
+
VERBOSE("%s %" PRIaPGNO " numkeys %zu\n", type, pgno, nkeys);
|
|
181
|
+
|
|
182
|
+
for (i = 0; i < nkeys; i++) {
|
|
183
|
+
if (is_dupfix_leaf(mp)) { /* DUPFIX pages have no entries[] or node headers */
|
|
184
|
+
key = page_dupfix_key(mp, i, nsize = mp->dupfix_ksize);
|
|
185
|
+
total += nsize;
|
|
186
|
+
VERBOSE("key %zu: nsize %zu, %s\n", i, nsize, DKEY(&key));
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
node = page_node(mp, i);
|
|
190
|
+
key.iov_len = node_ks(node);
|
|
191
|
+
key.iov_base = node->payload;
|
|
192
|
+
nsize = NODESIZE + key.iov_len;
|
|
193
|
+
if (is_branch(mp)) {
|
|
194
|
+
VERBOSE("key %zu: page %" PRIaPGNO ", %s\n", i, node_pgno(node), DKEY(&key));
|
|
195
|
+
total += nsize;
|
|
196
|
+
} else {
|
|
197
|
+
if (node_flags(node) & N_BIG)
|
|
198
|
+
nsize += sizeof(pgno_t);
|
|
199
|
+
else
|
|
200
|
+
nsize += node_ds(node);
|
|
201
|
+
total += nsize;
|
|
202
|
+
nsize += sizeof(indx_t);
|
|
203
|
+
VERBOSE("key %zu: nsize %zu, %s%s\n", i, nsize, DKEY(&key), leafnode_type(node));
|
|
204
|
+
}
|
|
205
|
+
total = EVEN_CEIL(total);
|
|
206
|
+
}
|
|
207
|
+
VERBOSE("Total: header %u + contents %zu + unused %zu\n", is_dupfix_leaf(mp) ? PAGEHDRSZ : PAGEHDRSZ + mp->lower,
|
|
208
|
+
total, page_room(mp));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
__cold static int setup_debug(MDBX_log_level_t level, MDBX_debug_flags_t flags, union logger_union logger, char *buffer,
|
|
212
|
+
size_t buffer_size) {
|
|
213
|
+
ENSURE(nullptr, osal_fastmutex_acquire(&globals.debug_lock) == 0);
|
|
214
|
+
|
|
215
|
+
const int rc = globals.runtime_flags | (globals.loglevel << 16);
|
|
216
|
+
if (level != MDBX_LOG_DONTCHANGE)
|
|
217
|
+
globals.loglevel = (uint8_t)level;
|
|
218
|
+
|
|
219
|
+
if (flags != MDBX_DBG_DONTCHANGE) {
|
|
220
|
+
flags &=
|
|
221
|
+
#if MDBX_DEBUG
|
|
222
|
+
MDBX_DBG_ASSERT | MDBX_DBG_AUDIT | MDBX_DBG_JITTER |
|
|
223
|
+
#endif
|
|
224
|
+
MDBX_DBG_DUMP | MDBX_DBG_LEGACY_MULTIOPEN | MDBX_DBG_LEGACY_OVERLAP | MDBX_DBG_DONT_UPGRADE;
|
|
225
|
+
globals.runtime_flags = (uint8_t)flags;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
assert(MDBX_LOGGER_DONTCHANGE == ((MDBX_debug_func *)(intptr_t)-1));
|
|
229
|
+
if (logger.ptr != (void *)((intptr_t)-1)) {
|
|
230
|
+
globals.logger.ptr = logger.ptr;
|
|
231
|
+
globals.logger_buffer = buffer;
|
|
232
|
+
globals.logger_buffer_size = buffer_size;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
ENSURE(nullptr, osal_fastmutex_release(&globals.debug_lock) == 0);
|
|
236
|
+
return rc;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
__cold int mdbx_setup_debug_nofmt(MDBX_log_level_t level, MDBX_debug_flags_t flags, MDBX_debug_func_nofmt *logger,
|
|
240
|
+
char *buffer, size_t buffer_size) {
|
|
241
|
+
union logger_union thunk;
|
|
242
|
+
thunk.nofmt = (logger && buffer && buffer_size) ? logger : MDBX_LOGGER_NOFMT_DONTCHANGE;
|
|
243
|
+
return setup_debug(level, flags, thunk, buffer, buffer_size);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
__cold int mdbx_setup_debug(MDBX_log_level_t level, MDBX_debug_flags_t flags, MDBX_debug_func *logger) {
|
|
247
|
+
union logger_union thunk;
|
|
248
|
+
thunk.fmt = logger;
|
|
249
|
+
return setup_debug(level, flags, thunk, nullptr, 0);
|
|
250
|
+
}
|