@nxtedition/rocksdb 5.2.27 → 5.2.28

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