mdbxmou 0.2.4 → 0.2.6

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/src/txnmou.cpp CHANGED
@@ -12,11 +12,6 @@ void txnmou::init(const char *class_name, Napi::Env env) {
12
12
  InstanceMethod("openMap", &txnmou::open_map),
13
13
  InstanceMethod("createMap", &txnmou::create_map),
14
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
15
  });
21
16
 
22
17
  ctor = Napi::Persistent(func);
@@ -28,22 +23,14 @@ Napi::Value txnmou::commit(const Napi::CallbackInfo& info) {
28
23
 
29
24
  try {
30
25
  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
26
+
39
27
  auto rc = mdbx_txn_commit(*this);
40
28
  if (rc != MDBX_SUCCESS) {
41
29
  throw Napi::Error::New(env, std::string("txn: ") + mdbx_strerror(rc));
42
30
  }
43
31
 
44
- is_committed_ = true;
45
- // Отключаем deleter, так как транзакция уже закоммичена
46
- txn_.reset();
32
+ dec_counter();
33
+ txn_.release();
47
34
  } catch (const std::exception& e) {
48
35
  throw Napi::Error::New(env, e.what());
49
36
  }
@@ -56,27 +43,14 @@ Napi::Value txnmou::abort(const Napi::CallbackInfo& info) {
56
43
 
57
44
  try {
58
45
  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
46
+
73
47
  auto rc = mdbx_txn_abort(*this);
74
48
  if (rc != MDBX_SUCCESS) {
75
49
  throw Napi::Error::New(env, std::string("txn: ") + mdbx_strerror(rc));
76
50
  }
77
51
 
78
- is_aborted_ = true;
79
- txn_.reset();
52
+ dec_counter();
53
+ txn_.release();
80
54
  } catch (const std::exception& e) {
81
55
  throw Napi::Error::New(env, e.what());
82
56
  }
@@ -84,6 +58,14 @@ Napi::Value txnmou::abort(const Napi::CallbackInfo& info) {
84
58
  return env.Undefined();
85
59
  }
86
60
 
61
+ // Уменьшает счетчик транзакций
62
+ void txnmou::dec_counter() noexcept
63
+ {
64
+ if (env_) {
65
+ --(*env_);
66
+ }
67
+ }
68
+
87
69
  Napi::Value txnmou::get_dbi(const Napi::CallbackInfo& info, db_mode db_mode)
88
70
  {
89
71
  Napi::Env env = info.Env();
@@ -115,7 +97,7 @@ Napi::Value txnmou::get_dbi(const Napi::CallbackInfo& info, db_mode db_mode)
115
97
  if (arg0.IsString()) {
116
98
  db_name = arg0.As<Napi::String>().Utf8Value();
117
99
  key_mode = parse_key_mode(env, arg1, key_flag);
118
- } else if (arg0.IsNumber()) {
100
+ } else if (arg0.IsNumber() || arg0.IsBigInt()) {
119
101
  key_mode = parse_key_mode(env, arg0, key_flag);
120
102
  value_mode = value_mode::parse(arg1);
121
103
  } else {
@@ -126,25 +108,25 @@ Napi::Value txnmou::get_dbi(const Napi::CallbackInfo& info, db_mode db_mode)
126
108
  auto arg0 = info[0];
127
109
  if (arg0.IsString()) {
128
110
  db_name = arg0.As<Napi::String>().Utf8Value();
129
- } else {
111
+ } else if (arg0.IsNumber() || arg0.IsBigInt()) {
130
112
  key_mode = parse_key_mode(env, arg0, key_flag);
113
+ } else {
114
+ throw Napi::Error::New(env, "Invalid argument type: expected string (db_name) or number (key_mode)");
131
115
  }
132
- } else {
133
- throw Napi::Error::New(env, "Invalid number of arguments for get_dbi");
134
116
  }
117
+ // arg_count == 0: используем значения по умолчанию (строковый ключ, default db)
135
118
 
136
119
  check();
137
120
 
138
- // создаем новый объект dbi
139
- auto obj = dbimou::ctor.New({});
140
- auto ptr = dbimou::Unwrap(obj);
141
-
142
121
  MDBX_dbi dbi{};
143
122
  auto flags = static_cast<MDBX_db_flags_t>(db_mode.val|key_mode.val|value_mode.val);
144
123
  auto rc = mdbx_dbi_open(*this, db_name.empty() ? nullptr : db_name.c_str(), flags, &dbi);
145
124
  if (rc != MDBX_SUCCESS) {
146
125
  throw std::runtime_error(std::string("mdbx_dbi_open ") + mdbx_strerror(rc));
147
126
  }
127
+ // создаем новый объект dbi
128
+ auto obj = dbimou::ctor.New({});
129
+ auto ptr = dbimou::Unwrap(obj);
148
130
  ptr->attach(dbi, db_mode, key_mode,
149
131
  value_mode, key_flag, value_flag);
150
132
  return obj;
@@ -159,96 +141,16 @@ Napi::Value txnmou::get_dbi(const Napi::CallbackInfo& info, db_mode db_mode)
159
141
 
160
142
  Napi::Value txnmou::is_active(const Napi::CallbackInfo& info) {
161
143
  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));
144
+ return Napi::Boolean::New(env, txn_ != nullptr);
210
145
  }
211
146
 
212
- #endif // MDBX_TXN_HAS_CHILD
213
-
214
- void txnmou::attach(envmou& env, MDBX_txn* txn,
215
- txn_mode mode, txnmou* parent)
147
+ void txnmou::attach(envmou& env, MDBX_txn* txn, txn_mode mode)
216
148
  {
217
- // увеличиваем счетчик транзакций в env
218
149
  env_ = &env;
219
-
220
- if (parent == nullptr) {
221
- // Если родительская транзакция не указана, увеличиваем счетчик
222
- ++(*env_);
223
- }
224
-
225
- parent_ = parent;
226
150
  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
151
+
152
+ ++(*env_);
235
153
  txn_.reset(txn);
236
154
  }
237
155
 
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
156
  } // namespace mdbxmou
