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.
- package/.github/workflows/ci.yml +32 -0
- package/.github/workflows/publish.yml +27 -0
- package/.gitmodules +3 -0
- package/CMakeLists.txt +53 -0
- package/LICENSE +201 -0
- package/README.md +639 -0
- package/build.js +11 -0
- package/deps/libmdbx/.clang-format +3 -0
- package/deps/libmdbx/.cmake-format.yaml +3 -0
- package/deps/libmdbx/.le.ini +40 -0
- package/deps/libmdbx/CMakeLists.txt +1269 -0
- package/deps/libmdbx/COPYRIGHT +159 -0
- package/deps/libmdbx/ChangeLog.md +2786 -0
- package/deps/libmdbx/GNUmakefile +950 -0
- package/deps/libmdbx/LICENSE +177 -0
- package/deps/libmdbx/Makefile +16 -0
- package/deps/libmdbx/NOTICE +39 -0
- package/deps/libmdbx/README.md +863 -0
- package/deps/libmdbx/TODO.md +43 -0
- package/deps/libmdbx/cmake/compiler.cmake +1221 -0
- package/deps/libmdbx/cmake/profile.cmake +58 -0
- package/deps/libmdbx/cmake/utils.cmake +524 -0
- package/deps/libmdbx/conanfile.py +323 -0
- package/deps/libmdbx/docs/Doxyfile.in +2734 -0
- package/deps/libmdbx/docs/_preface.md +47 -0
- package/deps/libmdbx/docs/_restrictions.md +248 -0
- package/deps/libmdbx/docs/_starting.md +245 -0
- package/deps/libmdbx/docs/_toc.md +34 -0
- package/deps/libmdbx/docs/header.html +96 -0
- package/deps/libmdbx/example/CMakeLists.txt +6 -0
- package/deps/libmdbx/example/README.md +1 -0
- package/deps/libmdbx/example/example-mdbx.c +154 -0
- package/deps/libmdbx/example/sample-bdb.txt +77 -0
- package/deps/libmdbx/mdbx.h +6655 -0
- package/deps/libmdbx/mdbx.h++ +6428 -0
- package/deps/libmdbx/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +173 -0
- package/deps/libmdbx/src/alloy.c +54 -0
- package/deps/libmdbx/src/api-cold.c +543 -0
- package/deps/libmdbx/src/api-copy.c +912 -0
- package/deps/libmdbx/src/api-cursor.c +754 -0
- package/deps/libmdbx/src/api-dbi.c +315 -0
- package/deps/libmdbx/src/api-env.c +1434 -0
- package/deps/libmdbx/src/api-extra.c +165 -0
- package/deps/libmdbx/src/api-key-transform.c +197 -0
- package/deps/libmdbx/src/api-misc.c +286 -0
- package/deps/libmdbx/src/api-opts.c +575 -0
- package/deps/libmdbx/src/api-range-estimate.c +365 -0
- package/deps/libmdbx/src/api-txn-data.c +454 -0
- package/deps/libmdbx/src/api-txn.c +921 -0
- package/deps/libmdbx/src/atomics-ops.h +364 -0
- package/deps/libmdbx/src/atomics-types.h +97 -0
- package/deps/libmdbx/src/audit.c +109 -0
- package/deps/libmdbx/src/bits.md +34 -0
- package/deps/libmdbx/src/chk.c +1796 -0
- package/deps/libmdbx/src/cogs.c +309 -0
- package/deps/libmdbx/src/cogs.h +506 -0
- package/deps/libmdbx/src/coherency.c +170 -0
- package/deps/libmdbx/src/config.h.in +88 -0
- package/deps/libmdbx/src/cursor.c +2396 -0
- package/deps/libmdbx/src/cursor.h +391 -0
- package/deps/libmdbx/src/dbi.c +717 -0
- package/deps/libmdbx/src/dbi.h +142 -0
- package/deps/libmdbx/src/debug_begin.h +36 -0
- package/deps/libmdbx/src/debug_end.h +15 -0
- package/deps/libmdbx/src/dpl.c +486 -0
- package/deps/libmdbx/src/dpl.h +134 -0
- package/deps/libmdbx/src/dxb.c +1335 -0
- package/deps/libmdbx/src/env.c +607 -0
- package/deps/libmdbx/src/essentials.h +125 -0
- package/deps/libmdbx/src/gc-get.c +1345 -0
- package/deps/libmdbx/src/gc-put.c +970 -0
- package/deps/libmdbx/src/gc.h +40 -0
- package/deps/libmdbx/src/global.c +474 -0
- package/deps/libmdbx/src/internals.h +585 -0
- package/deps/libmdbx/src/layout-dxb.h +288 -0
- package/deps/libmdbx/src/layout-lck.h +289 -0
- package/deps/libmdbx/src/lck-posix.c +859 -0
- package/deps/libmdbx/src/lck-windows.c +607 -0
- package/deps/libmdbx/src/lck.c +174 -0
- package/deps/libmdbx/src/lck.h +110 -0
- package/deps/libmdbx/src/logging_and_debug.c +250 -0
- package/deps/libmdbx/src/logging_and_debug.h +159 -0
- package/deps/libmdbx/src/man1/mdbx_chk.1 +106 -0
- package/deps/libmdbx/src/man1/mdbx_copy.1 +95 -0
- package/deps/libmdbx/src/man1/mdbx_drop.1 +48 -0
- package/deps/libmdbx/src/man1/mdbx_dump.1 +101 -0
- package/deps/libmdbx/src/man1/mdbx_load.1 +105 -0
- package/deps/libmdbx/src/man1/mdbx_stat.1 +86 -0
- package/deps/libmdbx/src/mdbx.c++ +1837 -0
- package/deps/libmdbx/src/meta.c +656 -0
- package/deps/libmdbx/src/meta.h +168 -0
- package/deps/libmdbx/src/mvcc-readers.c +414 -0
- package/deps/libmdbx/src/node.c +365 -0
- package/deps/libmdbx/src/node.h +102 -0
- package/deps/libmdbx/src/ntdll.def +1246 -0
- package/deps/libmdbx/src/options.h +534 -0
- package/deps/libmdbx/src/osal.c +3485 -0
- package/deps/libmdbx/src/osal.h +587 -0
- package/deps/libmdbx/src/page-get.c +483 -0
- package/deps/libmdbx/src/page-iov.c +185 -0
- package/deps/libmdbx/src/page-iov.h +34 -0
- package/deps/libmdbx/src/page-ops.c +744 -0
- package/deps/libmdbx/src/page-ops.h +142 -0
- package/deps/libmdbx/src/pnl.c +236 -0
- package/deps/libmdbx/src/pnl.h +146 -0
- package/deps/libmdbx/src/preface.h +990 -0
- package/deps/libmdbx/src/proto.h +105 -0
- package/deps/libmdbx/src/refund.c +212 -0
- package/deps/libmdbx/src/sort.h +484 -0
- package/deps/libmdbx/src/spill.c +431 -0
- package/deps/libmdbx/src/spill.h +74 -0
- package/deps/libmdbx/src/table.c +107 -0
- package/deps/libmdbx/src/tls.c +551 -0
- package/deps/libmdbx/src/tls.h +43 -0
- package/deps/libmdbx/src/tools/chk.c +673 -0
- package/deps/libmdbx/src/tools/copy.c +166 -0
- package/deps/libmdbx/src/tools/drop.c +199 -0
- package/deps/libmdbx/src/tools/dump.c +515 -0
- package/deps/libmdbx/src/tools/load.c +831 -0
- package/deps/libmdbx/src/tools/stat.c +516 -0
- package/deps/libmdbx/src/tools/wingetopt.c +87 -0
- package/deps/libmdbx/src/tools/wingetopt.h +30 -0
- package/deps/libmdbx/src/tree-ops.c +1554 -0
- package/deps/libmdbx/src/tree-search.c +140 -0
- package/deps/libmdbx/src/txl.c +99 -0
- package/deps/libmdbx/src/txl.h +26 -0
- package/deps/libmdbx/src/txn.c +1083 -0
- package/deps/libmdbx/src/unaligned.h +205 -0
- package/deps/libmdbx/src/utils.c +32 -0
- package/deps/libmdbx/src/utils.h +76 -0
- package/deps/libmdbx/src/version.c.in +44 -0
- package/deps/libmdbx/src/walk.c +290 -0
- package/deps/libmdbx/src/walk.h +20 -0
- package/deps/libmdbx/src/windows-import.c +152 -0
- package/deps/libmdbx/src/windows-import.h +128 -0
- package/deps/libmdbx/test/CMakeLists.txt +317 -0
- package/deps/libmdbx/test/append.c++ +237 -0
- package/deps/libmdbx/test/base.h++ +92 -0
- package/deps/libmdbx/test/battery-tmux.sh +64 -0
- package/deps/libmdbx/test/cases.c++ +118 -0
- package/deps/libmdbx/test/chrono.c++ +134 -0
- package/deps/libmdbx/test/chrono.h++ +85 -0
- package/deps/libmdbx/test/config.c++ +643 -0
- package/deps/libmdbx/test/config.h++ +334 -0
- package/deps/libmdbx/test/copy.c++ +62 -0
- package/deps/libmdbx/test/dead.c++ +39 -0
- package/deps/libmdbx/test/dump-load.sh +40 -0
- package/deps/libmdbx/test/extra/crunched_delete.c++ +409 -0
- package/deps/libmdbx/test/extra/cursor_closing.c++ +410 -0
- package/deps/libmdbx/test/extra/dbi.c++ +229 -0
- package/deps/libmdbx/test/extra/doubtless_positioning.c++ +253 -0
- package/deps/libmdbx/test/extra/dupfix_addodd.c +94 -0
- package/deps/libmdbx/test/extra/dupfix_multiple.c++ +311 -0
- package/deps/libmdbx/test/extra/early_close_dbi.c++ +137 -0
- package/deps/libmdbx/test/extra/hex_base64_base58.c++ +118 -0
- package/deps/libmdbx/test/extra/maindb_ordinal.c++ +61 -0
- package/deps/libmdbx/test/extra/open.c++ +96 -0
- package/deps/libmdbx/test/extra/pcrf/README.md +2 -0
- package/deps/libmdbx/test/extra/pcrf/pcrf_test.c +380 -0
- package/deps/libmdbx/test/extra/probe.c++ +10 -0
- package/deps/libmdbx/test/extra/txn.c++ +407 -0
- package/deps/libmdbx/test/extra/upsert_alldups.c +193 -0
- package/deps/libmdbx/test/fork.c++ +263 -0
- package/deps/libmdbx/test/hill.c++ +447 -0
- package/deps/libmdbx/test/jitter.c++ +197 -0
- package/deps/libmdbx/test/keygen.c++ +393 -0
- package/deps/libmdbx/test/keygen.h++ +130 -0
- package/deps/libmdbx/test/log.c++ +358 -0
- package/deps/libmdbx/test/log.h++ +91 -0
- package/deps/libmdbx/test/main.c++ +706 -0
- package/deps/libmdbx/test/nested.c++ +318 -0
- package/deps/libmdbx/test/osal-unix.c++ +647 -0
- package/deps/libmdbx/test/osal-windows.c++ +440 -0
- package/deps/libmdbx/test/osal.h++ +41 -0
- package/deps/libmdbx/test/stochastic.sh +690 -0
- package/deps/libmdbx/test/stub/LICENSE +24 -0
- package/deps/libmdbx/test/stub/README.md +8 -0
- package/deps/libmdbx/test/stub/pthread_barrier.c +104 -0
- package/deps/libmdbx/test/stub/pthread_barrier.h +77 -0
- package/deps/libmdbx/test/test.c++ +1551 -0
- package/deps/libmdbx/test/test.h++ +298 -0
- package/deps/libmdbx/test/tmux.conf +3 -0
- package/deps/libmdbx/test/try.c++ +30 -0
- package/deps/libmdbx/test/ttl.c++ +240 -0
- package/deps/libmdbx/test/utils.c++ +203 -0
- package/deps/libmdbx/test/utils.h++ +326 -0
- package/deps/libmdbx/test/valgrind_suppress.txt +536 -0
- package/lib/mdbx_evn_async.js +211 -0
- package/lib/mdbx_worker.js +195 -0
- package/lib/nativemou.js +6 -0
- package/package.json +38 -0
- package/src/async/envmou_close.cpp +34 -0
- package/src/async/envmou_close.hpp +32 -0
- package/src/async/envmou_copy_to.cpp +29 -0
- package/src/async/envmou_copy_to.hpp +38 -0
- package/src/async/envmou_keys.cpp +201 -0
- package/src/async/envmou_keys.hpp +50 -0
- package/src/async/envmou_open.cpp +38 -0
- package/src/async/envmou_open.hpp +33 -0
- package/src/async/envmou_query.cpp +167 -0
- package/src/async/envmou_query.hpp +53 -0
- package/src/dbimou.cpp +522 -0
- package/src/dbimou.hpp +82 -0
- package/src/env_arg0.hpp +24 -0
- package/src/envmou.cpp +445 -0
- package/src/envmou.hpp +116 -0
- package/src/modulemou.cpp +113 -0
- package/src/querymou.cpp +177 -0
- package/src/querymou.hpp +93 -0
- package/src/txnmou.cpp +254 -0
- package/src/txnmou.hpp +122 -0
- package/src/typemou.hpp +239 -0
- package/src/valuemou.hpp +194 -0
- package/test/async.js +67 -0
- package/test/e3.js +38 -0
- package/test/e4.js +89 -0
- package/test/e5.js +162 -0
- package/test/test-batch-ops.js +243 -0
- package/test/test-cursor-mode.js +84 -0
- package/test/test-multi-mode.js +87 -0
package/src/querymou.cpp
ADDED
|
@@ -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
|
package/src/querymou.hpp
ADDED
|
@@ -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
|