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
+ /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
3
+
4
+ #include "internals.h"
5
+
6
+ typedef struct diff_result {
7
+ ptrdiff_t diff;
8
+ intptr_t level;
9
+ ptrdiff_t root_nkeys;
10
+ } diff_t;
11
+
12
+ /* calculates: r = x - y */
13
+ __hot static int cursor_diff(const MDBX_cursor *const __restrict x, const MDBX_cursor *const __restrict y,
14
+ diff_t *const __restrict r) {
15
+ r->diff = 0;
16
+ r->level = 0;
17
+ r->root_nkeys = 0;
18
+
19
+ int rc = check_txn(x->txn, MDBX_TXN_BLOCKED);
20
+ if (unlikely(rc != MDBX_SUCCESS))
21
+ return rc;
22
+
23
+ if (unlikely(x->txn != y->txn))
24
+ return MDBX_BAD_TXN;
25
+
26
+ if (unlikely(y->dbi_state != x->dbi_state))
27
+ return MDBX_EINVAL;
28
+
29
+ const intptr_t depth = (x->top < y->top) ? x->top : y->top;
30
+ if (unlikely(depth < 0))
31
+ return MDBX_ENODATA;
32
+
33
+ r->root_nkeys = page_numkeys(x->pg[0]);
34
+ intptr_t nkeys = r->root_nkeys;
35
+ for (;;) {
36
+ if (unlikely(y->pg[r->level] != x->pg[r->level])) {
37
+ ERROR("Mismatch cursors's pages at %zu level", r->level);
38
+ return MDBX_PROBLEM;
39
+ }
40
+ r->diff = x->ki[r->level] - y->ki[r->level];
41
+ if (r->diff)
42
+ break;
43
+ r->level += 1;
44
+ if (r->level > depth) {
45
+ r->diff = CMP2INT(x->flags & z_eof_hard, y->flags & z_eof_hard);
46
+ return MDBX_SUCCESS;
47
+ }
48
+ nkeys = page_numkeys(x->pg[r->level]);
49
+ }
50
+
51
+ while (unlikely(r->diff == 1) && likely(r->level < depth)) {
52
+ r->level += 1;
53
+ /* DB'PAGEs: 0------------------>MAX
54
+ *
55
+ * CURSORs: y < x
56
+ * STACK[i ]: |
57
+ * STACK[+1]: ...y++N|0++x...
58
+ */
59
+ nkeys = page_numkeys(y->pg[r->level]);
60
+ r->diff = (nkeys - y->ki[r->level]) + x->ki[r->level];
61
+ assert(r->diff > 0);
62
+ }
63
+
64
+ while (unlikely(r->diff == -1) && likely(r->level < depth)) {
65
+ r->level += 1;
66
+ /* DB'PAGEs: 0------------------>MAX
67
+ *
68
+ * CURSORs: x < y
69
+ * STACK[i ]: |
70
+ * STACK[+1]: ...x--N|0--y...
71
+ */
72
+ nkeys = page_numkeys(x->pg[r->level]);
73
+ r->diff = -(nkeys - x->ki[r->level]) - y->ki[r->level];
74
+ assert(r->diff < 0);
75
+ }
76
+
77
+ return MDBX_SUCCESS;
78
+ }
79
+
80
+ __hot static ptrdiff_t estimate(const tree_t *tree, diff_t *const __restrict dr) {
81
+ /* root: branch-page => scale = leaf-factor * branch-factor^(N-1)
82
+ * level-1: branch-page(s) => scale = leaf-factor * branch-factor^2
83
+ * level-2: branch-page(s) => scale = leaf-factor * branch-factor
84
+ * level-N: branch-page(s) => scale = leaf-factor
85
+ * leaf-level: leaf-page(s) => scale = 1
86
+ */
87
+ ptrdiff_t btree_power = (ptrdiff_t)tree->height - 2 - (ptrdiff_t)dr->level;
88
+ if (btree_power < 0)
89
+ return dr->diff;
90
+
91
+ ptrdiff_t estimated = (ptrdiff_t)tree->items * dr->diff / (ptrdiff_t)tree->leaf_pages;
92
+ if (btree_power == 0)
93
+ return estimated;
94
+
95
+ if (tree->height < 4) {
96
+ assert(dr->level == 0 && btree_power == 1);
97
+ return (ptrdiff_t)tree->items * dr->diff / (ptrdiff_t)dr->root_nkeys;
98
+ }
99
+
100
+ /* average_branchpage_fillfactor = total(branch_entries) / branch_pages
101
+ total(branch_entries) = leaf_pages + branch_pages - 1 (root page) */
102
+ const size_t log2_fixedpoint = sizeof(size_t) - 1;
103
+ const size_t half = UINT64_C(1) << (log2_fixedpoint - 1);
104
+ const size_t factor = ((tree->leaf_pages + tree->branch_pages - 1) << log2_fixedpoint) / tree->branch_pages;
105
+ while (1) {
106
+ switch ((size_t)btree_power) {
107
+ default: {
108
+ const size_t square = (factor * factor + half) >> log2_fixedpoint;
109
+ const size_t quad = (square * square + half) >> log2_fixedpoint;
110
+ do {
111
+ estimated = estimated * quad + half;
112
+ estimated >>= log2_fixedpoint;
113
+ btree_power -= 4;
114
+ } while (btree_power >= 4);
115
+ continue;
116
+ }
117
+ case 3:
118
+ estimated = estimated * factor + half;
119
+ estimated >>= log2_fixedpoint;
120
+ __fallthrough /* fall through */;
121
+ case 2:
122
+ estimated = estimated * factor + half;
123
+ estimated >>= log2_fixedpoint;
124
+ __fallthrough /* fall through */;
125
+ case 1:
126
+ estimated = estimated * factor + half;
127
+ estimated >>= log2_fixedpoint;
128
+ __fallthrough /* fall through */;
129
+ case 0:
130
+ if (unlikely(estimated > (ptrdiff_t)tree->items))
131
+ return (ptrdiff_t)tree->items;
132
+ if (unlikely(estimated < -(ptrdiff_t)tree->items))
133
+ return -(ptrdiff_t)tree->items;
134
+ return estimated;
135
+ }
136
+ }
137
+ }
138
+
139
+ /*------------------------------------------------------------------------------
140
+ * Range-Estimation API */
141
+
142
+ __hot int mdbx_estimate_distance(const MDBX_cursor *first, const MDBX_cursor *last, ptrdiff_t *distance_items) {
143
+ if (unlikely(!distance_items))
144
+ return LOG_IFERR(MDBX_EINVAL);
145
+
146
+ int rc = cursor_check_pure(first);
147
+ if (unlikely(rc != MDBX_SUCCESS))
148
+ return LOG_IFERR(rc);
149
+
150
+ rc = cursor_check_pure(last);
151
+ if (unlikely(rc != MDBX_SUCCESS))
152
+ return LOG_IFERR(rc);
153
+
154
+ *distance_items = 0;
155
+ diff_t dr;
156
+ rc = cursor_diff(last, first, &dr);
157
+ if (unlikely(rc != MDBX_SUCCESS))
158
+ return LOG_IFERR(rc);
159
+
160
+ cASSERT(first, dr.diff || inner_pointed(first) == inner_pointed(last));
161
+ if (unlikely(dr.diff == 0) && inner_pointed(first)) {
162
+ first = &first->subcur->cursor;
163
+ last = &last->subcur->cursor;
164
+ rc = cursor_diff(first, last, &dr);
165
+ if (unlikely(rc != MDBX_SUCCESS))
166
+ return LOG_IFERR(rc);
167
+ }
168
+
169
+ if (likely(dr.diff != 0))
170
+ *distance_items = estimate(first->tree, &dr);
171
+
172
+ return MDBX_SUCCESS;
173
+ }
174
+
175
+ __hot int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data, MDBX_cursor_op move_op,
176
+ ptrdiff_t *distance_items) {
177
+ if (unlikely(!distance_items || move_op == MDBX_GET_CURRENT || move_op == MDBX_GET_MULTIPLE))
178
+ return LOG_IFERR(MDBX_EINVAL);
179
+
180
+ int rc = cursor_check_ro(cursor);
181
+ if (unlikely(rc != MDBX_SUCCESS))
182
+ return LOG_IFERR(rc);
183
+
184
+ if (unlikely(!is_pointed(cursor)))
185
+ return LOG_IFERR(MDBX_ENODATA);
186
+
187
+ cursor_couple_t next;
188
+ rc = cursor_init(&next.outer, cursor->txn, cursor_dbi(cursor));
189
+ if (unlikely(rc != MDBX_SUCCESS))
190
+ return LOG_IFERR(rc);
191
+
192
+ cursor_cpstk(cursor, &next.outer);
193
+ if (cursor->tree->flags & MDBX_DUPSORT) {
194
+ subcur_t *mx = &container_of(cursor, cursor_couple_t, outer)->inner;
195
+ cursor_cpstk(&mx->cursor, &next.inner.cursor);
196
+ }
197
+
198
+ MDBX_val stub_data;
199
+ if (data == nullptr) {
200
+ const unsigned mask = 1 << MDBX_GET_BOTH | 1 << MDBX_GET_BOTH_RANGE | 1 << MDBX_SET_KEY;
201
+ if (unlikely(mask & (1 << move_op)))
202
+ return LOG_IFERR(MDBX_EINVAL);
203
+ stub_data.iov_base = nullptr;
204
+ stub_data.iov_len = 0;
205
+ data = &stub_data;
206
+ }
207
+
208
+ MDBX_val stub_key;
209
+ if (key == nullptr) {
210
+ const unsigned mask =
211
+ 1 << MDBX_GET_BOTH | 1 << MDBX_GET_BOTH_RANGE | 1 << MDBX_SET_KEY | 1 << MDBX_SET | 1 << MDBX_SET_RANGE;
212
+ if (unlikely(mask & (1 << move_op)))
213
+ return LOG_IFERR(MDBX_EINVAL);
214
+ stub_key.iov_base = nullptr;
215
+ stub_key.iov_len = 0;
216
+ key = &stub_key;
217
+ }
218
+
219
+ next.outer.signature = cur_signature_live;
220
+ rc = cursor_ops(&next.outer, key, data, move_op);
221
+ if (unlikely(rc != MDBX_SUCCESS && (rc != MDBX_NOTFOUND || !is_pointed(&next.outer))))
222
+ return LOG_IFERR(rc);
223
+
224
+ if (move_op == MDBX_LAST) {
225
+ next.outer.flags |= z_eof_hard;
226
+ next.inner.cursor.flags |= z_eof_hard;
227
+ }
228
+ return mdbx_estimate_distance(cursor, &next.outer, distance_items);
229
+ }
230
+
231
+ __hot int mdbx_estimate_range(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *begin_key, const MDBX_val *begin_data,
232
+ const MDBX_val *end_key, const MDBX_val *end_data, ptrdiff_t *size_items) {
233
+ if (unlikely(!size_items))
234
+ return LOG_IFERR(MDBX_EINVAL);
235
+
236
+ if (unlikely(begin_data && (begin_key == nullptr || begin_key == MDBX_EPSILON)))
237
+ return LOG_IFERR(MDBX_EINVAL);
238
+
239
+ if (unlikely(end_data && (end_key == nullptr || end_key == MDBX_EPSILON)))
240
+ return LOG_IFERR(MDBX_EINVAL);
241
+
242
+ if (unlikely(begin_key == MDBX_EPSILON && end_key == MDBX_EPSILON))
243
+ return LOG_IFERR(MDBX_EINVAL);
244
+
245
+ int rc = check_txn(txn, MDBX_TXN_BLOCKED);
246
+ if (unlikely(rc != MDBX_SUCCESS))
247
+ return LOG_IFERR(rc);
248
+
249
+ cursor_couple_t begin;
250
+ /* LY: first, initialize cursor to refresh a DB in case it have DB_STALE */
251
+ rc = cursor_init(&begin.outer, txn, dbi);
252
+ if (unlikely(rc != MDBX_SUCCESS))
253
+ return LOG_IFERR(rc);
254
+
255
+ if (unlikely(begin.outer.tree->items == 0)) {
256
+ *size_items = 0;
257
+ return MDBX_SUCCESS;
258
+ }
259
+
260
+ if (!begin_key) {
261
+ if (unlikely(!end_key)) {
262
+ /* LY: FIRST..LAST case */
263
+ *size_items = (ptrdiff_t)begin.outer.tree->items;
264
+ return MDBX_SUCCESS;
265
+ }
266
+ rc = outer_first(&begin.outer, nullptr, nullptr);
267
+ if (unlikely(end_key == MDBX_EPSILON)) {
268
+ /* LY: FIRST..+epsilon case */
269
+ return LOG_IFERR((rc == MDBX_SUCCESS) ? mdbx_cursor_count(&begin.outer, (size_t *)size_items) : rc);
270
+ }
271
+ } else {
272
+ if (unlikely(begin_key == MDBX_EPSILON)) {
273
+ if (end_key == nullptr) {
274
+ /* LY: -epsilon..LAST case */
275
+ rc = outer_last(&begin.outer, nullptr, nullptr);
276
+ return LOG_IFERR((rc == MDBX_SUCCESS) ? mdbx_cursor_count(&begin.outer, (size_t *)size_items) : rc);
277
+ }
278
+ /* LY: -epsilon..value case */
279
+ assert(end_key != MDBX_EPSILON);
280
+ begin_key = end_key;
281
+ } else if (unlikely(end_key == MDBX_EPSILON)) {
282
+ /* LY: value..+epsilon case */
283
+ assert(begin_key != MDBX_EPSILON);
284
+ end_key = begin_key;
285
+ }
286
+ if (end_key && !begin_data && !end_data &&
287
+ (begin_key == end_key || begin.outer.clc->k.cmp(begin_key, end_key) == 0)) {
288
+ /* LY: single key case */
289
+ rc = cursor_seek(&begin.outer, (MDBX_val *)begin_key, nullptr, MDBX_SET).err;
290
+ if (unlikely(rc != MDBX_SUCCESS)) {
291
+ *size_items = 0;
292
+ return LOG_IFERR((rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc);
293
+ }
294
+ *size_items = 1;
295
+ if (inner_pointed(&begin.outer))
296
+ *size_items = (sizeof(*size_items) >= sizeof(begin.inner.nested_tree.items) ||
297
+ begin.inner.nested_tree.items <= PTRDIFF_MAX)
298
+ ? (size_t)begin.inner.nested_tree.items
299
+ : PTRDIFF_MAX;
300
+
301
+ return MDBX_SUCCESS;
302
+ } else {
303
+ MDBX_val proxy_key = *begin_key;
304
+ MDBX_val proxy_data = {nullptr, 0};
305
+ if (begin_data)
306
+ proxy_data = *begin_data;
307
+ rc = LOG_IFERR(cursor_seek(&begin.outer, &proxy_key, &proxy_data, MDBX_SET_LOWERBOUND).err);
308
+ }
309
+ }
310
+
311
+ if (unlikely(rc != MDBX_SUCCESS)) {
312
+ if (rc != MDBX_NOTFOUND || !is_pointed(&begin.outer))
313
+ return LOG_IFERR(rc);
314
+ }
315
+
316
+ cursor_couple_t end;
317
+ rc = cursor_init(&end.outer, txn, dbi);
318
+ if (unlikely(rc != MDBX_SUCCESS))
319
+ return LOG_IFERR(rc);
320
+ if (!end_key) {
321
+ rc = outer_last(&end.outer, nullptr, nullptr);
322
+ end.outer.flags |= z_eof_hard;
323
+ end.inner.cursor.flags |= z_eof_hard;
324
+ } else {
325
+ MDBX_val proxy_key = *end_key;
326
+ MDBX_val proxy_data = {nullptr, 0};
327
+ if (end_data)
328
+ proxy_data = *end_data;
329
+ rc = cursor_seek(&end.outer, &proxy_key, &proxy_data, MDBX_SET_LOWERBOUND).err;
330
+ }
331
+ if (unlikely(rc != MDBX_SUCCESS)) {
332
+ if (rc != MDBX_NOTFOUND || !is_pointed(&end.outer))
333
+ return LOG_IFERR(rc);
334
+ }
335
+
336
+ rc = mdbx_estimate_distance(&begin.outer, &end.outer, size_items);
337
+ if (unlikely(rc != MDBX_SUCCESS))
338
+ return LOG_IFERR(rc);
339
+ assert(*size_items >= -(ptrdiff_t)begin.outer.tree->items && *size_items <= (ptrdiff_t)begin.outer.tree->items);
340
+
341
+ #if 0 /* LY: Was decided to returns as-is (i.e. negative) the estimation \
342
+ * results for an inverted ranges. */
343
+
344
+ /* Commit 8ddfd1f34ad7cf7a3c4aa75d2e248ca7e639ed63
345
+ Change-Id: If59eccf7311123ab6384c4b93f9b1fed5a0a10d1 */
346
+
347
+ if (*size_items < 0) {
348
+ /* LY: inverted range case */
349
+ *size_items += (ptrdiff_t)begin.outer.tree->items;
350
+ } else if (*size_items == 0 && begin_key && end_key) {
351
+ int cmp = begin.outer.kvx->cmp(&origin_begin_key, &origin_end_key);
352
+ if (cmp == 0 && cursor_pointed(begin.inner.cursor.flags) &&
353
+ begin_data && end_data)
354
+ cmp = begin.outer.kvx->v.cmp(&origin_begin_data, &origin_end_data);
355
+ if (cmp > 0) {
356
+ /* LY: inverted range case with empty scope */
357
+ *size_items = (ptrdiff_t)begin.outer.tree->items;
358
+ }
359
+ }
360
+ assert(*size_items >= 0 &&
361
+ *size_items <= (ptrdiff_t)begin.outer.tree->items);
362
+ #endif
363
+
364
+ return MDBX_SUCCESS;
365
+ }