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,365 @@
1
+ /// \copyright SPDX-License-Identifier: Apache-2.0
2
+ /// \note Please refer to the COPYRIGHT file for explanations license change,
3
+ /// credits and acknowledgments.
4
+ /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
5
+
6
+ #include "internals.h"
7
+
8
+ __hot int __must_check_result node_add_dupfix(MDBX_cursor *mc, size_t indx, const MDBX_val *key) {
9
+ page_t *mp = mc->pg[mc->top];
10
+ MDBX_ANALYSIS_ASSUME(key != nullptr);
11
+ DKBUF_DEBUG;
12
+ DEBUG("add to leaf2-%spage %" PRIaPGNO " index %zi, "
13
+ " key size %" PRIuPTR " [%s]",
14
+ is_subpage(mp) ? "sub-" : "", mp->pgno, indx, key ? key->iov_len : 0, DKEY_DEBUG(key));
15
+
16
+ cASSERT(mc, key);
17
+ cASSERT(mc, page_type_compat(mp) == (P_LEAF | P_DUPFIX));
18
+ const size_t ksize = mc->tree->dupfix_size;
19
+ cASSERT(mc, ksize == key->iov_len);
20
+ const size_t nkeys = page_numkeys(mp);
21
+ cASSERT(mc, (((ksize & page_numkeys(mp)) ^ mp->upper) & 1) == 0);
22
+
23
+ /* Just using these for counting */
24
+ const intptr_t lower = mp->lower + sizeof(indx_t);
25
+ const intptr_t upper = mp->upper - (ksize - sizeof(indx_t));
26
+ if (unlikely(lower > upper)) {
27
+ mc->txn->flags |= MDBX_TXN_ERROR;
28
+ return MDBX_PAGE_FULL;
29
+ }
30
+ mp->lower = (indx_t)lower;
31
+ mp->upper = (indx_t)upper;
32
+
33
+ void *const ptr = page_dupfix_ptr(mp, indx, ksize);
34
+ cASSERT(mc, nkeys >= indx);
35
+ const size_t diff = nkeys - indx;
36
+ if (likely(diff > 0))
37
+ /* Move higher keys up one slot. */
38
+ memmove(ptr_disp(ptr, ksize), ptr, diff * ksize);
39
+ /* insert new key */
40
+ memcpy(ptr, key->iov_base, ksize);
41
+
42
+ cASSERT(mc, (((ksize & page_numkeys(mp)) ^ mp->upper) & 1) == 0);
43
+ return MDBX_SUCCESS;
44
+ }
45
+
46
+ int __must_check_result node_add_branch(MDBX_cursor *mc, size_t indx, const MDBX_val *key, pgno_t pgno) {
47
+ page_t *mp = mc->pg[mc->top];
48
+ DKBUF_DEBUG;
49
+ DEBUG("add to branch-%spage %" PRIaPGNO " index %zi, node-pgno %" PRIaPGNO " key size %" PRIuPTR " [%s]",
50
+ is_subpage(mp) ? "sub-" : "", mp->pgno, indx, pgno, key ? key->iov_len : 0, DKEY_DEBUG(key));
51
+
52
+ cASSERT(mc, page_type(mp) == P_BRANCH);
53
+ STATIC_ASSERT(NODESIZE % 2 == 0);
54
+
55
+ /* Move higher pointers up one slot. */
56
+ const size_t nkeys = page_numkeys(mp);
57
+ cASSERT(mc, nkeys >= indx);
58
+ for (size_t i = nkeys; i > indx; --i)
59
+ mp->entries[i] = mp->entries[i - 1];
60
+
61
+ /* Adjust free space offsets. */
62
+ const size_t branch_bytes = branch_size(mc->txn->env, key);
63
+ const intptr_t lower = mp->lower + sizeof(indx_t);
64
+ const intptr_t upper = mp->upper - (branch_bytes - sizeof(indx_t));
65
+ if (unlikely(lower > upper)) {
66
+ mc->txn->flags |= MDBX_TXN_ERROR;
67
+ return MDBX_PAGE_FULL;
68
+ }
69
+ mp->lower = (indx_t)lower;
70
+ mp->entries[indx] = mp->upper = (indx_t)upper;
71
+
72
+ /* Write the node data. */
73
+ node_t *node = page_node(mp, indx);
74
+ node_set_pgno(node, pgno);
75
+ node_set_flags(node, 0);
76
+ UNALIGNED_POKE_8(node, node_t, extra, 0);
77
+ node_set_ks(node, 0);
78
+ if (likely(key != nullptr)) {
79
+ node_set_ks(node, key->iov_len);
80
+ memcpy(node_key(node), key->iov_base, key->iov_len);
81
+ }
82
+ return MDBX_SUCCESS;
83
+ }
84
+
85
+ __hot int __must_check_result node_add_leaf(MDBX_cursor *mc, size_t indx, const MDBX_val *key, MDBX_val *data,
86
+ unsigned flags) {
87
+ MDBX_ANALYSIS_ASSUME(key != nullptr);
88
+ MDBX_ANALYSIS_ASSUME(data != nullptr);
89
+ page_t *mp = mc->pg[mc->top];
90
+ DKBUF_DEBUG;
91
+ DEBUG("add to leaf-%spage %" PRIaPGNO " index %zi, data size %" PRIuPTR " key size %" PRIuPTR " [%s]",
92
+ is_subpage(mp) ? "sub-" : "", mp->pgno, indx, data ? data->iov_len : 0, key ? key->iov_len : 0,
93
+ DKEY_DEBUG(key));
94
+ cASSERT(mc, key != nullptr && data != nullptr);
95
+ cASSERT(mc, page_type_compat(mp) == P_LEAF);
96
+ page_t *largepage = nullptr;
97
+
98
+ size_t node_bytes;
99
+ if (unlikely(flags & N_BIG)) {
100
+ /* Data already on large/overflow page. */
101
+ STATIC_ASSERT(sizeof(pgno_t) % 2 == 0);
102
+ node_bytes = node_size_len(key->iov_len, 0) + sizeof(pgno_t) + sizeof(indx_t);
103
+ cASSERT(mc, page_room(mp) >= node_bytes);
104
+ } else if (unlikely(node_size(key, data) > mc->txn->env->leaf_nodemax)) {
105
+ /* Put data on large/overflow page. */
106
+ if (unlikely(mc->tree->flags & MDBX_DUPSORT)) {
107
+ ERROR("Unexpected target %s flags 0x%x for large data-item", "dupsort-db", mc->tree->flags);
108
+ return MDBX_PROBLEM;
109
+ }
110
+ if (unlikely(flags & (N_DUP | N_TREE))) {
111
+ ERROR("Unexpected target %s flags 0x%x for large data-item", "node", flags);
112
+ return MDBX_PROBLEM;
113
+ }
114
+ cASSERT(mc, page_room(mp) >= leaf_size(mc->txn->env, key, data));
115
+ const pgno_t ovpages = largechunk_npages(mc->txn->env, data->iov_len);
116
+ const pgr_t npr = page_new_large(mc, ovpages);
117
+ if (unlikely(npr.err != MDBX_SUCCESS))
118
+ return npr.err;
119
+ largepage = npr.page;
120
+ DEBUG("allocated %u large/overflow page(s) %" PRIaPGNO "for %" PRIuPTR " data bytes", largepage->pages,
121
+ largepage->pgno, data->iov_len);
122
+ flags |= N_BIG;
123
+ node_bytes = node_size_len(key->iov_len, 0) + sizeof(pgno_t) + sizeof(indx_t);
124
+ cASSERT(mc, node_bytes == leaf_size(mc->txn->env, key, data));
125
+ } else {
126
+ cASSERT(mc, page_room(mp) >= leaf_size(mc->txn->env, key, data));
127
+ node_bytes = node_size(key, data) + sizeof(indx_t);
128
+ cASSERT(mc, node_bytes == leaf_size(mc->txn->env, key, data));
129
+ }
130
+
131
+ /* Move higher pointers up one slot. */
132
+ const size_t nkeys = page_numkeys(mp);
133
+ cASSERT(mc, nkeys >= indx);
134
+ for (size_t i = nkeys; i > indx; --i)
135
+ mp->entries[i] = mp->entries[i - 1];
136
+
137
+ /* Adjust free space offsets. */
138
+ const intptr_t lower = mp->lower + sizeof(indx_t);
139
+ const intptr_t upper = mp->upper - (node_bytes - sizeof(indx_t));
140
+ if (unlikely(lower > upper)) {
141
+ mc->txn->flags |= MDBX_TXN_ERROR;
142
+ return MDBX_PAGE_FULL;
143
+ }
144
+ mp->lower = (indx_t)lower;
145
+ mp->entries[indx] = mp->upper = (indx_t)upper;
146
+
147
+ /* Write the node data. */
148
+ node_t *node = page_node(mp, indx);
149
+ node_set_ks(node, key->iov_len);
150
+ node_set_flags(node, (uint8_t)flags);
151
+ UNALIGNED_POKE_8(node, node_t, extra, 0);
152
+ node_set_ds(node, data->iov_len);
153
+ memcpy(node_key(node), key->iov_base, key->iov_len);
154
+
155
+ void *nodedata = node_data(node);
156
+ if (likely(largepage == nullptr)) {
157
+ if (unlikely(flags & N_BIG)) {
158
+ memcpy(nodedata, data->iov_base, sizeof(pgno_t));
159
+ return MDBX_SUCCESS;
160
+ }
161
+ } else {
162
+ poke_pgno(nodedata, largepage->pgno);
163
+ nodedata = page_data(largepage);
164
+ }
165
+ if (unlikely(flags & MDBX_RESERVE))
166
+ data->iov_base = nodedata;
167
+ else if (likely(data->iov_len /* to avoid UBSAN traps */))
168
+ memcpy(nodedata, data->iov_base, data->iov_len);
169
+ return MDBX_SUCCESS;
170
+ }
171
+
172
+ __hot void node_del(MDBX_cursor *mc, size_t ksize) {
173
+ page_t *mp = mc->pg[mc->top];
174
+ const size_t hole = mc->ki[mc->top];
175
+ const size_t nkeys = page_numkeys(mp);
176
+
177
+ DEBUG("delete node %zu on %s page %" PRIaPGNO, hole, is_leaf(mp) ? "leaf" : "branch", mp->pgno);
178
+ cASSERT(mc, hole < nkeys);
179
+
180
+ if (is_dupfix_leaf(mp)) {
181
+ cASSERT(mc, ksize >= sizeof(indx_t));
182
+ size_t diff = nkeys - 1 - hole;
183
+ void *const base = page_dupfix_ptr(mp, hole, ksize);
184
+ if (diff)
185
+ memmove(base, ptr_disp(base, ksize), diff * ksize);
186
+ cASSERT(mc, mp->lower >= sizeof(indx_t));
187
+ mp->lower -= sizeof(indx_t);
188
+ cASSERT(mc, (size_t)UINT16_MAX - mp->upper >= ksize - sizeof(indx_t));
189
+ mp->upper += (indx_t)(ksize - sizeof(indx_t));
190
+ cASSERT(mc, (((ksize & page_numkeys(mp)) ^ mp->upper) & 1) == 0);
191
+ return;
192
+ }
193
+
194
+ node_t *node = page_node(mp, hole);
195
+ cASSERT(mc, !is_branch(mp) || hole || node_ks(node) == 0);
196
+ size_t hole_size = NODESIZE + node_ks(node);
197
+ if (is_leaf(mp))
198
+ hole_size += (node_flags(node) & N_BIG) ? sizeof(pgno_t) : node_ds(node);
199
+ hole_size = EVEN_CEIL(hole_size);
200
+
201
+ const indx_t hole_offset = mp->entries[hole];
202
+ size_t r, w;
203
+ for (r = w = 0; r < nkeys; r++)
204
+ if (r != hole)
205
+ mp->entries[w++] = (mp->entries[r] < hole_offset) ? mp->entries[r] + (indx_t)hole_size : mp->entries[r];
206
+
207
+ void *const base = ptr_disp(mp, mp->upper + PAGEHDRSZ);
208
+ memmove(ptr_disp(base, hole_size), base, hole_offset - mp->upper);
209
+
210
+ cASSERT(mc, mp->lower >= sizeof(indx_t));
211
+ mp->lower -= sizeof(indx_t);
212
+ cASSERT(mc, (size_t)UINT16_MAX - mp->upper >= hole_size);
213
+ mp->upper += (indx_t)hole_size;
214
+
215
+ if (AUDIT_ENABLED()) {
216
+ const uint8_t checking = mc->checking;
217
+ mc->checking |= z_updating;
218
+ const int page_check_err = page_check(mc, mp);
219
+ mc->checking = checking;
220
+ cASSERT(mc, page_check_err == MDBX_SUCCESS);
221
+ }
222
+ }
223
+
224
+ __noinline int node_read_bigdata(MDBX_cursor *mc, const node_t *node, MDBX_val *data, const page_t *mp) {
225
+ cASSERT(mc, node_flags(node) == N_BIG && data->iov_len == node_ds(node));
226
+
227
+ pgr_t lp = page_get_large(mc, node_largedata_pgno(node), mp->txnid);
228
+ if (unlikely((lp.err != MDBX_SUCCESS))) {
229
+ DEBUG("read large/overflow page %" PRIaPGNO " failed", node_largedata_pgno(node));
230
+ return lp.err;
231
+ }
232
+
233
+ cASSERT(mc, page_type(lp.page) == P_LARGE);
234
+ data->iov_base = page_data(lp.page);
235
+ if (!MDBX_DISABLE_VALIDATION) {
236
+ const MDBX_env *env = mc->txn->env;
237
+ const size_t dsize = data->iov_len;
238
+ const unsigned npages = largechunk_npages(env, dsize);
239
+ if (unlikely(lp.page->pages < npages))
240
+ return bad_page(lp.page, "too less n-pages %u for bigdata-node (%zu bytes)", lp.page->pages, dsize);
241
+ }
242
+ return MDBX_SUCCESS;
243
+ }
244
+
245
+ node_t *node_shrink(page_t *mp, size_t indx, node_t *node) {
246
+ assert(node == page_node(mp, indx));
247
+ page_t *sp = (page_t *)node_data(node);
248
+ assert(is_subpage(sp) && page_numkeys(sp) > 0);
249
+ const size_t delta = EVEN_FLOOR(page_room(sp) /* avoid the node uneven-sized */);
250
+ if (unlikely(delta) == 0)
251
+ return node;
252
+
253
+ /* Prepare to shift upward, set len = length(subpage part to shift) */
254
+ size_t nsize = node_ds(node) - delta, len = nsize;
255
+ assert(nsize % 1 == 0);
256
+ if (!is_dupfix_leaf(sp)) {
257
+ len = PAGEHDRSZ;
258
+ page_t *xp = ptr_disp(sp, delta); /* destination subpage */
259
+ for (intptr_t i = page_numkeys(sp); --i >= 0;) {
260
+ assert(sp->entries[i] >= delta);
261
+ xp->entries[i] = (indx_t)(sp->entries[i] - delta);
262
+ }
263
+ }
264
+ assert(sp->upper >= sp->lower + delta);
265
+ sp->upper -= (indx_t)delta;
266
+ sp->pgno = mp->pgno;
267
+ node_set_ds(node, nsize);
268
+
269
+ /* Shift <lower nodes...initial part of subpage> upward */
270
+ void *const base = ptr_disp(mp, mp->upper + PAGEHDRSZ);
271
+ memmove(ptr_disp(base, delta), base, ptr_dist(sp, base) + len);
272
+
273
+ const size_t pivot = mp->entries[indx];
274
+ for (intptr_t i = page_numkeys(mp); --i >= 0;) {
275
+ if (mp->entries[i] <= pivot) {
276
+ assert((size_t)UINT16_MAX - mp->entries[i] >= delta);
277
+ mp->entries[i] += (indx_t)delta;
278
+ }
279
+ }
280
+ assert((size_t)UINT16_MAX - mp->upper >= delta);
281
+ mp->upper += (indx_t)delta;
282
+
283
+ return ptr_disp(node, delta);
284
+ }
285
+
286
+ __hot struct node_search_result node_search(MDBX_cursor *mc, const MDBX_val *key) {
287
+ page_t *mp = mc->pg[mc->top];
288
+ const intptr_t nkeys = page_numkeys(mp);
289
+ DKBUF_DEBUG;
290
+
291
+ DEBUG("searching %zu keys in %s %spage %" PRIaPGNO, nkeys, is_leaf(mp) ? "leaf" : "branch",
292
+ is_subpage(mp) ? "sub-" : "", mp->pgno);
293
+
294
+ struct node_search_result ret;
295
+ ret.exact = false;
296
+ STATIC_ASSERT(P_BRANCH == 1);
297
+ intptr_t low = mp->flags & P_BRANCH;
298
+ intptr_t high = nkeys - 1;
299
+ if (unlikely(high < low)) {
300
+ mc->ki[mc->top] = 0;
301
+ ret.node = nullptr;
302
+ return ret;
303
+ }
304
+
305
+ intptr_t i;
306
+ MDBX_cmp_func *cmp = mc->clc->k.cmp;
307
+ MDBX_val nodekey;
308
+ if (unlikely(is_dupfix_leaf(mp))) {
309
+ cASSERT(mc, mp->dupfix_ksize == mc->tree->dupfix_size);
310
+ nodekey.iov_len = mp->dupfix_ksize;
311
+ do {
312
+ i = (low + high) >> 1;
313
+ nodekey.iov_base = page_dupfix_ptr(mp, i, nodekey.iov_len);
314
+ cASSERT(mc, ptr_disp(mp, mc->txn->env->ps) >= ptr_disp(nodekey.iov_base, nodekey.iov_len));
315
+ int cr = cmp(key, &nodekey);
316
+ DEBUG("found leaf index %zu [%s], rc = %i", i, DKEY_DEBUG(&nodekey), cr);
317
+ if (cr > 0)
318
+ low = ++i;
319
+ else if (cr < 0)
320
+ high = i - 1;
321
+ else {
322
+ ret.exact = true;
323
+ break;
324
+ }
325
+ } while (likely(low <= high));
326
+
327
+ /* store the key index */
328
+ mc->ki[mc->top] = (indx_t)i;
329
+ ret.node = (i < nkeys) ? /* fake for DUPFIX */ (node_t *)(intptr_t)-1
330
+ : /* There is no entry larger or equal to the key. */ nullptr;
331
+ return ret;
332
+ }
333
+
334
+ if (MDBX_UNALIGNED_OK < 4 && is_branch(mp) && cmp == cmp_int_align2)
335
+ /* Branch pages have no data, so if using integer keys,
336
+ * alignment is guaranteed. Use faster cmp_int_align4(). */
337
+ cmp = cmp_int_align4;
338
+
339
+ node_t *node;
340
+ do {
341
+ i = (low + high) >> 1;
342
+ node = page_node(mp, i);
343
+ nodekey.iov_len = node_ks(node);
344
+ nodekey.iov_base = node_key(node);
345
+ cASSERT(mc, ptr_disp(mp, mc->txn->env->ps) >= ptr_disp(nodekey.iov_base, nodekey.iov_len));
346
+ int cr = cmp(key, &nodekey);
347
+ if (is_leaf(mp))
348
+ DEBUG("found leaf index %zu [%s], rc = %i", i, DKEY_DEBUG(&nodekey), cr);
349
+ else
350
+ DEBUG("found branch index %zu [%s -> %" PRIaPGNO "], rc = %i", i, DKEY_DEBUG(&nodekey), node_pgno(node), cr);
351
+ if (cr > 0)
352
+ low = ++i;
353
+ else if (cr < 0)
354
+ high = i - 1;
355
+ else {
356
+ ret.exact = true;
357
+ break;
358
+ }
359
+ } while (likely(low <= high));
360
+
361
+ /* store the key index */
362
+ mc->ki[mc->top] = (indx_t)i;
363
+ ret.node = (i < nkeys) ? page_node(mp, i) : /* There is no entry larger or equal to the key. */ nullptr;
364
+ return ret;
365
+ }
@@ -0,0 +1,102 @@
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
+ /* valid flags for mdbx_node_add() */
9
+ #define NODE_ADD_FLAGS (N_DUP | N_TREE | MDBX_RESERVE | MDBX_APPEND)
10
+
11
+ /* Get the page number pointed to by a branch node */
12
+ MDBX_NOTHROW_PURE_FUNCTION static inline pgno_t node_pgno(const node_t *const __restrict node) {
13
+ pgno_t pgno = UNALIGNED_PEEK_32(node, node_t, child_pgno);
14
+ return pgno;
15
+ }
16
+
17
+ /* Set the page number in a branch node */
18
+ static inline void node_set_pgno(node_t *const __restrict node, pgno_t pgno) {
19
+ assert(pgno >= MIN_PAGENO && pgno <= MAX_PAGENO);
20
+
21
+ UNALIGNED_POKE_32(node, node_t, child_pgno, (uint32_t)pgno);
22
+ }
23
+
24
+ /* Get the size of the data in a leaf node */
25
+ MDBX_NOTHROW_PURE_FUNCTION static inline size_t node_ds(const node_t *const __restrict node) {
26
+ return UNALIGNED_PEEK_32(node, node_t, dsize);
27
+ }
28
+
29
+ /* Set the size of the data for a leaf node */
30
+ static inline void node_set_ds(node_t *const __restrict node, size_t size) {
31
+ assert(size < INT_MAX);
32
+ UNALIGNED_POKE_32(node, node_t, dsize, (uint32_t)size);
33
+ }
34
+
35
+ /* The size of a key in a node */
36
+ MDBX_NOTHROW_PURE_FUNCTION static inline size_t node_ks(const node_t *const __restrict node) {
37
+ return UNALIGNED_PEEK_16(node, node_t, ksize);
38
+ }
39
+
40
+ /* Set the size of the key for a leaf node */
41
+ static inline void node_set_ks(node_t *const __restrict node, size_t size) {
42
+ assert(size < INT16_MAX);
43
+ UNALIGNED_POKE_16(node, node_t, ksize, (uint16_t)size);
44
+ }
45
+
46
+ MDBX_NOTHROW_PURE_FUNCTION static inline uint8_t node_flags(const node_t *const __restrict node) {
47
+ return UNALIGNED_PEEK_8(node, node_t, flags);
48
+ }
49
+
50
+ static inline void node_set_flags(node_t *const __restrict node, uint8_t flags) {
51
+ UNALIGNED_POKE_8(node, node_t, flags, flags);
52
+ }
53
+
54
+ /* Address of the key for the node */
55
+ MDBX_NOTHROW_PURE_FUNCTION static inline void *node_key(const node_t *const __restrict node) {
56
+ return ptr_disp(node, NODESIZE);
57
+ }
58
+
59
+ /* Address of the data for a node */
60
+ MDBX_NOTHROW_PURE_FUNCTION static inline void *node_data(const node_t *const __restrict node) {
61
+ return ptr_disp(node_key(node), node_ks(node));
62
+ }
63
+
64
+ /* Size of a node in a leaf page with a given key and data.
65
+ * This is node header plus key plus data size. */
66
+ MDBX_NOTHROW_CONST_FUNCTION static inline size_t node_size_len(const size_t key_len, const size_t value_len) {
67
+ return NODESIZE + EVEN_CEIL(key_len + value_len);
68
+ }
69
+ MDBX_NOTHROW_PURE_FUNCTION static inline size_t node_size(const MDBX_val *key, const MDBX_val *value) {
70
+ return node_size_len(key ? key->iov_len : 0, value ? value->iov_len : 0);
71
+ }
72
+
73
+ MDBX_NOTHROW_PURE_FUNCTION static inline pgno_t node_largedata_pgno(const node_t *const __restrict node) {
74
+ assert(node_flags(node) & N_BIG);
75
+ return peek_pgno(node_data(node));
76
+ }
77
+
78
+ MDBX_INTERNAL int __must_check_result node_read_bigdata(MDBX_cursor *mc, const node_t *node, MDBX_val *data,
79
+ const page_t *mp);
80
+
81
+ static inline int __must_check_result node_read(MDBX_cursor *mc, const node_t *node, MDBX_val *data, const page_t *mp) {
82
+ data->iov_len = node_ds(node);
83
+ data->iov_base = node_data(node);
84
+ if (likely(node_flags(node) != N_BIG))
85
+ return MDBX_SUCCESS;
86
+ return node_read_bigdata(mc, node, data, mp);
87
+ }
88
+
89
+ /*----------------------------------------------------------------------------*/
90
+
91
+ MDBX_INTERNAL nsr_t node_search(MDBX_cursor *mc, const MDBX_val *key);
92
+
93
+ MDBX_INTERNAL int __must_check_result node_add_branch(MDBX_cursor *mc, size_t indx, const MDBX_val *key, pgno_t pgno);
94
+
95
+ MDBX_INTERNAL int __must_check_result node_add_leaf(MDBX_cursor *mc, size_t indx, const MDBX_val *key, MDBX_val *data,
96
+ unsigned flags);
97
+
98
+ MDBX_INTERNAL int __must_check_result node_add_dupfix(MDBX_cursor *mc, size_t indx, const MDBX_val *key);
99
+
100
+ MDBX_INTERNAL void node_del(MDBX_cursor *mc, size_t ksize);
101
+
102
+ MDBX_INTERNAL node_t *node_shrink(page_t *mp, size_t indx, node_t *node);