mdbxmou 0.2.5 → 0.2.7
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/README.md +8 -2
- package/package.json +3 -2
- package/src/dbimou.cpp +2 -2
- package/src/env_arg0.hpp +1 -4
- package/src/envmou.cpp +6 -6
- package/src/envmou.hpp +3 -2
- package/src/txnmou.cpp +68 -82
- package/src/txnmou.hpp +6 -11
- package/src/typemou.hpp +54 -9
- package/src/valuemou.hpp +19 -8
- package/src/async/envmou_async.cpp +0 -450
- package/src/async/envmou_async.hpp +0 -116
package/README.md
CHANGED
|
@@ -132,8 +132,11 @@ const result = await env.query([
|
|
|
132
132
|
|
|
133
133
|
#### Methods
|
|
134
134
|
|
|
135
|
-
**createMap(db_name | keyMode, [keyMode | valueMode], [valueMode]) → DBI**
|
|
135
|
+
**createMap([db_name | keyMode], [keyMode | valueMode], [valueMode]) → DBI**
|
|
136
136
|
```javascript
|
|
137
|
+
// No arguments - default DB with string keys
|
|
138
|
+
const dbi = txn.createMap();
|
|
139
|
+
|
|
137
140
|
// One argument - keyMode only
|
|
138
141
|
const dbi = txn.createMap(MDBX_Param.keyMode.ordinal);
|
|
139
142
|
|
|
@@ -152,8 +155,11 @@ const namedDbi = txn.createMap("my-table", MDBX_Param.keyMode.ordinal, MDBX_Para
|
|
|
152
155
|
|
|
153
156
|
> **Note**: Use `createMap` in write transactions - it will create the database if it doesn't exist, or open it if it does. This is safer for new environments.
|
|
154
157
|
|
|
155
|
-
**openMap(db_name | keyMode, [keyMode]) → DBI**
|
|
158
|
+
**openMap([db_name | keyMode], [keyMode]) → DBI**
|
|
156
159
|
```javascript
|
|
160
|
+
// No arguments - default DB with string keys
|
|
161
|
+
const dbi = txn.openMap();
|
|
162
|
+
|
|
157
163
|
// One argument - keyMode only
|
|
158
164
|
// Number keyMode - keys returned as numbers
|
|
159
165
|
const dbi = txn.openMap(MDBX_Param.keyMode.ordinal);
|
package/package.json
CHANGED
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"cmake-js": "^7.3.1",
|
|
49
|
-
"node-addon-api": "^8.5.0"
|
|
49
|
+
"node-addon-api": "^8.5.0",
|
|
50
|
+
"uuid": "^13.0.0"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@types/node": "^22.10.2",
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
},
|
|
66
67
|
"gypfile": true,
|
|
67
68
|
"name": "mdbxmou",
|
|
68
|
-
"version": "0.2.
|
|
69
|
+
"version": "0.2.7",
|
|
69
70
|
"description": "Node bindings for mdbx",
|
|
70
71
|
"repository": {
|
|
71
72
|
"type": "git",
|
package/src/dbimou.cpp
CHANGED
|
@@ -51,6 +51,7 @@ Napi::Value dbimou::put(const Napi::CallbackInfo& info)
|
|
|
51
51
|
auto key = (key_mode_.val & key_mode::ordinal) ?
|
|
52
52
|
keymou::from(info[1], env, t) :
|
|
53
53
|
keymou::from(info[1], env, key_buf_);
|
|
54
|
+
|
|
54
55
|
auto val = valuemou::from(info[2], env, val_buf_);
|
|
55
56
|
dbi::put(*txn, key, val, *this);
|
|
56
57
|
} catch (const std::exception& e) {
|
|
@@ -139,7 +140,7 @@ Napi::Value dbimou::has(const Napi::CallbackInfo& info) {
|
|
|
139
140
|
auto key = (key_mode_.val & key_mode::ordinal) ?
|
|
140
141
|
keymou::from(info[1], env, t) :
|
|
141
142
|
keymou::from(info[1], env, key_buf_);
|
|
142
|
-
|
|
143
|
+
|
|
143
144
|
bool result = dbi::has(*txn, key);
|
|
144
145
|
return Napi::Value::From(env, result);
|
|
145
146
|
} catch (const std::exception& e) {
|
|
@@ -177,7 +178,6 @@ Napi::Value dbimou::for_each(const Napi::CallbackInfo& info) {
|
|
|
177
178
|
}
|
|
178
179
|
|
|
179
180
|
uint32_t index{};
|
|
180
|
-
|
|
181
181
|
if (key_mode_.val & key_mode::ordinal) {
|
|
182
182
|
cursor.scan([&](const mdbx::pair& f) {
|
|
183
183
|
keymou key{f.key};
|
package/src/env_arg0.hpp
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include "valuemou.hpp"
|
|
4
|
-
#ifdef _WIN32
|
|
5
|
-
typedef unsigned short mode_t;
|
|
6
|
-
#endif
|
|
7
4
|
|
|
8
5
|
namespace mdbxmou {
|
|
9
6
|
|
|
@@ -12,7 +9,7 @@ struct env_arg0 {
|
|
|
12
9
|
MDBX_dbi max_dbi{32};
|
|
13
10
|
mdbx::env::geometry geom{};
|
|
14
11
|
env_flag flag{};
|
|
15
|
-
|
|
12
|
+
mdbx_mode_t file_mode{0664};
|
|
16
13
|
std::uint32_t max_readers{128};
|
|
17
14
|
base_flag key_flag{};
|
|
18
15
|
base_flag value_flag{};
|
package/src/envmou.cpp
CHANGED
|
@@ -103,7 +103,7 @@ env_arg0 envmou::parse(const Napi::Value& arg0)
|
|
|
103
103
|
|
|
104
104
|
if (obj.Has("mode")) {
|
|
105
105
|
auto value = obj.Get("mode").As<Napi::Number>();
|
|
106
|
-
rc.file_mode = static_cast<
|
|
106
|
+
rc.file_mode = static_cast<mdbx_mode_t>(value.Int32Value());
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
if (obj.Has("keyFlag")) {
|
|
@@ -234,7 +234,7 @@ Napi::Value envmou::close(const Napi::CallbackInfo& info)
|
|
|
234
234
|
return env.Undefined();
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
if (trx_count_
|
|
237
|
+
if (trx_count_ > 0) {
|
|
238
238
|
throw std::runtime_error("active transactions");
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -392,10 +392,10 @@ Napi::Value envmou::query(const Napi::CallbackInfo& info)
|
|
|
392
392
|
auto* worker = new async_query(env, *this, mode,
|
|
393
393
|
std::move(query), arg0.IsObject());
|
|
394
394
|
auto promise = worker->GetPromise();
|
|
395
|
-
worker->Queue();
|
|
396
395
|
|
|
397
|
-
// Увеличиваем счетчик
|
|
396
|
+
// Увеличиваем счетчик ДО Queue() — worker гарантированно вызовет --env_
|
|
398
397
|
++(*this);
|
|
398
|
+
worker->Queue();
|
|
399
399
|
|
|
400
400
|
return promise;
|
|
401
401
|
} catch (const std::exception& e) {
|
|
@@ -433,10 +433,10 @@ Napi::Value envmou::keys(const Napi::CallbackInfo& info)
|
|
|
433
433
|
auto* worker = new async_keys(env, *this, mode,
|
|
434
434
|
std::move(query), arg0.IsObject());
|
|
435
435
|
auto promise = worker->GetPromise();
|
|
436
|
-
worker->Queue();
|
|
437
436
|
|
|
438
|
-
// Увеличиваем счетчик
|
|
437
|
+
// Увеличиваем счетчик ДО Queue() — worker гарантированно вызовет --env_
|
|
439
438
|
++(*this);
|
|
439
|
+
worker->Queue();
|
|
440
440
|
|
|
441
441
|
return promise;
|
|
442
442
|
} catch (const std::exception& e) {
|
package/src/envmou.hpp
CHANGED
|
@@ -27,7 +27,8 @@ class envmou final
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
std::unique_ptr<MDBX_env, free_env> env_{};
|
|
30
|
-
|
|
30
|
+
// счетчик транзакицй, не требующий атомарности
|
|
31
|
+
std::size_t trx_count_{};
|
|
31
32
|
env_arg0 arg0_{};
|
|
32
33
|
std::mutex lock_{};
|
|
33
34
|
|
|
@@ -106,7 +107,7 @@ public:
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
void do_close() {
|
|
109
|
-
if (trx_count_
|
|
110
|
+
if (trx_count_ > 0) {
|
|
110
111
|
throw std::runtime_error("transaction in progress");
|
|
111
112
|
}
|
|
112
113
|
env_.reset();
|
package/src/txnmou.cpp
CHANGED
|
@@ -21,18 +21,14 @@ void txnmou::init(const char *class_name, Napi::Env env) {
|
|
|
21
21
|
Napi::Value txnmou::commit(const Napi::CallbackInfo& info) {
|
|
22
22
|
Napi::Env env = info.Env();
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
dec_counter();
|
|
33
|
-
txn_.release();
|
|
34
|
-
} catch (const std::exception& e) {
|
|
35
|
-
throw Napi::Error::New(env, e.what());
|
|
24
|
+
if (!txn_) {
|
|
25
|
+
throw Napi::Error::New(env, "txn already completed");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
dec_counter();
|
|
29
|
+
auto rc = mdbx_txn_commit(txn_.release());
|
|
30
|
+
if (rc != MDBX_SUCCESS) {
|
|
31
|
+
throw Napi::Error::New(env, std::string("txn commit: ") + mdbx_strerror(rc));
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
return env.Undefined();
|
|
@@ -41,18 +37,14 @@ Napi::Value txnmou::commit(const Napi::CallbackInfo& info) {
|
|
|
41
37
|
Napi::Value txnmou::abort(const Napi::CallbackInfo& info) {
|
|
42
38
|
Napi::Env env = info.Env();
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
dec_counter();
|
|
53
|
-
txn_.release();
|
|
54
|
-
} catch (const std::exception& e) {
|
|
55
|
-
throw Napi::Error::New(env, e.what());
|
|
40
|
+
if (!txn_) {
|
|
41
|
+
throw Napi::Error::New(env, "txn already completed");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
dec_counter();
|
|
45
|
+
auto rc = mdbx_txn_abort(txn_.release());
|
|
46
|
+
if (rc != MDBX_SUCCESS) {
|
|
47
|
+
throw Napi::Error::New(env, std::string("txn abort: ") + mdbx_strerror(rc));
|
|
56
48
|
}
|
|
57
49
|
|
|
58
50
|
return env.Undefined();
|
|
@@ -70,72 +62,66 @@ Napi::Value txnmou::get_dbi(const Napi::CallbackInfo& info, db_mode db_mode)
|
|
|
70
62
|
{
|
|
71
63
|
Napi::Env env = info.Env();
|
|
72
64
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
throw std::runtime_error("dbi: cannot open DB in read-only transaction");
|
|
77
|
-
}
|
|
65
|
+
if ((mode_.val & txn_mode::ro) && (db_mode.val & db_mode::create)) {
|
|
66
|
+
throw Napi::Error::New(env, "dbi: cannot open DB in read-only transaction");
|
|
67
|
+
}
|
|
78
68
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
69
|
+
key_mode key_mode{};
|
|
70
|
+
value_mode value_mode{};
|
|
71
|
+
std::string db_name{};
|
|
72
|
+
auto conf = get_env_userctx(*env_);
|
|
73
|
+
auto key_flag = conf->key_flag;
|
|
74
|
+
auto value_flag = conf->value_flag;
|
|
75
|
+
auto arg_count = info.Length();
|
|
76
|
+
if (arg_count == 3) {
|
|
77
|
+
auto arg0 = info[0]; // db_name
|
|
78
|
+
auto arg1 = info[1]; // key_mode
|
|
79
|
+
auto arg2 = info[2]; // value_mode
|
|
80
|
+
db_name = arg0.As<Napi::String>().Utf8Value();
|
|
81
|
+
key_mode = parse_key_mode(env, arg1, key_flag);
|
|
82
|
+
value_mode = value_mode::parse(arg2);
|
|
83
|
+
} else if (arg_count == 2) {
|
|
84
|
+
// db_name + key_mode || key_mode + value_mode
|
|
85
|
+
auto arg0 = info[0];
|
|
86
|
+
auto arg1 = info[1];
|
|
87
|
+
if (arg0.IsString()) {
|
|
90
88
|
db_name = arg0.As<Napi::String>().Utf8Value();
|
|
91
89
|
key_mode = parse_key_mode(env, arg1, key_flag);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
auto arg0 = info[0];
|
|
96
|
-
auto arg1 = info[1];
|
|
97
|
-
if (arg0.IsString()) {
|
|
98
|
-
db_name = arg0.As<Napi::String>().Utf8Value();
|
|
99
|
-
key_mode = parse_key_mode(env, arg1, key_flag);
|
|
100
|
-
} else if (arg0.IsNumber()) {
|
|
101
|
-
key_mode = parse_key_mode(env, arg0, key_flag);
|
|
102
|
-
value_mode = value_mode::parse(arg1);
|
|
103
|
-
} else {
|
|
104
|
-
throw Napi::Error::New(env, "Invalid argument type for db_name or value_mode");
|
|
105
|
-
}
|
|
106
|
-
} else if (arg_count == 1) {
|
|
107
|
-
// db_name || key_mode
|
|
108
|
-
auto arg0 = info[0];
|
|
109
|
-
if (arg0.IsString()) {
|
|
110
|
-
db_name = arg0.As<Napi::String>().Utf8Value();
|
|
111
|
-
} else {
|
|
112
|
-
key_mode = parse_key_mode(env, arg0, key_flag);
|
|
113
|
-
}
|
|
90
|
+
} else if (arg0.IsNumber() || arg0.IsBigInt()) {
|
|
91
|
+
key_mode = parse_key_mode(env, arg0, key_flag);
|
|
92
|
+
value_mode = value_mode::parse(arg1);
|
|
114
93
|
} else {
|
|
115
|
-
throw Napi::Error::New(env, "Invalid
|
|
94
|
+
throw Napi::Error::New(env, "Invalid argument type for db_name or value_mode");
|
|
116
95
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
96
|
+
} else if (arg_count == 1) {
|
|
97
|
+
// db_name || key_mode
|
|
98
|
+
auto arg0 = info[0];
|
|
99
|
+
if (arg0.IsString()) {
|
|
100
|
+
db_name = arg0.As<Napi::String>().Utf8Value();
|
|
101
|
+
} else if (arg0.IsNumber() || arg0.IsBigInt()) {
|
|
102
|
+
key_mode = parse_key_mode(env, arg0, key_flag);
|
|
103
|
+
} else {
|
|
104
|
+
throw Napi::Error::New(env, "Invalid argument type: expected string (db_name) or number (key_mode)");
|
|
125
105
|
}
|
|
126
|
-
// создаем новый объект dbi
|
|
127
|
-
auto obj = dbimou::ctor.New({});
|
|
128
|
-
auto ptr = dbimou::Unwrap(obj);
|
|
129
|
-
ptr->attach(dbi, db_mode, key_mode,
|
|
130
|
-
value_mode, key_flag, value_flag);
|
|
131
|
-
return obj;
|
|
132
106
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
107
|
+
// arg_count == 0: используем значения по умолчанию (строковый ключ, default db)
|
|
108
|
+
|
|
109
|
+
if (!txn_) {
|
|
110
|
+
throw Napi::Error::New(env, "txn already completed");
|
|
136
111
|
}
|
|
137
|
-
|
|
138
|
-
|
|
112
|
+
|
|
113
|
+
MDBX_dbi dbi{};
|
|
114
|
+
auto flags = static_cast<MDBX_db_flags_t>(db_mode.val|key_mode.val|value_mode.val);
|
|
115
|
+
auto rc = mdbx_dbi_open(*this, db_name.empty() ? nullptr : db_name.c_str(), flags, &dbi);
|
|
116
|
+
if (rc != MDBX_SUCCESS) {
|
|
117
|
+
throw Napi::Error::New(env, std::string("mdbx_dbi_open: ") + mdbx_strerror(rc));
|
|
118
|
+
}
|
|
119
|
+
// создаем новый объект dbi
|
|
120
|
+
auto obj = dbimou::ctor.New({});
|
|
121
|
+
auto ptr = dbimou::Unwrap(obj);
|
|
122
|
+
ptr->attach(dbi, db_mode, key_mode,
|
|
123
|
+
value_mode, key_flag, value_flag);
|
|
124
|
+
return obj;
|
|
139
125
|
}
|
|
140
126
|
|
|
141
127
|
Napi::Value txnmou::is_active(const Napi::CallbackInfo& info) {
|
package/src/txnmou.hpp
CHANGED
|
@@ -12,21 +12,16 @@ class txnmou final
|
|
|
12
12
|
private:
|
|
13
13
|
envmou* env_{nullptr};
|
|
14
14
|
|
|
15
|
-
//
|
|
16
|
-
struct free_txn
|
|
17
|
-
|
|
15
|
+
// свободу txn
|
|
16
|
+
struct free_txn
|
|
17
|
+
{
|
|
18
|
+
void operator()(MDBX_txn *txn) const noexcept {
|
|
18
19
|
mdbx_txn_abort(txn);
|
|
19
20
|
}
|
|
20
21
|
};
|
|
21
|
-
|
|
22
|
+
|
|
22
23
|
std::unique_ptr<MDBX_txn, free_txn> txn_{};
|
|
23
24
|
txn_mode mode_{};
|
|
24
|
-
|
|
25
|
-
void check() const {
|
|
26
|
-
if (!txn_) {
|
|
27
|
-
throw std::runtime_error("txn: inactive");
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
25
|
|
|
31
26
|
// Уменьшает счетчик транзакций
|
|
32
27
|
void dec_counter() noexcept;
|
|
@@ -57,7 +52,7 @@ public:
|
|
|
57
52
|
return get_dbi(info, {db_mode::create});
|
|
58
53
|
}
|
|
59
54
|
|
|
60
|
-
operator MDBX_txn*()
|
|
55
|
+
operator MDBX_txn*() noexcept {
|
|
61
56
|
return txn_.get();
|
|
62
57
|
}
|
|
63
58
|
|
package/src/typemou.hpp
CHANGED
|
@@ -4,27 +4,72 @@
|
|
|
4
4
|
#include <mdbx.h++>
|
|
5
5
|
#include <cstdint>
|
|
6
6
|
#include <vector>
|
|
7
|
+
#include <utility>
|
|
7
8
|
|
|
8
9
|
namespace mdbxmou {
|
|
9
10
|
|
|
10
11
|
using buffer_type = std::vector<char>;
|
|
11
12
|
|
|
12
13
|
struct txnmou_managed final
|
|
13
|
-
: mdbx::
|
|
14
|
+
: mdbx::txn
|
|
14
15
|
{
|
|
15
|
-
txnmou_managed(MDBX_txn*
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
txnmou_managed(MDBX_txn *txn) noexcept
|
|
17
|
+
: mdbx::txn(txn)
|
|
18
|
+
{ }
|
|
19
|
+
|
|
20
|
+
txnmou_managed(txnmou_managed &&other) noexcept
|
|
21
|
+
: mdbx::txn(std::exchange(other.txn::handle_, nullptr))
|
|
22
|
+
{ }
|
|
23
|
+
|
|
24
|
+
txnmou_managed(const txnmou_managed&) = delete;
|
|
25
|
+
txnmou_managed& operator=(const txnmou_managed&) = delete;
|
|
26
|
+
|
|
27
|
+
~txnmou_managed() noexcept
|
|
28
|
+
{
|
|
29
|
+
if (txn::handle_) {
|
|
30
|
+
::mdbx_txn_abort(txn::handle_);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void commit()
|
|
35
|
+
{
|
|
36
|
+
auto rc = ::mdbx_txn_commit(
|
|
37
|
+
std::exchange(txn::handle_, nullptr));
|
|
38
|
+
if (rc != MDBX_SUCCESS) {
|
|
39
|
+
throw std::runtime_error(::mdbx_strerror(rc));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void abort()
|
|
44
|
+
{
|
|
45
|
+
auto rc = ::mdbx_txn_abort(
|
|
46
|
+
std::exchange(txn::handle_, nullptr));
|
|
47
|
+
if (rc != MDBX_SUCCESS) {
|
|
48
|
+
throw std::runtime_error(::mdbx_strerror(rc));
|
|
49
|
+
}
|
|
18
50
|
}
|
|
19
51
|
};
|
|
20
52
|
|
|
21
53
|
struct cursormou_managed final
|
|
22
|
-
: mdbx::
|
|
54
|
+
: mdbx::cursor
|
|
23
55
|
{
|
|
24
|
-
cursormou_managed(MDBX_cursor* cursor) noexcept
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
56
|
+
explicit cursormou_managed(MDBX_cursor* cursor) noexcept
|
|
57
|
+
: mdbx::cursor(cursor)
|
|
58
|
+
{ }
|
|
59
|
+
|
|
60
|
+
cursormou_managed(cursormou_managed &&other) noexcept
|
|
61
|
+
: mdbx::cursor(std::exchange(other.cursor::handle_, nullptr))
|
|
62
|
+
{ }
|
|
63
|
+
|
|
64
|
+
cursormou_managed(const cursormou_managed&) = delete;
|
|
65
|
+
cursormou_managed& operator=(const cursormou_managed&) = delete;
|
|
66
|
+
|
|
67
|
+
~cursormou_managed() noexcept
|
|
68
|
+
{
|
|
69
|
+
if (cursor::handle_) {
|
|
70
|
+
::mdbx_cursor_close(cursor::handle_);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
28
73
|
};
|
|
29
74
|
|
|
30
75
|
struct env_flag {
|
package/src/valuemou.hpp
CHANGED
|
@@ -4,11 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
namespace mdbxmou {
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
// Обёртка над mdbx::slice — НЕ ВЛАДЕЕТ памятью.
|
|
8
|
+
// Хранит указатель на внешний буфер (buffer_type или stack).
|
|
9
|
+
// Copy и move эквивалентны — просто копируют указатель и размер.
|
|
10
|
+
// ВАЖНО: не использовать после уничтожения буфера!
|
|
11
|
+
struct valuemou
|
|
12
|
+
: mdbx::slice
|
|
9
13
|
{
|
|
10
|
-
public:
|
|
11
14
|
valuemou() = default;
|
|
15
|
+
valuemou(const valuemou&) = default;
|
|
16
|
+
valuemou& operator=(const valuemou&) = default;
|
|
17
|
+
valuemou(valuemou&&) = default;
|
|
18
|
+
valuemou& operator=(valuemou&&) = default;
|
|
12
19
|
|
|
13
20
|
valuemou(const mdbx::slice& arg0) noexcept
|
|
14
21
|
: mdbx::slice{arg0}
|
|
@@ -38,9 +45,8 @@ public:
|
|
|
38
45
|
if (status != napi_ok) {
|
|
39
46
|
throw Napi::Error::New(env, "napi_get_value_string_utf8 length");
|
|
40
47
|
}
|
|
41
|
-
|
|
48
|
+
|
|
42
49
|
mem.reserve(length + 1);
|
|
43
|
-
mem.resize(length);
|
|
44
50
|
|
|
45
51
|
status = napi_get_value_string_utf8(
|
|
46
52
|
env, arg0, mem.data(), mem.capacity(), nullptr);
|
|
@@ -48,6 +54,8 @@ public:
|
|
|
48
54
|
throw Napi::Error::New(env, "napi_get_value_string_utf8 copyout");
|
|
49
55
|
}
|
|
50
56
|
|
|
57
|
+
mem.resize(length);
|
|
58
|
+
|
|
51
59
|
assign(mem.data(), mem.size());
|
|
52
60
|
}
|
|
53
61
|
|
|
@@ -75,11 +83,14 @@ public:
|
|
|
75
83
|
}
|
|
76
84
|
};
|
|
77
85
|
|
|
78
|
-
|
|
79
|
-
:
|
|
86
|
+
struct keymou final
|
|
87
|
+
: valuemou
|
|
80
88
|
{
|
|
81
|
-
public:
|
|
82
89
|
keymou() = default;
|
|
90
|
+
keymou(const keymou&) = default;
|
|
91
|
+
keymou& operator=(const keymou&) = default;
|
|
92
|
+
keymou(keymou&&) = default;
|
|
93
|
+
keymou& operator=(keymou&&) = default;
|
|
83
94
|
|
|
84
95
|
keymou(const valuemou& arg0) noexcept
|
|
85
96
|
: valuemou{arg0}
|
|
@@ -1,450 +0,0 @@
|
|
|
1
|
-
#include "envmou.hpp"
|
|
2
|
-
#include "txnmou.hpp"
|
|
3
|
-
#include "async/envmou_copy_to.hpp"
|
|
4
|
-
#include "async/envmou_query.hpp"
|
|
5
|
-
#include "async/envmou_open.hpp"
|
|
6
|
-
#include "async/envmou_keys.hpp"
|
|
7
|
-
#include "async/envmou_close.hpp"
|
|
8
|
-
|
|
9
|
-
#ifdef _WIN32
|
|
10
|
-
#include <windows.h>
|
|
11
|
-
#else
|
|
12
|
-
#include <pthread.h>
|
|
13
|
-
#endif
|
|
14
|
-
|
|
15
|
-
namespace mdbxmou {
|
|
16
|
-
|
|
17
|
-
Napi::FunctionReference envmou::ctor{};
|
|
18
|
-
|
|
19
|
-
void envmou::init(const char *class_name, Napi::Env env, Napi::Object exports)
|
|
20
|
-
{
|
|
21
|
-
auto func = DefineClass(env, class_name, {
|
|
22
|
-
InstanceMethod("open", &envmou::open),
|
|
23
|
-
InstanceMethod("openSync", &envmou::open_sync),
|
|
24
|
-
InstanceMethod("close", &envmou::close),
|
|
25
|
-
InstanceMethod("closeSync", &envmou::close_sync),
|
|
26
|
-
InstanceMethod("copyTo", &envmou::copy_to),
|
|
27
|
-
InstanceMethod("copyToSync", &envmou::copy_to_sync),
|
|
28
|
-
InstanceMethod("version", &envmou::get_version),
|
|
29
|
-
InstanceMethod("startRead", &envmou::start_read),
|
|
30
|
-
InstanceMethod("startWrite", &envmou::start_write),
|
|
31
|
-
InstanceMethod("query", &envmou::query),
|
|
32
|
-
InstanceMethod("keys", &envmou::keys)
|
|
33
|
-
});
|
|
34
|
-
ctor = Napi::Persistent(func);
|
|
35
|
-
ctor.SuppressDestruct();
|
|
36
|
-
exports.Set(class_name, func);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
mdbx::env::geometry envmou::parse_geometry(const Napi::Value& arg0)
|
|
40
|
-
{
|
|
41
|
-
mdbx::env::geometry geom{};
|
|
42
|
-
|
|
43
|
-
auto obj = arg0.As<Napi::Object>();
|
|
44
|
-
|
|
45
|
-
if (obj.Has("fixedSize")) {
|
|
46
|
-
auto value = obj.Get("fixedSize").As<Napi::Number>();
|
|
47
|
-
auto fixed_size = static_cast<intptr_t>(value.Int64Value());
|
|
48
|
-
return geom.make_fixed(fixed_size);
|
|
49
|
-
} else if (obj.Has("dynamicSize")) {
|
|
50
|
-
auto arr = obj.Get("dynamicSize").As<Napi::Array>();
|
|
51
|
-
if (arr.Length() != 2) {
|
|
52
|
-
throw Napi::TypeError::New(obj.Env(), "dynamicSize must be an array of two numbers");
|
|
53
|
-
}
|
|
54
|
-
auto v1 = arr.Get(0u).As<Napi::Number>();
|
|
55
|
-
auto v2 = arr.Get(1u).As<Napi::Number>();
|
|
56
|
-
auto size_lower = static_cast<intptr_t>(v1.Int64Value());
|
|
57
|
-
auto size_upper = static_cast<intptr_t>(v2.Int64Value());
|
|
58
|
-
return geom.make_dynamic(size_lower, size_upper);
|
|
59
|
-
} else {
|
|
60
|
-
if (obj.Has("sizeNow")) {
|
|
61
|
-
auto value = obj.Get("sizeNow").As<Napi::Number>();
|
|
62
|
-
geom.size_now = static_cast<intptr_t>(value.Int64Value());
|
|
63
|
-
}
|
|
64
|
-
if (obj.Has("sizeUpper")) {
|
|
65
|
-
auto value = obj.Get("sizeUpper").As<Napi::Number>();
|
|
66
|
-
geom.size_upper = static_cast<intptr_t>(value.Int64Value());
|
|
67
|
-
}
|
|
68
|
-
if (obj.Has("growthStep")) {
|
|
69
|
-
auto value = obj.Get("growthStep").As<Napi::Number>();
|
|
70
|
-
geom.growth_step = static_cast<intptr_t>(value.Int64Value());
|
|
71
|
-
}
|
|
72
|
-
if (obj.Has("shrinkThreshold")) {
|
|
73
|
-
auto value = obj.Get("shrinkThreshold").As<Napi::Number>();
|
|
74
|
-
geom.shrink_threshold = static_cast<intptr_t>(value.Int64Value());
|
|
75
|
-
}
|
|
76
|
-
if (obj.Has("pageSize")) {
|
|
77
|
-
auto value = obj.Get("pageSize").As<Napi::Number>();
|
|
78
|
-
geom.pagesize = static_cast<intptr_t>(value.Int64Value());
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return geom;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
env_arg0 envmou::parse(const Napi::Value& arg0)
|
|
85
|
-
{
|
|
86
|
-
env_arg0 rc;
|
|
87
|
-
|
|
88
|
-
auto obj = arg0.As<Napi::Object>();
|
|
89
|
-
|
|
90
|
-
rc.path = obj.Get("path").As<Napi::String>().Utf8Value();
|
|
91
|
-
if (obj.Has("maxDbi")) {
|
|
92
|
-
auto value = obj.Get("maxDbi").As<Napi::Number>();
|
|
93
|
-
rc.max_dbi = static_cast<MDBX_dbi>(value.Uint32Value());
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (obj.Has("geometry")) {
|
|
97
|
-
rc.geom = parse_geometry(obj.Get("geometry"));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (obj.Has("flags")) {
|
|
101
|
-
rc.flag = env_flag::parse(obj.Get("flags"));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (obj.Has("mode")) {
|
|
105
|
-
auto value = obj.Get("mode").As<Napi::Number>();
|
|
106
|
-
rc.file_mode = static_cast<mdbx_mode_t>(value.Int32Value());
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (obj.Has("keyFlag")) {
|
|
110
|
-
rc.key_flag = base_flag::parse_key(obj.Get("keyFlag"));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (obj.Has("valueFlag")) {
|
|
114
|
-
rc.value_flag = base_flag::parse_value(obj.Get("valueFlag"));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return rc;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
Napi::Value envmou::open(const Napi::CallbackInfo& info)
|
|
121
|
-
{
|
|
122
|
-
auto env = info.Env();
|
|
123
|
-
auto arg0 = parse(info[0].As<Napi::Object>());
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
// асинхронный вызов разлочится внутри worker'a
|
|
127
|
-
if (!try_lock()) {
|
|
128
|
-
throw std::runtime_error("in progress");
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (is_open()) {
|
|
132
|
-
throw std::runtime_error("already opened");
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
auto* worker = new async_open(env, *this, arg0);
|
|
136
|
-
Napi::Promise promise = worker->GetPromise();
|
|
137
|
-
worker->Queue();
|
|
138
|
-
return promise;
|
|
139
|
-
} catch (const std::exception& e) {
|
|
140
|
-
unlock();
|
|
141
|
-
throw Napi::Error::New(env, e.what());
|
|
142
|
-
} catch (...) {
|
|
143
|
-
unlock();
|
|
144
|
-
throw;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return env.Undefined();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
Napi::Value envmou::open_sync(const Napi::CallbackInfo& info)
|
|
151
|
-
{
|
|
152
|
-
auto env = info.Env();
|
|
153
|
-
auto arg0 = parse(info[0].As<Napi::Object>());
|
|
154
|
-
|
|
155
|
-
try {
|
|
156
|
-
lock_guard l(*this);
|
|
157
|
-
if (is_open()) {
|
|
158
|
-
throw std::runtime_error("already opened");
|
|
159
|
-
}
|
|
160
|
-
attach(create_and_open(arg0), arg0);
|
|
161
|
-
} catch (const std::exception& e) {
|
|
162
|
-
throw Napi::Error::New(env, e.what());
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return env.Undefined();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
MDBX_env* envmou::create_and_open(const env_arg0& arg0)
|
|
169
|
-
{
|
|
170
|
-
MDBX_env *env;
|
|
171
|
-
auto rc = mdbx_env_create(&env);
|
|
172
|
-
if (rc != MDBX_SUCCESS) {
|
|
173
|
-
throw std::runtime_error(mdbx_strerror(rc));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
rc = mdbx_env_set_maxdbs(env, arg0.max_dbi);
|
|
177
|
-
if (rc != MDBX_SUCCESS) {
|
|
178
|
-
mdbx_env_close(env);
|
|
179
|
-
throw std::runtime_error(mdbx_strerror(rc));
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
rc = mdbx_env_set_maxreaders(env, arg0.max_readers);
|
|
183
|
-
if (rc != MDBX_SUCCESS) {
|
|
184
|
-
mdbx_env_close(env);
|
|
185
|
-
throw std::runtime_error(mdbx_strerror(rc));
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
auto& geom = arg0.geom;
|
|
189
|
-
rc = mdbx_env_set_geometry(env, geom.size_lower, geom.size_now,
|
|
190
|
-
geom.size_upper, geom.growth_step, geom.shrink_threshold, geom.pagesize);
|
|
191
|
-
if (rc != MDBX_SUCCESS) {
|
|
192
|
-
mdbx_env_close(env);
|
|
193
|
-
throw std::runtime_error(mdbx_strerror(rc));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
#ifdef _WIN32
|
|
197
|
-
auto id = static_cast<std::uint32_t>(GetCurrentThreadId());
|
|
198
|
-
#else
|
|
199
|
-
auto id = static_cast<std::uint32_t>(pthread_self());
|
|
200
|
-
#endif
|
|
201
|
-
// выдадим параметры mode, flag и id потока в котором открывается env
|
|
202
|
-
rc = mdbx_env_open(env, arg0.path.c_str(), arg0.flag, arg0.file_mode);
|
|
203
|
-
if (rc != MDBX_SUCCESS) {
|
|
204
|
-
mdbx_env_close(env);
|
|
205
|
-
throw std::runtime_error(mdbx_strerror(rc));
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return env;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
void envmou::attach(MDBX_env* env, const env_arg0& arg0)
|
|
212
|
-
{
|
|
213
|
-
arg0_ = arg0;
|
|
214
|
-
|
|
215
|
-
auto rc = mdbx_env_set_userctx(env, &arg0_);
|
|
216
|
-
if (rc != MDBX_SUCCESS) {
|
|
217
|
-
mdbx_env_close(env);
|
|
218
|
-
throw std::runtime_error(mdbx_strerror(rc));
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
env_.reset(env);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
Napi::Value envmou::close(const Napi::CallbackInfo& info)
|
|
225
|
-
{
|
|
226
|
-
auto env = info.Env();
|
|
227
|
-
try {
|
|
228
|
-
// асинхронный вызов разлочится внутри worker'a
|
|
229
|
-
if (!try_lock()) {
|
|
230
|
-
throw std::runtime_error("in progress");
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (!is_open()) {
|
|
234
|
-
return env.Undefined();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (trx_count_.load() > 0) {
|
|
238
|
-
throw std::runtime_error("active transactions");
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
auto* worker = new async_close(env, *this);
|
|
242
|
-
Napi::Promise promise = worker->GetPromise();
|
|
243
|
-
worker->Queue();
|
|
244
|
-
return promise;
|
|
245
|
-
} catch (const std::exception& e) {
|
|
246
|
-
unlock();
|
|
247
|
-
throw Napi::Error::New(env, e.what());
|
|
248
|
-
} catch (...) {
|
|
249
|
-
unlock();
|
|
250
|
-
throw;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return env.Undefined();
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
Napi::Value envmou::close_sync(const Napi::CallbackInfo& info)
|
|
257
|
-
{
|
|
258
|
-
auto env = info.Env();
|
|
259
|
-
try {
|
|
260
|
-
lock_guard l(*this);
|
|
261
|
-
|
|
262
|
-
do_close();
|
|
263
|
-
|
|
264
|
-
} catch (const std::exception& e) {
|
|
265
|
-
throw Napi::Error::New(env, e.what());
|
|
266
|
-
}
|
|
267
|
-
return env.Undefined();
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
Napi::Value envmou::copy_to_sync(const Napi::CallbackInfo& info)
|
|
271
|
-
{
|
|
272
|
-
auto env = info.Env();
|
|
273
|
-
|
|
274
|
-
if (info.Length() < 1 || !info[0].IsString()) {
|
|
275
|
-
throw Napi::TypeError::New(env, "expected a string argument for the destination path");
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
MDBX_copy_flags_t flags{MDBX_CP_COMPACT};
|
|
279
|
-
if ((info.Length() > 1) && info[1].IsNumber()) {
|
|
280
|
-
flags = static_cast<MDBX_copy_flags_t>(info[1].As<Napi::Number>().Uint32Value());
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
try {
|
|
284
|
-
auto dest_path = info[0].As<Napi::String>().Utf8Value();
|
|
285
|
-
|
|
286
|
-
lock_guard l(*this);
|
|
287
|
-
|
|
288
|
-
check();
|
|
289
|
-
|
|
290
|
-
auto rc = mdbx_env_copy(*this, dest_path.c_str(), flags);
|
|
291
|
-
if (rc != MDBX_SUCCESS) {
|
|
292
|
-
throw Napi::Error::New(env, mdbx_strerror(rc));
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
} catch (const std::exception& e) {
|
|
296
|
-
throw Napi::Error::New(env, e.what());
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
return env.Undefined();
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
Napi::Value envmou::copy_to(const Napi::CallbackInfo& info)
|
|
303
|
-
{
|
|
304
|
-
Napi::Env env = info.Env();
|
|
305
|
-
|
|
306
|
-
if (info.Length() < 1 || !info[0].IsString()) {
|
|
307
|
-
throw Napi::TypeError::New(env, "copyTo(path: string[, flags?: number]) -> Promise<void>");
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
MDBX_copy_flags_t flags{MDBX_CP_COMPACT};
|
|
311
|
-
if (info.Length() > 1 && info[1].IsNumber()) {
|
|
312
|
-
flags = static_cast<MDBX_copy_flags_t>(info[1].As<Napi::Number>().Uint32Value());
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
try {
|
|
316
|
-
auto dest = info[0].As<Napi::String>().Utf8Value();
|
|
317
|
-
|
|
318
|
-
if (!try_lock()) {
|
|
319
|
-
throw std::runtime_error("in progress");
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
check();
|
|
323
|
-
|
|
324
|
-
auto* worker = new mdbxmou::async_copy(env, *this, std::move(dest), flags);
|
|
325
|
-
Napi::Promise promise = worker->GetPromise();
|
|
326
|
-
worker->Queue();
|
|
327
|
-
return promise;
|
|
328
|
-
} catch (const std::exception& e) {
|
|
329
|
-
throw Napi::Error::New(env, e.what());
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return env.Undefined();
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
Napi::Value envmou::get_version(const Napi::CallbackInfo& info)
|
|
336
|
-
{
|
|
337
|
-
std::string version = "mdbx v" + std::to_string(MDBX_VERSION_MAJOR);
|
|
338
|
-
version += "." + std::to_string(MDBX_VERSION_MINOR);
|
|
339
|
-
return Napi::Value::From(info.Env(), version);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
Napi::Value envmou::start_transaction(const Napi::CallbackInfo& info, txn_mode mode)
|
|
343
|
-
{
|
|
344
|
-
auto env = info.Env();
|
|
345
|
-
|
|
346
|
-
try {
|
|
347
|
-
lock_guard l(*this);
|
|
348
|
-
|
|
349
|
-
check();
|
|
350
|
-
|
|
351
|
-
MDBX_txn* txn;
|
|
352
|
-
auto rc = mdbx_txn_begin(*this, nullptr, mode, &txn);
|
|
353
|
-
if (rc != MDBX_SUCCESS) {
|
|
354
|
-
throw Napi::Error::New(env, std::string("Env: ") + mdbx_strerror(rc));
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Создаем новый объект txnmou
|
|
358
|
-
auto txn_obj = txnmou::ctor.New({});
|
|
359
|
-
auto txn_wrapper = txnmou::Unwrap(txn_obj);
|
|
360
|
-
txn_wrapper->attach(*this, txn, mode, nullptr);
|
|
361
|
-
|
|
362
|
-
return txn_obj;
|
|
363
|
-
} catch (const std::exception& e) {
|
|
364
|
-
throw Napi::Error::New(env, e.what());
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
Napi::Value envmou::query(const Napi::CallbackInfo& info)
|
|
369
|
-
{
|
|
370
|
-
Napi::Env env = info.Env();
|
|
371
|
-
|
|
372
|
-
txn_mode mode{};
|
|
373
|
-
|
|
374
|
-
if (info.Length() < 1) {
|
|
375
|
-
throw Napi::TypeError::New(env, "expected array of requests");
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (info.Length() > 1 || info[1].IsNumber()) {
|
|
379
|
-
mode = txn_mode::parse(info[1].As<Napi::Number>());
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
try
|
|
383
|
-
{
|
|
384
|
-
lock_guard lock(*this);
|
|
385
|
-
|
|
386
|
-
check();
|
|
387
|
-
|
|
388
|
-
auto conf = get_env_userctx(*this);
|
|
389
|
-
|
|
390
|
-
auto arg0 = info[0];
|
|
391
|
-
query_request query = parse_query(mode, arg0);
|
|
392
|
-
auto* worker = new async_query(env, *this, mode,
|
|
393
|
-
std::move(query), arg0.IsObject());
|
|
394
|
-
auto promise = worker->GetPromise();
|
|
395
|
-
worker->Queue();
|
|
396
|
-
|
|
397
|
-
// Увеличиваем счетчик транзакций после успешного создания
|
|
398
|
-
++(*this);
|
|
399
|
-
|
|
400
|
-
return promise;
|
|
401
|
-
} catch (const std::exception& e) {
|
|
402
|
-
throw Napi::Error::New(env, e.what());
|
|
403
|
-
} catch (...) {
|
|
404
|
-
throw Napi::Error::New(env, "envmou::query");
|
|
405
|
-
}
|
|
406
|
-
return env.Undefined();
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
Napi::Value envmou::keys(const Napi::CallbackInfo& info)
|
|
410
|
-
{
|
|
411
|
-
Napi::Env env = info.Env();
|
|
412
|
-
|
|
413
|
-
txn_mode mode{};
|
|
414
|
-
|
|
415
|
-
if (info.Length() < 1) {
|
|
416
|
-
throw Napi::TypeError::New(env,
|
|
417
|
-
"expected array of requests: [{ db: String, db_mode: Number, key_mode: Number, key_flag: Number, value_mode: Number, value_flag: Number }, ...]");
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (info.Length() > 1 || info[1].IsNumber()) {
|
|
421
|
-
mode = txn_mode::parse(info[1].As<Napi::Number>());
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
try
|
|
425
|
-
{
|
|
426
|
-
lock_guard lock(*this);
|
|
427
|
-
|
|
428
|
-
check();
|
|
429
|
-
|
|
430
|
-
auto arg0 = info[0];
|
|
431
|
-
keys_request query = parse_keys(arg0);
|
|
432
|
-
|
|
433
|
-
auto* worker = new async_keys(env, *this, mode,
|
|
434
|
-
std::move(query), arg0.IsObject());
|
|
435
|
-
auto promise = worker->GetPromise();
|
|
436
|
-
worker->Queue();
|
|
437
|
-
|
|
438
|
-
// Увеличиваем счетчик транзакций после успешного создания
|
|
439
|
-
++(*this);
|
|
440
|
-
|
|
441
|
-
return promise;
|
|
442
|
-
} catch (const std::exception& e) {
|
|
443
|
-
throw Napi::Error::New(env, e.what());
|
|
444
|
-
} catch (...) {
|
|
445
|
-
throw Napi::Error::New(env, "envmou::keys");
|
|
446
|
-
}
|
|
447
|
-
return env.Undefined();
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
} // namespace mdbxmou
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "txnmou.hpp"
|
|
4
|
-
#include <memory>
|
|
5
|
-
#include <atomic>
|
|
6
|
-
#include <mutex>
|
|
7
|
-
|
|
8
|
-
namespace mdbxmou {
|
|
9
|
-
|
|
10
|
-
// Forward declaration
|
|
11
|
-
class txnmou;
|
|
12
|
-
|
|
13
|
-
class envmou final
|
|
14
|
-
: public Napi::ObjectWrap<envmou>
|
|
15
|
-
{
|
|
16
|
-
static Napi::FunctionReference ctor;
|
|
17
|
-
static mdbx::env::geometry parse_geometry(const Napi::Value& obj);
|
|
18
|
-
static env_arg0 parse(const Napi::Value& obj);
|
|
19
|
-
|
|
20
|
-
struct free_env {
|
|
21
|
-
void operator()(MDBX_env* env) const {
|
|
22
|
-
auto rc = mdbx_env_close(env);
|
|
23
|
-
if (rc != MDBX_SUCCESS) {
|
|
24
|
-
fprintf(stderr, "mdbx_env_close %s\n", mdbx_strerror(rc));
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
std::unique_ptr<MDBX_env, free_env> env_{};
|
|
30
|
-
std::atomic<std::size_t> trx_count_{};
|
|
31
|
-
env_arg0 arg0_{};
|
|
32
|
-
std::mutex lock_{};
|
|
33
|
-
|
|
34
|
-
bool is_open() const {
|
|
35
|
-
return env_ != nullptr;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Inline метод для проверки что база данных открыта
|
|
39
|
-
void check() const {
|
|
40
|
-
if (!is_open()) {
|
|
41
|
-
throw std::runtime_error("closed");
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Общий метод для создания транзакций
|
|
46
|
-
Napi::Value start_transaction(const Napi::CallbackInfo& info, txn_mode mode);
|
|
47
|
-
|
|
48
|
-
public:
|
|
49
|
-
envmou(const Napi::CallbackInfo& i)
|
|
50
|
-
: ObjectWrap{i}
|
|
51
|
-
{ }
|
|
52
|
-
|
|
53
|
-
static MDBX_env* create_and_open(const env_arg0& arg0);
|
|
54
|
-
void attach(MDBX_env* env, const env_arg0& arg0);
|
|
55
|
-
|
|
56
|
-
operator MDBX_env*() const noexcept {
|
|
57
|
-
return env_.get();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
static void init(const char *class_name, Napi::Env env, Napi::Object exports);
|
|
61
|
-
|
|
62
|
-
envmou& operator++() noexcept {
|
|
63
|
-
++trx_count_;
|
|
64
|
-
return *this;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
envmou& operator--() noexcept {
|
|
68
|
-
--trx_count_;
|
|
69
|
-
return *this;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
Napi::Value open(const Napi::CallbackInfo&);
|
|
73
|
-
Napi::Value open_sync(const Napi::CallbackInfo&);
|
|
74
|
-
Napi::Value close(const Napi::CallbackInfo&);
|
|
75
|
-
Napi::Value close_sync(const Napi::CallbackInfo&);
|
|
76
|
-
Napi::Value get_version(const Napi::CallbackInfo&);
|
|
77
|
-
Napi::Value copy_to_sync(const Napi::CallbackInfo&);
|
|
78
|
-
Napi::Value copy_to(const Napi::CallbackInfo&);
|
|
79
|
-
// метод для групповых вставок или чтения
|
|
80
|
-
// внутри транзакция, получение db и чтение/запись
|
|
81
|
-
Napi::Value query(const Napi::CallbackInfo&);
|
|
82
|
-
Napi::Value keys(const Napi::CallbackInfo&);
|
|
83
|
-
|
|
84
|
-
// Методы для создания транзакций
|
|
85
|
-
Napi::Value start_read(const Napi::CallbackInfo& info) {
|
|
86
|
-
return start_transaction(info, {txn_mode::ro});
|
|
87
|
-
}
|
|
88
|
-
Napi::Value start_write(const Napi::CallbackInfo& info) {
|
|
89
|
-
return start_transaction(info, {});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
using lock_guard = std::lock_guard<envmou>;
|
|
93
|
-
// для защиты асинхронных операций
|
|
94
|
-
void lock() {
|
|
95
|
-
auto rc = lock_.try_lock();
|
|
96
|
-
if (!rc) {
|
|
97
|
-
throw std::runtime_error("operation in progress");
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
void unlock() {
|
|
101
|
-
lock_.unlock();
|
|
102
|
-
}
|
|
103
|
-
bool try_lock() {
|
|
104
|
-
bool locked = lock_.try_lock();
|
|
105
|
-
return locked;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
void do_close() {
|
|
109
|
-
if (trx_count_.load() > 0) {
|
|
110
|
-
throw std::runtime_error("transaction in progress");
|
|
111
|
-
}
|
|
112
|
-
env_.reset();
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
} // namespace mdbxmou
|