@nxtedition/rocksdb 5.2.27 → 5.2.30

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/binding.cc CHANGED
@@ -1,30 +1,27 @@
1
1
  #define NAPI_VERSION 8
2
2
 
3
+ #include <assert.h>
3
4
  #include <napi-macros.h>
4
5
  #include <node_api.h>
5
- #include <assert.h>
6
6
 
7
- #include <rocksdb/db.h>
8
- #include <rocksdb/write_batch.h>
9
- #include <rocksdb/cache.h>
10
- #include <rocksdb/filter_policy.h>
11
7
  #include <rocksdb/cache.h>
12
8
  #include <rocksdb/comparator.h>
9
+ #include <rocksdb/db.h>
13
10
  #include <rocksdb/env.h>
11
+ #include <rocksdb/filter_policy.h>
14
12
  #include <rocksdb/options.h>
15
13
  #include <rocksdb/table.h>
16
-
17
- namespace leveldb = rocksdb;
14
+ #include <rocksdb/write_batch.h>
18
15
 
19
16
  #include <array>
20
- #include <set>
21
17
  #include <memory>
18
+ #include <optional>
19
+ #include <set>
22
20
  #include <string>
23
21
  #include <vector>
24
- #include <optional>
25
22
 
26
23
  class NullLogger : public rocksdb::Logger {
27
- public:
24
+ public:
28
25
  using rocksdb::Logger::Logv;
29
26
  virtual void Logv(const char* format, va_list ap) override {}
30
27
  virtual size_t GetLogFileSize() const override { return 0; }
@@ -33,7 +30,7 @@ public:
33
30
  struct Database;
34
31
  struct Iterator;
35
32
 
36
- #define NAPI_DB_CONTEXT() \
33
+ #define NAPI_DB_CONTEXT() \
37
34
  Database* database = nullptr; \
38
35
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
39
36
 
@@ -41,29 +38,29 @@ struct Iterator;
41
38
  Iterator* iterator = nullptr; \
42
39
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
43
40
 
44
- #define NAPI_BATCH_CONTEXT() \
41
+ #define NAPI_BATCH_CONTEXT() \
45
42
  rocksdb::WriteBatch* batch = nullptr; \
46
43
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&batch));
47
44
 