package/src/txnmou.hpp CHANGED
@@ -2,10 +2,6 @@
2
2
 
3
3
  #include "dbimou.hpp"
4
4
 
5
- #ifdef MDBX_TXN_HAS_CHILD
6
- #include <vector>
7
- #endif
8
-
9
5
  namespace mdbxmou {
10
6
 
11
7
  class envmou;
@@ -14,74 +10,21 @@ class txnmou final
14
10
  : public Napi::ObjectWrap<txnmou>
15
11
  {
16
12
  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_{};
13
+ envmou* env_{nullptr};
39
14
 
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
- }
15
+ std::unique_ptr<MDBX_txn,
16
+ txnmou_managed::free_txn> txn_{};
17
+ txn_mode mode_{};
47
18
 
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
- }
19
+ void check() const {
20
+ if (!txn_) {
21
+ throw std::runtime_error("txn: inactive");
63
22
  }
64
- return false;
65
23
  }
66
24
 
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);
25
+ // Уменьшает счетчик транзакций
26
+ void dec_counter() noexcept;
80
27
 
81
- void push_back(txnmou* child) {
82
- children_.push_back(child);
83
- }
84
- #endif
85
28
  Napi::Value get_dbi(const Napi::CallbackInfo&, db_mode);
86
29
 
87
30
  public:
@@ -91,9 +34,16 @@ public:
91
34
  : Napi::ObjectWrap<txnmou>(info)
92
35
  { }
93
36
 
37
+ ~txnmou() {
38
+ if (txn_) {
39
+ dec_counter();
40
+ }
41
+ }
42
+
43
+ //void Finalize(Napi::Env env) { fprintf(stderr, "txnmou::Finalize %p\n", this); }
44
+
94
45
  static void init(const char *class_name, Napi::Env env);
95
46
 
96
- // Основные операции (только синхронные)
97
47
  Napi::Value commit(const Napi::CallbackInfo&);
98
48
  Napi::Value abort(const Napi::CallbackInfo&);
99
49
  Napi::Value open_map(const Napi::CallbackInfo& info) {
@@ -107,16 +57,9 @@ public:
107
57
  return txn_.get();
108
58
  }
109
59
 
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
60
  Napi::Value is_active(const Napi::CallbackInfo&);
116
- Napi::Value is_top_level(const Napi::CallbackInfo&);
117
61
 
118
- void attach(envmou& env, MDBX_txn* txn,
119
- txn_mode mode, txnmou* parent = nullptr);
62
+ void attach(envmou& env, MDBX_txn* txn, txn_mode mode);
120
63
  };
121
64
 
122
65
  } // namespace mdbxmou
