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.
Files changed (220) hide show
  1. package/.github/workflows/ci.yml +32 -0
  2. package/.github/workflows/publish.yml +27 -0
  3. package/.gitmodules +3 -0
  4. package/CMakeLists.txt +53 -0
  5. package/LICENSE +201 -0
  6. package/README.md +639 -0
  7. package/build.js +11 -0
  8. package/deps/libmdbx/.clang-format +3 -0
  9. package/deps/libmdbx/.cmake-format.yaml +3 -0
  10. package/deps/libmdbx/.le.ini +40 -0
  11. package/deps/libmdbx/CMakeLists.txt +1269 -0
  12. package/deps/libmdbx/COPYRIGHT +159 -0
  13. package/deps/libmdbx/ChangeLog.md +2786 -0
  14. package/deps/libmdbx/GNUmakefile +950 -0
  15. package/deps/libmdbx/LICENSE +177 -0
  16. package/deps/libmdbx/Makefile +16 -0
  17. package/deps/libmdbx/NOTICE +39 -0
  18. package/deps/libmdbx/README.md +863 -0
  19. package/deps/libmdbx/TODO.md +43 -0
  20. package/deps/libmdbx/cmake/compiler.cmake +1221 -0
  21. package/deps/libmdbx/cmake/profile.cmake +58 -0
  22. package/deps/libmdbx/cmake/utils.cmake +524 -0
  23. package/deps/libmdbx/conanfile.py +323 -0
  24. package/deps/libmdbx/docs/Doxyfile.in +2734 -0
  25. package/deps/libmdbx/docs/_preface.md +47 -0
  26. package/deps/libmdbx/docs/_restrictions.md +248 -0
  27. package/deps/libmdbx/docs/_starting.md +245 -0
  28. package/deps/libmdbx/docs/_toc.md +34 -0
  29. package/deps/libmdbx/docs/header.html +96 -0
  30. package/deps/libmdbx/example/CMakeLists.txt +6 -0
  31. package/deps/libmdbx/example/README.md +1 -0
  32. package/deps/libmdbx/example/example-mdbx.c +154 -0
  33. package/deps/libmdbx/example/sample-bdb.txt +77 -0
  34. package/deps/libmdbx/mdbx.h +6655 -0
  35. package/deps/libmdbx/mdbx.h++ +6428 -0
  36. package/deps/libmdbx/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +173 -0
  37. package/deps/libmdbx/src/alloy.c +54 -0
  38. package/deps/libmdbx/src/api-cold.c +543 -0
  39. package/deps/libmdbx/src/api-copy.c +912 -0
  40. package/deps/libmdbx/src/api-cursor.c +754 -0
  41. package/deps/libmdbx/src/api-dbi.c +315 -0
  42. package/deps/libmdbx/src/api-env.c +1434 -0
  43. package/deps/libmdbx/src/api-extra.c +165 -0
  44. package/deps/libmdbx/src/api-key-transform.c +197 -0
  45. package/deps/libmdbx/src/api-misc.c +286 -0
  46. package/deps/libmdbx/src/api-opts.c +575 -0
  47. package/deps/libmdbx/src/api-range-estimate.c +365 -0
  48. package/deps/libmdbx/src/api-txn-data.c +454 -0
  49. package/deps/libmdbx/src/api-txn.c +921 -0
  50. package/deps/libmdbx/src/atomics-ops.h +364 -0
  51. package/deps/libmdbx/src/atomics-types.h +97 -0
  52. package/deps/libmdbx/src/audit.c +109 -0
  53. package/deps/libmdbx/src/bits.md +34 -0
  54. package/deps/libmdbx/src/chk.c +1796 -0
  55. package/deps/libmdbx/src/cogs.c +309 -0
  56. package/deps/libmdbx/src/cogs.h +506 -0
  57. package/deps/libmdbx/src/coherency.c +170 -0
  58. package/deps/libmdbx/src/config.h.in +88 -0
  59. package/deps/libmdbx/src/cursor.c +2396 -0
  60. package/deps/libmdbx/src/cursor.h +391 -0
  61. package/deps/libmdbx/src/dbi.c +717 -0
  62. package/deps/libmdbx/src/dbi.h +142 -0
  63. package/deps/libmdbx/src/debug_begin.h +36 -0
  64. package/deps/libmdbx/src/debug_end.h +15 -0
  65. package/deps/libmdbx/src/dpl.c +486 -0
  66. package/deps/libmdbx/src/dpl.h +134 -0
  67. package/deps/libmdbx/src/dxb.c +1335 -0
  68. package/deps/libmdbx/src/env.c +607 -0
  69. package/deps/libmdbx/src/essentials.h +125 -0
  70. package/deps/libmdbx/src/gc-get.c +1345 -0
  71. package/deps/libmdbx/src/gc-put.c +970 -0
  72. package/deps/libmdbx/src/gc.h +40 -0
  73. package/deps/libmdbx/src/global.c +474 -0
  74. package/deps/libmdbx/src/internals.h +585 -0
  75. package/deps/libmdbx/src/layout-dxb.h +288 -0
  76. package/deps/libmdbx/src/layout-lck.h +289 -0
  77. package/deps/libmdbx/src/lck-posix.c +859 -0
  78. package/deps/libmdbx/src/lck-windows.c +607 -0
  79. package/deps/libmdbx/src/lck.c +174 -0
  80. package/deps/libmdbx/src/lck.h +110 -0
  81. package/deps/libmdbx/src/logging_and_debug.c +250 -0
  82. package/deps/libmdbx/src/logging_and_debug.h +159 -0
  83. package/deps/libmdbx/src/man1/mdbx_chk.1 +106 -0
  84. package/deps/libmdbx/src/man1/mdbx_copy.1 +95 -0
  85. package/deps/libmdbx/src/man1/mdbx_drop.1 +48 -0
  86. package/deps/libmdbx/src/man1/mdbx_dump.1 +101 -0
  87. package/deps/libmdbx/src/man1/mdbx_load.1 +105 -0
  88. package/deps/libmdbx/src/man1/mdbx_stat.1 +86 -0
  89. package/deps/libmdbx/src/mdbx.c++ +1837 -0
  90. package/deps/libmdbx/src/meta.c +656 -0
  91. package/deps/libmdbx/src/meta.h +168 -0
  92. package/deps/libmdbx/src/mvcc-readers.c +414 -0
  93. package/deps/libmdbx/src/node.c +365 -0
  94. package/deps/libmdbx/src/node.h +102 -0
  95. package/deps/libmdbx/src/ntdll.def +1246 -0
  96. package/deps/libmdbx/src/options.h +534 -0
  97. package/deps/libmdbx/src/osal.c +3485 -0
  98. package/deps/libmdbx/src/osal.h +587 -0
  99. package/deps/libmdbx/src/page-get.c +483 -0
  100. package/deps/libmdbx/src/page-iov.c +185 -0
  101. package/deps/libmdbx/src/page-iov.h +34 -0
  102. package/deps/libmdbx/src/page-ops.c +744 -0
  103. package/deps/libmdbx/src/page-ops.h +142 -0
  104. package/deps/libmdbx/src/pnl.c +236 -0
  105. package/deps/libmdbx/src/pnl.h +146 -0
  106. package/deps/libmdbx/src/preface.h +990 -0
  107. package/deps/libmdbx/src/proto.h +105 -0
  108. package/deps/libmdbx/src/refund.c +212 -0
  109. package/deps/libmdbx/src/sort.h +484 -0
  110. package/deps/libmdbx/src/spill.c +431 -0
  111. package/deps/libmdbx/src/spill.h +74 -0
  112. package/deps/libmdbx/src/table.c +107 -0
  113. package/deps/libmdbx/src/tls.c +551 -0
  114. package/deps/libmdbx/src/tls.h +43 -0
  115. package/deps/libmdbx/src/tools/chk.c +673 -0
  116. package/deps/libmdbx/src/tools/copy.c +166 -0
  117. package/deps/libmdbx/src/tools/drop.c +199 -0
  118. package/deps/libmdbx/src/tools/dump.c +515 -0
  119. package/deps/libmdbx/src/tools/load.c +831 -0
  120. package/deps/libmdbx/src/tools/stat.c +516 -0
  121. package/deps/libmdbx/src/tools/wingetopt.c +87 -0
  122. package/deps/libmdbx/src/tools/wingetopt.h +30 -0
  123. package/deps/libmdbx/src/tree-ops.c +1554 -0
  124. package/deps/libmdbx/src/tree-search.c +140 -0
  125. package/deps/libmdbx/src/txl.c +99 -0
  126. package/deps/libmdbx/src/txl.h +26 -0
  127. package/deps/libmdbx/src/txn.c +1083 -0
  128. package/deps/libmdbx/src/unaligned.h +205 -0
  129. package/deps/libmdbx/src/utils.c +32 -0
  130. package/deps/libmdbx/src/utils.h +76 -0
  131. package/deps/libmdbx/src/version.c.in +44 -0
  132. package/deps/libmdbx/src/walk.c +290 -0
  133. package/deps/libmdbx/src/walk.h +20 -0
  134. package/deps/libmdbx/src/windows-import.c +152 -0
  135. package/deps/libmdbx/src/windows-import.h +128 -0
  136. package/deps/libmdbx/test/CMakeLists.txt +317 -0
  137. package/deps/libmdbx/test/append.c++ +237 -0
  138. package/deps/libmdbx/test/base.h++ +92 -0
  139. package/deps/libmdbx/test/battery-tmux.sh +64 -0
  140. package/deps/libmdbx/test/cases.c++ +118 -0
  141. package/deps/libmdbx/test/chrono.c++ +134 -0
  142. package/deps/libmdbx/test/chrono.h++ +85 -0
  143. package/deps/libmdbx/test/config.c++ +643 -0
  144. package/deps/libmdbx/test/config.h++ +334 -0
  145. package/deps/libmdbx/test/copy.c++ +62 -0
  146. package/deps/libmdbx/test/dead.c++ +39 -0
  147. package/deps/libmdbx/test/dump-load.sh +40 -0
  148. package/deps/libmdbx/test/extra/crunched_delete.c++ +409 -0
  149. package/deps/libmdbx/test/extra/cursor_closing.c++ +410 -0
  150. package/deps/libmdbx/test/extra/dbi.c++ +229 -0
  151. package/deps/libmdbx/test/extra/doubtless_positioning.c++ +253 -0
  152. package/deps/libmdbx/test/extra/dupfix_addodd.c +94 -0
  153. package/deps/libmdbx/test/extra/dupfix_multiple.c++ +311 -0
  154. package/deps/libmdbx/test/extra/early_close_dbi.c++ +137 -0
  155. package/deps/libmdbx/test/extra/hex_base64_base58.c++ +118 -0
  156. package/deps/libmdbx/test/extra/maindb_ordinal.c++ +61 -0
  157. package/deps/libmdbx/test/extra/open.c++ +96 -0
  158. package/deps/libmdbx/test/extra/pcrf/README.md +2 -0
  159. package/deps/libmdbx/test/extra/pcrf/pcrf_test.c +380 -0
  160. package/deps/libmdbx/test/extra/probe.c++ +10 -0
  161. package/deps/libmdbx/test/extra/txn.c++ +407 -0
  162. package/deps/libmdbx/test/extra/upsert_alldups.c +193 -0
  163. package/deps/libmdbx/test/fork.c++ +263 -0
  164. package/deps/libmdbx/test/hill.c++ +447 -0
  165. package/deps/libmdbx/test/jitter.c++ +197 -0
  166. package/deps/libmdbx/test/keygen.c++ +393 -0
  167. package/deps/libmdbx/test/keygen.h++ +130 -0
  168. package/deps/libmdbx/test/log.c++ +358 -0
  169. package/deps/libmdbx/test/log.h++ +91 -0
  170. package/deps/libmdbx/test/main.c++ +706 -0
  171. package/deps/libmdbx/test/nested.c++ +318 -0
  172. package/deps/libmdbx/test/osal-unix.c++ +647 -0
  173. package/deps/libmdbx/test/osal-windows.c++ +440 -0
  174. package/deps/libmdbx/test/osal.h++ +41 -0
  175. package/deps/libmdbx/test/stochastic.sh +690 -0
  176. package/deps/libmdbx/test/stub/LICENSE +24 -0
  177. package/deps/libmdbx/test/stub/README.md +8 -0
  178. package/deps/libmdbx/test/stub/pthread_barrier.c +104 -0
  179. package/deps/libmdbx/test/stub/pthread_barrier.h +77 -0
  180. package/deps/libmdbx/test/test.c++ +1551 -0
  181. package/deps/libmdbx/test/test.h++ +298 -0
  182. package/deps/libmdbx/test/tmux.conf +3 -0
  183. package/deps/libmdbx/test/try.c++ +30 -0
  184. package/deps/libmdbx/test/ttl.c++ +240 -0
  185. package/deps/libmdbx/test/utils.c++ +203 -0
  186. package/deps/libmdbx/test/utils.h++ +326 -0
  187. package/deps/libmdbx/test/valgrind_suppress.txt +536 -0
  188. package/lib/mdbx_evn_async.js +211 -0
  189. package/lib/mdbx_worker.js +195 -0
  190. package/lib/nativemou.js +6 -0
  191. package/package.json +38 -0
  192. package/src/async/envmou_close.cpp +34 -0
  193. package/src/async/envmou_close.hpp +32 -0
  194. package/src/async/envmou_copy_to.cpp +29 -0
  195. package/src/async/envmou_copy_to.hpp +38 -0
  196. package/src/async/envmou_keys.cpp +201 -0
  197. package/src/async/envmou_keys.hpp +50 -0
  198. package/src/async/envmou_open.cpp +38 -0
  199. package/src/async/envmou_open.hpp +33 -0
  200. package/src/async/envmou_query.cpp +167 -0
  201. package/src/async/envmou_query.hpp +53 -0
  202. package/src/dbimou.cpp +522 -0
  203. package/src/dbimou.hpp +82 -0
  204. package/src/env_arg0.hpp +24 -0
  205. package/src/envmou.cpp +445 -0
  206. package/src/envmou.hpp +116 -0
  207. package/src/modulemou.cpp +113 -0
  208. package/src/querymou.cpp +177 -0
  209. package/src/querymou.hpp +93 -0
  210. package/src/txnmou.cpp +254 -0
  211. package/src/txnmou.hpp +122 -0
  212. package/src/typemou.hpp +239 -0
  213. package/src/valuemou.hpp +194 -0
  214. package/test/async.js +67 -0
  215. package/test/e3.js +38 -0
  216. package/test/e4.js +89 -0
  217. package/test/e5.js +162 -0
  218. package/test/test-batch-ops.js +243 -0
  219. package/test/test-cursor-mode.js +84 -0
  220. 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
+ }