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,643 @@
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
+ #if defined(_MSC_VER) && !defined(strcasecmp)
7
+ #define strcasecmp(str, len) _stricmp(str, len)
8
+ #endif /* _MSC_VER && strcasecmp() */
9
+
10
+ namespace config {
11
+
12
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, const char **value,
13
+ const char *default_value) {
14
+ assert(narg < argc);
15
+ const char *current = argv[narg];
16
+ const size_t optlen = strlen(option);
17
+
18
+ if (strncmp(current, "--", 2) || strncmp(current + 2, option, optlen))
19
+ return false;
20
+
21
+ if (!value) {
22
+ if (current[optlen + 2] == '=')
23
+ failure("Option '--%s' doesn't accept any value\n", option);
24
+ return true;
25
+ }
26
+
27
+ *value = nullptr;
28
+ if (current[optlen + 2] == '=') {
29
+ *value = &current[optlen + 3];
30
+ return true;
31
+ }
32
+
33
+ if (narg + 1 < argc && strncmp("--", argv[narg + 1], 2) != 0) {
34
+ *value = argv[narg + 1];
35
+ if (strcmp(*value, "default") == 0) {
36
+ if (!default_value)
37
+ failure("Option '--%s' doesn't accept default value\n", option);
38
+ *value = default_value;
39
+ }
40
+ ++narg;
41
+ return true;
42
+ }
43
+
44
+ if (default_value) {
45
+ *value = default_value;
46
+ return true;
47
+ }
48
+
49
+ failure("No value given for '--%s' option\n", option);
50
+ }
51
+
52
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, std::string &value, bool allow_empty) {
53
+ return parse_option(argc, argv, narg, option, value, allow_empty, allow_empty ? "" : nullptr);
54
+ }
55
+
56
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, std::string &value, bool allow_empty,
57
+ const char *default_value) {
58
+ const char *value_cstr;
59
+ if (!parse_option(argc, argv, narg, option, &value_cstr, default_value))
60
+ return false;
61
+
62
+ if (!allow_empty && strlen(value_cstr) == 0)
63
+ failure("Value for option '--%s' couldn't be empty\n", option);
64
+
65
+ value = value_cstr;
66
+ return true;
67
+ }
68
+
69
+ template <>
70
+ bool parse_option<unsigned>(int argc, char *const argv[], int &narg, const char *option, unsigned &mask,
71
+ const option_verb *verbs) {
72
+ const char *list;
73
+ if (!parse_option(argc, argv, narg, option, &list))
74
+ return false;
75
+
76
+ unsigned clear = 0;
77
+ while (*list) {
78
+ if (*list == ',' || *list == ' ' || *list == '\t') {
79
+ ++list;
80
+ continue;
81
+ }
82
+
83
+ const char *const comma = strchr(list, ',');
84
+ const bool strikethrough = *list == '-' || *list == '~';
85
+ if (strikethrough || *list == '+')
86
+ ++list;
87
+ else
88
+ mask = clear;
89
+ const size_t len = (comma) ? comma - list : strlen(list);
90
+ const option_verb *scan = verbs;
91
+
92
+ while (true) {
93
+ if (!scan->verb)
94
+ failure("Unknown verb '%.*s', for option '--%s'\n", (int)len, list, option);
95
+ if (strlen(scan->verb) == len && strncmp(list, scan->verb, len) == 0) {
96
+ mask = strikethrough ? mask & ~scan->mask : mask | scan->mask;
97
+ clear = strikethrough ? clear & ~scan->mask : clear | scan->mask;
98
+ list += len;
99
+ break;
100
+ }
101
+ ++scan;
102
+ }
103
+ }
104
+
105
+ return true;
106
+ }
107
+
108
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, uint64_t &value, const scale_mode scale,
109
+ const uint64_t minval, const uint64_t maxval, const uint64_t default_value) {
110
+
111
+ const char *value_cstr;
112
+ if (!parse_option(argc, argv, narg, option, &value_cstr))
113
+ return false;
114
+
115
+ if (default_value && strcmp(value_cstr, "default") == 0) {
116
+ value = default_value;
117
+ return true;
118
+ }
119
+
120
+ if (strcmp(value_cstr, "min") == 0 || strcmp(value_cstr, "minimal") == 0) {
121
+ value = minval;
122
+ return true;
123
+ }
124
+
125
+ if (strcmp(value_cstr, "max") == 0 || strcmp(value_cstr, "maximal") == 0) {
126
+ value = maxval;
127
+ return true;
128
+ }
129
+
130
+ if (strcmp(value_cstr, "rnd") == 0 || strcmp(value_cstr, "rand") == 0 || strcmp(value_cstr, "random") == 0) {
131
+ value = minval;
132
+ if (maxval > minval) {
133
+ uint64_t salt = (scale != entropy) ? prng64() ^ UINT64_C(44263400549519813)
134
+ : (chrono::now_monotonic().fixedpoint ^ UINT64_C(0xD85794512ED321FD)) *
135
+ UINT64_C(0x9120038359EAF3) ^
136
+ chrono::now_realtime().fixedpoint * UINT64_C(0x2FE5232BDC8E5F);
137
+ value += salt % (maxval - minval);
138
+ }
139
+ if (scale == intkey)
140
+ value &= ~3u;
141
+ return true;
142
+ }
143
+
144
+ char *suffix = nullptr;
145
+ errno = 0;
146
+ unsigned long long raw = strtoull(value_cstr, &suffix, 0);
147
+ if ((suffix && *suffix) || errno) {
148
+ suffix = nullptr;
149
+ errno = 0;
150
+ raw = strtoull(value_cstr, &suffix, 10);
151
+ }
152
+ if (errno)
153
+ failure("Option '--%s' expects a numeric value (%s)\n", option, test_strerror(errno));
154
+
155
+ uint64_t multiplier = 1;
156
+ if (suffix && *suffix) {
157
+ if (scale == no_scale || scale == intkey)
158
+ failure("Option '--%s' doesn't accepts suffixes, so '%s' is unexpected\n", option, suffix);
159
+ if (strcmp(suffix, "K") == 0 || strcasecmp(suffix, "Kilo") == 0)
160
+ multiplier = (scale == decimal) ? UINT64_C(1000) : UINT64_C(1024);
161
+ else if (strcmp(suffix, "M") == 0 || strcasecmp(suffix, "Mega") == 0)
162
+ multiplier = (scale == decimal) ? UINT64_C(1000) * 1000 : UINT64_C(1024) * 1024;
163
+ else if (strcmp(suffix, "G") == 0 || strcasecmp(suffix, "Giga") == 0)
164
+ multiplier = (scale == decimal) ? UINT64_C(1000) * 1000 * 1000 : UINT64_C(1024) * 1024 * 1024;
165
+ else if (strcmp(suffix, "T") == 0 || strcasecmp(suffix, "Tera") == 0)
166
+ multiplier = (scale == decimal) ? UINT64_C(1000) * 1000 * 1000 * 1000 : UINT64_C(1024) * 1024 * 1024 * 1024;
167
+ else if (scale == duration && (strcmp(suffix, "s") == 0 || strcasecmp(suffix, "Seconds") == 0))
168
+ multiplier = 1;
169
+ else if (scale == duration && (strcmp(suffix, "m") == 0 || strcasecmp(suffix, "Minutes") == 0))
170
+ multiplier = 60;
171
+ else if (scale == duration && (strcmp(suffix, "h") == 0 || strcasecmp(suffix, "Hours") == 0))
172
+ multiplier = 3600;
173
+ else if (scale == duration && (strcmp(suffix, "d") == 0 || strcasecmp(suffix, "Days") == 0))
174
+ multiplier = 3600 * 24;
175
+ else
176
+ failure("Option '--%s' expects a numeric value with Kilo/Mega/Giga/Tera %s"
177
+ "suffixes, but '%s' is unexpected\n",
178
+ option, (scale == duration) ? "or Seconds/Minutes/Hours/Days " : "", suffix);
179
+ }
180
+
181
+ if (raw >= UINT64_MAX / multiplier)
182
+ failure("The value for option '--%s' is too huge\n", option);
183
+
184
+ value = raw * multiplier;
185
+ if (maxval && value > maxval)
186
+ failure("The maximal value for option '--%s' is %" PRIu64 "\n", option, maxval);
187
+ if (value < minval)
188
+ failure("The minimal value for option '--%s' is %" PRIu64 "\n", option, minval);
189
+ if (scale == intkey)
190
+ value &= ~3u;
191
+ return true;
192
+ }
193
+
194
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, unsigned &value, const scale_mode scale,
195
+ const unsigned minval, const unsigned maxval, const unsigned default_value) {
196
+
197
+ uint64_t huge;
198
+ if (!parse_option(argc, argv, narg, option, huge, scale, minval, maxval, default_value))
199
+ return false;
200
+ value = unsigned(huge);
201
+ return true;
202
+ }
203
+
204
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, uint8_t &value, const uint8_t minval,
205
+ const uint8_t maxval, const uint8_t default_value) {
206
+
207
+ uint64_t huge;
208
+ if (!parse_option(argc, argv, narg, option, huge, no_scale, minval, maxval, default_value))
209
+ return false;
210
+ value = uint8_t(huge);
211
+ return true;
212
+ }
213
+
214
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, int64_t &value, const int64_t minval,
215
+ const int64_t maxval, const int64_t default_value) {
216
+ uint64_t proxy = uint64_t(value);
217
+ if (parse_option(argc, argv, narg, option, proxy, config::binary, uint64_t(minval), uint64_t(maxval),
218
+ uint64_t(default_value))) {
219
+ value = int64_t(proxy);
220
+ return true;
221
+ }
222
+ return false;
223
+ }
224
+
225
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, int32_t &value, const int32_t minval,
226
+ const int32_t maxval, const int32_t default_value) {
227
+ uint64_t proxy = uint64_t(value);
228
+ if (parse_option(argc, argv, narg, option, proxy, config::binary, uint64_t(minval), uint64_t(maxval),
229
+ uint64_t(default_value))) {
230
+ value = int32_t(proxy);
231
+ return true;
232
+ }
233
+ return false;
234
+ }
235
+
236
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, logging::loglevel &loglevel) {
237
+ const char *value_cstr;
238
+ if (!parse_option(argc, argv, narg, option, &value_cstr))
239
+ return false;
240
+
241
+ if (strcmp(value_cstr, "min") == 0 || strcmp(value_cstr, "minimal") == 0 || strcmp(value_cstr, "fatal") == 0) {
242
+ loglevel = logging::failure;
243
+ return true;
244
+ }
245
+
246
+ if (strcmp(value_cstr, "error") == 0 || strcmp(value_cstr, "err") == 0) {
247
+ loglevel = logging::error;
248
+ return true;
249
+ }
250
+
251
+ if (strcmp(value_cstr, "warning") == 0 || strcmp(value_cstr, "warn") == 0) {
252
+ loglevel = logging::error;
253
+ return true;
254
+ }
255
+
256
+ if (strcmp(value_cstr, "default") == 0 || strcmp(value_cstr, "notice") == 0) {
257
+ loglevel = logging::notice;
258
+ return true;
259
+ }
260
+
261
+ if (strcmp(value_cstr, "verbose") == 0) {
262
+ loglevel = logging::verbose;
263
+ return true;
264
+ }
265
+
266
+ if (strcmp(value_cstr, "debug") == 0) {
267
+ loglevel = logging::debug;
268
+ return true;
269
+ }
270
+
271
+ if (strcmp(value_cstr, "trace") == 0) {
272
+ loglevel = logging::trace;
273
+ return true;
274
+ }
275
+
276
+ if (strcmp(value_cstr, "max") == 0 || strcmp(value_cstr, "maximal") == 0 || strcmp(value_cstr, "extra") == 0) {
277
+ loglevel = logging::extra;
278
+ return true;
279
+ }
280
+
281
+ char *suffix = nullptr;
282
+ unsigned long long raw = strtoull(value_cstr, &suffix, 0);
283
+ if ((suffix && *suffix) || errno) {
284
+ suffix = nullptr;
285
+ errno = 0;
286
+ raw = strtoull(value_cstr, &suffix, 10);
287
+ }
288
+ if ((!suffix || !*suffix) && !errno && raw < 8) {
289
+ loglevel = static_cast<logging::loglevel>(raw);
290
+ return true;
291
+ }
292
+
293
+ failure("Unknown log-level '%s', for option '--%s'\n", value_cstr, option);
294
+ }
295
+
296
+ bool parse_option(int argc, char *const argv[], int &narg, const char *option, bool &value) {
297
+ const char *value_cstr = nullptr;
298
+ if (!parse_option(argc, argv, narg, option, &value_cstr, "yes")) {
299
+ const char *current = argv[narg];
300
+ if (strncmp(current, "--no-", 5) == 0 && strcmp(current + 5, option) == 0) {
301
+ value = false;
302
+ return true;
303
+ }
304
+ if (strncmp(current, "--dont-", 7) == 0 && strcmp(current + 7, option) == 0) {
305
+ value = false;
306
+ return true;
307
+ }
308
+ return false;
309
+ }
310
+
311
+ if (!value_cstr) {
312
+ value = true;
313
+ return true;
314
+ }
315
+
316
+ if (strcasecmp(value_cstr, "yes") == 0 || strcasecmp(value_cstr, "1") == 0 || strcasecmp(value_cstr, "on") == 0) {
317
+ value = true;
318
+ return true;
319
+ }
320
+
321
+ if (strcasecmp(value_cstr, "no") == 0 || strcasecmp(value_cstr, "0") == 0 || strcasecmp(value_cstr, "off") == 0) {
322
+ value = false;
323
+ return true;
324
+ }
325
+
326
+ failure("Option '--%s' expects a 'boolean' value Yes/No, so '%s' is unexpected\n", option, value_cstr);
327
+ }
328
+
329
+ //-----------------------------------------------------------------------------
330
+
331
+ const struct option_verb mode_bits[] = {{"rdonly", unsigned(MDBX_RDONLY)},
332
+ {"nosync-utterly", unsigned(MDBX_UTTERLY_NOSYNC)},
333
+ {"nosubdir", unsigned(MDBX_NOSUBDIR)},
334
+ {"nosync-safe", unsigned(MDBX_SAFE_NOSYNC)},
335
+ {"nometasync", unsigned(MDBX_NOMETASYNC)},
336
+ {"writemap", unsigned(MDBX_WRITEMAP)},
337
+ {"nostickythreads", unsigned(MDBX_NOSTICKYTHREADS)},
338
+ {"no-sticky-threads", unsigned(MDBX_NOSTICKYTHREADS)},
339
+ {"nordahead", unsigned(MDBX_NORDAHEAD)},
340
+ {"nomeminit", unsigned(MDBX_NOMEMINIT)},
341
+ {"lifo", unsigned(MDBX_LIFORECLAIM)},
342
+ {"perturb", unsigned(MDBX_PAGEPERTURB)},
343
+ {"accede", unsigned(MDBX_ACCEDE)},
344
+ {"exclusive", unsigned(MDBX_EXCLUSIVE)},
345
+ {"validation", unsigned(MDBX_VALIDATION)},
346
+ {nullptr, 0}};
347
+
348
+ const struct option_verb table_bits[] = {{"key.reverse", unsigned(MDBX_REVERSEKEY)},
349
+ {"key.integer", unsigned(MDBX_INTEGERKEY)},
350
+ {"data.integer", unsigned(MDBX_INTEGERDUP | MDBX_DUPFIXED | MDBX_DUPSORT)},
351
+ {"data.fixed", unsigned(MDBX_DUPFIXED | MDBX_DUPSORT)},
352
+ {"data.reverse", unsigned(MDBX_REVERSEDUP | MDBX_DUPSORT)},
353
+ {"data.multi", unsigned(MDBX_DUPSORT)},
354
+ {nullptr, 0}};
355
+
356
+ static void dump_verbs(const char *caption, size_t bits, const struct option_verb *verbs) {
357
+ log_verbose("%s: 0x%" PRIx64 " = ", caption, (uint64_t)bits);
358
+
359
+ const char *comma = "";
360
+ while (verbs->mask && bits) {
361
+ if ((bits & verbs->mask) == verbs->mask) {
362
+ logging::feed("%s%s", comma, verbs->verb);
363
+ bits -= verbs->mask;
364
+ comma = ", ";
365
+ }
366
+ ++verbs;
367
+ }
368
+
369
+ logging::feed("%s\n", (*comma == '\0') ? "none" : "");
370
+ }
371
+
372
+ static void dump_duration(const char *caption, unsigned duration) {
373
+ log_verbose("%s: ", caption);
374
+ if (duration) {
375
+ if (duration > 24 * 3600)
376
+ logging::feed("%u_", duration / (24 * 3600));
377
+ if (duration > 3600)
378
+ logging::feed("%02u:", (duration % (24 * 3600)) / 3600);
379
+ logging::feed("%02u:%02u", (duration % 3600) / 60, duration % 60);
380
+ } else {
381
+ logging::feed("INFINITE");
382
+ }
383
+ logging::feed("\n");
384
+ }
385
+
386
+ void dump(const char *title) {
387
+ logging::local_suffix indent(title);
388
+
389
+ for (auto i = global::actors.begin(); i != global::actors.end(); ++i) {
390
+ log_verbose("#%u, testcase %s, space_id/table %u\n", i->actor_id, testcase2str(i->testcase), i->space_id);
391
+ indent.push();
392
+ log_verbose("prng-seed: %u\n", i->params.prng_seed);
393
+
394
+ if (i->params.loglevel) {
395
+ log_verbose("log: level %u, %s\n", i->params.loglevel,
396
+ i->params.pathname_log.empty() ? "console" : i->params.pathname_log.c_str());
397
+ }
398
+
399
+ log_verbose("database: %s, size %" PRIuPTR "[%" PRIiPTR "..%" PRIiPTR ", %i %i, %i]\n",
400
+ i->params.pathname_db.c_str(), i->params.size_now, i->params.size_lower, i->params.size_upper,
401
+ i->params.shrink_threshold, i->params.growth_step, i->params.pagesize);
402
+
403
+ dump_verbs("mode", i->params.mode_flags, mode_bits);
404
+ log_verbose("random-writemap: %s\n", i->params.random_writemap ? "Yes" : "No");
405
+ dump_verbs("table", i->params.table_flags, table_bits);
406
+
407
+ if (i->params.test_nops)
408
+ log_verbose("iterations/records %u\n", i->params.test_nops);
409
+ else
410
+ dump_duration("duration", i->params.test_duration);
411
+
412
+ if (i->params.nrepeat)
413
+ log_verbose("repeat %u\n", i->params.nrepeat);
414
+ else
415
+ log_verbose("repeat ETERNALLY\n");
416
+
417
+ log_verbose("threads %u\n", i->params.nthreads);
418
+
419
+ log_verbose("keygen.params: case %s, width %u, mesh %u, rotate %u, offset %" PRIu64 ", split %u/%u\n",
420
+ keygencase2str(i->params.keygen.keycase), i->params.keygen.width, i->params.keygen.mesh,
421
+ i->params.keygen.rotate, i->params.keygen.offset, i->params.keygen.split,
422
+ i->params.keygen.width - i->params.keygen.split);
423
+ log_verbose("keygen.zerofill: %s\n", i->params.keygen.zero_fill ? "Yes" : "No");
424
+ log_verbose("key: minlen %u, maxlen %u\n", i->params.keylen_min, i->params.keylen_max);
425
+ log_verbose("data: minlen %u, maxlen %u\n", i->params.datalen_min, i->params.datalen_max);
426
+
427
+ log_verbose("batch: read %u, write %u\n", i->params.batch_read, i->params.batch_write);
428
+
429
+ if (i->params.waitfor_nops)
430
+ log_verbose("wait: actor %u for %u ops\n", i->wait4id, i->params.waitfor_nops);
431
+ else if (i->params.delaystart)
432
+ dump_duration("delay", i->params.delaystart);
433
+ else
434
+ log_verbose("no-delay\n");
435
+
436
+ if (i->params.inject_writefaultn)
437
+ log_verbose("inject-writefault on %u ops\n", i->params.inject_writefaultn);
438
+ else
439
+ log_verbose("no-inject-writefault\n");
440
+
441
+ log_verbose("limits: readers %u, tables %u, txn-bytes %zu\n", i->params.max_readers, i->params.max_tables,
442
+ mdbx_limits_txnsize_max(i->params.pagesize));
443
+
444
+ log_verbose("drop table: %s\n", i->params.drop_table ? "Yes" : "No");
445
+ log_verbose("ignore MDBX_MAP_FULL error: %s\n", i->params.ignore_dbfull ? "Yes" : "No");
446
+ log_verbose("verifying by speculum: %s\n", i->params.speculum ? "Yes" : "No");
447
+
448
+ indent.pop();
449
+ }
450
+
451
+ dump_duration("timeout", global::config::timeout_duration_seconds);
452
+ log_verbose("cleanup: before %s, after %s\n", global::config::cleanup_before ? "Yes" : "No",
453
+ global::config::cleanup_after ? "Yes" : "No");
454
+
455
+ log_verbose("failfast: %s\n", global::config::failfast ? "Yes" : "No");
456
+ log_verbose("progress indicator: %s\n", global::config::progress_indicator ? "Yes" : "No");
457
+ log_verbose("console mode: %s\n", global::config::console_mode ? "Yes" : "No");
458
+ log_verbose("geometry jitter: %s\n", global::config::geometry_jitter ? "Yes" : "No");
459
+ }
460
+
461
+ } /* namespace config */
462
+
463
+ //-----------------------------------------------------------------------------
464
+
465
+ using namespace config;
466
+
467
+ actor_config::actor_config(actor_testcase testcase, const actor_params &params, unsigned space_id, unsigned wait4id)
468
+ : actor_config_pod(1 + unsigned(global::actors.size()), testcase, space_id, wait4id), params(params) {}
469
+
470
+ const std::string actor_config::serialize(const char *prefix) const {
471
+ simple_checksum checksum;
472
+ std::string result;
473
+
474
+ if (prefix)
475
+ result.append(prefix);
476
+
477
+ checksum.push(params.pathname_db);
478
+ result.append(params.pathname_db);
479
+ result.push_back('|');
480
+
481
+ checksum.push(params.pathname_log);
482
+ result.append(params.pathname_log);
483
+ result.push_back('|');
484
+
485
+ #if __cplusplus > 201400
486
+ static_assert(std::is_trivially_copyable<actor_params_pod>::value, "actor_params_pod should by POD");
487
+ #else
488
+ static_assert(std::is_standard_layout<actor_params_pod>::value, "actor_params_pod should by POD");
489
+ #endif
490
+ result.append(data2hex(static_cast<const actor_params_pod *>(&params), sizeof(actor_params_pod), checksum));
491
+ result.push_back('|');
492
+
493
+ #if __cplusplus > 201400
494
+ static_assert(std::is_trivially_copyable<actor_config_pod>::value, "actor_config_pod should by POD");
495
+ #else
496
+ static_assert(std::is_standard_layout<actor_config_pod>::value, "actor_config_pod should by POD");
497
+ #endif
498
+ result.append(data2hex(static_cast<const actor_config_pod *>(this), sizeof(actor_config_pod), checksum));
499
+ result.push_back('|');
500
+ result.push_back(global::config::progress_indicator ? 'Y' : 'N');
501
+ checksum.push(global::config::progress_indicator);
502
+ result.push_back(global::config::console_mode ? 'Y' : 'N');
503
+ checksum.push(global::config::console_mode);
504
+ result.push_back(global::config::geometry_jitter ? 'Y' : 'N');
505
+ checksum.push(global::config::geometry_jitter);
506
+ result.push_back('|');
507
+
508
+ result.append(osal_serialize(checksum));
509
+ result.push_back('|');
510
+
511
+ result.append(std::to_string(checksum.value));
512
+ return result;
513
+ }
514
+
515
+ bool actor_config::deserialize(const char *str, actor_config &config) {
516
+ simple_checksum checksum;
517
+
518
+ TRACE(">> actor_config::deserialize: %s\n", str);
519
+
520
+ const char *slash = strchr(str, '|');
521
+ if (!slash) {
522
+ TRACE("<< actor_config::deserialize: slash-1\n");
523
+ return false;
524
+ }
525
+ config.params.pathname_db.assign(str, slash - str);
526
+ checksum.push(config.params.pathname_db);
527
+ str = slash + 1;
528
+
529
+ slash = strchr(str, '|');
530
+ if (!slash) {
531
+ TRACE("<< actor_config::deserialize: slash-2\n");
532
+ return false;
533
+ }
534
+ config.params.pathname_log.assign(str, slash - str);
535
+ checksum.push(config.params.pathname_log);
536
+ str = slash + 1;
537
+
538
+ slash = strchr(str, '|');
539
+ if (!slash) {
540
+ TRACE("<< actor_config::deserialize: slash-3\n");
541
+ return false;
542
+ }
543
+ #if __cplusplus > 201400
544
+ static_assert(std::is_trivially_copyable<actor_params_pod>::value, "actor_params_pod should by POD");
545
+ #else
546
+ static_assert(std::is_standard_layout<actor_params_pod>::value, "actor_params_pod should by POD");
547
+ #endif
548
+ if (!hex2data(str, slash, static_cast<actor_params_pod *>(&config.params), sizeof(actor_params_pod), checksum)) {
549
+ TRACE("<< actor_config::deserialize: actor_params_pod(%.*s)\n", (int)(slash - str), str);
550
+ return false;
551
+ }
552
+ str = slash + 1;
553
+
554
+ slash = strchr(str, '|');
555
+ if (!slash) {
556
+ TRACE("<< actor_config::deserialize: slash-4\n");
557
+ return false;
558
+ }
559
+ #if __cplusplus > 201400
560
+ static_assert(std::is_trivially_copyable<actor_config_pod>::value, "actor_config_pod should by POD");
561
+ #else
562
+ static_assert(std::is_standard_layout<actor_config_pod>::value, "actor_config_pod should by POD");
563
+ #endif
564
+ if (!hex2data(str, slash, static_cast<actor_config_pod *>(&config), sizeof(actor_config_pod), checksum)) {
565
+ TRACE("<< actor_config::deserialize: actor_config_pod(%.*s)\n", (int)(slash - str), str);
566
+ return false;
567
+ }
568
+ str = slash + 1;
569
+
570
+ slash = strchr(str, '|');
571
+ if (!slash) {
572
+ TRACE("<< actor_config::deserialize: slash-5\n");
573
+ return false;
574
+ }
575
+ if ((str[0] == 'Y' || str[0] == 'N') && (str[1] == 'Y' || str[1] == 'N') && (str[2] == 'Y' || str[2] == 'N')) {
576
+ global::config::progress_indicator = str[0] == 'Y';
577
+ checksum.push(global::config::progress_indicator);
578
+ global::config::console_mode = str[1] == 'Y';
579
+ checksum.push(global::config::console_mode);
580
+ global::config::geometry_jitter = str[2] != 'N';
581
+ checksum.push(global::config::geometry_jitter);
582
+ str = slash + 1;
583
+
584
+ slash = strchr(str, '|');
585
+ if (!slash) {
586
+ TRACE("<< actor_config::deserialize: slash-6\n");
587
+ return false;
588
+ }
589
+ }
590
+
591
+ if (!config.osal_deserialize(str, slash, checksum)) {
592
+ TRACE("<< actor_config::deserialize: osal\n");
593
+ return false;
594
+ }
595
+ str = slash + 1;
596
+
597
+ uint64_t verify = 0;
598
+ while (*str >= '0' && *str <= '9')
599
+ verify = verify * 10 + *str++ - '0';
600
+
601
+ if (checksum.value != verify) {
602
+ TRACE("<< actor_config::deserialize: checksum mismatch\n");
603
+ return false;
604
+ }
605
+
606
+ TRACE("<< actor_config::deserialize: OK\n");
607
+ return true;
608
+ }
609
+
610
+ unsigned actor_params::mdbx_keylen_min() const { return unsigned(mdbx_limits_keysize_min(table_flags)); }
611
+
612
+ unsigned actor_params::mdbx_keylen_max() const { return unsigned(mdbx_limits_keysize_max(pagesize, table_flags)); }
613
+
614
+ unsigned actor_params::mdbx_datalen_min() const { return unsigned(mdbx_limits_valsize_min(table_flags)); }
615
+
616
+ unsigned actor_params::mdbx_datalen_max() const {
617
+ return std::min(unsigned(UINT16_MAX), unsigned(mdbx_limits_valsize_max(pagesize, table_flags)));
618
+ }
619
+
620
+ bool actor_params::make_keygen_linear() {
621
+ const auto base = serial_base();
622
+ keygen.mesh = (table_flags & MDBX_DUPSORT) ? 0 : keygen.split;
623
+ keygen.rotate = 0;
624
+ keygen.offset = 0;
625
+ const auto max_serial = serial_mask(keygen.width) + base;
626
+ const auto max_key_serial = (keygen.split && (table_flags & MDBX_DUPSORT)) ? max_serial >> keygen.split : max_serial;
627
+ const auto max_value_serial = (keygen.split && (table_flags & MDBX_DUPSORT)) ? serial_mask(keygen.split) : 0;
628
+
629
+ while (keylen_min < 8 && (keylen_min == 0 || serial_mask(keylen_min * 8) < max_key_serial)) {
630
+ keylen_min += (table_flags & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) ? 4 : 1;
631
+ if (keylen_max < keylen_min)
632
+ keylen_max = keylen_min;
633
+ }
634
+
635
+ if (table_flags & MDBX_DUPSORT)
636
+ while (datalen_min < 8 && (datalen_min == 0 || serial_mask(datalen_min * 8) < max_value_serial)) {
637
+ datalen_min += (table_flags & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) ? 4 : 1;
638
+ if (datalen_max < datalen_min)
639
+ datalen_max = datalen_min;
640
+ }
641
+
642
+ return true;
643
+ }