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,205 @@
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
+ /*------------------------------------------------------------------------------
7
+ * Unaligned access */
8
+
9
+ MDBX_NOTHROW_CONST_FUNCTION MDBX_MAYBE_UNUSED static inline size_t field_alignment(size_t alignment_baseline,
10
+ size_t field_offset) {
11
+ size_t merge = alignment_baseline | (size_t)field_offset;
12
+ return merge & -(int)merge;
13
+ }
14
+
15
+ /* read-thunk for UB-sanitizer */
16
+ MDBX_NOTHROW_PURE_FUNCTION static inline uint8_t peek_u8(const uint8_t *__restrict ptr) { return *ptr; }
17
+
18
+ /* write-thunk for UB-sanitizer */
19
+ static inline void poke_u8(uint8_t *__restrict ptr, const uint8_t v) { *ptr = v; }
20
+
21
+ static inline void *bcopy_2(void *__restrict dst, const void *__restrict src) {
22
+ uint8_t *__restrict d = (uint8_t *)dst;
23
+ const uint8_t *__restrict s = (uint8_t *)src;
24
+ d[0] = s[0];
25
+ d[1] = s[1];
26
+ return d;
27
+ }
28
+
29
+ static inline void *bcopy_4(void *const __restrict dst, const void *const __restrict src) {
30
+ uint8_t *__restrict d = (uint8_t *)dst;
31
+ const uint8_t *__restrict s = (uint8_t *)src;
32
+ d[0] = s[0];
33
+ d[1] = s[1];
34
+ d[2] = s[2];
35
+ d[3] = s[3];
36
+ return d;
37
+ }
38
+
39
+ static inline void *bcopy_8(void *const __restrict dst, const void *const __restrict src) {
40
+ uint8_t *__restrict d = (uint8_t *)dst;
41
+ const uint8_t *__restrict s = (uint8_t *)src;
42
+ d[0] = s[0];
43
+ d[1] = s[1];
44
+ d[2] = s[2];
45
+ d[3] = s[3];
46
+ d[4] = s[4];
47
+ d[5] = s[5];
48
+ d[6] = s[6];
49
+ d[7] = s[7];
50
+ return d;
51
+ }
52
+
53
+ MDBX_NOTHROW_PURE_FUNCTION static inline uint16_t unaligned_peek_u16(const size_t expected_alignment,
54
+ const void *const ptr) {
55
+ assert((uintptr_t)ptr % expected_alignment == 0);
56
+ if (MDBX_UNALIGNED_OK >= 2 || (expected_alignment % sizeof(uint16_t)) == 0)
57
+ return *(const uint16_t *)ptr;
58
+ else {
59
+ #if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64)
60
+ return *(const __unaligned uint16_t *)ptr;
61
+ #else
62
+ uint16_t v;
63
+ bcopy_2((uint8_t *)&v, (const uint8_t *)ptr);
64
+ return v;
65
+ #endif /* _MSC_VER || __unaligned */
66
+ }
67
+ }
68
+
69
+ static inline void unaligned_poke_u16(const size_t expected_alignment, void *const __restrict ptr, const uint16_t v) {
70
+ assert((uintptr_t)ptr % expected_alignment == 0);
71
+ if (MDBX_UNALIGNED_OK >= 2 || (expected_alignment % sizeof(v)) == 0)
72
+ *(uint16_t *)ptr = v;
73
+ else {
74
+ #if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64)
75
+ *((uint16_t __unaligned *)ptr) = v;
76
+ #else
77
+ bcopy_2((uint8_t *)ptr, (const uint8_t *)&v);
78
+ #endif /* _MSC_VER || __unaligned */
79
+ }
80
+ }
81
+
82
+ MDBX_NOTHROW_PURE_FUNCTION static inline uint32_t unaligned_peek_u32(const size_t expected_alignment,
83
+ const void *const __restrict ptr) {
84
+ assert((uintptr_t)ptr % expected_alignment == 0);
85
+ if (MDBX_UNALIGNED_OK >= 4 || (expected_alignment % sizeof(uint32_t)) == 0)
86
+ return *(const uint32_t *)ptr;
87
+ else if ((expected_alignment % sizeof(uint16_t)) == 0) {
88
+ const uint16_t lo = ((const uint16_t *)ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__];
89
+ const uint16_t hi = ((const uint16_t *)ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__];
90
+ return lo | (uint32_t)hi << 16;
91
+ } else {
92
+ #if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64)
93
+ return *(const __unaligned uint32_t *)ptr;
94
+ #else
95
+ uint32_t v;
96
+ bcopy_4((uint8_t *)&v, (const uint8_t *)ptr);
97
+ return v;
98
+ #endif /* _MSC_VER || __unaligned */
99
+ }
100
+ }
101
+
102
+ static inline void unaligned_poke_u32(const size_t expected_alignment, void *const __restrict ptr, const uint32_t v) {
103
+ assert((uintptr_t)ptr % expected_alignment == 0);
104
+ if (MDBX_UNALIGNED_OK >= 4 || (expected_alignment % sizeof(v)) == 0)
105
+ *(uint32_t *)ptr = v;
106
+ else if ((expected_alignment % sizeof(uint16_t)) == 0) {
107
+ ((uint16_t *)ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__] = (uint16_t)v;
108
+ ((uint16_t *)ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__] = (uint16_t)(v >> 16);
109
+ } else {
110
+ #if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64)
111
+ *((uint32_t __unaligned *)ptr) = v;
112
+ #else
113
+ bcopy_4((uint8_t *)ptr, (const uint8_t *)&v);
114
+ #endif /* _MSC_VER || __unaligned */
115
+ }
116
+ }
117
+
118
+ MDBX_NOTHROW_PURE_FUNCTION static inline uint64_t unaligned_peek_u64(const size_t expected_alignment,
119
+ const void *const __restrict ptr) {
120
+ assert((uintptr_t)ptr % expected_alignment == 0);
121
+ if (MDBX_UNALIGNED_OK >= 8 || (expected_alignment % sizeof(uint64_t)) == 0)
122
+ return *(const uint64_t *)ptr;
123
+ else if ((expected_alignment % sizeof(uint32_t)) == 0) {
124
+ const uint32_t lo = ((const uint32_t *)ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__];
125
+ const uint32_t hi = ((const uint32_t *)ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__];
126
+ return lo | (uint64_t)hi << 32;
127
+ } else {
128
+ #if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64)
129
+ return *(const __unaligned uint64_t *)ptr;
130
+ #else
131
+ uint64_t v;
132
+ bcopy_8((uint8_t *)&v, (const uint8_t *)ptr);
133
+ return v;
134
+ #endif /* _MSC_VER || __unaligned */
135
+ }
136
+ }
137
+
138
+ static inline uint64_t unaligned_peek_u64_volatile(const size_t expected_alignment,
139
+ const volatile void *const __restrict ptr) {
140
+ assert((uintptr_t)ptr % expected_alignment == 0);
141
+ assert(expected_alignment % sizeof(uint32_t) == 0);
142
+ if (MDBX_UNALIGNED_OK >= 8 || (expected_alignment % sizeof(uint64_t)) == 0)
143
+ return *(const volatile uint64_t *)ptr;
144
+ else {
145
+ #if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64)
146
+ return *(const volatile __unaligned uint64_t *)ptr;
147
+ #else
148
+ const uint32_t lo = ((const volatile uint32_t *)ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__];
149
+ const uint32_t hi = ((const volatile uint32_t *)ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__];
150
+ return lo | (uint64_t)hi << 32;
151
+ #endif /* _MSC_VER || __unaligned */
152
+ }
153
+ }
154
+
155
+ static inline void unaligned_poke_u64(const size_t expected_alignment, void *const __restrict ptr, const uint64_t v) {
156
+ assert((uintptr_t)ptr % expected_alignment == 0);
157
+ if (MDBX_UNALIGNED_OK >= 8 || (expected_alignment % sizeof(v)) == 0)
158
+ *(uint64_t *)ptr = v;
159
+ else if ((expected_alignment % sizeof(uint32_t)) == 0) {
160
+ ((uint32_t *)ptr)[__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__] = (uint32_t)v;
161
+ ((uint32_t *)ptr)[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__] = (uint32_t)(v >> 32);
162
+ } else {
163
+ #if defined(__unaligned) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64)
164
+ *((uint64_t __unaligned *)ptr) = v;
165
+ #else
166
+ bcopy_8((uint8_t *)ptr, (const uint8_t *)&v);
167
+ #endif /* _MSC_VER || __unaligned */
168
+ }
169
+ }
170
+
171
+ #define UNALIGNED_PEEK_8(ptr, struct, field) peek_u8(ptr_disp(ptr, offsetof(struct, field)))
172
+ #define UNALIGNED_POKE_8(ptr, struct, field, value) poke_u8(ptr_disp(ptr, offsetof(struct, field)), value)
173
+
174
+ #define UNALIGNED_PEEK_16(ptr, struct, field) unaligned_peek_u16(1, ptr_disp(ptr, offsetof(struct, field)))
175
+ #define UNALIGNED_POKE_16(ptr, struct, field, value) \
176
+ unaligned_poke_u16(1, ptr_disp(ptr, offsetof(struct, field)), value)
177
+
178
+ #define UNALIGNED_PEEK_32(ptr, struct, field) unaligned_peek_u32(1, ptr_disp(ptr, offsetof(struct, field)))
179
+ #define UNALIGNED_POKE_32(ptr, struct, field, value) \
180
+ unaligned_poke_u32(1, ptr_disp(ptr, offsetof(struct, field)), value)
181
+
182
+ #define UNALIGNED_PEEK_64(ptr, struct, field) unaligned_peek_u64(1, ptr_disp(ptr, offsetof(struct, field)))
183
+ #define UNALIGNED_POKE_64(ptr, struct, field, value) \
184
+ unaligned_poke_u64(1, ptr_disp(ptr, offsetof(struct, field)), value)
185
+
186
+ MDBX_NOTHROW_PURE_FUNCTION static inline pgno_t peek_pgno(const void *const __restrict ptr) {
187
+ if (sizeof(pgno_t) == sizeof(uint32_t))
188
+ return (pgno_t)unaligned_peek_u32(1, ptr);
189
+ else if (sizeof(pgno_t) == sizeof(uint64_t))
190
+ return (pgno_t)unaligned_peek_u64(1, ptr);
191
+ else {
192
+ pgno_t pgno;
193
+ memcpy(&pgno, ptr, sizeof(pgno));
194
+ return pgno;
195
+ }
196
+ }
197
+
198
+ static inline void poke_pgno(void *const __restrict ptr, const pgno_t pgno) {
199
+ if (sizeof(pgno) == sizeof(uint32_t))
200
+ unaligned_poke_u32(1, ptr, pgno);
201
+ else if (sizeof(pgno) == sizeof(uint64_t))
202
+ unaligned_poke_u64(1, ptr, pgno);
203
+ else
204
+ memcpy(ptr, &pgno, sizeof(pgno));
205
+ }
@@ -0,0 +1,32 @@
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
+ MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION MDBX_INTERNAL unsigned log2n_powerof2(size_t value_uintptr) {
7
+ assert(value_uintptr > 0 && value_uintptr < INT32_MAX && is_powerof2(value_uintptr));
8
+ assert((value_uintptr & -(intptr_t)value_uintptr) == value_uintptr);
9
+ const uint32_t value_uint32 = (uint32_t)value_uintptr;
10
+ #if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctz)
11
+ STATIC_ASSERT(sizeof(value_uint32) <= sizeof(unsigned));
12
+ return __builtin_ctz(value_uint32);
13
+ #elif defined(_MSC_VER)
14
+ unsigned long index;
15
+ STATIC_ASSERT(sizeof(value_uint32) <= sizeof(long));
16
+ _BitScanForward(&index, value_uint32);
17
+ return index;
18
+ #else
19
+ static const uint8_t debruijn_ctz32[32] = {0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
20
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
21
+ return debruijn_ctz32[(uint32_t)(value_uint32 * 0x077CB531ul) >> 27];
22
+ #endif
23
+ }
24
+
25
+ MDBX_NOTHROW_CONST_FUNCTION MDBX_INTERNAL uint64_t rrxmrrxmsx_0(uint64_t v) {
26
+ /* Pelle Evensen's mixer, https://bit.ly/2HOfynt */
27
+ v ^= (v << 39 | v >> 25) ^ (v << 14 | v >> 50);
28
+ v *= UINT64_C(0xA24BAED4963EE407);
29
+ v ^= (v << 40 | v >> 24) ^ (v << 15 | v >> 49);
30
+ v *= UINT64_C(0x9FB21C651E98DF25);
31
+ return v ^ v >> 28;
32
+ }
@@ -0,0 +1,76 @@
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
+ /* Test if the flags f are set in a flag word w. */
7
+ #define F_ISSET(w, f) (((w) & (f)) == (f))
8
+
9
+ /* Round n up to an even number. */
10
+ #define EVEN_CEIL(n) (((n) + 1UL) & -2L) /* sign-extending -2 to match n+1U */
11
+
12
+ /* Round n down to an even number. */
13
+ #define EVEN_FLOOR(n) ((n) & ~(size_t)1)
14
+
15
+ /*
16
+ * /
17
+ * | -1, a < b
18
+ * CMP2INT(a,b) = < 0, a == b
19
+ * | 1, a > b
20
+ * \
21
+ */
22
+ #define CMP2INT(a, b) (((a) != (b)) ? (((a) < (b)) ? -1 : 1) : 0)
23
+
24
+ /* Pointer displacement without casting to char* to avoid pointer-aliasing */
25
+ #define ptr_disp(ptr, disp) ((void *)(((intptr_t)(ptr)) + ((intptr_t)(disp))))
26
+
27
+ /* Pointer distance as signed number of bytes */
28
+ #define ptr_dist(more, less) (((intptr_t)(more)) - ((intptr_t)(less)))
29
+
30
+ #define MDBX_ASAN_POISON_MEMORY_REGION(addr, size) \
31
+ do { \
32
+ TRACE("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr), (size_t)(size), __LINE__); \
33
+ ASAN_POISON_MEMORY_REGION(addr, size); \
34
+ } while (0)
35
+
36
+ #define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size) \
37
+ do { \
38
+ TRACE("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr), (size_t)(size), __LINE__); \
39
+ ASAN_UNPOISON_MEMORY_REGION(addr, size); \
40
+ } while (0)
41
+
42
+ MDBX_NOTHROW_CONST_FUNCTION MDBX_MAYBE_UNUSED static inline size_t branchless_abs(intptr_t value) {
43
+ assert(value > INT_MIN);
44
+ const size_t expanded_sign = (size_t)(value >> (sizeof(value) * CHAR_BIT - 1));
45
+ return ((size_t)value + expanded_sign) ^ expanded_sign;
46
+ }
47
+
48
+ MDBX_NOTHROW_CONST_FUNCTION MDBX_MAYBE_UNUSED static inline bool is_powerof2(size_t x) { return (x & (x - 1)) == 0; }
49
+
50
+ MDBX_NOTHROW_CONST_FUNCTION MDBX_MAYBE_UNUSED static inline size_t floor_powerof2(size_t value, size_t granularity) {
51
+ assert(is_powerof2(granularity));
52
+ return value & ~(granularity - 1);
53
+ }
54
+
55
+ MDBX_NOTHROW_CONST_FUNCTION MDBX_MAYBE_UNUSED static inline size_t ceil_powerof2(size_t value, size_t granularity) {
56
+ return floor_powerof2(value + granularity - 1, granularity);
57
+ }
58
+
59
+ MDBX_NOTHROW_CONST_FUNCTION MDBX_MAYBE_UNUSED MDBX_INTERNAL unsigned log2n_powerof2(size_t value_uintptr);
60
+
61
+ MDBX_NOTHROW_CONST_FUNCTION MDBX_INTERNAL uint64_t rrxmrrxmsx_0(uint64_t v);
62
+
63
+ struct monotime_cache {
64
+ uint64_t value;
65
+ int expire_countdown;
66
+ };
67
+
68
+ MDBX_MAYBE_UNUSED static inline uint64_t monotime_since_cached(uint64_t begin_timestamp, struct monotime_cache *cache) {
69
+ if (cache->expire_countdown)
70
+ cache->expire_countdown -= 1;
71
+ else {
72
+ cache->value = osal_monotime();
73
+ cache->expire_countdown = 42 / 3;
74
+ }
75
+ return cache->value - begin_timestamp;
76
+ }
@@ -0,0 +1,44 @@
1
+ /* This is CMake-template for libmdbx's version.c
2
+ ******************************************************************************/
3
+
4
+ #include "internals.h"
5
+
6
+ #if MDBX_VERSION_MAJOR != ${MDBX_VERSION_MAJOR} || MDBX_VERSION_MINOR != ${MDBX_VERSION_MINOR}
7
+ #error "API version mismatch! Had `git fetch --tags` done?"
8
+ #endif
9
+
10
+ static const char sourcery[] = MDBX_STRINGIFY(MDBX_BUILD_SOURCERY);
11
+
12
+ __dll_export
13
+ #ifdef __attribute_used__
14
+ __attribute_used__
15
+ #elif defined(__GNUC__) || __has_attribute(__used__)
16
+ __attribute__((__used__))
17
+ #endif
18
+ #ifdef __attribute_externally_visible__
19
+ __attribute_externally_visible__
20
+ #elif (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__externally_visible__)
21
+ __attribute__((__externally_visible__))
22
+ #endif
23
+ const struct MDBX_version_info mdbx_version = {
24
+ ${MDBX_VERSION_MAJOR},
25
+ ${MDBX_VERSION_MINOR},
26
+ ${MDBX_VERSION_PATCH},
27
+ ${MDBX_VERSION_TWEAK},
28
+ "@MDBX_VERSION_PRERELEASE@", /* pre-release suffix of SemVer
29
+ @MDBX_VERSION_PURE@ */
30
+ {"@MDBX_GIT_TIMESTAMP@", "@MDBX_GIT_TREE@", "@MDBX_GIT_COMMIT@", "@MDBX_GIT_DESCRIBE@"},
31
+ sourcery};
32
+
33
+ __dll_export
34
+ #ifdef __attribute_used__
35
+ __attribute_used__
36
+ #elif defined(__GNUC__) || __has_attribute(__used__)
37
+ __attribute__((__used__))
38
+ #endif
39
+ #ifdef __attribute_externally_visible__
40
+ __attribute_externally_visible__
41
+ #elif (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(__externally_visible__)
42
+ __attribute__((__externally_visible__))
43
+ #endif
44
+ const char *const mdbx_sourcery_anchor = sourcery;
@@ -0,0 +1,290 @@
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
+ typedef struct walk_ctx {
7
+ void *userctx;
8
+ walk_options_t options;
9
+ int deep;
10
+ walk_func *visitor;
11
+ MDBX_txn *txn;
12
+ MDBX_cursor *cursor;
13
+ } walk_ctx_t;
14
+
15
+ __cold static int walk_tbl(walk_ctx_t *ctx, walk_tbl_t *tbl);
16
+
17
+ static page_type_t walk_page_type(const page_t *mp) {
18
+ if (mp)
19
+ switch (mp->flags & ~P_SPILLED) {
20
+ case P_BRANCH:
21
+ return page_branch;
22
+ case P_LEAF:
23
+ return page_leaf;
24
+ case P_LEAF | P_DUPFIX:
25
+ return page_dupfix_leaf;
26
+ case P_LARGE:
27
+ return page_large;
28
+ }
29
+ return page_broken;
30
+ }
31
+
32
+ static page_type_t walk_subpage_type(const page_t *sp) {
33
+ switch (sp->flags & /* ignore legacy P_DIRTY flag */ ~P_LEGACY_DIRTY) {
34
+ case P_LEAF | P_SUBP:
35
+ return page_sub_leaf;
36
+ case P_LEAF | P_DUPFIX | P_SUBP:
37
+ return page_sub_dupfix_leaf;
38
+ default:
39
+ return page_sub_broken;
40
+ }
41
+ }
42
+
43
+ /* Depth-first tree traversal. */
44
+ __cold static int walk_pgno(walk_ctx_t *ctx, walk_tbl_t *tbl, const pgno_t pgno, txnid_t parent_txnid) {
45
+ assert(pgno != P_INVALID);
46
+ page_t *mp = nullptr;
47
+ int err = page_get(ctx->cursor, pgno, &mp, parent_txnid);
48
+
49
+ const page_type_t type = walk_page_type(mp);
50
+ const size_t nentries = mp ? page_numkeys(mp) : 0;
51
+ size_t header_size = (mp && !is_dupfix_leaf(mp)) ? PAGEHDRSZ + mp->lower : PAGEHDRSZ;
52
+ size_t payload_size = 0;
53
+ size_t unused_size = (mp ? page_room(mp) : ctx->txn->env->ps - header_size) - payload_size;
54
+ size_t align_bytes = 0;
55
+
56
+ for (size_t i = 0; err == MDBX_SUCCESS && i < nentries; ++i) {
57
+ if (type == page_dupfix_leaf) {
58
+ /* DUPFIX pages have no entries[] or node headers */
59
+ payload_size += mp->dupfix_ksize;
60
+ continue;
61
+ }
62
+
63
+ const node_t *node = page_node(mp, i);
64
+ header_size += NODESIZE;
65
+ const size_t node_key_size = node_ks(node);
66
+ payload_size += node_key_size;
67
+
68
+ if (type == page_branch) {
69
+ assert(i > 0 || node_ks(node) == 0);
70
+ align_bytes += node_key_size & 1;
71
+ continue;
72
+ }
73
+
74
+ const size_t node_data_size = node_ds(node);
75
+ assert(type == page_leaf);
76
+ switch (node_flags(node)) {
77
+ case 0 /* usual node */:
78
+ payload_size += node_data_size;
79
+ align_bytes += (node_key_size + node_data_size) & 1;
80
+ break;
81
+
82
+ case N_BIG /* long data on the large/overflow page */: {
83
+ const pgno_t large_pgno = node_largedata_pgno(node);
84
+ const size_t over_payload = node_data_size;
85
+ const size_t over_header = PAGEHDRSZ;
86
+
87
+ assert(err == MDBX_SUCCESS);
88
+ pgr_t lp = page_get_large(ctx->cursor, large_pgno, mp->txnid);
89
+ const size_t npages = ((err = lp.err) == MDBX_SUCCESS) ? lp.page->pages : 1;
90
+ const size_t pagesize = pgno2bytes(ctx->txn->env, npages);
91
+ const size_t over_unused = pagesize - over_payload - over_header;
92
+ const int rc = ctx->visitor(large_pgno, npages, ctx->userctx, ctx->deep, tbl, pagesize, page_large, err, 1,
93
+ over_payload, over_header, over_unused);
94
+ if (unlikely(rc != MDBX_SUCCESS))
95
+ return (rc == MDBX_RESULT_TRUE) ? MDBX_SUCCESS : rc;
96
+ payload_size += sizeof(pgno_t);
97
+ align_bytes += node_key_size & 1;
98
+ } break;
99
+
100
+ case N_TREE /* sub-db */: {
101
+ if (unlikely(node_data_size != sizeof(tree_t))) {
102
+ ERROR("%s/%d: %s %u", "MDBX_CORRUPTED", MDBX_CORRUPTED, "invalid table node size", (unsigned)node_data_size);
103
+ assert(err == MDBX_CORRUPTED);
104
+ err = MDBX_CORRUPTED;
105
+ }
106
+ header_size += node_data_size;
107
+ align_bytes += (node_key_size + node_data_size) & 1;
108
+ } break;
109
+
110
+ case N_TREE | N_DUP /* dupsorted sub-tree */:
111
+ if (unlikely(node_data_size != sizeof(tree_t))) {
112
+ ERROR("%s/%d: %s %u", "MDBX_CORRUPTED", MDBX_CORRUPTED, "invalid sub-tree node size", (unsigned)node_data_size);
113
+ assert(err == MDBX_CORRUPTED);
114
+ err = MDBX_CORRUPTED;
115
+ }
116
+ header_size += node_data_size;
117
+ align_bytes += (node_key_size + node_data_size) & 1;
118
+ break;
119
+
120
+ case N_DUP /* short sub-page */: {
121
+ if (unlikely(node_data_size <= PAGEHDRSZ || (node_data_size & 1))) {
122
+ ERROR("%s/%d: %s %u", "MDBX_CORRUPTED", MDBX_CORRUPTED, "invalid sub-page node size", (unsigned)node_data_size);
123
+ assert(err == MDBX_CORRUPTED);
124
+ err = MDBX_CORRUPTED;
125
+ break;
126
+ }
127
+
128
+ const page_t *const sp = node_data(node);
129
+ const page_type_t subtype = walk_subpage_type(sp);
130
+ const size_t nsubkeys = page_numkeys(sp);
131
+ if (unlikely(subtype == page_sub_broken)) {
132
+ ERROR("%s/%d: %s 0x%x", "MDBX_CORRUPTED", MDBX_CORRUPTED, "invalid sub-page flags", sp->flags);
133
+ assert(err == MDBX_CORRUPTED);
134
+ err = MDBX_CORRUPTED;
135
+ }
136
+
137
+ size_t subheader_size = is_dupfix_leaf(sp) ? PAGEHDRSZ : PAGEHDRSZ + sp->lower;
138
+ size_t subunused_size = page_room(sp);
139
+ size_t subpayload_size = 0;
140
+ size_t subalign_bytes = 0;
141
+
142
+ for (size_t ii = 0; err == MDBX_SUCCESS && ii < nsubkeys; ++ii) {
143
+ if (subtype == page_sub_dupfix_leaf) {
144
+ /* DUPFIX pages have no entries[] or node headers */
145
+ subpayload_size += sp->dupfix_ksize;
146
+ } else {
147
+ assert(subtype == page_sub_leaf);
148
+ const node_t *subnode = page_node(sp, ii);
149
+ const size_t subnode_size = node_ks(subnode) + node_ds(subnode);
150
+ subheader_size += NODESIZE;
151
+ subpayload_size += subnode_size;
152
+ subalign_bytes += subnode_size & 1;
153
+ if (unlikely(node_flags(subnode) != 0)) {
154
+ ERROR("%s/%d: %s 0x%x", "MDBX_CORRUPTED", MDBX_CORRUPTED, "unexpected sub-node flags", node_flags(subnode));
155
+ assert(err == MDBX_CORRUPTED);
156
+ err = MDBX_CORRUPTED;
157
+ }
158
+ }
159
+ }
160
+
161
+ const int rc = ctx->visitor(pgno, 0, ctx->userctx, ctx->deep + 1, tbl, node_data_size, subtype, err, nsubkeys,
162
+ subpayload_size, subheader_size, subunused_size + subalign_bytes);
163
+ if (unlikely(rc != MDBX_SUCCESS))
164
+ return (rc == MDBX_RESULT_TRUE) ? MDBX_SUCCESS : rc;
165
+ header_size += subheader_size;
166
+ unused_size += subunused_size;
167
+ payload_size += subpayload_size;
168
+ align_bytes += subalign_bytes + (node_key_size & 1);
169
+ } break;
170
+
171
+ default:
172
+ ERROR("%s/%d: %s 0x%x", "MDBX_CORRUPTED", MDBX_CORRUPTED, "invalid node flags", node_flags(node));
173
+ assert(err == MDBX_CORRUPTED);
174
+ err = MDBX_CORRUPTED;
175
+ }
176
+ }
177
+
178
+ const int rc = ctx->visitor(pgno, 1, ctx->userctx, ctx->deep, tbl, ctx->txn->env->ps, type, err, nentries,
179
+ payload_size, header_size, unused_size + align_bytes);
180
+ if (unlikely(rc != MDBX_SUCCESS))
181
+ return (rc == MDBX_RESULT_TRUE) ? MDBX_SUCCESS : rc;
182
+
183
+ for (size_t i = 0; err == MDBX_SUCCESS && i < nentries; ++i) {
184
+ if (type == page_dupfix_leaf)
185
+ continue;
186
+
187
+ node_t *node = page_node(mp, i);
188
+ if (type == page_branch) {
189
+ assert(err == MDBX_SUCCESS);
190
+ ctx->deep += 1;
191
+ err = walk_pgno(ctx, tbl, node_pgno(node), mp->txnid);
192
+ ctx->deep -= 1;
193
+ if (unlikely(err != MDBX_SUCCESS)) {
194
+ if (err == MDBX_RESULT_TRUE)
195
+ break;
196
+ return err;
197
+ }
198
+ continue;
199
+ }
200
+
201
+ assert(type == page_leaf);
202
+ switch (node_flags(node)) {
203
+ default:
204
+ continue;
205
+
206
+ case N_TREE /* sub-db */:
207
+ if (unlikely(node_ds(node) != sizeof(tree_t))) {
208
+ ERROR("%s/%d: %s %u", "MDBX_CORRUPTED", MDBX_CORRUPTED, "invalid sub-tree node size", (unsigned)node_ds(node));
209
+ assert(err == MDBX_CORRUPTED);
210
+ err = MDBX_CORRUPTED;
211
+ } else {
212
+ tree_t aligned_db;
213
+ memcpy(&aligned_db, node_data(node), sizeof(aligned_db));
214
+ walk_tbl_t table = {{node_key(node), node_ks(node)}, nullptr, nullptr};
215
+ table.internal = &aligned_db;
216
+ assert(err == MDBX_SUCCESS);
217
+ ctx->deep += 1;
218
+ err = walk_tbl(ctx, &table);
219
+ ctx->deep -= 1;
220
+ }
221
+ break;
222
+
223
+ case N_TREE | N_DUP /* dupsorted sub-tree */:
224
+ if (unlikely(node_ds(node) != sizeof(tree_t))) {
225
+ ERROR("%s/%d: %s %u", "MDBX_CORRUPTED", MDBX_CORRUPTED, "invalid dupsort sub-tree node size",
226
+ (unsigned)node_ds(node));
227
+ assert(err == MDBX_CORRUPTED);
228
+ err = MDBX_CORRUPTED;
229
+ } else {
230
+ tree_t aligned_db;
231
+ memcpy(&aligned_db, node_data(node), sizeof(aligned_db));
232
+ assert(err == MDBX_SUCCESS);
233
+ err = cursor_dupsort_setup(ctx->cursor, node, mp);
234
+ if (likely(err == MDBX_SUCCESS)) {
235
+ assert(ctx->cursor->subcur == &container_of(ctx->cursor, cursor_couple_t, outer)->inner);
236
+ ctx->cursor = &ctx->cursor->subcur->cursor;
237
+ ctx->deep += 1;
238
+ tbl->nested = &aligned_db;
239
+ err = walk_pgno(ctx, tbl, aligned_db.root, mp->txnid);
240
+ tbl->nested = nullptr;
241
+ ctx->deep -= 1;
242
+ subcur_t *inner_xcursor = container_of(ctx->cursor, subcur_t, cursor);
243
+ cursor_couple_t *couple = container_of(inner_xcursor, cursor_couple_t, inner);
244
+ ctx->cursor = &couple->outer;
245
+ }
246
+ }
247
+ break;
248
+ }
249
+ }
250
+
251
+ return MDBX_SUCCESS;
252
+ }
253
+
254
+ __cold static int walk_tbl(walk_ctx_t *ctx, walk_tbl_t *tbl) {
255
+ tree_t *const db = tbl->internal;
256
+ if (unlikely(db->root == P_INVALID))
257
+ return MDBX_SUCCESS; /* empty db */
258
+
259
+ kvx_t kvx = {.clc = {.k = {.lmin = INT_MAX}, .v = {.lmin = INT_MAX}}};
260
+ cursor_couple_t couple;
261
+ int rc = cursor_init4walk(&couple, ctx->txn, db, &kvx);
262
+ if (unlikely(rc != MDBX_SUCCESS))
263
+ return rc;
264
+
265
+ const uint8_t cursor_checking = (ctx->options & dont_check_keys_ordering) ? z_pagecheck | z_ignord : z_pagecheck;
266
+ couple.outer.checking |= cursor_checking;
267
+ couple.inner.cursor.checking |= cursor_checking;
268
+ couple.outer.next = ctx->cursor;
269
+ couple.outer.top_and_flags = z_disable_tree_search_fastpath;
270
+ ctx->cursor = &couple.outer;
271
+ rc = walk_pgno(ctx, tbl, db->root, db->mod_txnid ? db->mod_txnid : ctx->txn->txnid);
272
+ ctx->cursor = couple.outer.next;
273
+ return rc;
274
+ }
275
+
276
+ __cold int walk_pages(MDBX_txn *txn, walk_func *visitor, void *user, walk_options_t options) {
277
+ int rc = check_txn(txn, MDBX_TXN_BLOCKED);
278
+ if (unlikely(rc != MDBX_SUCCESS))
279
+ return rc;
280
+
281
+ walk_ctx_t ctx = {.txn = txn, .userctx = user, .visitor = visitor, .options = options};
282
+ walk_tbl_t tbl = {.name = {.iov_base = MDBX_CHK_GC}, .internal = &txn->dbs[FREE_DBI]};
283
+ rc = walk_tbl(&ctx, &tbl);
284
+ if (!MDBX_IS_ERROR(rc)) {
285
+ tbl.name.iov_base = MDBX_CHK_MAIN;
286
+ tbl.internal = &txn->dbs[MAIN_DBI];
287
+ rc = walk_tbl(&ctx, &tbl);
288
+ }
289
+ return rc;
290
+ }
@@ -0,0 +1,20 @@
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
+ typedef struct walk_tbl {
9
+ MDBX_val name;
10
+ tree_t *internal, *nested;
11
+ } walk_tbl_t;
12
+
13
+ typedef int walk_func(const size_t pgno, const unsigned number, void *const ctx, const int deep,
14
+ const walk_tbl_t *table, const size_t page_size, const page_type_t page_type,
15
+ const MDBX_error_t err, const size_t nentries, const size_t payload_bytes,
16
+ const size_t header_bytes, const size_t unused_bytes);
17
+
18
+ typedef enum walk_options { dont_check_keys_ordering = 1 } walk_options_t;
19
+
20
+ MDBX_INTERNAL int walk_pages(MDBX_txn *txn, walk_func *visitor, void *user, walk_options_t options);