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,673 @@
1
+ /// \copyright SPDX-License-Identifier: Apache-2.0
2
+ /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
3
+ ///
4
+
5
+ ///
6
+ /// mdbx_chk.c - memory-mapped database check tool
7
+ ///
8
+
9
+ #ifdef _MSC_VER
10
+ #if _MSC_VER > 1800
11
+ #pragma warning(disable : 4464) /* relative include path contains '..' */
12
+ #endif
13
+ #pragma warning(disable : 4996) /* The POSIX name is deprecated... */
14
+ #endif /* _MSC_VER (warnings) */
15
+
16
+ #define xMDBX_TOOLS /* Avoid using internal eASSERT() */
17
+ #include "essentials.h"
18
+
19
+ #include <ctype.h>
20
+
21
+ #if defined(_WIN32) || defined(_WIN64)
22
+ #include "wingetopt.h"
23
+
24
+ static volatile BOOL user_break;
25
+ static BOOL WINAPI ConsoleBreakHandlerRoutine(DWORD dwCtrlType) {
26
+ (void)dwCtrlType;
27
+ user_break = 1;
28
+ return true;
29
+ }
30
+
31
+ static uint64_t GetMilliseconds(void) {
32
+ LARGE_INTEGER Counter, Frequency;
33
+ return (QueryPerformanceFrequency(&Frequency) && QueryPerformanceCounter(&Counter))
34
+ ? Counter.QuadPart * 1000ul / Frequency.QuadPart
35
+ : 0;
36
+ }
37
+
38
+ #else /* WINDOWS */
39
+
40
+ static volatile sig_atomic_t user_break;
41
+ static void signal_handler(int sig) {
42
+ (void)sig;
43
+ user_break = 1;
44
+ }
45
+
46
+ #endif /* !WINDOWS */
47
+
48
+ #define EXIT_INTERRUPTED (EXIT_FAILURE + 4)
49
+ #define EXIT_FAILURE_SYS (EXIT_FAILURE + 3)
50
+ #define EXIT_FAILURE_MDBX (EXIT_FAILURE + 2)
51
+ #define EXIT_FAILURE_CHECK_MAJOR (EXIT_FAILURE + 1)
52
+ #define EXIT_FAILURE_CHECK_MINOR EXIT_FAILURE
53
+
54
+ MDBX_env_flags_t env_flags = MDBX_RDONLY | MDBX_EXCLUSIVE | MDBX_VALIDATION;
55
+ MDBX_env *env;
56
+ MDBX_txn *txn;
57
+ unsigned verbose = 0;
58
+ bool quiet;
59
+ MDBX_val only_table;
60
+ int stuck_meta = -1;
61
+ MDBX_chk_context_t chk;
62
+ bool turn_meta = false;
63
+ bool force_turn_meta = false;
64
+ MDBX_chk_flags_t chk_flags = MDBX_CHK_DEFAULTS;
65
+ MDBX_chk_stage_t chk_stage = MDBX_chk_none;
66
+
67
+ static MDBX_chk_line_t line_struct;
68
+ static size_t anchor_lineno;
69
+ static size_t line_count;
70
+ static FILE *line_output;
71
+
72
+ #define LINE_SEVERITY_NONE 255
73
+ static bool lf(void) {
74
+ if (!line_struct.empty) {
75
+ line_count += 1;
76
+ line_struct.empty = true;
77
+ line_struct.severity = LINE_SEVERITY_NONE;
78
+ line_struct.scope_depth = 0;
79
+ if (line_output) {
80
+ fputc('\n', line_output);
81
+ return true;
82
+ }
83
+ }
84
+ return false;
85
+ }
86
+
87
+ static void flush(void) { fflush(nullptr); }
88
+
89
+ static void lf_flush(void) {
90
+ if (lf())
91
+ flush();
92
+ }
93
+
94
+ static bool silently(enum MDBX_chk_severity severity) {
95
+ int cutoff = chk.scope ? chk.scope->verbosity >> MDBX_chk_severity_prio_shift
96
+ : verbose + (MDBX_chk_result >> MDBX_chk_severity_prio_shift);
97
+ int prio = (severity >> MDBX_chk_severity_prio_shift);
98
+ if (chk.scope && chk.scope->stage == MDBX_chk_tables && verbose < 2)
99
+ prio += 1;
100
+ return quiet || cutoff < ((prio > 0) ? prio : 0);
101
+ }
102
+
103
+ static FILE *prefix(enum MDBX_chk_severity severity) {
104
+ if (silently(severity))
105
+ return nullptr;
106
+
107
+ static const char *const prefixes[16] = {
108
+ "!!!fatal: ", // 0 fatal
109
+ " ! ", // 1 error
110
+ " ~ ", // 2 warning
111
+ " ", // 3 notice
112
+ "", // 4 result
113
+ " = ", // 5 resolution
114
+ " - ", // 6 processing
115
+ " ", // 7 info
116
+ " ", // 8 verbose
117
+ " ", // 9 details
118
+ " // ", // A lib-verbose
119
+ " //// ", // B lib-debug
120
+ " ////// ", // C lib-trace
121
+ " ////// ", // D lib-extra
122
+ " ////// ", // E +1
123
+ " ////// " // F +2
124
+ };
125
+
126
+ const bool nl = line_struct.scope_depth != chk.scope_nesting ||
127
+ (line_struct.severity != severity && (line_struct.severity != MDBX_chk_processing ||
128
+ severity < MDBX_chk_result || severity > MDBX_chk_resolution));
129
+ if (nl)
130
+ lf();
131
+ if (severity < MDBX_chk_warning)
132
+ flush();
133
+ FILE *out = (severity > MDBX_chk_error) ? stdout : stderr;
134
+ if (nl || line_struct.empty) {
135
+ line_struct.severity = severity;
136
+ line_struct.scope_depth = chk.scope_nesting;
137
+ unsigned kind = line_struct.severity & MDBX_chk_severity_kind_mask;
138
+ if (line_struct.scope_depth || *prefixes[kind]) {
139
+ line_struct.empty = false;
140
+ for (size_t i = 0; i < line_struct.scope_depth; ++i)
141
+ fputs(" ", out);
142
+ fputs(prefixes[kind], out);
143
+ }
144
+ }
145
+ return line_output = out;
146
+ }
147
+
148
+ static void suffix(size_t cookie, const char *str) {
149
+ if (cookie == line_count && !line_struct.empty) {
150
+ fprintf(line_output, " %s", str);
151
+ line_struct.empty = false;
152
+ lf();
153
+ }
154
+ }
155
+
156
+ static size_t MDBX_PRINTF_ARGS(2, 3) print(enum MDBX_chk_severity severity, const char *msg, ...) {
157
+ FILE *out = prefix(severity);
158
+ if (out) {
159
+ va_list args;
160
+ va_start(args, msg);
161
+ vfprintf(out, msg, args);
162
+ va_end(args);
163
+ line_struct.empty = false;
164
+ return line_count;
165
+ }
166
+ return 0;
167
+ }
168
+
169
+ static FILE *MDBX_PRINTF_ARGS(2, 3) print_ln(enum MDBX_chk_severity severity, const char *msg, ...) {
170
+ FILE *out = prefix(severity);
171
+ if (out) {
172
+ va_list args;
173
+ va_start(args, msg);
174
+ vfprintf(out, msg, args);
175
+ va_end(args);
176
+ line_struct.empty = false;
177
+ lf();
178
+ }
179
+ return out;
180
+ }
181
+
182
+ static void logger(MDBX_log_level_t level, const char *function, int line, const char *fmt, va_list args) {
183
+ if (level <= MDBX_LOG_ERROR)
184
+ mdbx_env_chk_encount_problem(&chk);
185
+
186
+ const unsigned kind =
187
+ (level > MDBX_LOG_NOTICE) ? level - MDBX_LOG_NOTICE + (MDBX_chk_extra & MDBX_chk_severity_kind_mask) : level;
188
+ const unsigned prio = kind << MDBX_chk_severity_prio_shift;
189
+ enum MDBX_chk_severity severity = prio + kind;
190
+ FILE *out = prefix(severity);
191
+ if (out) {
192
+ vfprintf(out, fmt, args);
193
+ const bool have_lf = fmt[strlen(fmt) - 1] == '\n';
194
+ if (level == MDBX_LOG_FATAL && function && line) {
195
+ if (have_lf)
196
+ for (size_t i = 0; i < line_struct.scope_depth; ++i)
197
+ fputs(" ", out);
198
+ fprintf(out, have_lf ? " %s(), %u" : " (%s:%u)", function + (strncmp(function, "mdbx_", 5) ? 0 : 5),
199
+ line);
200
+ lf();
201
+ } else if (have_lf) {
202
+ line_struct.empty = true;
203
+ line_struct.severity = LINE_SEVERITY_NONE;
204
+ line_count += 1;
205
+ } else
206
+ lf();
207
+ }
208
+ if (level < MDBX_LOG_VERBOSE)
209
+ flush();
210
+ if (level == MDBX_LOG_FATAL) {
211
+ #if !MDBX_DEBUG && !MDBX_FORCE_ASSERTIONS
212
+ exit(EXIT_FAILURE_MDBX);
213
+ #endif
214
+ abort();
215
+ }
216
+ }
217
+
218
+ static void MDBX_PRINTF_ARGS(1, 2) error_fmt(const char *msg, ...) {
219
+ va_list args;
220
+ va_start(args, msg);
221
+ logger(MDBX_LOG_ERROR, nullptr, 0, msg, args);
222
+ va_end(args);
223
+ }
224
+
225
+ static int error_fn(const char *fn, int err) {
226
+ if (err)
227
+ error_fmt("%s() failed, error %d, %s", fn, err, mdbx_strerror(err));
228
+ return err;
229
+ }
230
+
231
+ static bool check_break(MDBX_chk_context_t *ctx) {
232
+ (void)ctx;
233
+ if (!user_break)
234
+ return false;
235
+ if (user_break == 1) {
236
+ print(MDBX_chk_resolution, "interrupted by signal");
237
+ lf_flush();
238
+ user_break = 2;
239
+ }
240
+ return true;
241
+ }
242
+
243
+ static int scope_push(MDBX_chk_context_t *ctx, MDBX_chk_scope_t *scope, MDBX_chk_scope_t *inner, const char *fmt,
244
+ va_list args) {
245
+ (void)scope;
246
+ if (fmt && *fmt) {
247
+ FILE *out = prefix(MDBX_chk_processing);
248
+ if (out) {
249
+ vfprintf(out, fmt, args);
250
+ inner->usr_o.number = line_count;
251
+ line_struct.ctx = ctx;
252
+ flush();
253
+ }
254
+ }
255
+ return MDBX_SUCCESS;
256
+ }
257
+
258
+ static void scope_pop(MDBX_chk_context_t *ctx, MDBX_chk_scope_t *scope, MDBX_chk_scope_t *inner) {
259
+ (void)ctx;
260
+ (void)scope;
261
+ suffix(inner->usr_o.number, inner->subtotal_issues ? "error(s)" : "done");
262
+ flush();
263
+ }
264
+
265
+ static MDBX_chk_user_table_cookie_t *table_filter(MDBX_chk_context_t *ctx, const MDBX_val *name,
266
+ MDBX_db_flags_t flags) {
267
+ (void)ctx;
268
+ (void)flags;
269
+ return (!only_table.iov_base ||
270
+ (only_table.iov_len == name->iov_len && memcmp(only_table.iov_base, name->iov_base, name->iov_len) == 0))
271
+ ? (void *)(intptr_t)-1
272
+ : nullptr;
273
+ }
274
+
275
+ static int stage_begin(MDBX_chk_context_t *ctx, enum MDBX_chk_stage stage) {
276
+ (void)ctx;
277
+ chk_stage = stage;
278
+ anchor_lineno = line_count;
279
+ flush();
280
+ return MDBX_SUCCESS;
281
+ }
282
+
283
+ static int conclude(MDBX_chk_context_t *ctx);
284
+ static int stage_end(MDBX_chk_context_t *ctx, enum MDBX_chk_stage stage, int err) {
285
+ if (stage == MDBX_chk_conclude && !err)
286
+ err = conclude(ctx);
287
+ suffix(anchor_lineno, err ? "error(s)" : "done");
288
+ flush();
289
+ chk_stage = MDBX_chk_none;
290
+ return err;
291
+ }
292
+
293
+ static MDBX_chk_line_t *print_begin(MDBX_chk_context_t *ctx, enum MDBX_chk_severity severity) {
294
+ (void)ctx;
295
+ if (silently(severity))
296
+ return nullptr;
297
+ if (line_struct.ctx) {
298
+ if (line_struct.severity == MDBX_chk_processing && severity >= MDBX_chk_result && severity <= MDBX_chk_resolution &&
299
+ line_output)
300
+ fputc(' ', line_output);
301
+ else
302
+ lf();
303
+ line_struct.ctx = nullptr;
304
+ }
305
+ line_struct.severity = severity;
306
+ return &line_struct;
307
+ }
308
+
309
+ static void print_flush(MDBX_chk_line_t *line) {
310
+ (void)line;
311
+ flush();
312
+ }
313
+
314
+ static void print_done(MDBX_chk_line_t *line) {
315
+ lf();
316
+ line->ctx = nullptr;
317
+ }
318
+
319
+ static void print_chars(MDBX_chk_line_t *line, const char *str, size_t len) {
320
+ if (line->empty)
321
+ prefix(line->severity);
322
+ fwrite(str, 1, len, line_output);
323
+ }
324
+
325
+ static void print_format(MDBX_chk_line_t *line, const char *fmt, va_list args) {
326
+ if (line->empty)
327
+ prefix(line->severity);
328
+ vfprintf(line_output, fmt, args);
329
+ }
330
+
331
+ static const MDBX_chk_callbacks_t cb = {.check_break = check_break,
332
+ .scope_push = scope_push,
333
+ .scope_pop = scope_pop,
334
+ .table_filter = table_filter,
335
+ .stage_begin = stage_begin,
336
+ .stage_end = stage_end,
337
+ .print_begin = print_begin,
338
+ .print_flush = print_flush,
339
+ .print_done = print_done,
340
+ .print_chars = print_chars,
341
+ .print_format = print_format};
342
+
343
+ static void usage(char *prog) {
344
+ fprintf(stderr,
345
+ "usage: %s "
346
+ "[-V] [-v] [-q] [-c] [-0|1|2] [-w] [-d] [-i] [-s table] [-u|U] dbpath\n"
347
+ " -V\t\tprint version and exit\n"
348
+ " -v\t\tmore verbose, could be repeated upto 9 times for extra details\n"
349
+ " -q\t\tbe quiet\n"
350
+ " -c\t\tforce cooperative mode (don't try exclusive)\n"
351
+ " -w\t\twrite-mode checking\n"
352
+ " -d\t\tdisable page-by-page traversal of B-tree\n"
353
+ " -i\t\tignore wrong order errors (for custom comparators case)\n"
354
+ " -s table\tprocess a specific subdatabase only\n"
355
+ " -u\t\twarmup database before checking\n"
356
+ " -U\t\twarmup and try lock database pages in memory before checking\n"
357
+ " -0|1|2\tforce using specific meta-page 0, or 2 for checking\n"
358
+ " -t\t\tturn to a specified meta-page on successful check\n"
359
+ " -T\t\tturn to a specified meta-page EVEN ON UNSUCCESSFUL CHECK!\n",
360
+ prog);
361
+ exit(EXIT_INTERRUPTED);
362
+ }
363
+
364
+ static int conclude(MDBX_chk_context_t *ctx) {
365
+ int err = MDBX_SUCCESS;
366
+ if (ctx->result.total_problems == 1 && ctx->result.problems_meta == 1 &&
367
+ (chk_flags & (MDBX_CHK_SKIP_BTREE_TRAVERSAL | MDBX_CHK_SKIP_KV_TRAVERSAL)) == 0 &&
368
+ (env_flags & MDBX_RDONLY) == 0 && !only_table.iov_base && stuck_meta < 0 &&
369
+ ctx->result.steady_txnid < ctx->result.recent_txnid) {
370
+ const size_t step_lineno = print(MDBX_chk_resolution,
371
+ "Perform sync-to-disk for make steady checkpoint"
372
+ " at txn-id #%" PRIi64 "...",
373
+ ctx->result.recent_txnid);
374
+ flush();
375
+ err = error_fn("walk_pages", mdbx_env_sync_ex(ctx->env, true, false));
376
+ if (err == MDBX_SUCCESS) {
377
+ ctx->result.problems_meta -= 1;
378
+ ctx->result.total_problems -= 1;
379
+ suffix(step_lineno, "done");
380
+ }
381
+ }
382
+
383
+ if (turn_meta && stuck_meta >= 0 && (chk_flags & (MDBX_CHK_SKIP_BTREE_TRAVERSAL | MDBX_CHK_SKIP_KV_TRAVERSAL)) == 0 &&
384
+ !only_table.iov_base && (env_flags & (MDBX_RDONLY | MDBX_EXCLUSIVE)) == MDBX_EXCLUSIVE) {
385
+ const bool successful_check = (err | ctx->result.total_problems | ctx->result.problems_meta) == 0;
386
+ if (successful_check || force_turn_meta) {
387
+ const size_t step_lineno =
388
+ print(MDBX_chk_resolution, "Performing turn to the specified meta-page (%d) due to %s!", stuck_meta,
389
+ successful_check ? "successful check" : "the -T option was given");
390
+ flush();
391
+ err = mdbx_env_turn_for_recovery(ctx->env, stuck_meta);
392
+ if (err != MDBX_SUCCESS)
393
+ error_fn("mdbx_env_turn_for_recovery", err);
394
+ else
395
+ suffix(step_lineno, "done");
396
+ } else {
397
+ print(MDBX_chk_resolution,
398
+ "Skipping turn to the specified meta-page (%d) due to "
399
+ "unsuccessful check!",
400
+ stuck_meta);
401
+ lf_flush();
402
+ }
403
+ }
404
+
405
+ return err;
406
+ }
407
+
408
+ int main(int argc, char *argv[]) {
409
+ int rc;
410
+ char *prog = argv[0];
411
+ char *envname;
412
+ bool warmup = false;
413
+ MDBX_warmup_flags_t warmup_flags = MDBX_warmup_default;
414
+
415
+ if (argc < 2)
416
+ usage(prog);
417
+
418
+ double elapsed;
419
+ #if defined(_WIN32) || defined(_WIN64)
420
+ uint64_t timestamp_start, timestamp_finish;
421
+ timestamp_start = GetMilliseconds();
422
+ #else
423
+ struct timespec timestamp_start, timestamp_finish;
424
+ if (clock_gettime(CLOCK_MONOTONIC, &timestamp_start)) {
425
+ error_fn("clock_gettime", errno);
426
+ return EXIT_FAILURE_SYS;
427
+ }
428
+ #endif
429
+
430
+ for (int i; (i = getopt(argc, argv,
431
+ "uU"
432
+ "0"
433
+ "1"
434
+ "2"
435
+ "T"
436
+ "V"
437
+ "v"
438
+ "q"
439
+ "n"
440
+ "w"
441
+ "c"
442
+ "t"
443
+ "d"
444
+ "i"
445
+ "s:")) != EOF;) {
446
+ switch (i) {
447
+ case 'V':
448
+ printf("mdbx_chk version %d.%d.%d.%d\n"
449
+ " - source: %s %s, commit %s, tree %s\n"
450
+ " - anchor: %s\n"
451
+ " - build: %s for %s by %s\n"
452
+ " - flags: %s\n"
453
+ " - options: %s\n",
454
+ mdbx_version.major, mdbx_version.minor, mdbx_version.patch, mdbx_version.tweak, mdbx_version.git.describe,
455
+ mdbx_version.git.datetime, mdbx_version.git.commit, mdbx_version.git.tree, mdbx_sourcery_anchor,
456
+ mdbx_build.datetime, mdbx_build.target, mdbx_build.compiler, mdbx_build.flags, mdbx_build.options);
457
+ return EXIT_SUCCESS;
458
+ case 'v':
459
+ if (verbose >= 9 && 0)
460
+ usage(prog);
461
+ else {
462
+ verbose += 1;
463
+ if (verbose == 0 && !MDBX_DEBUG)
464
+ printf("Verbosity level %u exposures only to"
465
+ " a debug/extra-logging-enabled builds (with NDEBUG undefined"
466
+ " or MDBX_DEBUG > 0)\n",
467
+ verbose);
468
+ }
469
+ break;
470
+ case '0':
471
+ stuck_meta = 0;
472
+ break;
473
+ case '1':
474
+ stuck_meta = 1;
475
+ break;
476
+ case '2':
477
+ stuck_meta = 2;
478
+ break;
479
+ case 't':
480
+ turn_meta = true;
481
+ break;
482
+ case 'T':
483
+ turn_meta = force_turn_meta = true;
484
+ quiet = false;
485
+ break;
486
+ case 'q':
487
+ quiet = true;
488
+ break;
489
+ case 'n':
490
+ break;
491
+ case 'w':
492
+ env_flags &= ~MDBX_RDONLY;
493
+ chk_flags |= MDBX_CHK_READWRITE;
494
+ #if MDBX_MMAP_INCOHERENT_FILE_WRITE
495
+ /* Temporary `workaround` for OpenBSD kernel's flaw.
496
+ * See https://libmdbx.dqdkfa.ru/dead-github/issues/67 */
497
+ env_flags |= MDBX_WRITEMAP;
498
+ #endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
499
+ break;
500
+ case 'c':
501
+ env_flags = (env_flags & ~MDBX_EXCLUSIVE) | MDBX_ACCEDE;
502
+ break;
503
+ case 'd':
504
+ chk_flags |= MDBX_CHK_SKIP_BTREE_TRAVERSAL;
505
+ break;
506
+ case 's':
507
+ if (only_table.iov_base && strcmp(only_table.iov_base, optarg))
508
+ usage(prog);
509
+ else {
510
+ only_table.iov_base = optarg;
511
+ only_table.iov_len = strlen(optarg);
512
+ }
513
+ break;
514
+ case 'i':
515
+ chk_flags |= MDBX_CHK_IGNORE_ORDER;
516
+ break;
517
+ case 'u':
518
+ warmup = true;
519
+ break;
520
+ case 'U':
521
+ warmup = true;
522
+ warmup_flags = MDBX_warmup_force | MDBX_warmup_touchlimit | MDBX_warmup_lock;
523
+ break;
524
+ default:
525
+ usage(prog);
526
+ }
527
+ }
528
+
529
+ if (optind != argc - 1)
530
+ usage(prog);
531
+
532
+ rc = MDBX_SUCCESS;
533
+ if (stuck_meta >= 0 && (env_flags & MDBX_EXCLUSIVE) == 0) {
534
+ error_fmt("exclusive mode is required to using specific meta-page(%d) for "
535
+ "checking.",
536
+ stuck_meta);
537
+ rc = EXIT_INTERRUPTED;
538
+ }
539
+ if (turn_meta) {
540
+ if (stuck_meta < 0) {
541
+ error_fmt("meta-page must be specified (by -0, -1 or -2 options) to turn to "
542
+ "it.");
543
+ rc = EXIT_INTERRUPTED;
544
+ }
545
+ if (env_flags & MDBX_RDONLY) {
546
+ error_fmt("write-mode must be enabled to turn to the specified meta-page.");
547
+ rc = EXIT_INTERRUPTED;
548
+ }
549
+ if (only_table.iov_base || (chk_flags & (MDBX_CHK_SKIP_BTREE_TRAVERSAL | MDBX_CHK_SKIP_KV_TRAVERSAL))) {
550
+ error_fmt("whole database checking with b-tree traversal are required to turn "
551
+ "to the specified meta-page.");
552
+ rc = EXIT_INTERRUPTED;
553
+ }
554
+ }
555
+ if (rc)
556
+ exit(rc);
557
+
558
+ #if defined(_WIN32) || defined(_WIN64)
559
+ SetConsoleCtrlHandler(ConsoleBreakHandlerRoutine, true);
560
+ #else
561
+ #ifdef SIGPIPE
562
+ signal(SIGPIPE, signal_handler);
563
+ #endif
564
+ #ifdef SIGHUP
565
+ signal(SIGHUP, signal_handler);
566
+ #endif
567
+ signal(SIGINT, signal_handler);
568
+ signal(SIGTERM, signal_handler);
569
+ #endif /* !WINDOWS */
570
+
571
+ envname = argv[optind];
572
+ print(MDBX_chk_result,
573
+ "mdbx_chk %s (%s, T-%s)\nRunning for %s in 'read-%s' mode with "
574
+ "verbosity level %u (%s)...",
575
+ mdbx_version.git.describe, mdbx_version.git.datetime, mdbx_version.git.tree, envname,
576
+ (env_flags & MDBX_RDONLY) ? "only" : "write", verbose,
577
+ (verbose > 8)
578
+ ? (MDBX_DEBUG ? "extra details for debugging" : "same as 8 for non-debug builds with MDBX_DEBUG=0")
579
+ : "of 0..9");
580
+ lf_flush();
581
+ mdbx_setup_debug(
582
+ (verbose + MDBX_LOG_WARN < MDBX_LOG_TRACE) ? (MDBX_log_level_t)(verbose + MDBX_LOG_WARN) : MDBX_LOG_TRACE,
583
+ MDBX_DBG_DUMP | MDBX_DBG_ASSERT | MDBX_DBG_AUDIT | MDBX_DBG_LEGACY_OVERLAP | MDBX_DBG_DONT_UPGRADE, logger);
584
+
585
+ rc = mdbx_env_create(&env);
586
+ if (rc) {
587
+ error_fn("mdbx_env_create", rc);
588
+ return rc < 0 ? EXIT_FAILURE_MDBX : EXIT_FAILURE_SYS;
589
+ }
590
+
591
+ rc = mdbx_env_set_maxdbs(env, CORE_DBS);
592
+ if (rc) {
593
+ error_fn("mdbx_env_set_maxdbs", rc);
594
+ goto bailout;
595
+ }
596
+
597
+ if (stuck_meta >= 0) {
598
+ rc = mdbx_env_open_for_recovery(env, envname, stuck_meta, (env_flags & MDBX_RDONLY) ? false : true);
599
+ } else {
600
+ rc = mdbx_env_open(env, envname, env_flags, 0);
601
+ if ((env_flags & MDBX_EXCLUSIVE) && (rc == MDBX_BUSY ||
602
+ #if defined(_WIN32) || defined(_WIN64)
603
+ rc == ERROR_LOCK_VIOLATION || rc == ERROR_SHARING_VIOLATION
604
+ #else
605
+ rc == EBUSY || rc == EAGAIN
606
+ #endif
607
+ )) {
608
+ env_flags &= ~MDBX_EXCLUSIVE;
609
+ rc = mdbx_env_open(env, envname, env_flags | MDBX_ACCEDE, 0);
610
+ }
611
+ }
612
+
613
+ if (rc) {
614
+ error_fn("mdbx_env_open", rc);
615
+ if (rc == MDBX_WANNA_RECOVERY && (env_flags & MDBX_RDONLY))
616
+ print_ln(MDBX_chk_result, "Please run %s in the read-write mode (with '-w' option).", prog);
617
+ goto bailout;
618
+ }
619
+ print_ln(MDBX_chk_verbose, "%s mode", (env_flags & MDBX_EXCLUSIVE) ? "monopolistic" : "cooperative");
620
+
621
+ if (warmup) {
622
+ anchor_lineno = print(MDBX_chk_verbose, "warming up...");
623
+ flush();
624
+ rc = mdbx_env_warmup(env, nullptr, warmup_flags, 3600 * 65536);
625
+ if (MDBX_IS_ERROR(rc)) {
626
+ error_fn("mdbx_env_warmup", rc);
627
+ goto bailout;
628
+ }
629
+ suffix(anchor_lineno, rc ? "timeout" : "done");
630
+ }
631
+
632
+ rc = mdbx_env_chk(env, &cb, &chk, chk_flags, MDBX_chk_result + (verbose << MDBX_chk_severity_prio_shift), 0);
633
+ if (rc) {
634
+ if (chk.result.total_problems == 0)
635
+ error_fn("mdbx_env_chk", rc);
636
+ else if (rc != MDBX_EINTR && rc != MDBX_RESULT_TRUE && !user_break)
637
+ rc = 0;
638
+ }
639
+
640
+ bailout:
641
+ if (env) {
642
+ const bool dont_sync = rc != 0 || chk.result.total_problems || (chk_flags & MDBX_CHK_READWRITE) == 0;
643
+ mdbx_env_close_ex(env, dont_sync);
644
+ }
645
+ flush();
646
+ if (rc) {
647
+ if (rc > 0)
648
+ return user_break ? EXIT_INTERRUPTED : EXIT_FAILURE_SYS;
649
+ return EXIT_FAILURE_MDBX;
650
+ }
651
+
652
+ #if defined(_WIN32) || defined(_WIN64)
653
+ timestamp_finish = GetMilliseconds();
654
+ elapsed = (timestamp_finish - timestamp_start) * 1e-3;
655
+ #else
656
+ if (clock_gettime(CLOCK_MONOTONIC, &timestamp_finish)) {
657
+ error_fn("clock_gettime", errno);
658
+ return EXIT_FAILURE_SYS;
659
+ }
660
+ elapsed =
661
+ timestamp_finish.tv_sec - timestamp_start.tv_sec + (timestamp_finish.tv_nsec - timestamp_start.tv_nsec) * 1e-9;
662
+ #endif /* !WINDOWS */
663
+
664
+ if (chk.result.total_problems) {
665
+ print_ln(MDBX_chk_result, "Total %" PRIuSIZE " error%s detected, elapsed %.3f seconds.", chk.result.total_problems,
666
+ (chk.result.total_problems > 1) ? "s are" : " is", elapsed);
667
+ if (chk.result.problems_meta || chk.result.problems_kv || chk.result.problems_gc)
668
+ return EXIT_FAILURE_CHECK_MAJOR;
669
+ return EXIT_FAILURE_CHECK_MINOR;
670
+ }
671
+ print_ln(MDBX_chk_result, "No error is detected, elapsed %.3f seconds.", elapsed);
672
+ return EXIT_SUCCESS;
673
+ }