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,237 @@
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_append : public testcase {
7
+ public:
8
+ testcase_append(const actor_config &config, const mdbx_pid_t pid) : testcase(config, pid) {}
9
+ bool run() override;
10
+
11
+ static bool review_params(actor_params &params, unsigned space_id) {
12
+ if (!testcase::review_params(params, space_id))
13
+ return false;
14
+ const bool ordered = !flipcoin_x3();
15
+ log_notice("the '%s' key-generation mode is selected", ordered ? "ordered/linear" : "unordered/non-linear");
16
+ if (ordered && !params.make_keygen_linear())
17
+ return false;
18
+ return true;
19
+ }
20
+ };
21
+ REGISTER_TESTCASE(append);
22
+
23
+ bool testcase_append::run() {
24
+ const bool reverse = flipcoin();
25
+ const char *const caption = reverse ? "ahead" : "append";
26
+ log_notice("the '%s' scenario is selected", caption);
27
+
28
+ int err = db_open__begin__table_create_open_clean(dbi);
29
+ if (unlikely(err != MDBX_SUCCESS)) {
30
+ log_notice("%s: bailout-prepare due '%s'", caption, mdbx_strerror(err));
31
+ return true;
32
+ }
33
+
34
+ cursor_open(dbi);
35
+ keyvalue_maker.setup(config.params, 0 /* thread_number */);
36
+ /* LY: тест наполнения таблиц в append-режиме,
37
+ * при котором записи добавляются строго в конец (в порядке сортировки) */
38
+ const MDBX_put_flags_t flags = reverse ? ((config.params.table_flags & MDBX_DUPSORT) ? MDBX_UPSERT : MDBX_NOOVERWRITE)
39
+ : ((config.params.table_flags & MDBX_DUPSORT)
40
+ ? (flipcoin() ? MDBX_APPEND | MDBX_APPENDDUP : MDBX_APPENDDUP)
41
+ : MDBX_APPEND);
42
+
43
+ key = keygen::alloc(config.params.keylen_max);
44
+ data = keygen::alloc(config.params.datalen_max);
45
+
46
+ simple_checksum inserted_checksum;
47
+ uint64_t inserted_number = 0;
48
+ uint64_t serial_count = 0;
49
+ if (reverse)
50
+ keyvalue_maker.seek2end(serial_count);
51
+
52
+ unsigned txn_nops = 0;
53
+ uint64_t committed_inserted_number = inserted_number;
54
+ simple_checksum committed_inserted_checksum = inserted_checksum;
55
+ while (should_continue()) {
56
+ const keygen::serial_t serial = serial_count;
57
+ const bool turn_key = (config.params.table_flags & MDBX_DUPSORT) == 0 || flipcoin_n(config.params.keygen.split);
58
+ if (turn_key ? !keyvalue_maker.increment_key_part(serial_count, reverse ? -1 : 1)
59
+ : !keyvalue_maker.increment(serial_count, reverse ? -1 : 1)) {
60
+ // дошли до границы пространства ключей
61
+ break;
62
+ }
63
+
64
+ log_trace("%s: insert-a %" PRIu64, caption, serial);
65
+ generate_pair(serial);
66
+ // keygen::log_pair(logging::verbose, "append.", key, data);
67
+
68
+ bool expect_key_mismatch = false;
69
+ if (flags & (MDBX_APPEND | MDBX_APPENDDUP)) {
70
+ MDBX_val ge_key = key->value;
71
+ MDBX_val ge_data = data->value;
72
+ err = mdbx_get_equal_or_great(txn_guard.get(), dbi, &ge_key, &ge_data);
73
+
74
+ if (err == MDBX_SUCCESS /* exact match */) {
75
+ expect_key_mismatch = true;
76
+ assert(inserted_number > 0);
77
+ assert(mdbx_cmp(txn_guard.get(), dbi, &key->value, &ge_key) == 0);
78
+ assert((config.params.table_flags & MDBX_DUPSORT) == 0 ||
79
+ mdbx_dcmp(txn_guard.get(), dbi, &data->value, &ge_data) == 0);
80
+ assert(inserted_number > 0);
81
+ } else if (err == MDBX_RESULT_TRUE /* have key-value pair great than */) {
82
+ assert(mdbx_cmp(txn_guard.get(), dbi, &key->value, &ge_key) < 0 ||
83
+ ((config.params.table_flags & MDBX_DUPSORT) &&
84
+ mdbx_cmp(txn_guard.get(), dbi, &key->value, &ge_key) == 0 &&
85
+ mdbx_dcmp(txn_guard.get(), dbi, &data->value, &ge_data) < 0));
86
+ switch (int(flags)) {
87
+ default:
88
+ abort();
89
+ #if CONSTEXPR_ENUM_FLAGS_OPERATIONS
90
+ case MDBX_APPEND | MDBX_APPENDDUP:
91
+ #else
92
+ case int(MDBX_APPEND) | int(MDBX_APPENDDUP):
93
+ #endif
94
+ assert((config.params.table_flags & MDBX_DUPSORT) != 0);
95
+ __fallthrough;
96
+ // fall through
97
+ case MDBX_APPEND:
98
+ expect_key_mismatch = true;
99
+ break;
100
+ case MDBX_APPENDDUP:
101
+ assert((config.params.table_flags & MDBX_DUPSORT) != 0);
102
+ expect_key_mismatch = mdbx_cmp(txn_guard.get(), dbi, &key->value, &ge_key) == 0;
103
+ break;
104
+ }
105
+ } else if (err == MDBX_NOTFOUND /* all pair are less than */) {
106
+ switch (int(flags)) {
107
+ default:
108
+ abort();
109
+ case MDBX_APPENDDUP:
110
+ #if CONSTEXPR_ENUM_FLAGS_OPERATIONS
111
+ case MDBX_APPEND | MDBX_APPENDDUP:
112
+ #else
113
+ case int(MDBX_APPEND) | int(MDBX_APPENDDUP):
114
+ #endif
115
+ assert((config.params.table_flags & MDBX_DUPSORT) != 0);
116
+ __fallthrough;
117
+ // fall through
118
+ case MDBX_APPEND:
119
+ expect_key_mismatch = false;
120
+ break;
121
+ }
122
+ } else
123
+ failure_perror("mdbx_get_equal_or_great()", err);
124
+ }
125
+
126
+ err = mdbx_cursor_put(cursor_guard.get(), &key->value, &data->value, flags);
127
+ if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) {
128
+ log_notice("%s: bailout-insert due '%s'", caption, mdbx_strerror(err));
129
+ txn_end(true);
130
+ inserted_number = committed_inserted_number;
131
+ inserted_checksum = committed_inserted_checksum;
132
+ break;
133
+ }
134
+
135
+ if (!expect_key_mismatch) {
136
+ if (unlikely(err != MDBX_SUCCESS))
137
+ failure_perror("mdbx_cursor_put(append)", err);
138
+ ++inserted_number;
139
+ inserted_checksum.push((uint32_t)inserted_number, key->value);
140
+ inserted_checksum.push(10639, data->value);
141
+
142
+ if (config.params.speculum) {
143
+ Item item(iov2dataview(key), iov2dataview(data));
144
+ const auto insertion_result = speculum.insert(item);
145
+ if (!insertion_result.second) {
146
+ char dump_key[32], dump_value[32];
147
+ log_error("speculum.append: unexpected %s {%s, %s}", "MDBX_SUCCESS",
148
+ mdbx_dump_val(&key->value, dump_key, sizeof(dump_key)),
149
+ mdbx_dump_val(&data->value, dump_value, sizeof(dump_value)));
150
+ return false;
151
+ }
152
+ }
153
+ } else if (unlikely(err != MDBX_EKEYMISMATCH))
154
+ failure_perror("mdbx_cursor_put(append) != MDBX_EKEYMISMATCH", err);
155
+
156
+ if (++txn_nops >= config.params.batch_write) {
157
+ err = breakable_restart();
158
+ if (unlikely(err != MDBX_SUCCESS)) {
159
+ log_notice("%s: bailout-commit due '%s'", caption, mdbx_strerror(err));
160
+ inserted_number = committed_inserted_number;
161
+ inserted_checksum = committed_inserted_checksum;
162
+ break;
163
+ }
164
+ committed_inserted_number = inserted_number;
165
+ committed_inserted_checksum = inserted_checksum;
166
+ txn_nops = 0;
167
+ if (!speculum_verify()) {
168
+ log_notice("append: bailout breakable_restart");
169
+ return false;
170
+ }
171
+ }
172
+
173
+ report(1);
174
+ }
175
+
176
+ if (txn_guard) {
177
+ err = breakable_commit();
178
+ if (unlikely(err != MDBX_SUCCESS)) {
179
+ log_notice("%s: bailout-commit due '%s'", caption, mdbx_strerror(err));
180
+ inserted_number = committed_inserted_number;
181
+ inserted_checksum = committed_inserted_checksum;
182
+ }
183
+ }
184
+ //----------------------------------------------------------------------------
185
+ txn_begin(true);
186
+ if (!speculum_verify()) {
187
+ log_notice("append: bailout verify");
188
+ return false;
189
+ }
190
+ cursor_renew();
191
+
192
+ MDBX_val check_key, check_data;
193
+ err = mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, reverse ? MDBX_LAST : MDBX_FIRST);
194
+ if (likely(inserted_number)) {
195
+ if (unlikely(err != MDBX_SUCCESS))
196
+ failure_perror("mdbx_cursor_get(MDBX_FIRST)", err);
197
+ }
198
+
199
+ simple_checksum read_checksum;
200
+ uint64_t read_count = 0;
201
+ while (err == MDBX_SUCCESS) {
202
+ ++read_count;
203
+ read_checksum.push((uint32_t)read_count, check_key);
204
+ read_checksum.push(10639, check_data);
205
+
206
+ err = mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, reverse ? MDBX_PREV : MDBX_NEXT);
207
+ }
208
+
209
+ if (unlikely(err != MDBX_NOTFOUND))
210
+ failure_perror("mdbx_cursor_get(MDBX_NEXT) != EOF", err);
211
+
212
+ if (unlikely(read_count != inserted_number))
213
+ failure("read_count(%" PRIu64 ") != inserted_number(%" PRIu64 ")", read_count, inserted_number);
214
+
215
+ if (unlikely(read_checksum.value != inserted_checksum.value) && !keyvalue_maker.is_unordered())
216
+ failure("read_checksum(0x%016" PRIu64 ") "
217
+ "!= inserted_checksum(0x%016" PRIu64 ")",
218
+ read_checksum.value, inserted_checksum.value);
219
+
220
+ cursor_close();
221
+ txn_end(true);
222
+ //----------------------------------------------------------------------------
223
+
224
+ if (dbi) {
225
+ if (config.params.drop_table && !mode_readonly()) {
226
+ txn_begin(false);
227
+ db_table_drop(dbi);
228
+ err = breakable_commit();
229
+ if (unlikely(err != MDBX_SUCCESS)) {
230
+ log_notice("%s: bailout-clean due '%s'", caption, mdbx_strerror(err));
231
+ return true;
232
+ }
233
+ } else
234
+ db_table_close(dbi);
235
+ }
236
+ return true;
237
+ }
@@ -0,0 +1,92 @@
1
+ /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
2
+ /// \copyright SPDX-License-Identifier: Apache-2.0
3
+
4
+ #pragma once
5
+
6
+ #include "../src/essentials.h"
7
+
8
+ #ifdef _MSC_VER
9
+ #pragma warning(push, 1)
10
+ #pragma warning(disable : 4548) /* expression before comma has no effect; \
11
+ expected expression with side - effect */
12
+ #pragma warning(disable : 4530) /* C++ exception handler used, but unwind \
13
+ semantics are not enabled. Specify /EHsc */
14
+ #pragma warning(disable : 4577) /* 'noexcept' used with no exception handling \
15
+ mode specified; termination on exception \
16
+ is not guaranteed. Specify /EHsc */
17
+ #endif /* _MSC_VER (warnings) */
18
+
19
+ #if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
20
+ /* If you wish to build your application for a previous Windows platform,
21
+ * include WinSDKVer.h and set the _WIN32_WINNT macro to the platform you
22
+ * wish to support before including SDKDDKVer.h.
23
+ *
24
+ * TODO: #define _WIN32_WINNT WIN32_MUSTDIE */
25
+ #include <SDKDDKVer.h>
26
+ #endif /* WINDOWS */
27
+
28
+ #include <errno.h>
29
+ #include <limits.h>
30
+ #include <stdio.h>
31
+ #include <stdlib.h>
32
+ #include <string.h>
33
+ #include <time.h>
34
+
35
+ #if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
36
+ #include <io.h>
37
+ #else
38
+ #include <fcntl.h>
39
+ #include <sys/param.h>
40
+ #include <sys/stat.h>
41
+ #include <sys/time.h>
42
+ #include <sys/types.h>
43
+ #include <unistd.h>
44
+ #endif
45
+
46
+ #ifdef _BSD_SOURCE
47
+ #include <endian.h>
48
+ #endif
49
+
50
+ #include <algorithm>
51
+ #include <cassert>
52
+ #include <cinttypes> // for PRId64, PRIu64
53
+ #include <cstdarg>
54
+ #include <cstddef>
55
+ #include <cstdint>
56
+ #include <map>
57
+ #include <memory>
58
+ #include <set>
59
+ #include <string>
60
+ #include <type_traits>
61
+ #include <unordered_map>
62
+ #include <unordered_set>
63
+ #include <vector>
64
+
65
+ #define MDBX_INTERNAL
66
+ #define xMDBX_TOOLS /* Avoid using internal eASSERT() */
67
+ #include "../mdbx.h++"
68
+ #include "../src/osal.h"
69
+
70
+ #include "../src/options.h"
71
+
72
+ #ifdef _MSC_VER
73
+ #pragma warning(pop)
74
+ #pragma warning(disable : 4201) /* nonstandard extension used: nameless \
75
+ struct/union */
76
+ #pragma warning(disable : 4127) /* conditional expression is constant */
77
+ #if _MSC_VER < 1900
78
+ #pragma warning(disable : 4510) /* default constructor could \
79
+ not be generated */
80
+ #pragma warning(disable : 4512) /* assignment operator could \
81
+ not be generated */
82
+ #pragma warning(disable : 4610) /* user-defined constructor required */
83
+ #ifndef snprintf
84
+ #define snprintf(buffer, buffer_size, format, ...) _snprintf_s(buffer, buffer_size, _TRUNCATE, format, __VA_ARGS__)
85
+ #endif
86
+ #ifndef vsnprintf
87
+ #define vsnprintf(buffer, buffer_size, format, args) _vsnprintf_s(buffer, buffer_size, _TRUNCATE, format, args)
88
+ #endif
89
+ #pragma warning(disable : 4996) /* 'vsnprintf': This function or variable \
90
+ may be unsafe */
91
+ #endif
92
+ #endif /* _MSC_VER */
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru>
4
+ # SPDX-License-Identifier: Apache-2.0
5
+
6
+ TMUX=tmux
7
+ DIR="$(dirname ${BASH_SOURCE[0]})"
8
+ TEST="${DIR}/stochastic.sh --skip-make --db-upto-gb 32"
9
+ PREFIX="/dev/shm/mdbxtest-"
10
+
11
+ NUMACTL="$(which numactl 2>-)"
12
+ NUMALIST=()
13
+ NUMAIDX=0
14
+ if [ -n "${NUMACTL}" -a $(${NUMACTL} --hardware | grep 'node [0-9]\+ cpus' | wc -l) -gt 1 ]; then
15
+ NUMALIST=($(${NUMACTL} --hardware | grep 'node [0-9]\+ cpus' | cut -d ' ' -f 2))
16
+ fi
17
+
18
+ function test_numacycle {
19
+ NUMAIDX=$((NUMAIDX + 1))
20
+ if [ ${NUMAIDX} -ge ${#NUMALIST[@]} ]; then
21
+ NUMAIDX=0
22
+ fi
23
+ }
24
+
25
+ function test_numanode {
26
+ if [[ ${#NUMALIST[@]} > 1 ]]; then
27
+ echo "${TEST} --numa ${NUMALIST[$NUMAIDX]}"
28
+ else
29
+ echo "${TEST}"
30
+ fi
31
+ }
32
+
33
+ ${TMUX} kill-session -t mdbx
34
+ rm -rf ${PREFIX}*
35
+ # git clean -x -f -d && make test-assertions
36
+ ${TMUX} -f "${DIR}/tmux.conf" new-session -d -s mdbx htop
37
+
38
+ W=0
39
+ for ps in min 4k max; do
40
+ for from in 1 30000; do
41
+ for n in 0 1 2 3; do
42
+ CMD="$(test_numanode) --delay $((n * 7)) --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}"
43
+ if [ $n -eq 0 ]; then
44
+ ${TMUX} new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}" -k -d "$CMD"
45
+ ${TMUX} select-layout -E tiled
46
+ else
47
+ ${TMUX} split-window -t mdbx:$W -l 20% -d $CMD
48
+ fi
49
+ test_numacycle
50
+ done
51
+ for n in 0 1 2 3; do
52
+ CMD="$(test_numanode) --delay $((3 + n * 7)) --extra --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}-extra"
53
+ if [ $n -eq 0 ]; then
54
+ ${TMUX} new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}-extra" -k -d "$CMD"
55
+ ${TMUX} select-layout -E tiled
56
+ else
57
+ ${TMUX} split-window -t mdbx:$W -l 20% -d $CMD
58
+ fi
59
+ test_numacycle
60
+ done
61
+ done
62
+ done
63
+
64
+ ${TMUX} attach -t mdbx
@@ -0,0 +1,118 @@
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
+ registry *registry::instance() {
7
+ static registry *singleton;
8
+ if (!singleton)
9
+ singleton = new registry();
10
+ return singleton;
11
+ }
12
+
13
+ bool registry::add(const record *item) {
14
+ auto const singleton = instance();
15
+ assert(singleton->name2id.count(std::string(item->name)) == 0);
16
+ assert(singleton->id2record.count(item->id) == 0);
17
+ if (singleton->name2id.count(std::string(item->name)) + singleton->id2record.count(item->id) == 0) {
18
+ singleton->name2id[std::string(item->name)] = item;
19
+ singleton->id2record[item->id] = item;
20
+ return true;
21
+ }
22
+ return false;
23
+ }
24
+
25
+ testcase *registry::create_actor(const actor_config &config, const mdbx_pid_t pid) {
26
+ return instance()->id2record.at(config.testcase)->constructor(config, pid);
27
+ }
28
+
29
+ bool registry::review_actor_params(const actor_testcase id, actor_params &params, const unsigned space_id) {
30
+ return instance()->id2record.at(id)->review_params(params, space_id);
31
+ }
32
+
33
+ //-----------------------------------------------------------------------------
34
+
35
+ void configure_actor(unsigned &last_space_id, const actor_testcase testcase, const char *space_id_cstr,
36
+ actor_params params) {
37
+ unsigned wait4id = 0;
38
+ if (params.waitfor_nops) {
39
+ for (auto i = global::actors.rbegin(); i != global::actors.rend(); ++i) {
40
+ if (i->is_waitable(params.waitfor_nops)) {
41
+ if (i->signal_nops && i->signal_nops != params.waitfor_nops)
42
+ failure("Previous waitable actor (id=%u) already linked on %u-ops\n", i->actor_id, i->signal_nops);
43
+ wait4id = i->actor_id;
44
+ i->signal_nops = params.waitfor_nops;
45
+ break;
46
+ }
47
+ }
48
+ if (!wait4id)
49
+ failure("No previous waitable actor for %u-ops\n", params.waitfor_nops);
50
+ }
51
+
52
+ unsigned long space_id = 0;
53
+ if (!space_id_cstr || strcmp(space_id_cstr, "auto") == 0)
54
+ space_id = last_space_id + 1;
55
+ else {
56
+ char *end = nullptr;
57
+ errno = 0;
58
+ space_id = strtoul(space_id_cstr, &end, 0);
59
+ if (errno)
60
+ failure_perror("Expects an integer value for space-id\n", errno);
61
+ if (end && *end)
62
+ failure("The '%s' is unexpected for space-id\n", end);
63
+ }
64
+
65
+ if (space_id > ACTOR_ID_MAX)
66
+ failure("Invalid space-id %lu\n", space_id);
67
+
68
+ if (!registry::review_actor_params(testcase, params, unsigned(space_id)))
69
+ failure("Actor config-review failed for space-id %lu\n", space_id);
70
+
71
+ last_space_id = unsigned(space_id);
72
+ log_trace("configure_actor: space %lu for %s", space_id, testcase2str(testcase));
73
+ global::actors.emplace_back(actor_config(testcase, params, unsigned(space_id), wait4id));
74
+ global::databases.insert(params.pathname_db);
75
+ }
76
+
77
+ void testcase_setup(const char *casename, const actor_params &params, unsigned &last_space_id) {
78
+ if (strcmp(casename, "basic") == 0) {
79
+ log_notice(">>> testcase_setup(%s)", casename);
80
+ configure_actor(last_space_id, ac_nested, nullptr, params);
81
+ configure_actor(last_space_id, ac_hill, nullptr, params);
82
+ configure_actor(last_space_id, ac_ttl, nullptr, params);
83
+ configure_actor(last_space_id, ac_copy, nullptr, params);
84
+ configure_actor(last_space_id, ac_append, nullptr, params);
85
+ configure_actor(last_space_id, ac_jitter, nullptr, params);
86
+ configure_actor(last_space_id, ac_try, nullptr, params);
87
+ configure_actor(last_space_id, ac_jitter, nullptr, params);
88
+ configure_actor(last_space_id, ac_try, nullptr, params);
89
+ #if !defined(_WIN32) && !defined(_WIN64)
90
+ configure_actor(last_space_id, ac_forkread, nullptr, params);
91
+ configure_actor(last_space_id, ac_forkwrite, nullptr, params);
92
+ #endif /* Windows */
93
+ log_notice("<<< testcase_setup(%s): done", casename);
94
+ } else {
95
+ failure("unknown testcase `%s`", casename);
96
+ }
97
+ }
98
+
99
+ void keycase_setup(const char *casename, actor_params &params) {
100
+ if (strcmp(casename, "random") == 0 || strcmp(casename, "prng") == 0) {
101
+ log_notice(">>> keycase_setup(%s)", casename);
102
+ params.keygen.keycase = kc_random;
103
+ // TODO
104
+ log_notice("<<< keycase_setup(%s): done", casename);
105
+ } else if (strcmp(casename, "dashes") == 0 || strcmp(casename, "aside") == 0) {
106
+ log_notice(">>> keycase_setup(%s)", casename);
107
+ params.keygen.keycase = kc_dashes;
108
+ // TODO
109
+ log_notice("<<< keycase_setup(%s): done", casename);
110
+ } else if (strcmp(casename, "custom") == 0) {
111
+ log_notice("=== keycase_setup(%s): skip", casename);
112
+ params.keygen.keycase = kc_custom;
113
+ } else {
114
+ failure("unknown keycase `%s`", casename);
115
+ }
116
+ }
117
+
118
+ /* TODO */
@@ -0,0 +1,134 @@
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
+ namespace chrono {
7
+
8
+ #ifndef NSEC_PER_SEC
9
+ #define NSEC_PER_SEC 1000000000u
10
+ #endif /* NSEC_PER_SEC */
11
+
12
+ uint32_t ns2fractional(uint32_t ns) {
13
+ assert(ns < NSEC_PER_SEC);
14
+ /* LY: здесь и далее используется "длинное деление", которое
15
+ * для ясности кода оставлено как есть (без ручной оптимизации). Так как
16
+ * GCC, Clang и даже MSVC сами давно умеют конвертировать деление на
17
+ * константу в быструю reciprocal-форму. */
18
+ return uint32_t((uint64_t(ns) << 32) / NSEC_PER_SEC);
19
+ }
20
+
21
+ uint32_t fractional2ns(uint32_t fractional) { return uint32_t((fractional * uint64_t(NSEC_PER_SEC)) >> 32); }
22
+
23
+ #ifndef USEC_PER_SEC
24
+ #define USEC_PER_SEC 1000000u
25
+ #endif /* USEC_PER_SEC */
26
+ uint32_t us2fractional(uint32_t us) {
27
+ assert(us < USEC_PER_SEC);
28
+ return uint32_t((uint64_t(us) << 32) / USEC_PER_SEC);
29
+ }
30
+
31
+ uint32_t fractional2us(uint32_t fractional) {
32
+ #if !(defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64))
33
+ /* Смеяться или плакать, но все существующие на май 2024 компиляторы Microsoft
34
+ * для ARM/ARM64, уже порядка 10 лет, падают на этом коде из-за внтутренней
35
+ * ошибке (aka ICE). */
36
+ return uint32_t((fractional * uint64_t(USEC_PER_SEC)) >> 32);
37
+ #else
38
+ static_assert(USEC_PER_SEC % 16 == 0, "WTF?");
39
+ /* Crutch for MSVC ARM/ARM64 compilers to avoid internal compiler error. */
40
+ return UInt32x32To64(fractional, USEC_PER_SEC / 16) >> 28;
41
+ #endif
42
+ }
43
+
44
+ #ifndef MSEC_PER_SEC
45
+ #define MSEC_PER_SEC 1000u
46
+ #endif /* MSEC_PER_SEC */
47
+ uint32_t ms2fractional(uint32_t ms) {
48
+ assert(ms < MSEC_PER_SEC);
49
+ return uint32_t((uint64_t(ms) << 32) / MSEC_PER_SEC);
50
+ }
51
+
52
+ uint32_t fractional2ms(uint32_t fractional) { return uint32_t((fractional * uint64_t(MSEC_PER_SEC)) >> 32); }
53
+
54
+ time from_ns(uint64_t ns) {
55
+ time result;
56
+ result.fixedpoint = ((ns / NSEC_PER_SEC) << 32) | ns2fractional(uint32_t(ns % NSEC_PER_SEC));
57
+ return result;
58
+ }
59
+
60
+ time from_us(uint64_t us) {
61
+ time result;
62
+ result.fixedpoint = ((us / USEC_PER_SEC) << 32) | us2fractional(uint32_t(us % USEC_PER_SEC));
63
+ return result;
64
+ }
65
+
66
+ time from_ms(uint64_t ms) {
67
+ time result;
68
+ result.fixedpoint = ((ms / MSEC_PER_SEC) << 32) | ms2fractional(uint32_t(ms % MSEC_PER_SEC));
69
+ return result;
70
+ }
71
+
72
+ #if __GNUC_PREREQ(8, 0) && (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
73
+ #pragma GCC diagnostic push
74
+ #pragma GCC diagnostic ignored "-Wcast-function-type"
75
+ #endif /* GCC/MINGW */
76
+
77
+ time now_realtime() {
78
+ #if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
79
+ static void(WINAPI * query_time)(LPFILETIME);
80
+ if (unlikely(!query_time)) {
81
+ HMODULE hModule = GetModuleHandle(TEXT("kernel32.dll"));
82
+ if (hModule)
83
+ query_time = (void(WINAPI *)(LPFILETIME))GetProcAddress(hModule, "GetSystemTimePreciseAsFileTime");
84
+ if (!query_time)
85
+ query_time = GetSystemTimeAsFileTime;
86
+ }
87
+
88
+ FILETIME filetime;
89
+ query_time(&filetime);
90
+ uint64_t ns100 = (uint64_t)filetime.dwHighDateTime << 32 | filetime.dwLowDateTime;
91
+ return from_ns((ns100 - UINT64_C(116444736000000000)) * 100u);
92
+ #else
93
+ struct timespec ts;
94
+ if (unlikely(clock_gettime(CLOCK_REALTIME, &ts)))
95
+ failure_perror("clock_gettime(CLOCK_REALTIME", errno);
96
+
97
+ return from_timespec(ts);
98
+ #endif
99
+ }
100
+
101
+ time now_monotonic() {
102
+ #if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
103
+ static uint64_t reciprocal;
104
+ static LARGE_INTEGER Frequency;
105
+ if (reciprocal == 0) {
106
+ if (!QueryPerformanceFrequency(&Frequency))
107
+ failure_perror("QueryPerformanceFrequency()", GetLastError());
108
+ reciprocal = (((UINT64_C(1) << 48) + Frequency.QuadPart / 2 + 1) / Frequency.QuadPart);
109
+ assert(reciprocal);
110
+ }
111
+
112
+ LARGE_INTEGER Counter;
113
+ if (!QueryPerformanceCounter(&Counter))
114
+ failure_perror("QueryPerformanceCounter()", GetLastError());
115
+
116
+ time result;
117
+ result.fixedpoint = (Counter.QuadPart / Frequency.QuadPart) << 32;
118
+ uint64_t mod = Counter.QuadPart % Frequency.QuadPart;
119
+ result.fixedpoint += (mod * reciprocal) >> 16;
120
+ return result;
121
+ #else
122
+ struct timespec ts;
123
+ if (unlikely(clock_gettime(CLOCK_MONOTONIC, &ts)))
124
+ failure_perror("clock_gettime(CLOCK_MONOTONIC)", errno);
125
+
126
+ return from_timespec(ts);
127
+ #endif
128
+ }
129
+
130
+ #if __GNUC_PREREQ(8, 0) && (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
131
+ #pragma GCC diagnostic pop
132
+ #endif /* GCC/MINGW */
133
+
134
+ } /* namespace chrono */