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,197 @@
1
+ /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
2
+ /// \copyright SPDX-License-Identifier: Apache-2.0
3
+
4
+ #include "test.h++"
5
+
6
+ class testcase_jitter : public testcase {
7
+ protected:
8
+ void check_dbi_error(int expect, const char *stage);
9
+
10
+ public:
11
+ testcase_jitter(const actor_config &config, const mdbx_pid_t pid) : testcase(config, pid) {}
12
+ bool run() override;
13
+ };
14
+ REGISTER_TESTCASE(jitter);
15
+
16
+ void testcase_jitter::check_dbi_error(int expect, const char *stage) {
17
+ MDBX_stat stat;
18
+ int err = mdbx_dbi_stat(txn_guard.get(), dbi, &stat, sizeof(stat));
19
+ if (err != expect)
20
+ failure("unexpected result for %s dbi-handle: expect %d, got %d", stage, expect, err);
21
+ }
22
+
23
+ bool testcase_jitter::run() {
24
+ int err;
25
+ size_t upper_limit = config.params.size_upper;
26
+ if (upper_limit < 1)
27
+ upper_limit = config.params.size_now * 2;
28
+
29
+ tablename_buf buffer;
30
+ const char *const tablename = db_tablename(buffer);
31
+ tablename_buf buffer_renamed;
32
+ const char *const tablename_renamed = db_tablename(buffer_renamed, ".renamed");
33
+
34
+ while (should_continue()) {
35
+ jitter_delay();
36
+ db_open();
37
+
38
+ if (!dbi && !mode_readonly()) {
39
+ // create table
40
+ txn_begin(false);
41
+ dbi = db_table_open(true);
42
+ check_dbi_error(MDBX_SUCCESS, "created-uncommitted");
43
+
44
+ bool renamed = false;
45
+ if (flipcoin()) {
46
+ err = mdbx_dbi_rename(txn_guard.get(), dbi, tablename_renamed);
47
+ if (err != MDBX_SUCCESS)
48
+ failure_perror("jitter.rename-1", err);
49
+ renamed = true;
50
+ }
51
+
52
+ // note: here and below the 4-byte length keys and value are used
53
+ // to be compatible with any Db-flags given from command line.
54
+ MDBX_val k = {(void *)"k000", 4}, v = {(void *)"v001", 4};
55
+ err = mdbx_put(txn_guard.get(), dbi, &k, &v, MDBX_UPSERT);
56
+ if (err != MDBX_SUCCESS)
57
+ failure_perror("jitter.put-1", err);
58
+ txn_end(false);
59
+
60
+ // drop & re-create table, but abort txn
61
+ txn_begin(false);
62
+ check_dbi_error(MDBX_SUCCESS, "created-committed");
63
+ err = mdbx_drop(txn_guard.get(), dbi, true);
64
+ if (unlikely(err != MDBX_SUCCESS))
65
+ failure_perror("mdbx_drop(delete=true)", err);
66
+ check_dbi_error(MDBX_BAD_DBI, "dropped-uncommitted");
67
+ dbi = db_table_open(true);
68
+ check_dbi_error(MDBX_SUCCESS, "recreated-uncommitted");
69
+ txn_end(true);
70
+
71
+ // check after aborted txn
72
+ txn_begin(false);
73
+ v = {(void *)"v002", 4};
74
+ err = mdbx_put(txn_guard.get(), dbi, &k, &v, MDBX_UPSERT);
75
+ if (err != MDBX_BAD_DBI)
76
+ failure_perror("jitter.put-2", err);
77
+ check_dbi_error(MDBX_BAD_DBI, "dropped-recreated-aborted");
78
+ // restore DBI
79
+ dbi = db_table_open(false, renamed);
80
+ if (renamed) {
81
+ err = mdbx_dbi_open(txn_guard.get(), tablename_renamed, flipcoin() ? MDBX_DB_ACCEDE : config.params.table_flags,
82
+ &dbi);
83
+ if (unlikely(err != MDBX_SUCCESS))
84
+ failure_perror("open-renamed", err);
85
+ err = mdbx_dbi_rename(txn_guard.get(), dbi, tablename);
86
+ if (err != MDBX_SUCCESS)
87
+ failure_perror("jitter.rename-2", err);
88
+ }
89
+ check_dbi_error(MDBX_SUCCESS, "dropped-recreated-aborted+reopened");
90
+ v = {(void *)"v003", 4};
91
+ err = mdbx_put(txn_guard.get(), dbi, &k, &v, MDBX_UPSERT);
92
+ if (err != MDBX_SUCCESS)
93
+ failure_perror("jitter.put-3", err);
94
+ txn_end(false);
95
+ }
96
+
97
+ if (upper_limit < 1) {
98
+ MDBX_envinfo info;
99
+ err = mdbx_env_info_ex(db_guard.get(), txn_guard.get(), &info, sizeof(info));
100
+ if (err)
101
+ failure_perror("mdbx_env_info_ex()", err);
102
+ upper_limit = (info.mi_geo.upper < INTPTR_MAX) ? (intptr_t)info.mi_geo.upper : INTPTR_MAX;
103
+ }
104
+
105
+ if (flipcoin()) {
106
+ jitter_delay();
107
+ txn_begin(true);
108
+ fetch_canary();
109
+ if (flipcoin()) {
110
+ MDBX_txn_info info;
111
+ err = mdbx_txn_reset(txn_guard.get());
112
+ if (err)
113
+ failure_perror("mdbx_txn_reset()", err);
114
+ err = mdbx_txn_info(txn_guard.get(), &info, false);
115
+ if (err != MDBX_BAD_TXN)
116
+ failure_perror("mdbx_txn_info(MDBX_BAD_TXN)", err);
117
+ err = mdbx_txn_reset(txn_guard.get());
118
+ if (err)
119
+ failure_perror("mdbx_txn_reset(again)", err);
120
+ err = mdbx_txn_break(txn_guard.get());
121
+ if (err)
122
+ failure_perror("mdbx_txn_break()", err);
123
+
124
+ err = mdbx_txn_abort(txn_guard.get());
125
+ if (err)
126
+ failure_perror("mdbx_txn_abort()", err);
127
+ txn_guard.release();
128
+ txn_begin(true);
129
+ err = mdbx_txn_reset(txn_guard.get());
130
+ if (err)
131
+ failure_perror("mdbx_txn_reset()", err);
132
+
133
+ err = mdbx_txn_renew(txn_guard.get());
134
+ if (err)
135
+ failure_perror("mdbx_txn_renew()", err);
136
+ err = mdbx_txn_info(txn_guard.get(), &info, false);
137
+ if (err)
138
+ failure_perror("mdbx_txn_info()", err);
139
+ }
140
+ jitter_delay();
141
+ txn_end(flipcoin());
142
+ }
143
+
144
+ const bool coin4size = flipcoin();
145
+ jitter_delay();
146
+ txn_begin(mode_readonly());
147
+ jitter_delay();
148
+ if (!mode_readonly()) {
149
+ fetch_canary();
150
+ update_canary(1);
151
+ if (global::config::geometry_jitter) {
152
+ err = mdbx_env_set_geometry(db_guard.get(), -1, -1, coin4size ? upper_limit * 2 / 3 : upper_limit * 3 / 2, -1,
153
+ -1, -1);
154
+ if (err != MDBX_SUCCESS && err != MDBX_UNABLE_EXTEND_MAPSIZE && err != MDBX_MAP_FULL && err != MDBX_TOO_LARGE &&
155
+ err != MDBX_EPERM)
156
+ failure_perror("mdbx_env_set_geometry-1", err);
157
+ }
158
+ }
159
+ if (flipcoin()) {
160
+ uint64_t unused;
161
+ err = mdbx_dbi_sequence(txn_guard.get(), MAIN_DBI, &unused, mode_readonly() ? 0 : 1);
162
+ if (err)
163
+ failure_perror("mdbx_dbi_sequence()", err);
164
+ }
165
+ txn_end(flipcoin());
166
+
167
+ if (global::config::geometry_jitter) {
168
+ err = mdbx_env_set_geometry(db_guard.get(), -1, -1, !coin4size ? upper_limit * 2 / 3 : upper_limit * 3 / 2, -1,
169
+ -1, -1);
170
+ if (err != MDBX_SUCCESS && err != MDBX_UNABLE_EXTEND_MAPSIZE && err != MDBX_MAP_FULL && err != MDBX_TOO_LARGE &&
171
+ err != MDBX_EPERM)
172
+ failure_perror("mdbx_env_set_geometry-2", err);
173
+ }
174
+
175
+ if (flipcoin()) {
176
+ jitter_delay();
177
+ txn_begin(true);
178
+ jitter_delay();
179
+ txn_end(flipcoin());
180
+ }
181
+
182
+ if (global::config::geometry_jitter) {
183
+ jitter_delay();
184
+ err = mdbx_env_set_geometry(db_guard.get(), -1, -1, upper_limit, -1, -1, -1);
185
+ if (err != MDBX_SUCCESS && err != MDBX_UNABLE_EXTEND_MAPSIZE && err != MDBX_MAP_FULL && err != MDBX_TOO_LARGE &&
186
+ err != MDBX_EPERM)
187
+ failure_perror("mdbx_env_set_geometry-3", err);
188
+ }
189
+
190
+ db_close();
191
+
192
+ /* just 'align' nops with other tests with batching */
193
+ const auto batching = std::max(config.params.batch_read, config.params.batch_write);
194
+ report(std::max(1u, batching / 2));
195
+ }
196
+ return true;
197
+ }
@@ -0,0 +1,393 @@
1
+ /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
2
+ /// \copyright SPDX-License-Identifier: Apache-2.0
3
+
4
+ #include "test.h++"
5
+
6
+ static const uint64_t primes[64] = {
7
+ /* */
8
+ 0, 1, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381,
9
+ /* */
10
+ UINT64_C(32749), UINT64_C(65521), UINT64_C(131071), UINT64_C(262139), UINT64_C(524287), UINT64_C(1048573),
11
+ UINT64_C(2097143), UINT64_C(4194301), UINT64_C(8388593), UINT64_C(16777213), UINT64_C(33554393), UINT64_C(67108859),
12
+ UINT64_C(134217689), UINT64_C(268435399), UINT64_C(536870909), UINT64_C(1073741789), UINT64_C(2147483647),
13
+ UINT64_C(4294967291), UINT64_C(8589934583), UINT64_C(17179869143), UINT64_C(34359738337), UINT64_C(68719476731),
14
+ UINT64_C(137438953447), UINT64_C(274877906899), UINT64_C(549755813881), UINT64_C(1099511627689),
15
+ UINT64_C(2199023255531), UINT64_C(4398046511093), UINT64_C(8796093022151), UINT64_C(17592186044399),
16
+ UINT64_C(35184372088777), UINT64_C(70368744177643), UINT64_C(140737488355213), UINT64_C(281474976710597),
17
+ UINT64_C(562949953421231), UINT64_C(1125899906842597), UINT64_C(2251799813685119), UINT64_C(4503599627370449),
18
+ UINT64_C(9007199254740881), UINT64_C(18014398509481951), UINT64_C(36028797018963913), UINT64_C(72057594037927931),
19
+ UINT64_C(144115188075855859), UINT64_C(288230376151711717), UINT64_C(576460752303423433),
20
+ UINT64_C(1152921504606846883), UINT64_C(2305843009213693951), UINT64_C(4611686018427387847),
21
+ UINT64_C(9223372036854775783)};
22
+
23
+ /* static unsigned supid_log2(uint64_t v) {
24
+ unsigned r = 0;
25
+ while (v > 1) {
26
+ v >>= 1;
27
+ r += 1;
28
+ }
29
+ return r;
30
+ } */
31
+
32
+ namespace keygen {
33
+
34
+ /* LY: https://en.wikipedia.org/wiki/Injective_function */
35
+ serial_t injective(const serial_t serial, const unsigned bits /* at least serial_minwith (8) */, const serial_t salt) {
36
+ assert(bits >= serial_minwith && bits <= serial_maxwith);
37
+
38
+ /* LY: All these "magic" prime numbers were found
39
+ * and verified with a bit of brute force. */
40
+
41
+ static const uint64_t m[64 - serial_minwith + 1] = {
42
+ /* 8 - 24 */
43
+ 113, 157, 397, 653, 1753, 5641, 9697, 23873, 25693, 80833, 105953, 316937, 309277, 834497, 1499933, 4373441,
44
+ 10184137,
45
+ /* 25 - 64 */
46
+ 10184137, 17279209, 33990377, 67295161, 284404553, 1075238767, 6346721573, 6924051577, 19204053433, 45840188887,
47
+ 53625693977, 73447827913, 141638870249, 745683604649, 1283334050489, 1100828289853, 2201656586197, 5871903036137,
48
+ 11238507001417, 45264020802263, 105008404482889, 81921776907059, 199987980256399, 307207457507641,
49
+ 946769023178273, 2420886491930041, 3601632139991929, 11984491914483833, 21805846439714153, 23171543400565993,
50
+ 53353226456762893, 155627817337932409, 227827205384840249, 816509268558278821, 576933057762605689,
51
+ 2623957345935638441, 5048241705479929949, 4634245581946485653, 4613509448041658233, 4952535426879925961};
52
+ static const uint8_t s[64 - serial_minwith + 1] = {/* 8 - 24 */
53
+ 2, 3, 4, 4, 2, 4, 3, 3, 7, 3, 3, 4, 8, 3, 10, 3, 11,
54
+ /* 25 - 64 */
55
+ 11, 9, 9, 9, 11, 10, 5, 14, 11, 16, 14, 12, 13, 16, 19, 10, 10, 21,
56
+ 7, 20, 10, 14, 22, 19, 3, 21, 18, 19, 26, 24, 2, 21, 25, 29, 24,
57
+ 10, 11, 14, 20, 19};
58
+
59
+ const auto mask = actor_params::serial_mask(bits);
60
+ const auto mult = m[bits - 8];
61
+ const auto shift = s[bits - 8];
62
+ serial_t result = serial * mult;
63
+ if (salt) {
64
+ const unsigned left = bits / 2;
65
+ const unsigned right = bits - left;
66
+ result = (result << left) | ((result & mask) >> right);
67
+ result = (result ^ salt) * mult;
68
+ }
69
+
70
+ result ^= (result & mask) >> shift;
71
+ result &= mask;
72
+ log_trace("keygen-injective: serial %" PRIu64 "/%u @%" PRIx64 ",%u,%" PRIu64 " => %" PRIu64 "/%u", serial, bits, mult,
73
+ shift, salt, result, bits);
74
+ return result;
75
+ }
76
+
77
+ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value, serial_t value_age,
78
+ const bool keylen_changeable) {
79
+ assert(mapping.width >= serial_minwith && mapping.width <= serial_maxwith);
80
+ assert(mapping.split <= mapping.width);
81
+ assert(mapping.mesh <= mapping.width);
82
+ assert(mapping.rotate <= mapping.width);
83
+ assert(mapping.offset <= actor_params::serial_mask(mapping.width));
84
+ assert(!(key_essentials.flags &
85
+ ~(essentials::prng_fill_flag | unsigned(MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT))));
86
+ assert(!(value_essentials.flags &
87
+ ~(essentials::prng_fill_flag | unsigned(MDBX_INTEGERDUP | MDBX_REVERSEDUP | MDBX_DUPFIXED))));
88
+
89
+ log_trace("keygen-pair: serial %" PRIu64 ", data-age %" PRIu64, serial, value_age);
90
+
91
+ if (mapping.mesh >= serial_minwith) {
92
+ serial = (serial & ~actor_params::serial_mask(mapping.mesh)) | injective(serial, mapping.mesh, salt);
93
+ log_trace("keygen-pair: mesh@%u => %" PRIu64, mapping.mesh, serial);
94
+ }
95
+
96
+ if (mapping.rotate) {
97
+ const unsigned right = mapping.rotate;
98
+ const unsigned left = mapping.width - right;
99
+ serial = (serial << left) | ((serial & actor_params::serial_mask(mapping.width)) >> right);
100
+ log_trace("keygen-pair: rotate@%u => %" PRIu64 ", 0x%" PRIx64, mapping.rotate, serial, serial);
101
+ }
102
+
103
+ if (mapping.offset) {
104
+ serial = (serial + mapping.offset) & actor_params::serial_mask(mapping.width);
105
+ log_trace("keygen-pair: offset@%" PRIu64 " => %" PRIu64, mapping.offset, serial);
106
+ }
107
+ if (base) {
108
+ serial += base;
109
+ log_trace("keygen-pair: base@%" PRIu64 " => %" PRIu64, base, serial);
110
+ }
111
+
112
+ serial_t key_serial = serial;
113
+ serial_t value_serial = (value_age & value_age_mask) << mapping.split;
114
+ if (mapping.split) {
115
+ if (MDBX_db_flags_t(key_essentials.flags) & MDBX_DUPSORT) {
116
+ key_serial >>= mapping.split;
117
+ value_serial += serial & actor_params::serial_mask(mapping.split);
118
+ } else {
119
+ /* Без MDBX_DUPSORT требуется уникальность ключей, а для этого нельзя
120
+ * отбрасывать какие-либо биты serial после инъективного преобразования.
121
+ * Поэтому key_serial не трогаем, а в value_serial нелинейно вмешиваем
122
+ * запрошенное количество бит из serial */
123
+ value_serial +=
124
+ (serial ^ (serial >> mapping.split) * UINT64_C(57035339200100753)) & actor_params::serial_mask(mapping.split);
125
+ }
126
+
127
+ log_trace("keygen-pair: split@%u => k%" PRIu64 ", v%" PRIu64, mapping.split, key_serial, value_serial);
128
+ }
129
+
130
+ log_trace("keygen-pair: key %" PRIu64 ", value %" PRIu64, key_serial, value_serial);
131
+ key_serial = mk_begin(key_serial, key_essentials, *key);
132
+ value_serial = mk_begin(value_serial, value_essentials, *value);
133
+
134
+ #if 0 /* unused for now */
135
+ if (key->value.iov_len + value->value.iov_len > pair_maxlen) {
136
+ unsigned extra = key->value.iov_len + value->value.iov_len - pair_maxlen;
137
+ if (keylen_changeable &&
138
+ key->value.iov_len > std::max(8u, (unsigned)key_essentials.minlen)) {
139
+ #if defined(__GNUC__) || defined(__clang__)
140
+ const bool coin = __builtin_parityll(serial) != 0;
141
+ #else
142
+ const bool coin = INT64_C(0xF2CEECA9989BD96A) * int64_t(serial) < 0;
143
+ #endif
144
+ if (coin) {
145
+ const unsigned gap =
146
+ key->value.iov_len - std::max(8u, (unsigned)key_essentials.minlen);
147
+ const unsigned chop = std::min(gap, extra);
148
+ log_trace("keygen-pair: chop %u key-len %u -> %u", chop,
149
+ (unsigned)key->value.iov_len,
150
+ (unsigned)key->value.iov_len - chop);
151
+ key->value.iov_len -= chop;
152
+ extra -= chop;
153
+ }
154
+ }
155
+ if (extra && value->value.iov_len >
156
+ std::max(8u, (unsigned)value_essentials.minlen)) {
157
+ const unsigned gap = value->value.iov_len -
158
+ std::max(8u, (unsigned)value_essentials.minlen);
159
+ const unsigned chop = std::min(gap, extra);
160
+ log_trace("keygen-pair: chop %u value-len %u -> %u", chop,
161
+ (unsigned)value->value.iov_len,
162
+ (unsigned)value->value.iov_len - chop);
163
+ value->value.iov_len -= chop;
164
+ extra -= chop;
165
+ }
166
+ if (keylen_changeable && extra &&
167
+ key->value.iov_len > std::max(8u, (unsigned)key_essentials.minlen)) {
168
+ const unsigned gap =
169
+ key->value.iov_len - std::max(8u, (unsigned)key_essentials.minlen);
170
+ const unsigned chop = std::min(gap, extra);
171
+ log_trace("keygen-pair: chop %u key-len %u -> %u", chop,
172
+ (unsigned)key->value.iov_len,
173
+ (unsigned)key->value.iov_len - chop);
174
+ key->value.iov_len -= chop;
175
+ extra -= chop;
176
+ }
177
+ }
178
+ #else
179
+ (void)keylen_changeable;
180
+ #endif /* unused for now */
181
+
182
+ mk_continue(key_serial, key_essentials, *key);
183
+ mk_continue(value_serial, value_essentials, *value);
184
+ log_pair(logging::trace, "kv", key, value);
185
+ }
186
+
187
+ void maker::setup(const config::actor_params_pod &actor, unsigned thread_number) {
188
+ #if CONSTEXPR_ENUM_FLAGS_OPERATIONS
189
+ static_assert(unsigned(MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP |
190
+ MDBX_REVERSEDUP) < UINT16_MAX,
191
+ "WTF?");
192
+ #else
193
+ assert(unsigned(MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP |
194
+ MDBX_REVERSEDUP) < UINT16_MAX);
195
+ #endif
196
+
197
+ key_essentials.flags =
198
+ uint16_t(actor.table_flags & MDBX_db_flags_t(MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT));
199
+ assert(actor.keylen_min <= UINT16_MAX);
200
+ key_essentials.minlen = uint16_t(actor.keylen_min);
201
+ assert(actor.keylen_max <= UINT32_MAX);
202
+ key_essentials.maxlen =
203
+ std::min(uint32_t(actor.keylen_max), uint32_t(mdbx_limits_keysize_max(actor.pagesize, actor.table_flags)));
204
+ key_essentials.bits =
205
+ (key_essentials.maxlen < sizeof(serial_t)) ? key_essentials.maxlen * CHAR_BIT : sizeof(serial_t) * CHAR_BIT;
206
+ key_essentials.mask = actor_params::serial_mask(key_essentials.bits);
207
+ assert(key_essentials.bits > 63 || key_essentials.mask > primes[key_essentials.bits]);
208
+
209
+ value_essentials.flags =
210
+ uint16_t(actor.table_flags & MDBX_db_flags_t(MDBX_INTEGERDUP | MDBX_REVERSEDUP | MDBX_DUPFIXED));
211
+ assert(actor.datalen_min <= UINT16_MAX);
212
+ value_essentials.minlen = uint16_t(actor.datalen_min);
213
+ assert(actor.datalen_max <= UINT32_MAX);
214
+ value_essentials.maxlen =
215
+ std::min(uint32_t(actor.datalen_max), uint32_t(mdbx_limits_valsize_max(actor.pagesize, actor.table_flags)));
216
+ value_essentials.bits =
217
+ (value_essentials.maxlen < sizeof(serial_t)) ? value_essentials.maxlen * CHAR_BIT : sizeof(serial_t) * CHAR_BIT;
218
+ value_essentials.mask = actor_params::serial_mask(value_essentials.bits);
219
+ assert(value_essentials.bits > 63 || value_essentials.mask > primes[value_essentials.bits]);
220
+
221
+ if (!actor.keygen.zero_fill) {
222
+ key_essentials.flags |= essentials::prng_fill_flag;
223
+ value_essentials.flags |= essentials::prng_fill_flag;
224
+ }
225
+
226
+ mapping = actor.keygen;
227
+ const auto split = mapping.split;
228
+ while (mapping.split > value_essentials.bits - essentials::value_age_minwidth || mapping.split >= mapping.width)
229
+ mapping.split -= 1;
230
+ if (split != mapping.split)
231
+ log_notice("keygen: reduce mapping-split from %u to %u", split, mapping.split);
232
+
233
+ const auto width = mapping.width;
234
+ while (unsigned((actor.table_flags & MDBX_DUPSORT) ? mapping.width - mapping.split : mapping.width) >
235
+ key_essentials.bits)
236
+ mapping.width -= 1;
237
+ if (width != mapping.width)
238
+ log_notice("keygen: reduce mapping-width from %u to %u", width, mapping.width);
239
+
240
+ value_age_bits = value_essentials.bits - mapping.split;
241
+ value_age_mask = actor_params::serial_mask(value_age_bits);
242
+ assert(value_age_bits >= essentials::value_age_minwidth);
243
+
244
+ salt = (prng_state ^ (thread_number * 1575554837) * UINT64_C(59386707711075671)) * UINT64_C(14653293970879851569);
245
+ base = actor.serial_base();
246
+ }
247
+
248
+ bool maker::is_unordered() const {
249
+ return mapping.rotate || mapping.mesh > ((MDBX_db_flags_t(key_essentials.flags) & MDBX_DUPSORT) ? 0 : mapping.split);
250
+ }
251
+
252
+ void maker::seek2end(serial_t &serial) const { serial = actor_params::serial_mask(mapping.width) - 1; }
253
+
254
+ bool maker::increment(serial_t &serial, int64_t delta) const {
255
+ if (serial > actor_params::serial_mask(mapping.width)) {
256
+ log_extra("keygen-increment: %" PRIu64 " > %" PRIu64 ", overflow", serial,
257
+ actor_params::serial_mask(mapping.width));
258
+ return false;
259
+ }
260
+
261
+ serial_t target = serial + delta;
262
+ if (target > actor_params::serial_mask(mapping.width) || ((delta > 0) ? target < serial : target > serial)) {
263
+ log_extra("keygen-increment: %" PRIu64 "%-" PRId64 " => %" PRIu64 ", overflow", serial, delta, target);
264
+ return false;
265
+ }
266
+
267
+ log_extra("keygen-increment: %" PRIu64 "%-" PRId64 " => %" PRIu64 ", continue", serial, delta, target);
268
+ serial = target;
269
+ return true;
270
+ }
271
+
272
+ //-----------------------------------------------------------------------------
273
+
274
+ MDBX_NOTHROW_PURE_FUNCTION static inline unsigned length(serial_t serial) {
275
+ #if defined(__clang__) && __clang__ > 8
276
+ unsigned n = 0;
277
+ if (serial > UINT32_MAX) {
278
+ n = 4;
279
+ serial >>= 32;
280
+ }
281
+ if (serial > UINT16_MAX) {
282
+ n += 2;
283
+ serial >>= 16;
284
+ }
285
+ if (serial > UINT8_MAX) {
286
+ n += 1;
287
+ serial >>= 8;
288
+ }
289
+ #else
290
+ unsigned n = (serial > UINT32_MAX) ? 4 : 0;
291
+ serial = (serial > UINT32_MAX) ? serial >> 32 : serial;
292
+
293
+ n += (serial > UINT16_MAX) ? 2 : 0;
294
+ serial = (serial > UINT16_MAX) ? serial >> 16 : serial;
295
+
296
+ n += (serial > UINT8_MAX);
297
+ serial = (serial > UINT8_MAX) ? serial >> 8 : serial;
298
+ #endif
299
+ return n + (serial > 0);
300
+ }
301
+
302
+ buffer alloc(size_t limit) {
303
+ result *ptr = (result *)malloc(sizeof(result) + limit + 8);
304
+ if (unlikely(ptr == nullptr))
305
+ failure_perror("malloc(keyvalue_buffer)", errno);
306
+ ptr->value.iov_base = ptr->bytes;
307
+ ptr->value.iov_len = 0;
308
+ ptr->limit = limit + 8;
309
+ return buffer(ptr);
310
+ }
311
+
312
+ serial_t __hot maker::mk_begin(serial_t serial, const essentials &params, result &out) {
313
+ assert(out.limit >= params.maxlen);
314
+ assert(params.maxlen >= params.minlen);
315
+ assert(serial <= params.mask);
316
+ if (unlikely(serial > params.mask)) {
317
+ #if 1
318
+ serial %= primes[params.bits];
319
+ assert(params.mask > primes[params.bits]);
320
+ #else
321
+ const serial_t maxbits = params.maxlen * CHAR_BIT;
322
+ serial ^=
323
+ (serial >> maxbits / 2) * serial_t((sizeof(serial_t) > 4) ? UINT64_C(40719303417517073) : UINT32_C(3708688457));
324
+ serial &= params.mask;
325
+ #endif
326
+ assert(params.maxlen >= length(serial));
327
+ }
328
+
329
+ out.value.iov_len = std::max(unsigned(params.minlen), length(serial));
330
+ const auto variation = params.maxlen - params.minlen;
331
+ if (variation) {
332
+ if (serial % (variation + serial_t(1))) {
333
+ auto refix = serial * UINT64_C(48835288005252737);
334
+ refix ^= refix >> 32;
335
+ out.value.iov_len = std::max(out.value.iov_len, params.minlen + size_t(1) + size_t(refix) % variation);
336
+ }
337
+ }
338
+
339
+ assert(length(serial) <= out.value.iov_len);
340
+ assert(out.value.iov_len >= params.minlen);
341
+ assert(out.value.iov_len <= params.maxlen);
342
+ return serial;
343
+ }
344
+
345
+ void __hot maker::mk_continue(const serial_t serial, const essentials &params, result &out) {
346
+ #if CONSTEXPR_ENUM_FLAGS_OPERATIONS
347
+ static_assert((essentials::prng_fill_flag & unsigned(MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERKEY |
348
+ MDBX_INTEGERDUP | MDBX_REVERSEKEY | MDBX_REVERSEDUP)) == 0,
349
+ "WTF?");
350
+ #else
351
+ assert((essentials::prng_fill_flag & unsigned(MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERKEY | MDBX_INTEGERDUP |
352
+ MDBX_REVERSEKEY | MDBX_REVERSEDUP)) == 0);
353
+ #endif
354
+ assert(length(serial) <= out.value.iov_len);
355
+ out.value.iov_base = out.bytes;
356
+ if (MDBX_db_flags_t(params.flags) & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) {
357
+ assert(params.maxlen == params.minlen);
358
+ if (MDBX_db_flags_t(params.flags) & (MDBX_INTEGERKEY | MDBX_INTEGERDUP))
359
+ assert(params.minlen == 4 || params.minlen == 8);
360
+ out.u64 = serial;
361
+ if (!is_byteorder_le() && out.value.iov_len != 8)
362
+ out.u32 = uint32_t(serial);
363
+ } else {
364
+ const auto prefix = std::max(std::min(unsigned(params.minlen), 8u), length(serial));
365
+ out.u64 = htobe64(serial);
366
+ out.value.iov_base = out.bytes + 8 - prefix;
367
+ if (out.value.iov_len > prefix) {
368
+ if (params.flags & essentials::prng_fill_flag) {
369
+ uint64_t state = serial ^ UINT64_C(0x923ab47b7ee6f6e4);
370
+ prng_fill(state, out.bytes + 8, out.value.iov_len - prefix);
371
+ } else
372
+ memset(out.bytes + 8, '\0', out.value.iov_len - prefix);
373
+ }
374
+ if (unlikely(MDBX_db_flags_t(params.flags) & (MDBX_REVERSEKEY | MDBX_REVERSEDUP)))
375
+ std::reverse((char *)out.value.iov_base, (char *)out.value.iov_base + out.value.iov_len);
376
+ }
377
+
378
+ assert(out.value.iov_len >= params.minlen);
379
+ assert(out.value.iov_len <= params.maxlen);
380
+ assert(out.value.iov_len >= length(serial));
381
+ assert(out.value.iov_base >= out.bytes);
382
+ assert((char *)out.value.iov_base + out.value.iov_len <= (char *)&out.bytes + out.limit);
383
+ }
384
+
385
+ void log_pair(logging::loglevel level, const char *prefix, const buffer &key, buffer &value) {
386
+ if (log_enabled(level)) {
387
+ char dump_key[4096], dump_value[4096];
388
+ logging::output(level, "%s-pair: key %s, value %s", prefix, mdbx_dump_val(&key->value, dump_key, sizeof(dump_key)),
389
+ mdbx_dump_val(&value->value, dump_value, sizeof(dump_value)));
390
+ }
391
+ }
392
+
393
+ } /* namespace keygen */