package/src/typemou.hpp CHANGED
@@ -10,21 +10,97 @@ namespace mdbxmou {
10
10
  using buffer_type = std::vector<char>;
11
11
 
12
12
  struct txnmou_managed final
13
- : mdbx::txn_managed
13
+ : mdbx::txn
14
14
  {
15
- txnmou_managed(MDBX_txn* txn)
16
- {
17
- txn::handle_ = txn;
15
+ // свободу txn
16
+ struct free_txn
17
+ {
18
+ void operator()(MDBX_txn *txn) const noexcept {
19
+ mdbx_txn_abort(txn);
20
+ }
21
+ };
22
+
23
+ std::unique_ptr<MDBX_txn, free_txn> guard_;
24
+
25
+ txnmou_managed(MDBX_txn* txn) noexcept
26
+ : mdbx::txn(txn)
27
+ , guard_(txn)
28
+ { }
29
+
30
+ // Move конструктор
31
+ txnmou_managed(txnmou_managed&& other) noexcept
32
+ : mdbx::txn(other.txn::handle_)
33
+ , guard_(std::move(other.guard_))
34
+ {
35
+ other.txn::handle_ = nullptr;
36
+ }
37
+
38
+ // Запрет копирования
39
+ txnmou_managed(const txnmou_managed&) = delete;
40
+ txnmou_managed& operator=(const txnmou_managed&) = delete;
41
+
42
+ ~txnmou_managed() noexcept {
43
+ // guard_ автоматически откатит транзакцию
44
+ txn::handle_ = nullptr;
45
+ }
46
+
47
+ // Commit транзакции
48
+ void commit() {
49
+ if (guard_) {
50
+ auto rc = ::mdbx_txn_commit(guard_.release());
51
+ txn::handle_ = nullptr;
52
+ if (rc != MDBX_SUCCESS) {
53
+ throw std::runtime_error(::mdbx_strerror(rc));
54
+ }
55
+ }
56
+ }
57
+
58
+ // Abort транзакции
59
+ void abort() {
60
+ if (guard_) {
61
+ auto rc = ::mdbx_txn_abort(guard_.release());
62
+ txn::handle_ = nullptr;
63
+ if (rc != MDBX_SUCCESS) {
64
+ throw std::runtime_error(::mdbx_strerror(rc));
65
+ }
66
+ }
18
67
  }
19
68
  };
20
69
 
21
70
  struct cursormou_managed final
22
- : mdbx::cursor_managed
71
+ : mdbx::cursor
23
72
  {
24
- cursormou_managed(MDBX_cursor* cursor) noexcept
25
- {
26
- cursor::handle_ = cursor;
27
- }
73
+ // свободу курсору
74
+ struct free_cursor
75
+ {
76
+ void operator()(MDBX_cursor* c) const noexcept {
77
+ if (c) ::mdbx_cursor_close(c);
78
+ }
79
+ };
80
+
81
+ std::unique_ptr<MDBX_cursor, free_cursor> guard_;
82
+
83
+ explicit cursormou_managed(MDBX_cursor* cursor) noexcept
84
+ : mdbx::cursor(cursor)
85
+ , guard_(cursor)
86
+ { }
87
+
88
+ // Move конструктор
89
+ cursormou_managed(cursormou_managed&& other) noexcept
90
+ : mdbx::cursor(other.cursor::handle_)
91
+ , guard_(std::move(other.guard_))
92
+ {
93
+ other.cursor::handle_ = nullptr;
94
+ }
95
+
96
+ // Запрет копирования
97
+ cursormou_managed(const cursormou_managed&) = delete;
98
+ cursormou_managed& operator=(const cursormou_managed&) = delete;
99
+
100
+ ~cursormou_managed() noexcept {
101
+ // guard_ автоматически закроет курсор
102
+ cursor::handle_ = nullptr;
103
+ }
28
104
  };
29
105
 
30
106
  struct env_flag {
package/src/valuemou.hpp CHANGED
@@ -38,9 +38,8 @@ public:
38
38
  if (status != napi_ok) {
39
39
  throw Napi::Error::New(env, "napi_get_value_string_utf8 length");
40
40
  }
41
-
41
+
42
42
  mem.reserve(length + 1);
43
- mem.resize(length);
44
43
 
45
44
  status = napi_get_value_string_utf8(
46
45
  env, arg0, mem.data(), mem.capacity(), nullptr);
@@ -48,6 +47,8 @@ public:
48
47
  throw Napi::Error::New(env, "napi_get_value_string_utf8 copyout");
49
48
  }
50
49
 
50
+ mem.resize(length);
51
+
51
52
  assign(mem.data(), mem.size());
52
53
  }
53
54