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,410 @@
1
+ #include "mdbx.h++"
2
+
3
+ #include <chrono>
4
+ #include <deque>
5
+ #include <iostream>
6
+ #include <vector>
7
+ #if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L
8
+ #include <latch>
9
+ #include <thread>
10
+ #endif
11
+
12
+ #if defined(ENABLE_MEMCHECK) || defined(MDBX_CI)
13
+ #if MDBX_DEBUG || !defined(NDEBUG)
14
+ #define RELIEF_FACTOR 16
15
+ #else
16
+ #define RELIEF_FACTOR 8
17
+ #endif
18
+ #elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32)
19
+ #define RELIEF_FACTOR 4
20
+ #elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
21
+ #define RELIEF_FACTOR 2
22
+ #else
23
+ #define RELIEF_FACTOR 1
24
+ #endif
25
+
26
+ #define NN (1000 / RELIEF_FACTOR)
27
+
28
+ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
29
+ unsigned length) noexcept {
30
+ (void)length;
31
+ (void)loglevel;
32
+ std::cout << function << ":" << line << " " << msg;
33
+ }
34
+
35
+ static char log_buffer[1024];
36
+
37
+ //--------------------------------------------------------------------------------------------
38
+
39
+ bool case0(mdbx::env env) {
40
+ auto txn = env.start_write();
41
+ auto table = txn.create_map("case0", mdbx::key_mode::usual, mdbx::value_mode::single);
42
+ auto cursor_1 = txn.open_cursor(table);
43
+ auto cursor_2 = cursor_1.clone();
44
+
45
+ auto nested = env.start_write(txn);
46
+ auto nested_cursor_1 = nested.open_cursor(table);
47
+ auto nested_cursor_2 = nested_cursor_1.clone();
48
+ auto nested_cursor_3 = cursor_1.clone();
49
+
50
+ auto deep = env.start_write(nested);
51
+ auto deep_cursor_1 = deep.open_cursor(table);
52
+ auto deep_cursor_2 = nested_cursor_1.clone();
53
+ auto deep_cursor_3 = cursor_1.clone();
54
+ deep_cursor_1.close();
55
+ deep.commit();
56
+ deep_cursor_2.close();
57
+
58
+ nested_cursor_1.close();
59
+ nested.abort();
60
+ nested_cursor_2.close();
61
+
62
+ cursor_1.close();
63
+ txn.commit();
64
+ cursor_2.close();
65
+ return true;
66
+ }
67
+
68
+ //--------------------------------------------------------------------------------------------
69
+
70
+ /* Сценарий:
71
+ *
72
+ * 0. Создаём N таблиц, курсор для каждой таблицы и заполняем (1000 ключей, от 1 до 1000 значений в каждом ключе).
73
+ * 1. Запускаем N-1 фоновых потоков и используем текущий/основной.
74
+ * 2. В каждом потоке 100500 раз повторяем последовательность действий:
75
+ * - 100500 раз запускаем читающую транзакцию и выполняем "читающий цикл":
76
+ * - в читающей транзакции создаем 0..3 курсоров, потом подключаем заранее созданный курсор,
77
+ * потом еще 0..3 курсоров;
78
+ * - выполняем по паре поисков через каждый курсор;
79
+ * - отключаем заранее созданный курсор;
80
+ * - снова выполняем несколько поисков по каждому курсору;
81
+ * - псевдослучайно закрываем один из курсоров и один отключаем;
82
+ * - псевдослучайно выполняем один из путей:
83
+ * - закрываем все курсоры посредством mdbx_txn_release_all_cursors();
84
+ * - отсоединяем все курсоры посредством mdbx_txn_release_all_cursors();
85
+ * - псевдослучайно закрываем один из курсоров и один отключаем;
86
+ * - ничего не делаем;
87
+ * - завершаем читающую транзакцию псевдослучайно выбирая между commit и abort;
88
+ * - закрываем оставшиеся курсоры.
89
+ * 3. Выполняем "пишущий цикл":
90
+ * - запускаем пишущую или вложенную транзакцию;
91
+ * - из оставшихся с предыдущих итераций курсоров половину закрываем,
92
+ * половину подключаем к транзакции;
93
+ * - для каждой таблицы с вероятностью 1/2 выполняем "читающий цикл";
94
+ * - для каждой таблицы с вероятностью 1/2 выполняем "модифицирующий" цикл:
95
+ * - подключаем курсор, либо создаем при отсутствии подходящих;
96
+ * - 100 раз выполняем поиск случайных пар ключ/значение;
97
+ * - при успешном поиске удаляем значение, иначе вставляем;
98
+ * - с вероятностью 1/2 повторяем "читающий цикл";
99
+ * - с вероятностью 7/16 запускаем вложенную транзакцию:
100
+ * - действуем рекурсивно как с пишущей транзакцией;
101
+ * - в "читающих циклах" немного меняем поведение:
102
+ * - игнорируем ожидаемые ошибки mdbx_cursor_unbind();
103
+ * - в 2-3 раза уменьшаем вероятность использования mdbx_txn_release_all_cursors();
104
+ * - завершаем вложенную транзакцию псевдослучайно выбирая между commit и abort;
105
+ * - для каждой таблицы с вероятностью 1/2 выполняем "читающий цикл";
106
+ * - завершаем транзакцию псевдослучайно выбирая между commit и abort;
107
+ * 4. Ждем завершения фоновых потоков.
108
+ * 5. Закрываем оставшиеся курсоры и закрываем БД. */
109
+
110
+ thread_local size_t salt;
111
+
112
+ static size_t prng() {
113
+ salt = salt * 134775813 + 1;
114
+ return salt ^ ((salt >> 11) * 1822226723);
115
+ }
116
+
117
+ static inline bool flipcoin() { return prng() & 1; }
118
+
119
+ static inline size_t prng(size_t range) { return prng() % range; }
120
+
121
+ void case1_shuffle_pool(std::vector<MDBX_cursor *> &pool) {
122
+ for (size_t n = 1; n < pool.size(); ++n) {
123
+ const auto i = prng(n);
124
+ if (i != n)
125
+ std::swap(pool[n], pool[i]);
126
+ }
127
+ }
128
+
129
+ void case1_read_pool(std::vector<MDBX_cursor *> &pool) {
130
+ for (auto c : pool)
131
+ if (flipcoin())
132
+ mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(NN)), mdbx::slice::wrap(prng(NN)), false);
133
+ for (auto c : pool)
134
+ if (flipcoin())
135
+ mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(NN)), mdbx::slice::wrap(prng(NN)), false);
136
+ }
137
+
138
+ MDBX_cursor *case1_try_unbind(MDBX_cursor *cursor) {
139
+ if (cursor) {
140
+ auto err = mdbx::error(static_cast<MDBX_error_t>(mdbx_cursor_unbind(cursor)));
141
+ if (err.code() != MDBX_EINVAL)
142
+ err.success_or_throw();
143
+ }
144
+ return cursor;
145
+ }
146
+
147
+ MDBX_cursor *case1_pool_remove(std::vector<MDBX_cursor *> &pool) {
148
+ switch (pool.size()) {
149
+ case 0:
150
+ return nullptr;
151
+ case 1:
152
+ if (flipcoin()) {
153
+ const auto c = pool[0];
154
+ pool.pop_back();
155
+ return c;
156
+ }
157
+ return nullptr;
158
+ default:
159
+ const auto i = prng(pool.size());
160
+ const auto c = pool[i];
161
+ pool.erase(pool.begin() + i);
162
+ return c;
163
+ }
164
+ }
165
+
166
+ mdbx::map_handle case1_cycle_dbi(std::deque<mdbx::map_handle> &dbi) {
167
+ const auto h = dbi.front();
168
+ dbi.pop_front();
169
+ dbi.push_back(h);
170
+ return h;
171
+ }
172
+
173
+ void case1_read_cycle(mdbx::txn txn, std::deque<mdbx::map_handle> &dbi, std::vector<MDBX_cursor *> &pool,
174
+ mdbx::cursor pre, bool nested = false) {
175
+ if (nested) {
176
+ for (auto c : pool)
177
+ try {
178
+ mdbx::cursor(c).bind(txn, case1_cycle_dbi(dbi));
179
+ } catch (const std::invalid_argument &) {
180
+ }
181
+ try {
182
+ pre.bind(txn, case1_cycle_dbi(dbi));
183
+ } catch (const std::invalid_argument &) {
184
+ }
185
+ } else {
186
+ for (auto c : pool)
187
+ mdbx::cursor(c).bind(txn, case1_cycle_dbi(dbi));
188
+ pre.bind(txn, case1_cycle_dbi(dbi));
189
+ }
190
+
191
+ for (auto n = prng(3 + dbi.size()); n > 0; --n) {
192
+ auto c = txn.open_cursor(dbi[prng(dbi.size())]);
193
+ pool.push_back(c.withdraw_handle());
194
+ }
195
+ case1_shuffle_pool(pool);
196
+ case1_read_pool(pool);
197
+
198
+ pool.push_back(pre);
199
+ case1_read_pool(pool);
200
+ pool.pop_back();
201
+
202
+ for (auto n = prng(3 + dbi.size()); n > 0; --n) {
203
+ auto c = txn.open_cursor(dbi[prng(dbi.size())]);
204
+ pool.push_back(c.withdraw_handle());
205
+ }
206
+ pool.push_back(pre);
207
+ case1_read_pool(pool);
208
+ pool.pop_back();
209
+
210
+ case1_try_unbind(pre);
211
+ case1_shuffle_pool(pool);
212
+ case1_read_pool(pool);
213
+
214
+ if (flipcoin()) {
215
+ mdbx_cursor_close(case1_pool_remove(pool));
216
+ auto u = case1_try_unbind(case1_pool_remove(pool));
217
+ case1_read_pool(pool);
218
+ if (u)
219
+ pool.push_back(u);
220
+ } else {
221
+ auto u = case1_try_unbind(case1_pool_remove(pool));
222
+ mdbx_cursor_close(case1_pool_remove(pool));
223
+ case1_read_pool(pool);
224
+ if (u)
225
+ pool.push_back(u);
226
+ }
227
+
228
+ switch (prng(nested ? 7 : 3)) {
229
+ case 0:
230
+ if (pre.txn()) {
231
+ if (nested)
232
+ try {
233
+ pre.unbind();
234
+ } catch (const std::invalid_argument &) {
235
+ return;
236
+ }
237
+ else
238
+ pre.unbind();
239
+ }
240
+ for (auto i = pool.begin(); i != pool.end();)
241
+ if (mdbx_cursor_txn(*i))
242
+ i = pool.erase(i);
243
+ else
244
+ ++i;
245
+ txn.close_all_cursors();
246
+ break;
247
+ case 1:
248
+ txn.unbind_all_cursors();
249
+ break;
250
+ }
251
+ }
252
+
253
+ void case1_write_cycle(mdbx::txn_managed txn, std::deque<mdbx::map_handle> &dbi, std::vector<MDBX_cursor *> &pool,
254
+ mdbx::cursor pre, bool nested = false) {
255
+ if (flipcoin())
256
+ case1_cycle_dbi(dbi);
257
+ if (flipcoin())
258
+ case1_shuffle_pool(pool);
259
+
260
+ for (auto n = prng(dbi.size() + 1); n > 1; n -= 2) {
261
+ if (!nested)
262
+ pre.unbind();
263
+ if (!pre.txn())
264
+ pre.bind(txn, dbi[prng(dbi.size())]);
265
+ for (auto i = 0; i < NN; ++i) {
266
+ auto k = mdbx::default_buffer::wrap(prng(NN));
267
+ auto v = mdbx::default_buffer::wrap(prng(NN));
268
+ if (pre.find_multivalue(k, v, false))
269
+ pre.erase();
270
+ else
271
+ pre.upsert(k, v);
272
+ }
273
+ }
274
+
275
+ if (prng(16) > 8)
276
+ case1_write_cycle(txn.start_nested(), dbi, pool, pre, true);
277
+
278
+ case1_read_cycle(txn, dbi, pool, pre, nested);
279
+
280
+ if (flipcoin())
281
+ txn.commit();
282
+ else
283
+ txn.abort();
284
+ }
285
+
286
+ bool case1_thread(mdbx::env env, std::deque<mdbx::map_handle> dbi, mdbx::cursor pre) {
287
+ salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count());
288
+ std::vector<MDBX_cursor *> pool;
289
+ for (auto loop = 0; loop < 333 / RELIEF_FACTOR; ++loop) {
290
+ for (auto read = 0; read < 333 / RELIEF_FACTOR; ++read) {
291
+ auto txn = env.start_read();
292
+ case1_read_cycle(txn, dbi, pool, pre);
293
+ if (flipcoin())
294
+ txn.commit();
295
+ else
296
+ txn.abort();
297
+ }
298
+
299
+ case1_write_cycle(env.start_write(), dbi, pool, pre);
300
+
301
+ for (auto c : pool)
302
+ mdbx_cursor_close(c);
303
+ pool.clear();
304
+ }
305
+
306
+ pre.unbind();
307
+ return true;
308
+ }
309
+
310
+ bool case1(mdbx::env env) {
311
+ bool ok = true;
312
+ std::deque<mdbx::map_handle> dbi;
313
+ std::vector<mdbx::cursor_managed> cursors;
314
+ #if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L
315
+ static const auto N = 10;
316
+ #else
317
+ static const auto N = 3;
318
+ #endif
319
+ for (auto t = 0; t < N; ++t) {
320
+ auto txn = env.start_write();
321
+ auto table = txn.create_map(std::to_string(t), mdbx::key_mode::ordinal, mdbx::value_mode::multi_samelength);
322
+ auto cursor = txn.open_cursor(table);
323
+ for (size_t i = 0; i < NN * 11; ++i)
324
+ cursor.upsert(mdbx::default_buffer::wrap(prng(NN)), mdbx::default_buffer::wrap(prng(NN)));
325
+ txn.commit();
326
+
327
+ cursors.push_back(std::move(cursor));
328
+ dbi.push_back(table);
329
+ }
330
+
331
+ #if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L
332
+ std::latch s(1);
333
+ std::vector<std::thread> threads;
334
+ for (auto t = 1; t < N; ++t) {
335
+ case1_cycle_dbi(dbi);
336
+ threads.push_back(std::thread([&, t]() {
337
+ s.wait();
338
+ if (!case1_thread(env, dbi, cursors[t]))
339
+ ok = false;
340
+ }));
341
+ }
342
+ case1_cycle_dbi(dbi);
343
+ s.count_down();
344
+ #endif
345
+
346
+ if (!case1_thread(env, dbi, cursors[0]))
347
+ ok = false;
348
+
349
+ #if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L
350
+ for (auto &t : threads)
351
+ t.join();
352
+ #endif
353
+
354
+ return ok;
355
+ }
356
+
357
+ //--------------------------------------------------------------------------------------------
358
+
359
+ bool case2(mdbx::env env) {
360
+ bool ok = true;
361
+
362
+ auto txn = env.start_write();
363
+ auto dbi = txn.create_map("case2", mdbx::key_mode::usual, mdbx::value_mode::single);
364
+ txn.commit_embark_read();
365
+ auto cursor1 = txn.open_cursor(dbi);
366
+ auto cursor2 = txn.open_cursor(0);
367
+ cursor1.move(mdbx::cursor::next, false);
368
+ cursor2.move(mdbx::cursor::next, false);
369
+ txn.commit_embark_read();
370
+ cursor2.bind(txn, dbi);
371
+ cursor1.bind(txn, 0);
372
+ cursor1.move(mdbx::cursor::last, false);
373
+ cursor2.move(mdbx::cursor::last, false);
374
+
375
+ return ok;
376
+ }
377
+
378
+ //--------------------------------------------------------------------------------------------
379
+
380
+ int doit() {
381
+ mdbx::path db_filename = "test-cursor-closing";
382
+ mdbx::env::remove(db_filename);
383
+
384
+ mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(),
385
+ mdbx::env::operate_parameters(42, 0, mdbx::env::nested_transactions));
386
+
387
+ bool ok = case0(env);
388
+ ok = case1(env) && ok;
389
+ ok = case2(env) && ok;
390
+
391
+ if (ok) {
392
+ std::cout << "OK\n";
393
+ return EXIT_SUCCESS;
394
+ } else {
395
+ std::cout << "FAIL!\n";
396
+ return EXIT_FAILURE;
397
+ }
398
+ }
399
+
400
+ int main(int argc, char *argv[]) {
401
+ (void)argc;
402
+ (void)argv;
403
+ mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer));
404
+ try {
405
+ return doit();
406
+ } catch (const std::exception &ex) {
407
+ std::cerr << "Exception: " << ex.what() << "\n";
408
+ return EXIT_FAILURE;
409
+ }
410
+ }
@@ -0,0 +1,229 @@
1
+ #include "mdbx.h++"
2
+
3
+ #include <iostream>
4
+
5
+ mdbx::path db_filename = "test-dbi";
6
+
7
+ bool case1() {
8
+ mdbx::env::remove(db_filename);
9
+
10
+ mdbx::env::operate_parameters operateParameters(100, 10, mdbx::env::nested_transactions);
11
+ mdbx::env_managed::create_parameters createParameters;
12
+ {
13
+ mdbx::env_managed env(db_filename, createParameters, operateParameters);
14
+ mdbx::txn_managed txn = env.start_write();
15
+ /* mdbx::map_handle dbi = */ txn.create_map("fap1", mdbx::key_mode::reverse, mdbx::value_mode::single);
16
+ txn.commit();
17
+ }
18
+
19
+ mdbx::env_managed env(db_filename, createParameters, operateParameters);
20
+ {
21
+ // проверяем доступность в родительской транзакции хендла открытого в дочерней транзакции после коммита
22
+ mdbx::txn_managed txn = env.start_write();
23
+ mdbx::txn_managed nested = txn.start_nested();
24
+ mdbx::map_handle dbi = nested.open_map_accede("fap1");
25
+ nested.commit();
26
+ MDBX_MAYBE_UNUSED auto stat = txn.get_map_stat(dbi);
27
+ txn.commit();
28
+ env.close_map(dbi);
29
+ }
30
+
31
+ {
32
+ // проверяем НЕ доступность в родительской транзакции хендла открытого в дочерней транзакции после прерывания
33
+ mdbx::txn_managed txn = env.start_write();
34
+ mdbx::txn_managed nested = txn.start_nested();
35
+ mdbx::map_handle dbi = nested.open_map_accede("fap1");
36
+ nested.abort();
37
+ MDBX_stat stat;
38
+ int err = mdbx_dbi_stat(txn, dbi, &stat, sizeof(stat));
39
+ if (err != MDBX_BAD_DBI) {
40
+ std::cerr << "Unexpected err " << err << " (wanna MDBX_BAD_DBI/-30780)\n";
41
+ return false;
42
+ }
43
+ txn.commit();
44
+ }
45
+
46
+ {
47
+ // снова проверяем что таблица открывается и хендл доступень в родительской транзакции,
48
+ // после коммита открывшей его дочерней
49
+ mdbx::txn_managed txn = env.start_write();
50
+ mdbx::txn_managed nested = txn.start_nested();
51
+ mdbx::map_handle dbi = nested.open_map_accede("fap1");
52
+ nested.commit();
53
+ MDBX_MAYBE_UNUSED auto stat = txn.get_map_stat(dbi);
54
+ txn.commit();
55
+ env.close_map(dbi);
56
+ }
57
+
58
+ return true;
59
+ }
60
+
61
+ bool case2() {
62
+ bool ok = true;
63
+ mdbx::env_managed::create_parameters createParameters;
64
+ mdbx::env::remove(db_filename);
65
+ {
66
+ mdbx::env::operate_parameters operateParameters(0, 10, mdbx::env::nested_transactions);
67
+ mdbx::env_managed env(db_filename, createParameters, operateParameters);
68
+ {
69
+ mdbx::txn_managed txn = env.start_write();
70
+ MDBX_dbi dbi = 0;
71
+ int err = mdbx_dbi_open(txn, "test", MDBX_CREATE, &dbi);
72
+ if (err != MDBX_DBS_FULL) {
73
+ std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
74
+ ok = false;
75
+ }
76
+ }
77
+ {
78
+ mdbx::txn_managed txn = env.start_write();
79
+ MDBX_dbi dbi = 0;
80
+ int err = mdbx_dbi_open(txn, "test", MDBX_CREATE | MDBX_DUPSORT | MDBX_DUPFIXED, &dbi);
81
+ if (err != MDBX_DBS_FULL) {
82
+ std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
83
+ ok = false;
84
+ }
85
+ }
86
+ }
87
+
88
+ {
89
+ mdbx::env::operate_parameters operateParameters(1, 10, mdbx::env::nested_transactions);
90
+ mdbx::env_managed env(db_filename, createParameters, operateParameters);
91
+ {
92
+ mdbx::txn_managed txn = env.start_write();
93
+ mdbx::map_handle dbi = txn.create_map("dup", mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal);
94
+ txn.commit();
95
+ env.close_map(dbi);
96
+ }
97
+ {
98
+ mdbx::txn_managed txn = env.start_write();
99
+ mdbx::map_handle dbi = txn.create_map("uni", mdbx::key_mode::reverse, mdbx::value_mode::single);
100
+ txn.commit();
101
+ env.close_map(dbi);
102
+ }
103
+ }
104
+
105
+ {
106
+ mdbx::env::operate_parameters operateParameters(0, 10, mdbx::env::nested_transactions);
107
+ mdbx::env_managed env(db_filename, createParameters, operateParameters);
108
+ {
109
+ mdbx::txn_managed txn = env.start_read();
110
+ MDBX_dbi dbi = 0;
111
+ int err = mdbx_dbi_open(txn, "uni", MDBX_DB_ACCEDE, &dbi);
112
+ if (err != MDBX_DBS_FULL) {
113
+ std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
114
+ ok = false;
115
+ }
116
+ if (dbi)
117
+ env.close_map(dbi);
118
+ }
119
+
120
+ {
121
+ mdbx::txn_managed txn = env.start_read();
122
+ MDBX_dbi dbi = 0;
123
+ int err = mdbx_dbi_open(txn, "dup", MDBX_DB_ACCEDE, &dbi);
124
+ if (err != MDBX_DBS_FULL) {
125
+ std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
126
+ ok = false;
127
+ }
128
+ if (dbi)
129
+ env.close_map(dbi);
130
+ }
131
+ }
132
+
133
+ {
134
+ {
135
+ mdbx::env::operate_parameters operateParameters(1, 10, mdbx::env::nested_transactions);
136
+ mdbx::env_managed env(db_filename, createParameters, operateParameters);
137
+ {
138
+ mdbx::txn_managed txn = env.start_read();
139
+ MDBX_dbi dbi = 0;
140
+ int err = mdbx_dbi_open(txn, "uni", MDBX_DB_ACCEDE, &dbi);
141
+ if (err != MDBX_SUCCESS) {
142
+ std::cerr << "Unexpected err " << err << "\n";
143
+ ok = false;
144
+ }
145
+ if (dbi)
146
+ env.close_map(dbi);
147
+ }
148
+ {
149
+ mdbx::txn_managed txn = env.start_read();
150
+ MDBX_dbi dbi = 0;
151
+ int err = mdbx_dbi_open(txn, "dup", MDBX_DB_ACCEDE, &dbi);
152
+ if (err != MDBX_SUCCESS) {
153
+ std::cerr << "Unexpected err " << err << "\n";
154
+ ok = false;
155
+ }
156
+ if (dbi)
157
+ env.close_map(dbi);
158
+ }
159
+ }
160
+ }
161
+
162
+ return ok;
163
+ }
164
+
165
+ bool case3() {
166
+ bool ok = true;
167
+ mdbx::env_managed::create_parameters createParameters;
168
+ mdbx::env::remove(db_filename);
169
+ {
170
+ mdbx::env::operate_parameters operateParameters(1, 10, mdbx::env::nested_transactions);
171
+ mdbx::env_managed env(db_filename, createParameters, operateParameters);
172
+ {
173
+ mdbx::txn_managed txn = env.start_write();
174
+ MDBX_dbi notexists_dbi = 0;
175
+ int err = mdbx_dbi_open(txn, "test", MDBX_DB_DEFAULTS, &notexists_dbi);
176
+ if (err != MDBX_NOTFOUND) {
177
+ std::cerr << "Unexpected err " << err << " (wanna MDBX_NOTFOUND/-30798)\n";
178
+ ok = false;
179
+ }
180
+ mdbx::map_handle dbi = txn.create_map("test", mdbx::key_mode::ordinal, mdbx::value_mode::single);
181
+ dbi = txn.open_map("test", mdbx::key_mode::ordinal, mdbx::value_mode::single);
182
+ err = mdbx_dbi_close(env, dbi);
183
+ if (err != MDBX_DANGLING_DBI) {
184
+ std::cerr << "Unexpected err " << err << " (wanna MDBX_DANGLING_DBI/-30412)\n";
185
+ ok = false;
186
+ }
187
+ txn.commit();
188
+ env.close_map(dbi);
189
+ }
190
+ }
191
+ return ok;
192
+ }
193
+
194
+ int doit() {
195
+
196
+ bool ok = true;
197
+ ok = case1() && ok;
198
+ ok = case2() && ok;
199
+ ok = case3() && ok;
200
+
201
+ if (ok) {
202
+ std::cout << "OK\n";
203
+ return EXIT_SUCCESS;
204
+ } else {
205
+ std::cerr << "FAIL\n";
206
+ return EXIT_FAILURE;
207
+ }
208
+ }
209
+
210
+ static char log_buffer[1024];
211
+
212
+ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
213
+ unsigned length) noexcept {
214
+ (void)length;
215
+ (void)loglevel;
216
+ fprintf(stdout, "%s:%u %s", function, line, msg);
217
+ }
218
+
219
+ int main(int argc, char *argv[]) {
220
+ (void)argc;
221
+ (void)argv;
222
+ mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer));
223
+ try {
224
+ return doit();
225
+ } catch (const std::exception &ex) {
226
+ std::cerr << "Exception: " << ex.what() << "\n";
227
+ return EXIT_FAILURE;
228
+ }
229
+ }