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,177 @@
1
+ #include "querymou.hpp"
2
+
3
+ namespace mdbxmou {
4
+
5
+ void async_common::parse(txn_mode txn, const Napi::Object& obj)
6
+ {
7
+ if (obj.Has("db")) {
8
+ db_name = obj.Get("db").As<Napi::String>().Utf8Value();
9
+ db = mdbx::slice{db_name};
10
+ }
11
+
12
+ if (obj.Has("dbMode")) {
13
+ db_mod = db_mode::parse(txn, obj.Get("dbMode").As<Napi::Number>());
14
+ }
15
+
16
+ if (obj.Has("keyFlag")) {
17
+ key_flag = base_flag::parse_key(obj.Get("keyFlag").As<Napi::Number>());
18
+ }
19
+
20
+ if (obj.Has("keyMode")) {
21
+ key_mod = parse_key_mode(obj.Env(), obj.Get("keyMode").As<Napi::Number>(), key_flag);
22
+ }
23
+
24
+ // парсим value
25
+ if (obj.Has("valueMode")) {
26
+ val_mod = value_mode::parse(obj.Get("valueMode").As<Napi::Number>());
27
+ }
28
+ }
29
+
30
+ void async_key::parse(const async_common& common, const Napi::Value& item)
31
+ {
32
+ // утснавлиаем общие параметры
33
+ auto key_flag = common.key_flag;
34
+
35
+ keymou key{};
36
+ if (common.key_mod.val & key_mode::ordinal) {
37
+ if (item.IsBigInt()) {
38
+ key = keymou{item.As<Napi::BigInt>(), id_buf};
39
+ } else if (item.IsNumber()) {
40
+ key = keymou{item.As<Napi::Number>(), id_buf};
41
+ }
42
+ } else {
43
+ key = (key_flag.val & base_flag::string) ?
44
+ keymou{item.As<Napi::String>(), item.Env(), key_buf} :
45
+ keymou{item.As<Napi::Buffer<char>>(), key_buf};
46
+ }
47
+ }
48
+
49
+ void async_keyval::parse(const query_line& common, const Napi::Object& item)
50
+ {
51
+ async_key::parse(common, item);
52
+ // проверяем надо ли что-то писать
53
+ if (common.mode.val & query_mode::write_mask) {
54
+ valuemou val{};
55
+ auto item_val = item.Get("value");
56
+ val = (common.value_flag.val & base_flag::string) ?
57
+ valuemou{item_val.As<Napi::String>(), item_val.Env(), val_buf} :
58
+ valuemou{item_val.As<Napi::Buffer<char>>(), val_buf};
59
+ }
60
+ }
61
+
62
+ void query_line::parse(txn_mode txn, const Napi::Object& obj)
63
+ {
64
+ // парсим общие параметры
65
+ async_common::parse(txn, obj);
66
+
67
+ if (obj.Has("valueFlag")) {
68
+ value_flag = base_flag::parse_value(val_mod,
69
+ obj.Get("valueFlag").As<Napi::Number>());
70
+ }
71
+
72
+ if (obj.Has("mode")) {
73
+ mode = query_mode::parse(txn, obj.Get("mode").As<Napi::Number>());
74
+ } else if (obj.Has("queryMode")) {
75
+ mode = query_mode::parse(txn, obj.Get("queryMode").As<Napi::Number>());
76
+ }
77
+ }
78
+
79
+ void query_line::parse(txn_mode txn, base_flag kf,
80
+ base_flag vf, const Napi::Object& obj)
81
+ {
82
+ // утснавлиаем общие параметры
83
+ this->key_flag = kf;
84
+ this->value_flag = vf;
85
+
86
+ // парсим общие параметры
87
+ parse(txn, obj);
88
+
89
+ // Парсим элементы
90
+ if (obj.Has("item")) {
91
+ auto items_array = obj.Get("item").As<Napi::Array>();
92
+ auto length = items_array.Length();
93
+ item.reserve(length);
94
+ for (std::size_t i = 0; i < length; ++i) {
95
+ auto item_obj = items_array.Get(i).As<Napi::Object>();
96
+ async_keyval keyval{};
97
+ keyval.parse(*this, item_obj);
98
+ item.emplace_back(std::move(keyval));
99
+ }
100
+ } else {
101
+ throw std::runtime_error("query: no item");
102
+ }
103
+ }
104
+
105
+ query_request parse_query(txn_mode mode, base_flag key_flag,
106
+ base_flag value_flag, const Napi::Value& obj)
107
+ {
108
+ query_request rc{};
109
+ if (obj.IsArray()) {
110
+ auto arr = obj.As<Napi::Array>();
111
+ rc.reserve(arr.Length());
112
+ for (std::size_t i = 0; i < arr.Length(); ++i) {
113
+ query_line row{};
114
+ row.parse(mode, key_flag, value_flag, arr.Get(i).As<Napi::Object>());
115
+ rc.push_back(std::move(row));
116
+ }
117
+ } else if (obj.IsObject()) {
118
+ query_line row{};
119
+ row.parse(mode, key_flag, value_flag, obj.As<Napi::Object>());
120
+ rc.push_back(std::move(row));
121
+ } else {
122
+ throw Napi::TypeError::New(obj.Env(), "Expected array or object for query");
123
+ }
124
+ return rc;
125
+ }
126
+
127
+ void keys_line::parse(txn_mode txn,
128
+ base_flag kf, const Napi::Object& obj)
129
+ {
130
+ // утснавлиаем общие параметры
131
+ this->key_flag = kf;
132
+
133
+ // парсим общие параметры
134
+ async_common::parse(txn, obj);
135
+
136
+ // парсим параметры scan_from
137
+ if (obj.Has("from")) {
138
+ keymou key{};
139
+ has_from_key = true;
140
+ async_key::parse(*this, obj.Get("from"));
141
+ }
142
+
143
+ if (obj.Has("limit")) {
144
+ auto limit_val = obj.Get("limit");
145
+ if (limit_val.IsNumber()) {
146
+ limit = limit_val.As<Napi::Number>().Uint32Value();
147
+ }
148
+ }
149
+
150
+ if (obj.Has("cursorMode")) {
151
+ cursor_mode = parse_cursor_mode(obj.Get("cursorMode"));
152
+ }
153
+ }
154
+
155
+ keys_request parse_keys(txn_mode txn, base_flag key_flag,
156
+ base_flag value_flag, const Napi::Value& obj)
157
+ {
158
+ keys_request rc{};
159
+ if (obj.IsArray()) {
160
+ auto arr = obj.As<Napi::Array>();
161
+ rc.reserve(arr.Length());
162
+ for (std::size_t i = 0; i < arr.Length(); ++i) {
163
+ keys_line row{};
164
+ row.parse(txn, key_flag, arr.Get(i).As<Napi::Object>());
165
+ rc.push_back(std::move(row));
166
+ }
167
+ } else if (obj.IsObject()) {
168
+ keys_line row{};
169
+ row.parse(txn, key_flag, obj.As<Napi::Object>());
170
+ rc.push_back(std::move(row));
171
+ } else {
172
+ throw Napi::TypeError::New(obj.Env(), "Expected array or object for query");
173
+ }
174
+ return rc;
175
+ }
176
+
177
+ } // namespace mdbxmou
@@ -0,0 +1,93 @@
1
+ #pragma once
2
+
3
+ #include "valuemou.hpp"
4
+ #include <mdbx.h++>
5
+
6
+ namespace mdbxmou {
7
+
8
+ struct keys_line;
9
+ struct query_line;
10
+
11
+ struct async_common
12
+ {
13
+ // чтобы уметь открыть базу по умолчанию
14
+ mdbx::slice db{};
15
+ std::string db_name{};
16
+ db_mode db_mod{};
17
+ // тут важен для нас ordinal он влияет на option_mask
18
+ key_mode key_mod{};
19
+ base_flag key_flag{};
20
+ // общий используется для открытия db
21
+ value_mode val_mod{};
22
+
23
+ void parse(txn_mode mode, const Napi::Object& obj);
24
+ };
25
+
26
+ struct async_key
27
+ {
28
+ buffer_type key_buf{};
29
+ std::uint64_t id_buf{};
30
+ void parse(const async_common& common, const Napi::Value& item);
31
+
32
+ void parse(const async_common& common, const Napi::Object& item)
33
+ {
34
+ parse(common, item.Get("key"));
35
+ }
36
+ };
37
+
38
+ struct async_keyval
39
+ : async_key
40
+ {
41
+ buffer_type val_buf{};
42
+ bool found{false};
43
+
44
+ void parse(const query_line& line, const Napi::Object& obj);
45
+
46
+ void set(const mdbx::slice& val) {
47
+ if (val.empty()) {
48
+ val_buf.clear();
49
+ } else {
50
+ val_buf.assign(val.char_ptr(), val.end_char_ptr());
51
+ }
52
+ }
53
+ };
54
+
55
+ struct query_line
56
+ : async_common
57
+ {
58
+ base_flag value_flag{};
59
+ query_mode mode{};
60
+
61
+ void parse(txn_mode mode, const Napi::Object& obj);
62
+
63
+ // буффер для запроса / ответа
64
+ std::vector<async_keyval> item{};
65
+ void parse(txn_mode txn, base_flag key_flag,
66
+ base_flag value_flag, const Napi::Object& obj);
67
+ };
68
+
69
+ using query_request = std::vector<query_line>;
70
+ query_request parse_query(txn_mode txn, base_flag key_flag,
71
+ base_flag value_flag, const Napi::Value& obj);
72
+
73
+
74
+ struct keys_line
75
+ : async_common
76
+ , async_key
77
+ {
78
+ using move_operation = mdbx::cursor::move_operation;
79
+ bool has_from_key{false};
80
+ std::size_t limit{SIZE_MAX};
81
+ move_operation cursor_mode{move_operation::key_greater_or_equal}; // режим курсора
82
+ // буффер для ответов
83
+ std::vector<async_key> item{};
84
+
85
+ void parse(txn_mode txn, base_flag key_flag,
86
+ const Napi::Object& obj);
87
+ };
88
+
89
+ using keys_request = std::vector<keys_line>;
90
+ keys_request parse_keys(txn_mode txn, base_flag key_flag,
91
+ base_flag value_flag, const Napi::Value& obj);
92
+
93
+ } // namespace mdbxmou
package/src/txnmou.cpp ADDED
@@ -0,0 +1,254 @@
1
+ #include "txnmou.hpp"
2
+ #include "envmou.hpp"
3
+
4
+ namespace mdbxmou {
5
+
6
+ Napi::FunctionReference txnmou::ctor{};
7
+
8
+ void txnmou::init(const char *class_name, Napi::Env env) {
9
+ auto func = DefineClass(env, class_name, {
10
+ InstanceMethod("commit", &txnmou::commit),
11
+ InstanceMethod("abort", &txnmou::abort),
12
+ InstanceMethod("openMap", &txnmou::open_map),
13
+ InstanceMethod("createMap", &txnmou::create_map),
14
+ InstanceMethod("isActive", &txnmou::is_active),
15
+ InstanceMethod("isTopLevel", &txnmou::is_top_level),
16
+ #ifdef MDBX_TXN_HAS_CHILD
17
+ InstanceMethod("startTransaction", &txnmou::start_transaction),
18
+ InstanceMethod("getChildrenCount", &txnmou::get_children_count),
19
+ #endif
20
+ });
21
+
22
+ ctor = Napi::Persistent(func);
23
+ ctor.SuppressDestruct();
24
+ }
25
+
26
+ Napi::Value txnmou::commit(const Napi::CallbackInfo& info) {
27
+ Napi::Env env = info.Env();
28
+
29
+ try {
30
+ check();
31
+ #ifdef MDBX_TXN_HAS_CHILD
32
+ // Проверяем активные дочерние транзакции
33
+ cleanup_children();
34
+
35
+ if (has_active_children()) {
36
+ throw std::runtime_error("txn: active child exist");
37
+ }
38
+ #endif // MDBX_TXN_HAS_CHILD
39
+ auto rc = mdbx_txn_commit(*this);
40
+ if (rc != MDBX_SUCCESS) {
41
+ throw Napi::Error::New(env, std::string("txn: ") + mdbx_strerror(rc));
42
+ }
43
+
44
+ is_committed_ = true;
45
+ // Отключаем deleter, так как транзакция уже закоммичена
46
+ txn_.reset();
47
+ } catch (const std::exception& e) {
48
+ throw Napi::Error::New(env, e.what());
49
+ }
50
+
51
+ return env.Undefined();
52
+ }
53
+
54
+ Napi::Value txnmou::abort(const Napi::CallbackInfo& info) {
55
+ Napi::Env env = info.Env();
56
+
57
+ try {
58
+ check();
59
+ #ifdef MDBX_TXN_HAS_CHILD
60
+ // Сначала отменяем все дочерние транзакции
61
+ cleanup_children();
62
+
63
+ for (const auto& child : children_) {
64
+ if (child && child->txn_ && !child->is_committed_ && !child->is_aborted_) {
65
+ try {
66
+ child->abort(info);
67
+ } catch (...) {
68
+ // Игнорируем ошибки при abort дочерних
69
+ }
70
+ }
71
+ }
72
+ #endif // MDBX_TXN_HAS_CHILD
73
+ auto rc = mdbx_txn_abort(*this);
74
+ if (rc != MDBX_SUCCESS) {
75
+ throw Napi::Error::New(env, std::string("txn: ") + mdbx_strerror(rc));
76
+ }
77
+
78
+ is_aborted_ = true;
79
+ txn_.reset();
80
+ } catch (const std::exception& e) {
81
+ throw Napi::Error::New(env, e.what());
82
+ }
83
+
84
+ return env.Undefined();
85
+ }
86
+
87
+ Napi::Value txnmou::get_dbi(const Napi::CallbackInfo& info, db_mode db_mode)
88
+ {
89
+ Napi::Env env = info.Env();
90
+
91
+ try
92
+ {
93
+ if ((mode_.val & txn_mode::ro) && (db_mode.val & db_mode::create)) {
94
+ throw std::runtime_error("dbi: cannot open DB in read-only transaction");
95
+ }
96
+
97
+ key_mode key_mode{};
98
+ value_mode value_mode{};
99
+ std::string db_name{};
100
+ auto conf = dbimou::get_env_userctx(*env_);
101
+ auto key_flag = conf->key_flag;
102
+ auto value_flag = conf->value_flag;
103
+ auto arg_count = info.Length();
104
+ if (arg_count == 3) {
105
+ auto arg0 = info[0]; // db_name
106
+ auto arg1 = info[1]; // key_mode
107
+ auto arg2 = info[2]; // value_mode
108
+ db_name = arg0.As<Napi::String>().Utf8Value();
109
+ key_mode = parse_key_mode(env, arg1, key_flag);
110
+ value_mode = value_mode::parse(arg2);
111
+ } else if (arg_count == 2) {
112
+ // db_name + key_mode || key_mode + value_mode
113
+ auto arg0 = info[0];
114
+ auto arg1 = info[1];
115
+ if (arg0.IsString()) {
116
+ db_name = arg0.As<Napi::String>().Utf8Value();
117
+ key_mode = parse_key_mode(env, arg1, key_flag);
118
+ } else if (arg0.IsNumber()) {
119
+ key_mode = parse_key_mode(env, arg0, key_flag);
120
+ value_mode = value_mode::parse(arg1);
121
+ } else {
122
+ throw Napi::Error::New(env, "Invalid argument type for db_name or value_mode");
123
+ }
124
+ } else if (arg_count == 1) {
125
+ // db_name || key_mode
126
+ auto arg0 = info[0];
127
+ if (arg0.IsString()) {
128
+ db_name = arg0.As<Napi::String>().Utf8Value();
129
+ } else {
130
+ key_mode = parse_key_mode(env, arg0, key_flag);
131
+ }
132
+ } else {
133
+ throw Napi::Error::New(env, "Invalid number of arguments for get_dbi");
134
+ }
135
+
136
+ check();
137
+
138
+ // создаем новый объект dbi
139
+ auto obj = dbimou::ctor.New({});
140
+ auto ptr = dbimou::Unwrap(obj);
141
+
142
+ MDBX_dbi dbi{};
143
+ auto flags = static_cast<MDBX_db_flags_t>(db_mode.val|key_mode.val|value_mode.val);
144
+ auto rc = mdbx_dbi_open(*this, db_name.empty() ? nullptr : db_name.c_str(), flags, &dbi);
145
+ if (rc != MDBX_SUCCESS) {
146
+ throw std::runtime_error(std::string("mdbx_dbi_open ") + mdbx_strerror(rc));
147
+ }
148
+ ptr->attach(env_, this, dbi, db_mode, key_mode,
149
+ value_mode, key_flag, value_flag);
150
+ return obj;
151
+ }
152
+ catch(const std::exception& e)
153
+ {
154
+ throw Napi::Error::New(env, std::string("txn: get_dbi ") + e.what());
155
+ }
156
+
157
+ return env.Undefined();
158
+ }
159
+
160
+ Napi::Value txnmou::is_active(const Napi::CallbackInfo& info) {
161
+ Napi::Env env = info.Env();
162
+ bool active = txn_ && !is_committed_ && !is_aborted_;
163
+ return Napi::Boolean::New(env, active);
164
+ }
165
+
166
+ Napi::Value txnmou::is_top_level(const Napi::CallbackInfo& info) {
167
+ Napi::Env env = info.Env();
168
+ return Napi::Boolean::New(env, parent_ == nullptr);
169
+ }
170
+
171
+ #ifdef MDBX_TXN_HAS_CHILD
172
+
173
+ Napi::Value txnmou::start_transaction(const Napi::CallbackInfo& info) {
174
+ Napi::Env env = info.Env();
175
+
176
+ // Создаем новый объект txnmou для дочерней транзакции
177
+ auto child_obj = ctor.New({});
178
+ auto child_wrapper = txnmou::Unwrap(child_obj);
179
+
180
+ int rc{MDBX_SUCCESS};
181
+ try {
182
+ check();
183
+
184
+ MDBX_txn* child_txn;
185
+ auto rc = mdbx_txn_begin(*env_, txn_.get(), flags_, &child_txn);
186
+ if (rc != MDBX_SUCCESS) {
187
+ std::string flag_name = (flags_ == MDBX_TXN_RDONLY) ? "read" : "write";
188
+ throw Napi::Error::New(env, std::string("txn ") + flag_name + ": " + mdbx_strerror(rc));
189
+ }
190
+ child_wrapper->attach(*env_, child_txn, flags_, this);
191
+ } catch (const std::exception& e) {
192
+ throw Napi::Error::New(env, e.what());
193
+ }
194
+
195
+ return child_obj;
196
+ }
197
+
198
+ Napi::Value txnmou::get_children_count(const Napi::CallbackInfo& info) {
199
+ Napi::Env env = info.Env();
200
+ cleanup_children();
201
+
202
+ size_t active_count = 0;
203
+ for (const auto& child : children_) {
204
+ if (child && child->txn_ && !child->is_committed_ && !child->is_aborted_) {
205
+ active_count++;
206
+ }
207
+ }
208
+
209
+ return Napi::Number::New(env, static_cast<double>(active_count));
210
+ }
211
+
212
+ #endif // MDBX_TXN_HAS_CHILD
213
+
214
+ void txnmou::attach(envmou& env, MDBX_txn* txn,
215
+ txn_mode mode, txnmou* parent)
216
+ {
217
+ // увеличиваем счетчик транзакций в env
218
+ env_ = &env;
219
+
220
+ if (parent == nullptr) {
221
+ // Если родительская транзакция не указана, увеличиваем счетчик
222
+ ++(*env_);
223
+ }
224
+
225
+ parent_ = parent;
226
+ mode_ = mode;
227
+ is_committed_ = false;
228
+ is_aborted_ = false;
229
+
230
+ #ifdef MDBX_TXN_HAS_CHILD
231
+ if (parent) {
232
+ parent->push_back(this);
233
+ }
234
+ #endif
235
+ txn_.reset(txn);
236
+ }
237
+
238
+ void txnmou::free_txn::operator()(MDBX_txn* txn) const noexcept {
239
+ if (!that.is_committed_ && !that.is_aborted_) {
240
+ // Автоматический abort при деструкции
241
+ auto rc = mdbx_txn_abort(that);
242
+ if (rc != MDBX_SUCCESS) {
243
+ fprintf(stderr, "mdbx_txn_abort code: %d, msg: %s\n", rc, mdbx_strerror(rc));
244
+ }
245
+ that.is_aborted_ = true;
246
+ }
247
+ // уменьшаем счетчик транзакций (только родительских)
248
+ if (that.parent_ == nullptr) {
249
+ //fprintf(stderr, "free_txn: --env\n");
250
+ --(*that.env_);
251
+ }
252
+ }
253
+
254
+ } // namespace mdbxmou
package/src/txnmou.hpp ADDED
@@ -0,0 +1,122 @@
1
+ #pragma once
2
+
3
+ #include "dbimou.hpp"
4
+
5
+ #ifdef MDBX_TXN_HAS_CHILD
6
+ #include <vector>
7
+ #endif
8
+
9
+ namespace mdbxmou {
10
+
11
+ class envmou;
12
+
13
+ class txnmou final
14
+ : public Napi::ObjectWrap<txnmou>
15
+ {
16
+ private:
17
+ envmou* env_{nullptr};
18
+ // транзакция
19
+ struct free_txn {
20
+ txnmou& that;
21
+ void operator()(MDBX_txn* txn) const noexcept;
22
+ };
23
+
24
+ free_txn erase_{*this};
25
+ std::unique_ptr<MDBX_txn, free_txn> txn_{nullptr, erase_};
26
+
27
+ // Иерархия транзакций
28
+ txnmou* parent_{nullptr};
29
+ #ifdef MDBX_TXN_HAS_CHILD
30
+ std::vector<txnmou*> children_{};
31
+ #endif
32
+
33
+ // Флаг для отслеживания состояния
34
+ bool is_committed_{};
35
+ bool is_aborted_{};
36
+
37
+ // Сохраняем тип транзакции для создания дочерних того же типа
38
+ txn_mode mode_{};
39
+
40
+ void check_valid() const
41
+ {
42
+ if (is_committed_)
43
+ throw std::runtime_error("txn: already committed");
44
+ if (is_aborted_)
45
+ throw std::runtime_error("txn: already aborted");
46
+ }
47
+
48
+ void check() const
49
+ {
50
+ check_valid();
51
+
52
+ if (!txn_)
53
+ throw std::runtime_error("txn: not initialized");
54
+ }
55
+
56
+ #ifdef MDBX_TXN_HAS_CHILD
57
+ // Проверка активных дочерних транзакций
58
+ bool has_active_children() const {
59
+ for (const auto& child : children_) {
60
+ if (child && child->txn_ && !child->is_committed_ && !child->is_aborted_) {
61
+ return true;
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+
67
+ // Очистка завершенных дочерних транзакций
68
+ void cleanup_children() {
69
+ children_.erase(
70
+ std::remove_if(children_.begin(), children_.end(),
71
+ [](const txnmou* child) {
72
+ return !child || child->is_committed_ || child->is_aborted_;
73
+ }),
74
+ children_.end()
75
+ );
76
+ }
77
+
78
+ // Общий метод для создания дочерних транзакций
79
+ Napi::Value start_transaction(const Napi::CallbackInfo& info, MDBX_txn_flags_t flags);
80
+
81
+ void push_back(txnmou* child) {
82
+ children_.push_back(child);
83
+ }
84
+ #endif
85
+ Napi::Value get_dbi(const Napi::CallbackInfo&, db_mode);
86
+
87
+ public:
88
+ static Napi::FunctionReference ctor;
89
+
90
+ txnmou(const Napi::CallbackInfo& info)
91
+ : Napi::ObjectWrap<txnmou>(info)
92
+ { }
93
+
94
+ static void init(const char *class_name, Napi::Env env);
95
+
96
+ // Основные операции (только синхронные)
97
+ Napi::Value commit(const Napi::CallbackInfo&);
98
+ Napi::Value abort(const Napi::CallbackInfo&);
99
+ Napi::Value open_map(const Napi::CallbackInfo& info) {
100
+ return get_dbi(info, db_mode{});
101
+ }
102
+ Napi::Value create_map(const Napi::CallbackInfo& info) {
103
+ return get_dbi(info, {db_mode::create});
104
+ }
105
+
106
+ operator MDBX_txn*() const noexcept {
107
+ return txn_.get();
108
+ }
109
+
110
+ #ifdef MDBX_TXN_HAS_CHILD
111
+ // Работа с вложенными транзакциями
112
+ Napi::Value start_transaction(const Napi::CallbackInfo&);
113
+ Napi::Value get_children_count(const Napi::CallbackInfo&);
114
+ #endif
115
+ Napi::Value is_active(const Napi::CallbackInfo&);
116
+ Napi::Value is_top_level(const Napi::CallbackInfo&);
117
+
118
+ void attach(envmou& env, MDBX_txn* txn,
119
+ txn_mode mode, txnmou* parent = nullptr);
120
+ };
121
+
122
+ } // namespace mdbxmou