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,706 @@
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(_WIN32) || defined(_WIN64))
7
+ #include <sys/resource.h>
8
+ #include <sys/time.h>
9
+ #endif /* !Windows */
10
+
11
+ MDBX_NORETURN void usage(void) {
12
+ puts("usage:\n"
13
+ " --help or -h Show this text\n"
14
+ "Common parameters:\n"
15
+ " --loglevel=[0-7]|[fatal..extra]s"
16
+ " --pathname=... Path and/or name of database files\n"
17
+ " --repeat=N Set repeat counter\n"
18
+ " --threads=N Number of thread (unsupported for now)\n"
19
+ " --timeout=N[s|m|h|d] Set timeout in seconds/minutes/hours/days\n"
20
+ " --failfast[=YES/no] Lill all actors on first failure/error\n"
21
+ " --max-readers=N See mdbx_env_set_maxreaders() description\n"
22
+ " --max-tables=N Se mdbx_env_set_maxdbs() description\n"
23
+ " --dump-config[=YES/no] Dump entire test config before run\n"
24
+ " --progress[=YES/no] Enable/disable progress `canary`\n"
25
+ " --console[=yes/no] Enable/disable console-like output\n"
26
+ " --cleanup-before[=YES/no] Cleanup/remove and re-create database\n"
27
+ " --cleanup-after[=YES/no] Cleanup/remove database after completion\n"
28
+ " --prng-seed=N Seed PRNG\n"
29
+ "Database size control:\n"
30
+ " --pagesize=... Database page size: min, max, 256..65536\n"
31
+ " --size-lower=N[K|M|G|T] Lower-bound of size in Kb/Mb/Gb/Tb\n"
32
+ " --size-upper Upper-bound of size in Kb/Mb/Gb/Tb\n"
33
+ " --size Initial size in Kb/Mb/Gb/Tb\n"
34
+ " --shrink-threshold Shrink threshold in Kb/Mb/Gb/Tb\n"
35
+ " --growth-step Grow step in Kb/Mb/Gb/Tb\n"
36
+ "Predefined complex scenarios/cases:\n"
37
+ " --case=... Only `basic` scenario implemented for now\n"
38
+ " basic == Simultaneous multi-process execution\n"
39
+ " of test-actors: nested,hill,ttl,copy,append,jitter,try\n"
40
+ "Test actors:\n"
41
+ " --hill Fill-up and empty-down\n"
42
+ " by CRUD-operation quads\n"
43
+ " --ttl Stochastic time-to-live simulation\n"
44
+ " --nested Nested transactionы\n"
45
+ " with stochastic-size bellows\n"
46
+ " --jitter Jitter/delays simulation\n"
47
+ " --try Try write-transaction, no more\n"
48
+ " --copy Online copy/backup\n"
49
+ " --append Append-mode insertions\n"
50
+ " --dead.reader Dead-reader simulator\n"
51
+ " --dead.writer Dead-writer simulator\n"
52
+ #if !defined(_WIN32) && !defined(_WIN64)
53
+ " --fork.reader After-fork reader\n"
54
+ " --fork.writer After-fork writer\n"
55
+ #endif /* Windows */
56
+ "Actor options:\n"
57
+ " --batch.read=N Read-operations batch size\n"
58
+ " --batch.write=N Write-operations batch size\n"
59
+ " --delay=N | --no-delay (no)Delay test-actor before start\n"
60
+ " --wait4ops=N | --no-wait4ops (no)Wait for previous test-actor\n"
61
+ " completes # ops before start\n"
62
+ " --duration=N[s|m|h|d] Define running duration\n"
63
+ " --nops=N[K|M|G|T] Define number of operations/steps\n"
64
+ " --inject-writefault[=yes|NO] TBD (see the source code)\n"
65
+ " --drop[=yes|NO] Drop key-value space/table on "
66
+ "completion\n"
67
+ " --ignore-dbfull[=yes|NO] Ignore MDBX_MAP_FULL error\n"
68
+ " --speculum[=yes|NO] Use internal `speculum` to check "
69
+ "dataset\n"
70
+ " --geometry-jitter[=YES|no] Use jitter for geometry upper-limit\n"
71
+ "Keys and Value:\n"
72
+ " --keylen.min=N Minimal keys length\n"
73
+ " --keylen.max=N Miximal keys length\n"
74
+ " --keylen=N Set both min/max for keys length\n"
75
+ " --datalen.min=N Minimal data length\n"
76
+ " --datalen.max=N Miximal data length\n"
77
+ " --datalen=N Set both min/max for data length\n"
78
+ " --keygen.width=N TBD (see the source code)\n"
79
+ " --keygen.mesh=N TBD (see the source code)\n"
80
+ " --keygen.zerofill=yes|NO TBD (see the source code)\n"
81
+ " --keygen.split=N TBD (see the source code)\n"
82
+ " --keygen.rotate=N TBD (see the source code)\n"
83
+ " --keygen.offset=N TBD (see the source code)\n"
84
+ " --keygen.case=random Generator case (only `random` for now)\n"
85
+ "Database operation mode:\n"
86
+ " --mode={[+-]FLAG}[,[+-]FLAG]...\n"
87
+ " nosubdir == MDBX_NOSUBDIR\n"
88
+ " rdonly == MDBX_RDONLY\n"
89
+ " exclusive == MDBX_EXCLUSIVE\n"
90
+ " accede == MDBX_ACCEDE\n"
91
+ " nometasync == MDBX_NOMETASYNC\n"
92
+ " lifo == MDBX_LIFORECLAIM\n"
93
+ " nosync-safe == MDBX_SAFE_NOSYNC\n"
94
+ " writemap == MDBX_WRITEMAP\n"
95
+ " nosync-utterly == MDBX_UTTERLY_NOSYNC\n"
96
+ " perturb == MDBX_PAGEPERTURB\n"
97
+ " nostickythreads== MDBX_NOSTICKYTHREADS\n"
98
+ " nordahead == MDBX_NORDAHEAD\n"
99
+ " nomeminit == MDBX_NOMEMINIT\n"
100
+ " --random-writemap[=YES|no] Toggle MDBX_WRITEMAP randomly\n"
101
+ "Key-value space/table options:\n"
102
+ " --table={[+-]FLAG}[,[+-]FLAG]...\n"
103
+ " key.reverse == MDBX_REVERSEKEY\n"
104
+ " key.integer == MDBX_INTEGERKEY\n"
105
+ " data.multi == MDBX_DUPSORT\n"
106
+ " data.integer == MDBX_INTEGERDUP | MDBX_DUPFIXED | MDBX_DUPSORT\n"
107
+ " data.fixed == MDBX_DUPFIXED | MDBX_DUPSORT\n"
108
+ " data.reverse == MDBX_REVERSEDUP | MDBX_DUPSORT\n");
109
+ exit(EXIT_FAILURE);
110
+ }
111
+
112
+ //-----------------------------------------------------------------------------
113
+
114
+ void actor_params::set_defaults(const std::string &tmpdir) {
115
+ pathname_log = "";
116
+ loglevel =
117
+ #if MDBX_DEBUG < 1
118
+ logging::verbose;
119
+ #elif MDBX_DEBUG > 1
120
+ logging::trace;
121
+ #elif defined(_WIN32) || defined(_WIN64) || defined(__APPLE__)
122
+ logging::verbose;
123
+ #else
124
+ logging::debug;
125
+ #endif
126
+
127
+ pathname_db = tmpdir + "mdbx-test.db";
128
+ mode_flags = MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_SYNC_DURABLE | MDBX_ACCEDE;
129
+ table_flags = MDBX_DUPSORT;
130
+
131
+ size_lower = -1;
132
+ size_now = intptr_t((table_flags & MDBX_DUPSORT) ? 256 : 1024) << 20;
133
+ size_now = std::min(size_now, mdbx_limits_dbsize_max(-1));
134
+ size_upper = -1;
135
+ shrink_threshold = -1;
136
+ growth_step = -1;
137
+ pagesize = -1;
138
+
139
+ prng_seed = 0;
140
+ keygen.zero_fill = false;
141
+ keygen.keycase = kc_random;
142
+ keygen.width = (table_flags & MDBX_DUPSORT) ? 32 : 64;
143
+ keygen.mesh = keygen.width;
144
+ keygen.split = keygen.width / 2;
145
+ keygen.rotate = 3;
146
+ keygen.offset = 41;
147
+
148
+ test_duration = 0;
149
+ test_nops = 1000;
150
+ nrepeat = 1;
151
+ nthreads = 1;
152
+
153
+ keylen_min = mdbx_keylen_min();
154
+ keylen_max = mdbx_keylen_max();
155
+ datalen_min = mdbx_datalen_min();
156
+ datalen_max = std::min(mdbx_datalen_max(), 256u * 1024 + 42);
157
+
158
+ batch_read = 42;
159
+ batch_write = 42;
160
+
161
+ delaystart = 0;
162
+ waitfor_nops = 0;
163
+ inject_writefaultn = 0;
164
+
165
+ drop_table = false;
166
+ ignore_dbfull = false;
167
+ speculum = false;
168
+ random_writemap = true;
169
+
170
+ max_readers = 42;
171
+ max_tables = 42;
172
+
173
+ global::config::timeout_duration_seconds = 0 /* infinite */;
174
+ global::config::dump_config = true;
175
+ global::config::cleanup_before = true;
176
+ global::config::cleanup_after = true;
177
+ global::config::failfast = true;
178
+ global::config::progress_indicator = true;
179
+ global::config::console_mode = osal_istty(STDERR_FILENO);
180
+ global::config::geometry_jitter = true;
181
+ }
182
+
183
+ namespace global {
184
+
185
+ std::vector<actor_config> actors;
186
+ std::unordered_map<unsigned, actor_config *> events;
187
+ std::unordered_map<mdbx_pid_t, actor_config *> pid2actor;
188
+ std::set<std::string> databases;
189
+ unsigned nactors;
190
+ chrono::time start_monotonic;
191
+ chrono::time deadline_monotonic;
192
+ bool singlemode;
193
+
194
+ namespace config {
195
+ unsigned timeout_duration_seconds;
196
+ bool dump_config;
197
+ bool cleanup_before;
198
+ bool cleanup_after;
199
+ bool failfast;
200
+ bool progress_indicator;
201
+ bool console_mode;
202
+ bool geometry_jitter;
203
+ } /* namespace config */
204
+
205
+ } /* namespace global */
206
+
207
+ //-----------------------------------------------------------------------------
208
+
209
+ const char global::thunk_param_prefix[] = "--execute=";
210
+
211
+ std::string thunk_param(const actor_config &config) { return config.serialize(global::thunk_param_prefix); }
212
+
213
+ void cleanup() {
214
+ log_trace(">> cleanup");
215
+ for (const auto &db_path : global::databases) {
216
+ int err = mdbx_env_delete(db_path.c_str(), MDBX_ENV_JUST_DELETE);
217
+ if (err != MDBX_SUCCESS && err != MDBX_RESULT_TRUE)
218
+ failure_perror(db_path.c_str(), err);
219
+ }
220
+ log_trace("<< cleanup");
221
+ }
222
+
223
+ static void fixup4qemu(actor_params &params) {
224
+ #ifdef MDBX_SAFE4QEMU
225
+ #if MDBX_WORDBITS == 32
226
+ intptr_t safe4qemu_limit = size_t(512) << 20 /* 512 megabytes */;
227
+ #if defined(__SANITIZE_ADDRESS__)
228
+ safe4qemu_limit >>= 1;
229
+ #else
230
+ if (RUNNING_ON_VALGRIND)
231
+ safe4qemu_limit >>= 1;
232
+ #endif /* __SANITIZE_ADDRESS__ */
233
+
234
+ if (params.size_lower > safe4qemu_limit || params.size_now > safe4qemu_limit || params.size_upper > safe4qemu_limit) {
235
+ params.size_upper = std::min(params.size_upper, safe4qemu_limit);
236
+ params.size_now = std::min(params.size_now, params.size_upper);
237
+ params.size_lower = std::min(params.size_lower, params.size_now);
238
+ log_notice("workaround: for conformance 32-bit build with "
239
+ "QEMU/ASAN/Valgrind database size reduced to %zu megabytes",
240
+ safe4qemu_limit >> 20);
241
+ }
242
+ #endif /* MDBX_WORDBITS == 32 */
243
+
244
+ #if defined(__alpha__) || defined(__alpha) || defined(__sparc__) || defined(__sparc) || defined(__sparc64__) || \
245
+ defined(__sparc64)
246
+ if (params.size_lower != params.size_upper) {
247
+ log_notice("workaround: for conformance Alpha/Sparc build with QEMU/ASAN/Valgrind "
248
+ "enforce fixed database size %zu megabytes",
249
+ params.size_upper >> 20);
250
+ params.size_lower = params.size_now = params.size_upper;
251
+ }
252
+ #endif /* Alpha || Sparc */
253
+ #endif /* MDBX_SAFE4QEMU */
254
+ (void)params;
255
+ }
256
+
257
+ static void set_linebuf_append(FILE *out) {
258
+ setvbuf(out, NULL, _IOLBF, 65536);
259
+ #if !defined(_WIN32) && !defined(_WIN64)
260
+ int fd = fileno(out);
261
+ int flags = fcntl(fd, F_GETFD);
262
+ if (flags != -1)
263
+ (void)fcntl(fd, F_SETFD, O_APPEND | flags);
264
+ #endif /* !Windows */
265
+ }
266
+
267
+ int main(int argc, char *const argv[]) {
268
+ set_linebuf_append(stdout);
269
+ set_linebuf_append(stderr);
270
+ #ifdef _DEBUG
271
+ log_trace("#argc = %d", argc);
272
+ for (int i = 0; i < argc; ++i)
273
+ log_trace("#argv[%d] = %s", i, argv[i]);
274
+ #endif /* _DEBUG */
275
+
276
+ if (argc < 2)
277
+ failure("No parameters given. Try --help\n");
278
+
279
+ if (argc == 2 && strncmp(argv[1], global::thunk_param_prefix, strlen(global::thunk_param_prefix)) == 0)
280
+ return test_execute(actor_config(argv[1] + strlen(global::thunk_param_prefix))) ? EXIT_SUCCESS : EXIT_FAILURE;
281
+
282
+ if (argc == 2 && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0))
283
+ usage();
284
+
285
+ actor_params params;
286
+ params.set_defaults(osal_tempdir());
287
+ global::config::dump_config = true;
288
+ logging::setup((logging::loglevel)params.loglevel, "main");
289
+ unsigned last_space_id = 0;
290
+
291
+ for (int narg = 1; narg < argc; ++narg) {
292
+ if (config::parse_option(argc, argv, narg, "dump-config", global::config::dump_config))
293
+ continue;
294
+ if (config::parse_option(argc, argv, narg, "cleanup-before", global::config::cleanup_before))
295
+ continue;
296
+ if (config::parse_option(argc, argv, narg, "cleanup-after", global::config::cleanup_after))
297
+ continue;
298
+ if (config::parse_option(argc, argv, narg, "failfast", global::config::failfast))
299
+ continue;
300
+ if (config::parse_option(argc, argv, narg, "progress", global::config::progress_indicator))
301
+ continue;
302
+ if (config::parse_option(argc, argv, narg, "console", global::config::console_mode))
303
+ continue;
304
+ if (config::parse_option(argc, argv, narg, "geometry-jitter", global::config::geometry_jitter))
305
+ continue;
306
+ if (config::parse_option(argc, argv, narg, "timeout", global::config::timeout_duration_seconds, config::duration,
307
+ 1))
308
+ continue;
309
+
310
+ logging::loglevel loglevel;
311
+ if (config::parse_option(argc, argv, narg, "loglevel", loglevel)) {
312
+ logging::setup(loglevel, "main");
313
+ params.loglevel = static_cast<uint8_t>(loglevel);
314
+ continue;
315
+ }
316
+
317
+ const char *value = nullptr;
318
+ if (config::parse_option(argc, argv, narg, "case", &value)) {
319
+ fixup4qemu(params);
320
+ testcase_setup(value, params, last_space_id);
321
+ continue;
322
+ }
323
+ if (config::parse_option(argc, argv, narg, "pathname", params.pathname_db))
324
+ continue;
325
+ if (config::parse_option(argc, argv, narg, "mode", params.mode_flags, config::mode_bits))
326
+ continue;
327
+ if (config::parse_option(argc, argv, narg, "random-writemap", params.random_writemap))
328
+ continue;
329
+ if (config::parse_option(argc, argv, narg, "table", params.table_flags, config::table_bits)) {
330
+ if ((params.table_flags & MDBX_DUPFIXED) == 0)
331
+ params.table_flags &= ~MDBX_INTEGERDUP;
332
+ if ((params.table_flags & MDBX_DUPSORT) == 0)
333
+ params.table_flags &= ~(MDBX_DUPFIXED | MDBX_REVERSEDUP | MDBX_INTEGERDUP);
334
+ const unsigned keylen_max = params.mdbx_keylen_max();
335
+ if (params.keylen_min > keylen_max)
336
+ params.keylen_min = keylen_max;
337
+ if (params.keylen_max > keylen_max)
338
+ params.keylen_max = keylen_max;
339
+ const unsigned keylen_min = params.mdbx_keylen_min();
340
+ if (params.keylen_min < keylen_min)
341
+ params.keylen_min = keylen_min;
342
+ if (params.keylen_max < keylen_min)
343
+ params.keylen_max = keylen_min;
344
+
345
+ const unsigned datalen_max = params.mdbx_datalen_max();
346
+ if (params.datalen_min > datalen_max)
347
+ params.datalen_min = datalen_max;
348
+ if (params.datalen_max > datalen_max)
349
+ params.datalen_max = datalen_max;
350
+ const unsigned datalen_min = params.mdbx_datalen_min();
351
+ if (params.datalen_min < datalen_min)
352
+ params.datalen_min = datalen_min;
353
+ if (params.datalen_max < datalen_min)
354
+ params.datalen_max = datalen_min;
355
+ continue;
356
+ }
357
+
358
+ if (config::parse_option(argc, argv, narg, "pagesize", params.pagesize, int(mdbx_limits_pgsize_min()),
359
+ int(mdbx_limits_pgsize_max()))) {
360
+ const unsigned keylen_max = params.mdbx_keylen_max();
361
+ if (params.keylen_min > keylen_max)
362
+ params.keylen_min = keylen_max;
363
+ if (params.keylen_max > keylen_max)
364
+ params.keylen_max = keylen_max;
365
+ const unsigned datalen_max = params.mdbx_datalen_max();
366
+ if (params.datalen_min > datalen_max)
367
+ params.datalen_min = datalen_max;
368
+ if (params.datalen_max > datalen_max)
369
+ params.datalen_max = datalen_max;
370
+ continue;
371
+ }
372
+ if (config::parse_option(argc, argv, narg, "repeat", params.nrepeat, config::entropy))
373
+ continue;
374
+ if (config::parse_option(argc, argv, narg, "threads", params.nthreads, config::no_scale, 1, 64))
375
+ continue;
376
+
377
+ if (config::parse_option_intptr(argc, argv, narg, "size-lower", params.size_lower,
378
+ mdbx_limits_dbsize_min(params.pagesize), mdbx_limits_dbsize_max(params.pagesize)))
379
+ continue;
380
+ int64_t i64 = params.size_upper;
381
+ if (config::parse_option(argc, argv, narg, "size-upper-upto", i64, int64_t(mdbx_limits_dbsize_min(params.pagesize)),
382
+ INT64_MAX, -1)) {
383
+ if (i64 > mdbx_limits_dbsize_max(params.pagesize))
384
+ i64 = mdbx_limits_dbsize_max(params.pagesize);
385
+ params.size_upper = intptr_t(i64);
386
+ continue;
387
+ }
388
+ if (config::parse_option_intptr(argc, argv, narg, "size-upper", params.size_upper,
389
+ mdbx_limits_dbsize_min(params.pagesize), mdbx_limits_dbsize_max(params.pagesize)))
390
+ continue;
391
+ if (config::parse_option_intptr(argc, argv, narg, "size", params.size_now, mdbx_limits_dbsize_min(params.pagesize),
392
+ mdbx_limits_dbsize_max(params.pagesize)))
393
+ continue;
394
+ if (config::parse_option(argc, argv, narg, "shrink-threshold", params.shrink_threshold, 0,
395
+ (int)std::min((intptr_t)INT_MAX, mdbx_limits_dbsize_max(params.pagesize) -
396
+ mdbx_limits_dbsize_min(params.pagesize))))
397
+ continue;
398
+ if (config::parse_option(argc, argv, narg, "growth-step", params.growth_step, 0,
399
+ (int)std::min((intptr_t)INT_MAX, mdbx_limits_dbsize_max(params.pagesize) -
400
+ mdbx_limits_dbsize_min(params.pagesize))))
401
+ continue;
402
+
403
+ if (config::parse_option(argc, argv, narg, "keygen.width", params.keygen.width, 8, 64))
404
+ continue;
405
+ if (config::parse_option(argc, argv, narg, "keygen.mesh", params.keygen.mesh, 0, 64))
406
+ continue;
407
+ if (config::parse_option(argc, argv, narg, "prng-seed", params.prng_seed, config::entropy)) {
408
+ prng_seed(params.prng_seed);
409
+ continue;
410
+ }
411
+ if (config::parse_option(argc, argv, narg, "keygen.zerofill", params.keygen.zero_fill))
412
+ continue;
413
+ if (config::parse_option(argc, argv, narg, "keygen.split", params.keygen.split, 0, 63))
414
+ continue;
415
+ if (config::parse_option(argc, argv, narg, "keygen.rotate", params.keygen.rotate, 0, 63))
416
+ continue;
417
+ if (config::parse_option(argc, argv, narg, "keygen.offset", params.keygen.offset, config::binary))
418
+ continue;
419
+ if (config::parse_option(argc, argv, narg, "keygen.case", &value)) {
420
+ keycase_setup(value, params);
421
+ continue;
422
+ }
423
+ if (config::parse_option(argc, argv, narg, "keylen.min", params.keylen_min,
424
+ (params.table_flags & MDBX_INTEGERKEY) ? config::intkey : config::no_scale,
425
+ params.mdbx_keylen_min(), params.mdbx_keylen_max())) {
426
+ if ((params.table_flags & MDBX_INTEGERKEY) || params.keylen_max < params.keylen_min)
427
+ params.keylen_max = params.keylen_min;
428
+ continue;
429
+ }
430
+ if (config::parse_option(argc, argv, narg, "keylen.max", params.keylen_max,
431
+ (params.table_flags & MDBX_INTEGERKEY) ? config::intkey : config::no_scale,
432
+ params.mdbx_keylen_min(), params.mdbx_keylen_max())) {
433
+ if ((params.table_flags & MDBX_INTEGERKEY) || params.keylen_min > params.keylen_max)
434
+ params.keylen_min = params.keylen_max;
435
+ continue;
436
+ }
437
+ if (config::parse_option(argc, argv, narg, "keylen", params.keylen_min,
438
+ (params.table_flags & MDBX_INTEGERKEY) ? config::intkey : config::no_scale,
439
+ params.mdbx_keylen_min(), params.mdbx_keylen_max())) {
440
+ params.keylen_max = params.keylen_min;
441
+ continue;
442
+ }
443
+ if (config::parse_option(argc, argv, narg, "datalen.min", params.datalen_min,
444
+ (params.table_flags & MDBX_INTEGERDUP) ? config::intkey : config::no_scale,
445
+ params.mdbx_datalen_min(), params.mdbx_datalen_max())) {
446
+ if ((params.table_flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED)) || params.datalen_max < params.datalen_min)
447
+ params.datalen_max = params.datalen_min;
448
+ continue;
449
+ }
450
+ if (config::parse_option(argc, argv, narg, "datalen.max", params.datalen_max,
451
+ (params.table_flags & MDBX_INTEGERDUP) ? config::intkey : config::no_scale,
452
+ params.mdbx_datalen_min(), params.mdbx_datalen_max())) {
453
+ if ((params.table_flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED)) || params.datalen_min > params.datalen_max)
454
+ params.datalen_min = params.datalen_max;
455
+ continue;
456
+ }
457
+ if (config::parse_option(argc, argv, narg, "datalen", params.datalen_min,
458
+ (params.table_flags & MDBX_INTEGERDUP) ? config::intkey : config::no_scale,
459
+ params.mdbx_datalen_min(), params.mdbx_datalen_max())) {
460
+ params.datalen_max = params.datalen_min;
461
+ continue;
462
+ }
463
+ if (config::parse_option(argc, argv, narg, "batch.read", params.batch_read, config::no_scale, 1))
464
+ continue;
465
+ if (config::parse_option(argc, argv, narg, "batch.write", params.batch_write, config::no_scale, 1))
466
+ continue;
467
+ if (config::parse_option(argc, argv, narg, "delay", params.delaystart, config::duration))
468
+ continue;
469
+ if (config::parse_option(argc, argv, narg, "wait4ops", params.waitfor_nops, config::decimal))
470
+ continue;
471
+ if (config::parse_option(argc, argv, narg, "inject-writefault", params.inject_writefaultn, config::decimal))
472
+ continue;
473
+ if (config::parse_option(argc, argv, narg, "drop", params.drop_table))
474
+ continue;
475
+ if (config::parse_option(argc, argv, narg, "ignore-dbfull", params.ignore_dbfull))
476
+ continue;
477
+ if (config::parse_option(argc, argv, narg, "speculum", params.speculum))
478
+ continue;
479
+ if (config::parse_option(argc, argv, narg, "max-readers", params.max_readers, config::no_scale, 1, 255))
480
+ continue;
481
+ if (config::parse_option(argc, argv, narg, "max-tables", params.max_tables, config::no_scale, 1, INT16_MAX))
482
+ continue;
483
+
484
+ if (config::parse_option(argc, argv, narg, "no-delay", nullptr)) {
485
+ params.delaystart = 0;
486
+ continue;
487
+ }
488
+ if (config::parse_option(argc, argv, narg, "no-wait4ops", nullptr)) {
489
+ params.waitfor_nops = 0;
490
+ continue;
491
+ }
492
+ if (config::parse_option(argc, argv, narg, "duration", params.test_duration, config::duration, 1)) {
493
+ params.test_nops = 0;
494
+ continue;
495
+ }
496
+ if (config::parse_option(argc, argv, narg, "nops", params.test_nops, config::decimal, 1)) {
497
+ params.test_duration = 0;
498
+ continue;
499
+ }
500
+ if (config::parse_option(argc, argv, narg, "hill", &value, "auto")) {
501
+ fixup4qemu(params);
502
+ configure_actor(last_space_id, ac_hill, value, params);
503
+ continue;
504
+ }
505
+ if (config::parse_option(argc, argv, narg, "jitter", nullptr)) {
506
+ fixup4qemu(params);
507
+ configure_actor(last_space_id, ac_jitter, value, params);
508
+ continue;
509
+ }
510
+ if (config::parse_option(argc, argv, narg, "dead.reader", nullptr)) {
511
+ fixup4qemu(params);
512
+ configure_actor(last_space_id, ac_deadread, value, params);
513
+ continue;
514
+ }
515
+ if (config::parse_option(argc, argv, narg, "dead.writer", nullptr)) {
516
+ fixup4qemu(params);
517
+ configure_actor(last_space_id, ac_deadwrite, value, params);
518
+ continue;
519
+ }
520
+ if (config::parse_option(argc, argv, narg, "try", nullptr)) {
521
+ fixup4qemu(params);
522
+ configure_actor(last_space_id, ac_try, value, params);
523
+ continue;
524
+ }
525
+ if (config::parse_option(argc, argv, narg, "copy", nullptr)) {
526
+ fixup4qemu(params);
527
+ configure_actor(last_space_id, ac_copy, value, params);
528
+ continue;
529
+ }
530
+ if (config::parse_option(argc, argv, narg, "append", nullptr)) {
531
+ fixup4qemu(params);
532
+ configure_actor(last_space_id, ac_append, value, params);
533
+ continue;
534
+ }
535
+ if (config::parse_option(argc, argv, narg, "ttl", nullptr)) {
536
+ fixup4qemu(params);
537
+ configure_actor(last_space_id, ac_ttl, value, params);
538
+ continue;
539
+ }
540
+ if (config::parse_option(argc, argv, narg, "nested", nullptr)) {
541
+ fixup4qemu(params);
542
+ configure_actor(last_space_id, ac_nested, value, params);
543
+ continue;
544
+ }
545
+ #if !defined(_WIN32) && !defined(_WIN64)
546
+ if (config::parse_option(argc, argv, narg, "fork.reader", nullptr)) {
547
+ fixup4qemu(params);
548
+ configure_actor(last_space_id, ac_forkread, value, params);
549
+ continue;
550
+ }
551
+ if (config::parse_option(argc, argv, narg, "fork.writer", nullptr)) {
552
+ fixup4qemu(params);
553
+ configure_actor(last_space_id, ac_forkwrite, value, params);
554
+ continue;
555
+ }
556
+ #endif /* Windows */
557
+
558
+ if (*argv[narg] != '-') {
559
+ fixup4qemu(params);
560
+ testcase_setup(argv[narg], params, last_space_id);
561
+ } else
562
+ failure("Unknown option '%s'. Try --help\n", argv[narg]);
563
+ }
564
+
565
+ if (global::config::dump_config)
566
+ config::dump();
567
+
568
+ //--------------------------------------------------------------------------
569
+
570
+ if (global::actors.empty()) {
571
+ log_notice("no testcase(s) configured, exiting");
572
+ return EXIT_SUCCESS;
573
+ }
574
+
575
+ bool failed = false;
576
+ global::start_monotonic = chrono::now_monotonic();
577
+ global::deadline_monotonic.fixedpoint =
578
+ (global::config::timeout_duration_seconds == 0)
579
+ ? chrono::infinite().fixedpoint
580
+ : global::start_monotonic.fixedpoint +
581
+ chrono::from_seconds(global::config::timeout_duration_seconds).fixedpoint;
582
+
583
+ if (global::config::cleanup_before)
584
+ cleanup();
585
+
586
+ if (global::actors.size() == 1) {
587
+ logging::setup("main");
588
+ global::singlemode = true;
589
+ if (!test_execute(global::actors.front()))
590
+ failed = true;
591
+ } else {
592
+ logging::setup("overlord");
593
+
594
+ log_trace("=== preparing...");
595
+ log_trace(">> osal_setup");
596
+ osal_setup(global::actors);
597
+ log_trace("<< osal_setup");
598
+
599
+ for (auto &a : global::actors) {
600
+ mdbx_pid_t pid;
601
+ log_trace(">> actor_start");
602
+ int rc = osal_actor_start(a, pid);
603
+ log_trace("<< actor_start");
604
+ if (rc) {
605
+ log_trace(">> killall_actors: (%s)", "start failed");
606
+ osal_killall_actors();
607
+ log_trace("<< killall_actors");
608
+ failure("Failed to start actor #%u (%s)\n", a.actor_id, test_strerror(rc));
609
+ }
610
+ global::pid2actor[pid] = &a;
611
+ }
612
+
613
+ log_trace("=== ready to start...");
614
+ atexit(osal_killall_actors);
615
+ log_trace(">> wait4barrier");
616
+ osal_wait4barrier();
617
+ log_trace("<< wait4barrier");
618
+
619
+ size_t left = global::actors.size();
620
+ log_trace("=== polling...");
621
+ while (left > 0) {
622
+ unsigned timeout_seconds_left = INT_MAX;
623
+ chrono::time now_monotonic = chrono::now_monotonic();
624
+ if (now_monotonic.fixedpoint >= global::deadline_monotonic.fixedpoint)
625
+ timeout_seconds_left = 0;
626
+ else {
627
+ chrono::time left_monotonic;
628
+ left_monotonic.fixedpoint = global::deadline_monotonic.fixedpoint - now_monotonic.fixedpoint;
629
+ timeout_seconds_left = left_monotonic.seconds();
630
+ }
631
+
632
+ mdbx_pid_t pid;
633
+ int rc = osal_actor_poll(pid, timeout_seconds_left);
634
+ if (rc)
635
+ failure("Poll error: %s (%d)\n", test_strerror(rc), rc);
636
+
637
+ if (pid) {
638
+ actor_status status = osal_actor_info(pid);
639
+ actor_config *actor = global::pid2actor.at(pid);
640
+ if (!actor)
641
+ continue;
642
+
643
+ if (status > as_running) {
644
+ log_notice("actor #%u, id %d, pid %ld: %s\n", actor->actor_id, actor->space_id, (long)pid,
645
+ status2str(status));
646
+ left -= 1;
647
+ if (status != as_successful) {
648
+ if (global::config::failfast && !failed) {
649
+ log_trace(">> killall_actors: (%s)", "failfast");
650
+ osal_killall_actors();
651
+ log_trace("<< killall_actors");
652
+ }
653
+ failed = true;
654
+ }
655
+ } else {
656
+ log_verbose("actor #%u, id %d, pid %ld: %s\n", actor->actor_id, actor->space_id, (long)pid,
657
+ status2str(status));
658
+ }
659
+ } else {
660
+ if (timeout_seconds_left == 0)
661
+ failure("Timeout\n");
662
+ }
663
+ }
664
+ log_trace("=== done...");
665
+ }
666
+
667
+ if (!failed) {
668
+ MDBX_envinfo info;
669
+ int err = mdbx_preopen_snapinfo(params.pathname_db.c_str(), &info, sizeof(info));
670
+ if (err != MDBX_SUCCESS)
671
+ failure_perror("mdbx_preopen_snapinfo()", err);
672
+ }
673
+
674
+ log_notice("RESULT: %s\n", failed ? "Failed" : "Successful");
675
+ if (global::config::cleanup_after) {
676
+ if (failed)
677
+ log_verbose("skip cleanup");
678
+ else
679
+ cleanup();
680
+ }
681
+
682
+ #if !(defined(_WIN32) || defined(_WIN64))
683
+ struct rusage spent;
684
+ if (!getrusage(global::singlemode ? RUSAGE_SELF : RUSAGE_CHILDREN, &spent)) {
685
+ log_notice("%6s: user %f, system %f", "CPU", spent.ru_utime.tv_sec + spent.ru_utime.tv_usec * 1e-6,
686
+ spent.ru_stime.tv_sec + spent.ru_stime.tv_usec * 1e-6);
687
+ #if defined(__linux__) || defined(__gnu_linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
688
+ defined(__OpenBSD__) || defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__APPLE__) || \
689
+ defined(__MACH__) || defined(__sun)
690
+ log_notice("%6s: read %ld, write %ld", "IOPs", spent.ru_inblock, spent.ru_oublock);
691
+ if (spent.ru_maxrss > 0)
692
+ log_notice("%6s: %ld Kb", "RAM",
693
+ spent.ru_maxrss
694
+ #if defined(__sun)
695
+ * getpagesize() / 1024u
696
+ #elif defined(__APPLE__)
697
+ / 1024u
698
+ #endif
699
+ );
700
+ log_notice("%6s: reclaims %ld, faults %ld, swaps %ld", "Paging", spent.ru_minflt, spent.ru_majflt, spent.ru_nswap);
701
+ #endif /* Linux */
702
+ }
703
+ #endif /* !Windows */
704
+
705
+ return failed ? EXIT_FAILURE : EXIT_SUCCESS;
706
+ }