48
- static bool IsString (napi_env env, napi_value value) {
45
+ static bool IsString(napi_env env, napi_value value) {
49
46
  napi_valuetype type;
50
47
  napi_typeof(env, value, &type);
51
48
  return type == napi_string;
52
49
  }
53
50
 
54
- static bool IsBuffer (napi_env env, napi_value value) {
51
+ static bool IsBuffer(napi_env env, napi_value value) {
55
52
  bool isBuffer;
56
53
  napi_is_buffer(env, value, &isBuffer);
57
54
  return isBuffer;
58
55
  }
59
56
 
60
- static bool IsObject (napi_env env, napi_value value) {
57
+ static bool IsObject(napi_env env, napi_value value) {
61
58
  napi_valuetype type;
62
59
  napi_typeof(env, value, &type);
63
60
  return type == napi_object;
64
61
  }
65
62
 
66
- static napi_value CreateError (napi_env env, const std::string_view& str) {
63
+ static napi_value CreateError(napi_env env, const std::string_view& str) {
67
64
  napi_value msg;
68
65
  napi_create_string_utf8(env, str.data(), str.size(), &msg);
69
66
  napi_value error;
@@ -71,7 +68,7 @@ static napi_value CreateError (napi_env env, const std::string_view& str) {
71
68
  return error;
72
69
  }
73
70
 
74
- static napi_value CreateCodeError (napi_env env, const std::string_view& code, const std::string_view& msg) {
71
+ static napi_value CreateCodeError(napi_env env, const std::string_view& code, const std::string_view& msg) {
75
72
  napi_value codeValue;
76
73
  napi_create_string_utf8(env, code.data(), code.size(), &codeValue);
77
74
  napi_value msgValue;
@@ -81,19 +78,19 @@ static napi_value CreateCodeError (napi_env env, const std::string_view& code, c
81
78
  return error;
82
79
  }
83
80
 
84
- static bool HasProperty (napi_env env, napi_value obj, const std::string_view& key) {
81
+ static bool HasProperty(napi_env env, napi_value obj, const std::string_view& key) {
85
82
  bool has = false;
86
83
  napi_has_named_property(env, obj, key.data(), &has);
87
84
  return has;
88
85
  }
89
86
 
90
- static napi_value GetProperty (napi_env env, napi_value obj, const std::string_view& key) {
87
+ static napi_value GetProperty(napi_env env, napi_value obj, const std::string_view& key) {
91
88
  napi_value value;
92
89
  napi_get_named_property(env, obj, key.data(), &value);
93
90
  return value;
94
91
  }
95
92
 
96
- static bool BooleanProperty (napi_env env, napi_value obj, const std::string_view& key, bool defaultValue) {
93
+ static bool BooleanProperty(napi_env env, napi_value obj, const std::string_view& key, bool defaultValue) {
97
94
  if (HasProperty(env, obj, key.data())) {
98
95
  const auto value = GetProperty(env, obj, key.data());
99
96
  bool result;
@@ -104,12 +101,12 @@ static bool BooleanProperty (napi_env env, napi_value obj, const std::string_vie
104
101
  return defaultValue;
105
102
  }
106
103
 
107
- static bool EncodingIsBuffer (napi_env env, napi_value obj, const std::string_view& option) {
104
+ static bool EncodingIsBuffer(napi_env env, napi_value obj, const std::string_view& option) {
108
105
  napi_value value;
109
106
  size_t size;
110
107
 
111
108
  if (napi_get_named_property(env, obj, option.data(), &value) == napi_ok &&
112
- napi_get_value_string_utf8(env, value, nullptr, 0, &size) == napi_ok) {
109
+ napi_get_value_string_utf8(env, value, nullptr, 0, &size) == napi_ok) {
113
110
  // Value is either "buffer" or "utf8" so we can tell them apart just by size
114
111
  return size == 6;
115
112
  }
@@ -117,7 +114,7 @@ static bool EncodingIsBuffer (napi_env env, napi_value obj, const std::string_vi
117
114
  return false;
118
115
  }
119
116
 
120
- static uint32_t Uint32Property (napi_env env, napi_value obj, const std::string_view& key, uint32_t defaultValue) {
117
+ static uint32_t Uint32Property(napi_env env, napi_value obj, const std::string_view& key, uint32_t defaultValue) {
121
118
  if (HasProperty(env, obj, key.data())) {
122
119
  const auto value = GetProperty(env, obj, key.data());
123
120
  uint32_t result;
@@ -128,7 +125,7 @@ static uint32_t Uint32Property (napi_env env, napi_value obj, const std::string_
128
125
  return defaultValue;
129
126
  }
130
127
 
131
- static int Int32Property (napi_env env, napi_value obj, const std::string_view& key, int defaultValue) {
128
+ static int Int32Property(napi_env env, napi_value obj, const std::string_view& key, int defaultValue) {
132
129
  if (HasProperty(env, obj, key.data())) {
133
130
  const auto value = GetProperty(env, obj, key.data());
134
131
  int result;
@@ -139,7 +136,7 @@ static int Int32Property (napi_env env, napi_value obj, const std::string_view&
139
136
  return defaultValue;
140
137
  }
141
138
 
142
- static std::string ToString (napi_env env, napi_value from, const std::string& defaultValue = "") {
139
+ static std::string ToString(napi_env env, napi_value from, const std::string& defaultValue = "") {
143
140
  if (IsString(env, from)) {
144
141
  size_t length = 0;
145
142
  napi_get_value_string_utf8(env, from, nullptr, 0, &length);
@@ -149,14 +146,17 @@ static std::string ToString (napi_env env, napi_value from, const std::string& d
149
146
  } else if (IsBuffer(env, from)) {
150
147
  char* buf = nullptr;
151
148
  size_t length = 0;
152
- napi_get_buffer_info(env, from, reinterpret_cast<void **>(&buf), &length);
149
+ napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length);
153
150
  return std::string(buf, length);
154
151
  }
155
152
 
156
153
  return defaultValue;
157
154
  }
158
155
 
159
- static std::string StringProperty (napi_env env, napi_value obj, const std::string_view& key, const std::string& defaultValue = "") {
156
+ static std::string StringProperty(napi_env env,
157
+ napi_value obj,
158
+ const std::string_view& key,
159
+ const std::string& defaultValue = "") {
160
160
  if (HasProperty(env, obj, key)) {
161
161
  napi_value value = GetProperty(env, obj, key);
162
162
  if (IsString(env, value)) {
@@ -167,52 +167,30 @@ static std::string StringProperty (napi_env env, napi_value obj, const std::stri
167
167
  return defaultValue;
168
168
  }
169
169
 
170
- static size_t StringOrBufferLength (napi_env env, napi_value value) {
171
- size_t size = 0;
172
-
173
- if (IsString(env, value)) {
174
- napi_get_value_string_utf8(env, value, nullptr, 0, &size);
175
- } else if (IsBuffer(env, value)) {
176
- char* buf = nullptr;
177
- napi_get_buffer_info(env, value, (void **)&buf, &size);
178
- }
179
-
180
- return size;
181
- }
182
-
183
- static std::optional<std::string> RangeOption (napi_env env, napi_value opts, const std::string_view& name) {
170
+ static std::optional<std::string> RangeOption(napi_env env, napi_value opts, const std::string_view& name) {
184
171
  if (HasProperty(env, opts, name)) {
185
172
  const auto value = GetProperty(env, opts, name);
186
- return std::string(ToString(env, value));
173
+ return ToString(env, value);
187
174
  }
188
175
 
189
176
  return {};
190
177
  }
191
178
 
192
- static std::vector<std::string> KeyArray (napi_env env, napi_value arr) {
193
- uint32_t length;
194
- std::vector<std::string> result;
195
-
196
- if (napi_get_array_length(env, arr, &length) == napi_ok) {
197
- result.reserve(length);
198
-
199
- for (uint32_t i = 0; i < length; i++) {
200
- napi_value element;
179
+ static napi_status CallFunction(napi_env env, napi_value callback, const int argc, napi_value* argv) {
180
+ napi_status status;
181
+ napi_value global;
201
182
 
202
- if (napi_get_element(env, arr, i, &element) == napi_ok &&
203
- StringOrBufferLength(env, element) > 0) {
204
- result.push_back(ToString(env, element));
205
- }
206
- }
183
+ status = napi_get_global(env, &global);
184
+ if (status != napi_ok) {
185
+ return status;
207
186
  }
208
187
 
209
- return result;
210
- }
188
+ status = napi_call_function(env, global, callback, argc, argv, nullptr);
189
+ if (status != napi_ok) {
190
+ return status;
191
+ }
211
192
 
212
- static napi_status CallFunction (napi_env env, napi_value callback, const int argc, napi_value* argv) {
213
- napi_value global;
214
- napi_get_global(env, &global);
215
- return napi_call_function(env, global, callback, argc, argv, nullptr);
193
+ return napi_ok;
216
194
  }
217
195
 
218
196
  static napi_value ToError(napi_env env, const rocksdb::Status& status) {
@@ -227,11 +205,11 @@ static napi_value ToError(napi_env env, const rocksdb::Status& status) {
227
205
  } else if (status.IsCorruption()) {
228
206
  return CreateCodeError(env, "LEVEL_CORRUPTION", msg);
229
207
  } else if (status.IsIOError()) {
230
- if (msg.find("IO error: lock ") != std::string::npos) { // env_posix.cc
208
+ if (msg.find("IO error: lock ") != std::string::npos) { // env_posix.cc
231
209
  return CreateCodeError(env, "LEVEL_LOCKED", msg);
232
- } else if (msg.find("IO error: LockFile ") != std::string::npos) { // env_win.cc
210
+ } else if (msg.find("IO error: LockFile ") != std::string::npos) { // env_win.cc
233
211
  return CreateCodeError(env, "LEVEL_LOCKED", msg);
234
- } else if (msg.find("IO error: While lock file") != std::string::npos) { // env_mac.cc
212
+ } else if (msg.find("IO error: While lock file") != std::string::npos) { // env_mac.cc
235
213
  return CreateCodeError(env, "LEVEL_LOCKED", msg);
236
214
  } else {
237
215
  return CreateCodeError(env, "LEVEL_IO_ERROR", msg);
@@ -242,16 +220,16 @@ static napi_value ToError(napi_env env, const rocksdb::Status& status) {
242
220
  }
243
221
 
244
222
  template <typename T>
245
- void Convert (napi_env env, const T& s, bool asBuffer, napi_value& result) {
223
+ napi_status Convert(napi_env env, const T& s, bool asBuffer, napi_value& result) {
246
224
  if (asBuffer) {
247
- napi_create_buffer_copy(env, s.size(), s.data(), nullptr, &result);
225
+ return napi_create_buffer_copy(env, s.size(), s.data(), nullptr, &result);
248
226
  } else {
249
- napi_create_string_utf8(env, s.data(), s.size(), &result);
227
+ return napi_create_string_utf8(env, s.data(), s.size(), &result);
250
228
  }
251
229
  }
252
230
 
253
231
  struct NapiSlice : public rocksdb::Slice {
254
- NapiSlice (napi_env env, napi_value from) {
232
+ NapiSlice(napi_env env, napi_value from) {
255
233
  if (IsString(env, from)) {
256
234
  napi_get_value_string_utf8(env, from, nullptr, 0, &size_);
257
235
  char* data;
@@ -270,7 +248,7 @@ struct NapiSlice : public rocksdb::Slice {
270
248
  data_ = static_cast<char*>(data);
271
249
  }
272
250
  }
273
-
251
+
274
252
  std::unique_ptr<char[]> heap_;
275
253
  std::array<char, 8192> stack_;
276
254
  };
@@ -284,33 +262,25 @@ struct NapiSlice : public rocksdb::Slice {
284
262
  * - OnError (main thread): call JS callback on error
285
263
  * - Destroy (main thread): do cleanup regardless of success
286
264
  */
287
- struct BaseWorker {
288
- BaseWorker (napi_env env,
289
- Database* database,
290
- napi_value callback,
291
- const std::string& resourceName)
292
- : database_(database) {
265
+ struct Worker {
266
+ Worker(napi_env env, Database* database, napi_value callback, const std::string& resourceName)
267
+ : database_(database) {
293
268
  NAPI_STATUS_THROWS_VOID(napi_create_reference(env, callback, 1, &callbackRef_));
294
269
  napi_value asyncResourceName;
295
- NAPI_STATUS_THROWS_VOID(napi_create_string_utf8(env, resourceName.data(),
296
- NAPI_AUTO_LENGTH,
297
- &asyncResourceName));
298
- NAPI_STATUS_THROWS_VOID(napi_create_async_work(env, callback,
299
- asyncResourceName,
300
- BaseWorker::Execute,
301
- BaseWorker::Complete,
302
- this, &asyncWork_));
270
+ NAPI_STATUS_THROWS_VOID(napi_create_string_utf8(env, resourceName.data(), resourceName.size(), &asyncResourceName));
271
+ NAPI_STATUS_THROWS_VOID(napi_create_async_work(env, callback, asyncResourceName, Worker::Execute,
272
+ Worker::Complete, this, &asyncWork_));
303
273
  }
304
274
 
305
- virtual ~BaseWorker () {}
275
+ virtual ~Worker() {}
306
276
 
307
- static void Execute (napi_env env, void* data) {
308
- auto self = reinterpret_cast<BaseWorker*>(data);
277
+ static void Execute(napi_env env, void* data) {
278
+ auto self = reinterpret_cast<Worker*>(data);
309
279
  self->status_ = self->Execute(*self->database_);
310
280
  }
311
281
 
312
- static void Complete (napi_env env, napi_status status, void* data) {
313
- auto self = reinterpret_cast<BaseWorker*>(data);
282
+ static void Complete(napi_env env, napi_status status, void* data) {
283
+ auto self = reinterpret_cast<Worker*>(data);
314
284
 
315
285
  napi_value callback;
316
286
  napi_get_reference_value(env, self->callbackRef_, &callback);
@@ -329,36 +299,30 @@ struct BaseWorker {
329
299
  delete self;
330
300
  }
331
301
 
332
- virtual rocksdb::Status Execute (Database& database) = 0;
302
+ virtual rocksdb::Status Execute(Database& database) = 0;
333
303
 
334
- virtual void OnOk (napi_env env, napi_value callback) {
304
+ virtual void OnOk(napi_env env, napi_value callback) {
335
305
  napi_value argv;
336
306
  napi_get_null(env, &argv);
337
307
  CallFunction(env, callback, 1, &argv);
338
308
  }
339
309
 
340
- virtual void OnError (napi_env env, napi_value callback, napi_value err) {
341
- CallFunction(env, callback, 1, &err);
342
- }
310
+ virtual void OnError(napi_env env, napi_value callback, napi_value err) { CallFunction(env, callback, 1, &err); }
343
311
 
344
- virtual void Destroy (napi_env env) {
345
- }
312
+ virtual void Destroy(napi_env env) {}
346
313
 
347
- void Queue (napi_env env) {
348
- napi_queue_async_work(env, asyncWork_);
349
- }
314
+ void Queue(napi_env env) { napi_queue_async_work(env, asyncWork_); }
350
315
 
351
316
  Database* database_;
352
- private:
317
+
318
+ private:
353
319
  napi_ref callbackRef_;
354
320
  napi_async_work asyncWork_;
355
321
  rocksdb::Status status_;
356
322
  };
357
323
 
358
324
  struct Database {
359
- rocksdb::Status Open (const rocksdb::Options& options,
360
- const bool readOnly,
361
- const char* location) {
325
+ rocksdb::Status Open(const rocksdb::Options& options, const bool readOnly, const char* location) {
362
326
  if (readOnly) {
363
327
  rocksdb::DB* db = nullptr;
364
328
  const auto status = rocksdb::DB::OpenForReadOnly(options, location, &db);
@@ -372,25 +336,19 @@ struct Database {
372
336
  }
373
337
  }
374
338
 
375
- void CloseDatabase () {
376
- db_.reset();
377
- }
378
-
379
- void AttachIterator (napi_env env, Iterator* iterator) {
339
+ void AttachIterator(napi_env env, Iterator* iterator) {
380
340
  iterators_.insert(iterator);
381
341
  IncrementPriorityWork(env);
382
342
  }
383
343
 
384
- void DetachIterator (napi_env env, Iterator* iterator) {
344
+ void DetachIterator(napi_env env, Iterator* iterator) {
385
345
  iterators_.erase(iterator);
386
346
  DecrementPriorityWork(env);
387
347
  }
388
348
 
389
- void IncrementPriorityWork (napi_env env) {
390
- napi_reference_ref(env, prioritRef_, &priorityWork_);
391
- }
349
+ void IncrementPriorityWork(napi_env env) { napi_reference_ref(env, prioritRef_, &priorityWork_); }
392
350
 
393
- void DecrementPriorityWork (napi_env env) {
351
+ void DecrementPriorityWork(napi_env env) {
394
352
  napi_reference_unref(env, prioritRef_, &priorityWork_);
395
353
 
396
354
  if (priorityWork_ == 0 && pendingCloseWorker_) {
@@ -399,36 +357,17 @@ struct Database {
399
357
  }
400
358
  }
401
359
 
402
- bool HasPriorityWork () const {
403
- return priorityWork_ > 0;
404
- }
360
+ bool HasPriorityWork() const { return priorityWork_ > 0; }
405
361
 
406
362
  std::unique_ptr<rocksdb::DB> db_;
407
- BaseWorker* pendingCloseWorker_;
363
+ Worker* pendingCloseWorker_;
408
364
  std::set<Iterator*> iterators_;
409
365
  napi_ref prioritRef_;
410
366
 
411
- private:
367
+ private:
412
368
  uint32_t priorityWork_ = 0;
413
369
  };
414
370
 
415
- /**
416
- * Base worker class for doing async work that defers closing the database.
417
- */
418
- struct PriorityWorker : public BaseWorker {
419
- PriorityWorker (napi_env env, Database* database, napi_value callback, const char* resourceName)
420
- : BaseWorker(env, database, callback, resourceName) {
421
- database_->IncrementPriorityWork(env);
422
- }
423
-
424
- virtual ~PriorityWorker () {}
425
-
426
- void Destroy (napi_env env) override {
427
- database_->DecrementPriorityWork(env);
428
- BaseWorker::Destroy(env);
429
- }
430
- };
431
-
432
371
  struct BaseIterator {
433
372
  BaseIterator(Database* database,
434
373
  const bool reverse,
@@ -438,67 +377,52 @@ struct BaseIterator {
438
377
  const std::optional<std::string>& gte,
439
378
  const int limit,
440
379
  const bool fillCache)
441
- : database_(database),
442
- lt_(lt),
443
- lte_(lte),
444
- gt_(gt),
445
- gte_(gte),
446
- snapshot_(database_->db_->GetSnapshot(), [this](const rocksdb::Snapshot* ptr) {
447
- database_->db_->ReleaseSnapshot(ptr);
448
- }),
449
- iterator_(database->db_->NewIterator([&]{
450
- rocksdb::ReadOptions options;
451
- if (lt_ && !lte_) {
452
- upper_bound_ = rocksdb::Slice(lt_->data(), lt_->size());
453
- options.iterate_upper_bound = &upper_bound_;
454
- }
455
- if (gte_) {
456
- lower_bound_ = rocksdb::Slice(gte_->data(), gte_->size());
457
- options.iterate_lower_bound = &lower_bound_;
458
- }
459
- options.fill_cache = fillCache;
460
- options.snapshot = snapshot_.get();
461
- return options;
462
- }())),
463
- reverse_(reverse),
464
- limit_(limit) {
465
- }
466
-
467
- virtual ~BaseIterator () {
468
- assert(!iterator_);
469
- }
470
-
471
- bool DidSeek () const {
472
- return didSeek_;
473
- }
474
-
475
- void SeekToRange () {
380
+ : database_(database),
381
+ lt_(!lte ? lt : *lte + '\0'),
382
+ gte_(gte ? gte : (gt ? std::optional<std::string>(*gt + '\0') : std::nullopt)),
383
+ snapshot_(database_->db_->GetSnapshot(),
384
+ [this](const rocksdb::Snapshot* ptr) { database_->db_->ReleaseSnapshot(ptr); }),
385
+ iterator_(database->db_->NewIterator([&] {
386
+ rocksdb::ReadOptions options;
387
+ if (lt_) {
388
+ upper_bound_ = rocksdb::Slice(lt_->data(), lt_->size());
389
+ options.iterate_upper_bound = &upper_bound_;
390
+ }
391
+ if (gte_) {
392
+ lower_bound_ = rocksdb::Slice(gte_->data(), gte_->size());
393
+ options.iterate_lower_bound = &lower_bound_;
394
+ }
395
+ options.fill_cache = fillCache;
396
+ options.snapshot = snapshot_.get();
397
+ return options;
398
+ }())),
399
+ reverse_(reverse),
400
+ limit_(limit) {}
401
+
402
+ virtual ~BaseIterator() { assert(!iterator_); }
403
+
404
+ bool DidSeek() const { return didSeek_; }
405
+
406
+ void SeekToRange() {
476
407
  didSeek_ = true;
477
408
 
478
- if (!reverse_ && gt_ && !gte_) {
479
- iterator_->Seek(*gt_);
480
-
481
- if (iterator_->Valid() && iterator_->key().compare(*gt_) == 0) {
482
- iterator_->Next();
483
- }
484
- } else if (reverse_ && lte_) {
485
- iterator_->SeekForPrev(*lte_);
486
- } else if (reverse_) {
409
+ if (reverse_) {
487
410
  iterator_->SeekToLast();
488
411
  } else {
489
412
  iterator_->SeekToFirst();
490
413
  }
491
414
  }
492
415
 
493
- void Seek (const std::string& target) {
416
+ void Seek(const std::string& target) {
494
417
  didSeek_ = true;
495
418
 
496
- // TODO (fix): Only check for (gt && !gte) and lte.
497
- // See, https://github.com/facebook/rocksdb/issues/9904.
498
-
499
- if (OutOfRange(target)) {
500
- SeekToLast();
501
- Next();
419
+ if ((lt_ && target.compare(*lt_) >= 0) || (gte_ && target.compare(*gte_) < 0)) {
420
+ // TODO (fix): Why is this required? Seek should handle it?
421
+ // https://github.com/facebook/rocksdb/issues/9904
422
+ iterator_->SeekToLast();
423
+ if (iterator_->Valid()) {
424
+ iterator_->Next();
425
+ }
502
426
  } else if (reverse_) {
503
427
  iterator_->SeekForPrev(target);
504
428
  } else {
@@ -506,80 +430,32 @@ struct BaseIterator {
506
430
  }
507
431
  }
508
432
 
509
- void Close () {
433
+ void Close() {
510
434
  snapshot_.reset();
511
435
  iterator_.reset();
512
436
  }
513
437
 
514
- bool Valid () const {
515
- if (!iterator_->Valid()) {
516
- return false;
517
- }
518
-
519
- if (lte_ && iterator_->key().compare(*lte_) > 0) {
520
- return false;
521
- }
522
-
523
- if (!gte_ && gt_ && iterator_->key().compare(*gt_) <= 0) {
524
- return false;
525
- }
526
-
527
- return true;
528
- }
438
+ bool Valid() const { return iterator_->Valid(); }
529
439
 
530
- bool Increment () {
531
- return limit_ < 0 || ++count_ <= limit_;
532
- }
440
+ bool Increment() { return limit_ < 0 || ++count_ <= limit_; }
533
441
 
534
- void Next () {
535
- if (reverse_) iterator_->Prev();
536
- else iterator_->Next();
442
+ void Next() {
443
+ if (reverse_)
444
+ iterator_->Prev();
445
+ else
446
+ iterator_->Next();
537
447
  }
538
448
 
539
- void SeekToFirst () {
540
- if (reverse_) iterator_->SeekToLast();
541
- else iterator_->SeekToFirst();
542
- }
449
+ rocksdb::Slice CurrentKey() const { return iterator_->key(); }
543
450
 
544
- void SeekToLast () {
545
- if (reverse_) iterator_->SeekToFirst();
546
- else iterator_->SeekToLast();
547
- }
451
+ rocksdb::Slice CurrentValue() const { return iterator_->value(); }
548
452
 
549
- rocksdb::Slice CurrentKey () const {
550
- return iterator_->key();
551
- }
552
-
553
- rocksdb::Slice CurrentValue () const {
554
- return iterator_->value();
555
- }
556
-
557
- rocksdb::Status Status () const {
558
- return iterator_->status();
559
- }
560
-
561
- bool OutOfRange (const rocksdb::Slice& target) const {
562
- if (lte_) {
563
- if (target.compare(*lte_) > 0) return true;
564
- } else if (lt_) {
565
- if (target.compare(*lt_) >= 0) return true;
566
- }
567
-
568
- if (gte_) {
569
- if (target.compare(*gte_) < 0) return true;
570
- } else if (gt_) {
571
- if (target.compare(*gt_) <= 0) return true;
572
- }
573
-
574
- return false;
575
- }
453
+ rocksdb::Status Status() const { return iterator_->status(); }
576
454
 
577
455
  Database* database_;
578
456
 
579
- private:
457
+ private:
580
458
  const std::optional<std::string> lt_;
581
- const std::optional<std::string> lte_;
582
- const std::optional<std::string> gt_;
583
459
  const std::optional<std::string> gte_;
584
460
  rocksdb::Slice lower_bound_;
585
461
  rocksdb::Slice upper_bound_;
@@ -592,37 +468,38 @@ private:
592
468
  };
593
469
 
594
470
  struct Iterator final : public BaseIterator {
595
- Iterator (Database* database,
596
- const bool reverse,
597
- const bool keys,
598
- const bool values,
599
- const int limit,
600
- const std::optional<std::string>& lt,
601
- const std::optional<std::string>& lte,
602
- const std::optional<std::string>& gt,
603
- const std::optional<std::string>& gte,
604
- const bool fillCache,
605
- const bool keyAsBuffer,
606
- const bool valueAsBuffer,
607
- const uint32_t highWaterMarkBytes)
608
- : BaseIterator(database, reverse, lt, lte, gt, gte, limit, fillCache),
609
- keys_(keys),
610
- values_(values),
611
- keyAsBuffer_(keyAsBuffer),
612
- valueAsBuffer_(valueAsBuffer),
613
- highWaterMarkBytes_(highWaterMarkBytes),
614
- first_(true),
615
- ref_(nullptr) {
616
- }
617
-
618
- void Attach (napi_env env, napi_value context) {
471
+ Iterator(Database* database,
472
+ const bool reverse,
473
+ const bool keys,
474
+ const bool values,
475
+ const int limit,
476
+ const std::optional<std::string>& lt,
477
+ const std::optional<std::string>& lte,
478
+ const std::optional<std::string>& gt,
479
+ const std::optional<std::string>& gte,
480
+ const bool fillCache,
481
+ const bool keyAsBuffer,
482
+ const bool valueAsBuffer,
483
+ const uint32_t highWaterMarkBytes)
484
+ : BaseIterator(database, reverse, lt, lte, gt, gte, limit, fillCache),
485
+ keys_(keys),
486
+ values_(values),
487
+ keyAsBuffer_(keyAsBuffer),
488
+ valueAsBuffer_(valueAsBuffer),
489
+ highWaterMarkBytes_(highWaterMarkBytes),
490
+ first_(true),
491
+ ref_(nullptr) {}
492
+
493
+ void Attach(napi_env env, napi_value context) {
619
494
  napi_create_reference(env, context, 1, &ref_);
620
495
  database_->AttachIterator(env, this);
621
496
  }
622
497
 
623
- void Detach (napi_env env) {
498
+ void Detach(napi_env env) {
624
499
  database_->DetachIterator(env, this);
625
- if (ref_) napi_delete_reference(env, ref_);
500
+ if (ref_) {
501
+ napi_delete_reference(env, ref_);
502
+ }
626
503
  }
627
504
 
628
505
  const bool keys_;
@@ -632,7 +509,7 @@ struct Iterator final : public BaseIterator {
632
509
  const uint32_t highWaterMarkBytes_;
633
510
  bool first_;
634
511
 
635
- private:
512
+ private:
636
513
  napi_ref ref_;
637
514
  };
638
515
 
@@ -641,15 +518,16 @@ private:
641
518
  * already-scheduled napi_async_work items have finished, which gives us
642
519
  * the guarantee that no db operations will be in-flight at this time.
643
520
  */
644
- static void env_cleanup_hook (void* arg) {
521
+ static void env_cleanup_hook(void* arg) {
645
522
  auto database = reinterpret_cast<Database*>(arg);
646
523
 
647
- // Do everything that db_close() does but synchronously. We're expecting that GC
648
- // did not (yet) collect the database because that would be a user mistake (not
649
- // closing their db) made during the lifetime of the environment. That's different
650
- // from an environment being torn down (like the main process or a worker thread)
651
- // where it's our responsibility to clean up. Note also, the following code must
652
- // be a safe noop if called before db_open() or after db_close().
524
+ // Do everything that db_close() does but synchronously. We're expecting that
525
+ // GC did not (yet) collect the database because that would be a user mistake
526
+ // (not closing their db) made during the lifetime of the environment. That's
527
+ // different from an environment being torn down (like the main process or a
528
+ // worker thread) where it's our responsibility to clean up. Note also, the
529
+ // following code must be a safe noop if called before db_open() or after
530
+ // db_close().
653
531
  if (database && database->db_) {
654
532
  // TODO: does not do `napi_delete_reference(env, iterator->ref_)`. Problem?
655
533
  for (auto it : database->iterators_) {
@@ -657,15 +535,16 @@ static void env_cleanup_hook (void* arg) {
657
535
  }
658
536
 
659
537
  // Having closed the iterators (and released snapshots) we can safely close.
660
- database->CloseDatabase();
538
+ database->db_->Close();
661
539
  }
662
540
  }
663
541
 
664
- static void FinalizeDatabase (napi_env env, void* data, void* hint) {
542
+ static void FinalizeDatabase(napi_env env, void* data, void* hint) {
665
543
  if (data) {
666
544
  auto database = reinterpret_cast<Database*>(data);
667
545
  napi_remove_env_cleanup_hook(env, env_cleanup_hook, database);
668
- if (database->prioritRef_) napi_delete_reference(env, database->prioritRef_);
546
+ if (database->prioritRef_)
547
+ napi_delete_reference(env, database->prioritRef_);
669
548
  delete database;
670
549
  }
671
550
  }
@@ -675,39 +554,33 @@ NAPI_METHOD(db_init) {
675
554
  napi_add_env_cleanup_hook(env, env_cleanup_hook, database);
676
555
 
677
556
  napi_value result;
678
- NAPI_STATUS_THROWS(napi_create_external(env, database,
679
- FinalizeDatabase,
680
- nullptr, &result));
557
+ NAPI_STATUS_THROWS(napi_create_external(env, database, FinalizeDatabase, nullptr, &result));
681
558
 
682
559
  NAPI_STATUS_THROWS(napi_create_reference(env, result, 0, &database->prioritRef_));
683
560
 
684
561
  return result;
685
562
  }
686
563
 
687
- struct OpenWorker final : public PriorityWorker {
688
- OpenWorker (napi_env env,
689
- Database* database,
690
- napi_value callback,
691
- const std::string& location,
692
- const bool createIfMissing,
693
- const bool errorIfExists,
694
- const bool compression,
695
- const uint32_t writeBufferSize,
696
- const uint32_t blockSize,
697
- const uint32_t maxOpenFiles,
698
- const uint32_t blockRestartInterval,
699
- const uint32_t maxFileSize,
700
- const uint32_t cacheSize,
701
- const std::string& infoLogLevel,
702
- const bool readOnly)
703
- : PriorityWorker(env, database, callback, "leveldown.db.open"),
704
- readOnly_(readOnly),
705
- location_(location) {
564
+ struct OpenWorker final : public Worker {
565
+ OpenWorker(napi_env env,
566
+ Database* database,
567
+ napi_value callback,
568
+ const std::string& location,
569
+ const bool createIfMissing,
570
+ const bool errorIfExists,
571
+ const bool compression,
572
+ const uint32_t writeBufferSize,
573
+ const uint32_t blockSize,
574
+ const uint32_t maxOpenFiles,
575
+ const uint32_t blockRestartInterval,
576
+ const uint32_t maxFileSize,
577
+ const uint32_t cacheSize,
578
+ const std::string& infoLogLevel,
579
+ const bool readOnly)
580
+ : Worker(env, database, callback, "leveldown.db.open"), readOnly_(readOnly), location_(location) {
706
581
  options_.create_if_missing = createIfMissing;
707
582
  options_.error_if_exists = errorIfExists;
708
- options_.compression = compression
709
- ? rocksdb::kSnappyCompression
710
- : rocksdb::kNoCompression;
583
+ options_.compression = compression ? rocksdb::kSnappyCompression : rocksdb::kNoCompression;
711
584
  options_.write_buffer_size = writeBufferSize;
712
585
  options_.max_open_files = maxOpenFiles;
713
586
  options_.max_log_file_size = maxFileSize;
@@ -716,13 +589,20 @@ struct OpenWorker final : public PriorityWorker {
716
589
  if (infoLogLevel.size() > 0) {
717
590
  rocksdb::InfoLogLevel lvl = {};
718
591
 
719
- if (infoLogLevel == "debug") lvl = rocksdb::InfoLogLevel::DEBUG_LEVEL;
720
- else if (infoLogLevel == "info") lvl = rocksdb::InfoLogLevel::INFO_LEVEL;
721
- else if (infoLogLevel == "warn") lvl = rocksdb::InfoLogLevel::WARN_LEVEL;
722
- else if (infoLogLevel == "error") lvl = rocksdb::InfoLogLevel::ERROR_LEVEL;
723
- else if (infoLogLevel == "fatal") lvl = rocksdb::InfoLogLevel::FATAL_LEVEL;
724
- else if (infoLogLevel == "header") lvl = rocksdb::InfoLogLevel::HEADER_LEVEL;
725
- else napi_throw_error(env, nullptr, "invalid log level");
592
+ if (infoLogLevel == "debug")
593
+ lvl = rocksdb::InfoLogLevel::DEBUG_LEVEL;
594
+ else if (infoLogLevel == "info")
595
+ lvl = rocksdb::InfoLogLevel::INFO_LEVEL;
596
+ else if (infoLogLevel == "warn")
597
+ lvl = rocksdb::InfoLogLevel::WARN_LEVEL;
598
+ else if (infoLogLevel == "error")
599
+ lvl = rocksdb::InfoLogLevel::ERROR_LEVEL;
600
+ else if (infoLogLevel == "fatal")
601
+ lvl = rocksdb::InfoLogLevel::FATAL_LEVEL;
602
+ else if (infoLogLevel == "header")
603
+ lvl = rocksdb::InfoLogLevel::HEADER_LEVEL;
604
+ else
605
+ napi_throw_error(env, nullptr, "invalid log level");
726
606
 
727
607
  options_.info_log_level = lvl;
728
608
  } else {
@@ -746,14 +626,10 @@ struct OpenWorker final : public PriorityWorker {
746
626
  tableOptions.format_version = 5;
747
627
  tableOptions.checksum = rocksdb::kxxHash64;
748
628
 
749
- options_.table_factory.reset(
750
- rocksdb::NewBlockBasedTableFactory(tableOptions)
751
- );
629
+ options_.table_factory.reset(rocksdb::NewBlockBasedTableFactory(tableOptions));
752
630
  }
753
631
 
754
- rocksdb::Status Execute (Database& database) override {
755
- return database.Open(options_, readOnly_, location_.c_str());
756
- }
632
+ rocksdb::Status Execute(Database& database) override { return database.Open(options_, readOnly_, location_.c_str()); }
757
633
 
758
634
  rocksdb::Options options_;
759
635
  const bool readOnly_;
@@ -774,38 +650,30 @@ NAPI_METHOD(db_open) {
774
650
  const auto infoLogLevel = StringProperty(env, options, "infoLogLevel");
775
651
 
776
652
  const auto cacheSize = Uint32Property(env, options, "cacheSize", 8 << 20);
777
- const auto writeBufferSize = Uint32Property(env, options , "writeBufferSize" , 4 << 20);
653
+ const auto writeBufferSize = Uint32Property(env, options, "writeBufferSize", 4 << 20);
778
654
  const auto blockSize = Uint32Property(env, options, "blockSize", 4096);
779
655
  const auto maxOpenFiles = Uint32Property(env, options, "maxOpenFiles", 1000);
780
- const auto blockRestartInterval = Uint32Property(env, options,
781
- "blockRestartInterval", 16);
656
+ const auto blockRestartInterval = Uint32Property(env, options, "blockRestartInterval", 16);
782
657
  const auto maxFileSize = Uint32Property(env, options, "maxFileSize", 2 << 20);
783
658
 
784
659
  const auto callback = argv[3];
785
660
 
786
- auto worker = new OpenWorker(env, database, callback, location,
787
- createIfMissing, errorIfExists,
788
- compression, writeBufferSize, blockSize,
789
- maxOpenFiles, blockRestartInterval,
790
- maxFileSize, cacheSize,
791
- infoLogLevel, readOnly);
661
+ auto worker =
662
+ new OpenWorker(env, database, callback, location, createIfMissing, errorIfExists, compression, writeBufferSize,
663
+ blockSize, maxOpenFiles, blockRestartInterval, maxFileSize, cacheSize, infoLogLevel, readOnly);
792
664
  worker->Queue(env);
793
665
 
794
666
  return 0;
795
667
  }
796
668
 
797
- struct CloseWorker final : public BaseWorker {
798
- CloseWorker (napi_env env,
799
- Database* database,
800
- napi_value callback)
801
- : BaseWorker(env, database, callback, "leveldown.db.close") {}
669
+ struct CloseWorker final : public Worker {
670
+ CloseWorker(napi_env env, Database* database, napi_value callback)
671
+ : Worker(env, database, callback, "leveldown.db.close") {}
802
672
 
803
- rocksdb::Status Execute (Database& database) override {
804
- return database.db_->Close();
805
- }
673
+ rocksdb::Status Execute(Database& database) override { return database.db_->Close(); }
806
674
  };
807
675
 
808
- napi_value noop_callback (napi_env env, napi_callback_info info) {
676
+ napi_value noop_callback(napi_env env, napi_callback_info info) {
809
677
  return 0;
810
678
  }
811
679
 
@@ -837,37 +705,46 @@ NAPI_METHOD(db_put) {
837
705
  return ToError(env, database->db_->Put(options, key, value));
838
706
  }
839
707
 
840
- struct GetWorker final : public PriorityWorker {
841
- GetWorker (napi_env env,
842
- Database* database,
843
- napi_value callback,
844
- const std::string& key,
845
- const bool asBuffer,
846
- const bool fillCache)
847
- : PriorityWorker(env, database, callback, "rocks_level.db.get"),
848
- key_(key), asBuffer_(asBuffer), fillCache_(fillCache),
849
- snapshot_(database_->db_->GetSnapshot(), [this](const rocksdb::Snapshot* ptr) {
850
- database_->db_->ReleaseSnapshot(ptr);
851
- }) {
708
+ struct GetWorker final : public Worker {
709
+ GetWorker(napi_env env,
710
+ Database* database,
711
+ napi_value callback,
712
+ const std::string& key,
713
+ const bool asBuffer,
714
+ const bool fillCache)
715
+ : Worker(env, database, callback, "rocks_level.db.get"),
716
+ key_(key),
717
+ asBuffer_(asBuffer),
718
+ fillCache_(fillCache),
719
+ snapshot_(database_->db_->GetSnapshot(),
720
+ [this](const rocksdb::Snapshot* ptr) { database_->db_->ReleaseSnapshot(ptr); }) {
721
+ database_->IncrementPriorityWork(env);
852
722
  }
853
723
 
854
- rocksdb::Status Execute (Database& database) override {
724
+ rocksdb::Status Execute(Database& database) override {
855
725
  rocksdb::ReadOptions options;
856
726
  options.fill_cache = fillCache_;
857
727
  options.snapshot = snapshot_.get();
728
+
858
729
  auto status = database.db_->Get(options, database.db_->DefaultColumnFamily(), key_, &value_);
859
- snapshot_.reset();
730
+ snapshot_ = nullptr;
731
+
860
732
  return status;
861
733
  }
862
734
 
863
- void OnOk (napi_env env, napi_value callback) override {
735
+ void OnOk(napi_env env, napi_value callback) override {
864
736
  napi_value argv[2];
865
737
  napi_get_null(env, &argv[0]);
866
738
  Convert(env, std::move(value_), asBuffer_, argv[1]);
867
739
  CallFunction(env, callback, 2, argv);
868
740
  }
869
741
 
870
- private:
742
+ void Destroy(napi_env env) override {
743
+ database_->DecrementPriorityWork(env);
744
+ Worker::Destroy(env);
745
+ }
746
+
747
+ private:
871
748
  const std::string key_;
872
749
  rocksdb::PinnableSlice value_;
873
750
  const bool asBuffer_;
@@ -891,30 +768,28 @@ NAPI_METHOD(db_get) {
891
768
  return 0;
892
769
  }
893
770
 
894
- struct GetManyWorker final : public PriorityWorker {
895
- GetManyWorker (napi_env env,
896
- Database* database,
897
- const std::vector<std::string>& keys,
898
- napi_value callback,
899
- const bool valueAsBuffer,
900
- const bool fillCache)
901
- : PriorityWorker(env, database, callback, "leveldown.get.many"),
902
- keys_(keys), valueAsBuffer_(valueAsBuffer), fillCache_(fillCache),
903
- snapshot_(database_->db_->GetSnapshot(), [this](const rocksdb::Snapshot* ptr) {
904
- database_->db_->ReleaseSnapshot(ptr);
905
- }) {
771
+ struct GetManyWorker final : public Worker {
772
+ GetManyWorker(napi_env env,
773
+ Database* database,
774
+ const std::vector<std::string>& keys,
775
+ napi_value callback,
776
+ const bool valueAsBuffer,
777
+ const bool fillCache)
778
+ : Worker(env, database, callback, "leveldown.get.many"),
779
+ keys_(keys),
780
+ valueAsBuffer_(valueAsBuffer),
781
+ fillCache_(fillCache),
782
+ snapshot_(database_->db_->GetSnapshot(),
783
+ [this](const rocksdb::Snapshot* ptr) { database_->db_->ReleaseSnapshot(ptr); }) {
784
+ database_->IncrementPriorityWork(env);
906
785
  }
907
786
 
908
- rocksdb::Status Execute (Database& database) override {
787
+ rocksdb::Status Execute(Database& database) override {
909
788
  rocksdb::ReadOptions options;
910
789
  options.fill_cache = fillCache_;
911
790
  options.snapshot = snapshot_.get();
912
-
913
- status_ = database.db_->MultiGet(
914
- options,
915
- std::vector<rocksdb::Slice>(keys_.begin(), keys_.end()),
916
- &values_
917
- );
791
+
792
+ status_ = database.db_->MultiGet(options, std::vector<rocksdb::Slice>(keys_.begin(), keys_.end()), &values_);
918
793
  snapshot_ = nullptr;
919
794
 
920
795
  for (auto status : status_) {
@@ -926,7 +801,7 @@ struct GetManyWorker final : public PriorityWorker {
926
801
  return rocksdb::Status::OK();
927
802
  }
928
803
 
929
- void OnOk (napi_env env, napi_value callback) override {
804
+ void OnOk(napi_env env, napi_value callback) override {
930
805
  const auto size = values_.size();
931
806
 
932
807
  napi_value array;
@@ -948,7 +823,12 @@ struct GetManyWorker final : public PriorityWorker {
948
823
  CallFunction(env, callback, 2, argv);
949
824
  }
950
825
 
951
- private:
826
+ void Destroy(napi_env env) override {
827
+ database_->DecrementPriorityWork(env);
828
+ Worker::Destroy(env);
829
+ }
830
+
831
+ private:
952
832
  const std::vector<std::string> keys_;
953
833
  std::vector<std::string> values_;
954
834
  std::vector<rocksdb::Status> status_;
@@ -961,7 +841,21 @@ NAPI_METHOD(db_get_many) {
961
841
  NAPI_ARGV(4);
962
842
  NAPI_DB_CONTEXT();
963
843
 
964
- const auto keys = KeyArray(env, argv[1]);
844
+ std::vector<std::string> keys;
845
+ {
846
+ uint32_t length;
847
+ NAPI_STATUS_THROWS(napi_get_array_length(env, argv[1], &length));
848
+
849
+ keys.reserve(length);
850
+
851
+ for (uint32_t i = 0; i < length; i++) {
852
+ napi_value element;
853
+
854
+ NAPI_STATUS_THROWS(napi_get_element(env, argv[1], i, &element));
855
+ keys.push_back(ToString(env, element));
856
+ }
857
+ }
858
+
965
859
  const auto options = argv[2];
966
860
  const bool asBuffer = EncodingIsBuffer(env, options, "valueEncoding");
967
861
  const bool fillCache = BooleanProperty(env, options, "fillCache", true);
@@ -995,6 +889,8 @@ NAPI_METHOD(db_clear) {
995
889
  const auto gt = RangeOption(env, argv[1], "gt");
996
890
  const auto gte = RangeOption(env, argv[1], "gte");
997
891
 
892
+ // TODO (perf): Use DeleteRange.
893
+
998
894
  BaseIterator it(database, reverse, lt, lte, gt, gte, limit, false);
999
895
 
1000
896
  it.SeekToRange();
@@ -1005,7 +901,7 @@ NAPI_METHOD(db_clear) {
1005
901
  rocksdb::WriteBatch batch;
1006
902
  rocksdb::WriteOptions options;
1007
903
  rocksdb::Status status;
1008
-
904
+
1009
905
  while (true) {
1010
906
  size_t bytesRead = 0;
1011
907
 
@@ -1030,7 +926,7 @@ NAPI_METHOD(db_clear) {
1030
926
  }
1031
927
 
1032
928
  it.Close();
1033
-
929
+
1034
930
  return ToError(env, status);
1035
931
  }
1036
932
 
@@ -1049,7 +945,7 @@ NAPI_METHOD(db_get_property) {
1049
945
  return result;
1050
946
  }
1051
947
 
1052
- static void FinalizeIterator (napi_env env, void* data, void* hint) {
948
+ static void FinalizeIterator(napi_env env, void* data, void* hint) {
1053
949
  if (data) {
1054
950
  delete reinterpret_cast<Iterator*>(data);
1055
951
  }
@@ -1074,9 +970,8 @@ NAPI_METHOD(iterator_init) {
1074
970
  const auto gt = RangeOption(env, options, "gt");
1075
971
  const auto gte = RangeOption(env, options, "gte");
1076
972
 
1077
- auto iterator = new Iterator(database, reverse, keys,
1078
- values, limit, lt, lte, gt, gte, fillCache,
1079
- keyAsBuffer, valueAsBuffer, highWaterMarkBytes);
973
+ auto iterator = new Iterator(database, reverse, keys, values, limit, lt, lte, gt, gte, fillCache, keyAsBuffer,
974
+ valueAsBuffer, highWaterMarkBytes);
1080
975
  napi_value result;
1081
976
 
1082
977
  NAPI_STATUS_THROWS(napi_create_external(env, iterator, FinalizeIterator, nullptr, &result));
@@ -1099,24 +994,21 @@ NAPI_METHOD(iterator_seek) {
1099
994
  return 0;
1100
995
  }
1101
996
 
1102
- struct CloseIteratorWorker final : public BaseWorker {
1103
- CloseIteratorWorker (napi_env env,
1104
- Iterator* iterator,
1105
- napi_value callback)
1106
- : BaseWorker(env, iterator->database_, callback, "leveldown.iterator.end"),
1107
- iterator_(iterator) {}
997
+ struct CloseIteratorWorker final : public Worker {
998
+ CloseIteratorWorker(napi_env env, Iterator* iterator, napi_value callback)
999
+ : Worker(env, iterator->database_, callback, "leveldown.iterator.end"), iterator_(iterator) {}
1108
1000
 
1109
- rocksdb::Status Execute (Database& database) override {
1001
+ rocksdb::Status Execute(Database& database) override {
1110
1002
  iterator_->Close();
1111
1003
  return rocksdb::Status::OK();
1112
1004
  }
1113
1005
 
1114
- void Destroy (napi_env env) override {
1006
+ void Destroy(napi_env env) override {
1115
1007
  iterator_->Detach(env);
1116
- BaseWorker::Destroy(env);
1008
+ Worker::Destroy(env);
1117
1009
  }
1118
1010
 
1119
- private:
1011
+ private:
1120
1012
  Iterator* iterator_;
1121
1013
  };
1122
1014
 
@@ -1132,16 +1024,11 @@ NAPI_METHOD(iterator_close) {
1132
1024
  return 0;
1133
1025
  }
1134
1026
 
1135
- struct NextWorker final : public BaseWorker {
1136
- NextWorker (napi_env env,
1137
- Iterator* iterator,
1138
- uint32_t size,
1139
- napi_value callback)
1140
- : BaseWorker(env, iterator->database_, callback,
1141
- "leveldown.iterator.next"),
1142
- iterator_(iterator), size_(size) {}
1027
+ struct NextWorker final : public Worker {
1028
+ NextWorker(napi_env env, Iterator* iterator, uint32_t size, napi_value callback)
1029
+ : Worker(env, iterator->database_, callback, "leveldown.iterator.next"), iterator_(iterator), size_(size) {}
1143
1030
 
1144
- rocksdb::Status Execute (Database& database) override {
1031
+ rocksdb::Status Execute(Database& database) override {
1145
1032
  if (!iterator_->DidSeek()) {
1146
1033
  iterator_->SeekToRange();
1147
1034
  }
@@ -1153,11 +1040,14 @@ struct NextWorker final : public BaseWorker {
1153
1040
  size_t bytesRead = 0;
1154
1041
 
1155
1042
  while (true) {
1156
- if (!iterator_->first_) iterator_->Next();
1157
- else iterator_->first_ = false;
1043
+ if (!iterator_->first_)
1044
+ iterator_->Next();
1045
+ else
1046
+ iterator_->first_ = false;
1047
+
1048
+ if (!iterator_->Valid() || !iterator_->Increment())
1049
+ break;
1158
1050
 
1159
- if (!iterator_->Valid() || !iterator_->Increment()) break;
1160
-
1161
1051
  if (iterator_->keys_ && iterator_->values_) {
1162
1052
  auto k = iterator_->CurrentKey();
1163
1053
  auto v = iterator_->CurrentValue();
@@ -1185,7 +1075,7 @@ struct NextWorker final : public BaseWorker {
1185
1075
  return iterator_->Status();
1186
1076
  }
1187
1077
 
1188
- void OnOk (napi_env env, napi_value callback) override {
1078
+ void OnOk(napi_env env, napi_value callback) override {
1189
1079
  const auto size = cache_.size();
1190
1080
  napi_value result;
1191
1081
  napi_create_array_with_length(env, size, &result);
@@ -1210,7 +1100,7 @@ struct NextWorker final : public BaseWorker {
1210
1100
  CallFunction(env, callback, 3, argv);
1211
1101
  }
1212
1102
 
1213
- private:
1103
+ private:
1214
1104
  std::vector<std::string> cache_;
1215
1105
  Iterator* iterator_ = nullptr;
1216
1106
  uint32_t size_ = 0;
@@ -1223,7 +1113,8 @@ NAPI_METHOD(iterator_nextv) {
1223
1113
 
1224
1114
  uint32_t size;
1225
1115
  NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &size));
1226
- if (size == 0) size = 1;
1116
+ if (size == 0)
1117
+ size = 1;
1227
1118
 
1228
1119
  const auto callback = argv[2];
1229
1120
 
@@ -1248,19 +1139,23 @@ NAPI_METHOD(batch_do) {
1248
1139
  napi_value element;
1249
1140
  NAPI_STATUS_THROWS(napi_get_element(env, operations, i, &element));
1250
1141
 
1251
- if (!IsObject(env, element)) continue;
1142
+ if (!IsObject(env, element))
1143
+ continue;
1252
1144
 
1253
1145
  const auto type = StringProperty(env, element, "type");
1254
1146
 
1255
1147
  if (type == "del") {
1256
- if (!HasProperty(env, element, "key")) continue;
1148
+ if (!HasProperty(env, element, "key"))
1149
+ continue;
1257
1150
 
1258
1151
  const auto key = NapiSlice(env, GetProperty(env, element, "key"));
1259
1152
 
1260
1153
  batch.Delete(key);
1261
1154
  } else if (type == "put") {
1262
- if (!HasProperty(env, element, "key")) continue;
1263
- if (!HasProperty(env, element, "value")) continue;
1155
+ if (!HasProperty(env, element, "key"))
1156
+ continue;
1157
+ if (!HasProperty(env, element, "value"))
1158
+ continue;
1264
1159
 
1265
1160
  const auto key = NapiSlice(env, GetProperty(env, element, "key"));
1266
1161
  const auto value = NapiSlice(env, GetProperty(env, element, "value"));
@@ -1273,7 +1168,7 @@ NAPI_METHOD(batch_do) {
1273
1168
  return ToError(env, database->db_->Write(options, &batch));
1274
1169
  }
1275
1170
 
1276
- static void FinalizeBatch (napi_env env, void* data, void* hint) {
1171
+ static void FinalizeBatch(napi_env env, void* data, void* hint) {
1277
1172
  if (data) {
1278
1173
  delete reinterpret_cast<rocksdb::WriteBatch*>(data);
1279
1174
  }
@@ -1323,7 +1218,7 @@ NAPI_METHOD(batch_clear) {
1323
1218
  }
1324
1219
 
1325
1220
  NAPI_METHOD(batch_write) {
1326
- NAPI_ARGV(4);
1221
+ NAPI_ARGV(3);
1327
1222
  NAPI_DB_CONTEXT();
1328
1223
 
1329
1224
  rocksdb::WriteBatch* batch;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/rocksdb",
3
- "version": "5.2.27",
3
+ "version": "5.2.30",
4
4
  "description": "A low-level Node.js RocksDB binding",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
Binary file
index 3f421a6..6a452a6 100755
Binary file