@nxtedition/rocksdb 5.2.2 → 5.2.13
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 +597 -100
- package/binding.gyp +5 -4
- package/chained-batch.js +13 -18
- package/deps/rocksdb/rocksdb/README.md +32 -0
- package/deps/rocksdb/rocksdb/hdfs/README +23 -0
- package/deps/rocksdb/rocksdb/port/README +10 -0
- package/deps/rocksdb/rocksdb/third-party/folly/folly/synchronization/test/DistributedMutexTest.cpp +1145 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_tree/lib/README +13 -0
- package/deps/rocksdb/rocksdb.gyp +44 -62
- package/deps/snappy/snappy-1.1.7/README.md +149 -0
- package/index.js +189 -0
- package/iterator.js +88 -24
- package/package.json +23 -17
- package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
- package/deps/rocksdb/rocksdb/cmake/modules/CxxFlags.cmake +0 -7
- package/deps/rocksdb/rocksdb/cmake/modules/FindJeMalloc.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/FindNUMA.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/FindSnappy.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/FindTBB.cmake +0 -33
- package/deps/rocksdb/rocksdb/cmake/modules/Findgflags.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/Findlz4.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/Findzstd.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/ReadVersion.cmake +0 -10
- package/leveldown.js +0 -113
- package/package-lock.json +0 -23687
package/binding.cc
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
namespace leveldb = rocksdb;
|
|
18
18
|
|
|
19
19
|
#include <set>
|
|
20
|
-
#include <
|
|
20
|
+
#include <memory>
|
|
21
|
+
#include <string>
|
|
21
22
|
#include <vector>
|
|
22
23
|
|
|
23
24
|
class NullLogger : public rocksdb::Logger {
|
|
@@ -63,28 +64,38 @@ static bool IsObject (napi_env env, napi_value value) {
|
|
|
63
64
|
|
|
64
65
|
static napi_value CreateError (napi_env env, const std::string& str) {
|
|
65
66
|
napi_value msg;
|
|
66
|
-
napi_create_string_utf8(env, str.
|
|
67
|
+
napi_create_string_utf8(env, str.data(), str.size(), &msg);
|
|
67
68
|
napi_value error;
|
|
68
69
|
napi_create_error(env, nullptr, msg, &error);
|
|
69
70
|
return error;
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
static
|
|
73
|
+
static napi_value CreateCodeError (napi_env env, const std::string& code, const std::string& msg) {
|
|
74
|
+
napi_value codeValue;
|
|
75
|
+
napi_create_string_utf8(env, code.data(), code.size(), &codeValue);
|
|
76
|
+
napi_value msgValue;
|
|
77
|
+
napi_create_string_utf8(env, msg.data(), msg.size(), &msgValue);
|
|
78
|
+
napi_value error;
|
|
79
|
+
napi_create_error(env, codeValue, msgValue, &error);
|
|
80
|
+
return error;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static bool HasProperty (napi_env env, napi_value obj, const std::string& key) {
|
|
73
84
|
bool has = false;
|
|
74
|
-
napi_has_named_property(env, obj, key, &has);
|
|
85
|
+
napi_has_named_property(env, obj, key.data(), &has);
|
|
75
86
|
return has;
|
|
76
87
|
}
|
|
77
88
|
|
|
78
|
-
static napi_value GetProperty (napi_env env, napi_value obj, const
|
|
89
|
+
static napi_value GetProperty (napi_env env, napi_value obj, const std::string& key) {
|
|
79
90
|
napi_value value;
|
|
80
|
-
napi_get_named_property(env, obj, key, &value);
|
|
91
|
+
napi_get_named_property(env, obj, key.data(), &value);
|
|
81
92
|
return value;
|
|
82
93
|
}
|
|
83
94
|
|
|
84
|
-
static bool BooleanProperty (napi_env env, napi_value obj, const
|
|
95
|
+
static bool BooleanProperty (napi_env env, napi_value obj, const std::string& key,
|
|
85
96
|
bool defaultValue) {
|
|
86
|
-
if (HasProperty(env, obj, key)) {
|
|
87
|
-
const auto value = GetProperty(env, obj, key);
|
|
97
|
+
if (HasProperty(env, obj, key.data())) {
|
|
98
|
+
const auto value = GetProperty(env, obj, key.data());
|
|
88
99
|
bool result;
|
|
89
100
|
napi_get_value_bool(env, value, &result);
|
|
90
101
|
return result;
|
|
@@ -93,10 +104,23 @@ static bool BooleanProperty (napi_env env, napi_value obj, const char* key,
|
|
|
93
104
|
return defaultValue;
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
static
|
|
107
|
+
static bool EncodingIsBuffer (napi_env env, napi_value obj, const std::string& option) {
|
|
108
|
+
napi_value value;
|
|
109
|
+
size_t size;
|
|
110
|
+
|
|
111
|
+
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) {
|
|
113
|
+
// Value is either "buffer" or "utf8" so we can tell them apart just by size
|
|
114
|
+
return size == 6;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static uint32_t Uint32Property (napi_env env, napi_value obj, const std::string& key,
|
|
97
121
|
uint32_t defaultValue) {
|
|
98
|
-
if (HasProperty(env, obj, key)) {
|
|
99
|
-
const auto value = GetProperty(env, obj, key);
|
|
122
|
+
if (HasProperty(env, obj, key.data())) {
|
|
123
|
+
const auto value = GetProperty(env, obj, key.data());
|
|
100
124
|
uint32_t result;
|
|
101
125
|
napi_get_value_uint32(env, value, &result);
|
|
102
126
|
return result;
|
|
@@ -105,10 +129,10 @@ static uint32_t Uint32Property (napi_env env, napi_value obj, const char* key,
|
|
|
105
129
|
return defaultValue;
|
|
106
130
|
}
|
|
107
131
|
|
|
108
|
-
static int Int32Property (napi_env env, napi_value obj, const
|
|
132
|
+
static int Int32Property (napi_env env, napi_value obj, const std::string& key,
|
|
109
133
|
int defaultValue) {
|
|
110
|
-
if (HasProperty(env, obj, key)) {
|
|
111
|
-
const auto value = GetProperty(env, obj, key);
|
|
134
|
+
if (HasProperty(env, obj, key.data())) {
|
|
135
|
+
const auto value = GetProperty(env, obj, key.data());
|
|
112
136
|
int result;
|
|
113
137
|
napi_get_value_int32(env, value, &result);
|
|
114
138
|
return result;
|
|
@@ -117,7 +141,7 @@ static int Int32Property (napi_env env, napi_value obj, const char* key,
|
|
|
117
141
|
return defaultValue;
|
|
118
142
|
}
|
|
119
143
|
|
|
120
|
-
static std::string ToString (napi_env env, napi_value from) {
|
|
144
|
+
static std::string ToString (napi_env env, napi_value from, const std::string& defaultValue = "") {
|
|
121
145
|
if (IsString(env, from)) {
|
|
122
146
|
size_t length = 0;
|
|
123
147
|
napi_get_value_string_utf8(env, from, nullptr, 0, &length);
|
|
@@ -131,10 +155,10 @@ static std::string ToString (napi_env env, napi_value from) {
|
|
|
131
155
|
return std::string(buf, length);
|
|
132
156
|
}
|
|
133
157
|
|
|
134
|
-
return
|
|
158
|
+
return defaultValue;
|
|
135
159
|
}
|
|
136
160
|
|
|
137
|
-
static std::string StringProperty (napi_env env, napi_value obj, const
|
|
161
|
+
static std::string StringProperty (napi_env env, napi_value obj, const std::string& key) {
|
|
138
162
|
if (HasProperty(env, obj, key)) {
|
|
139
163
|
napi_value value = GetProperty(env, obj, key);
|
|
140
164
|
if (IsString(env, value)) {
|
|
@@ -158,16 +182,13 @@ static size_t StringOrBufferLength (napi_env env, napi_value value) {
|
|
|
158
182
|
return size;
|
|
159
183
|
}
|
|
160
184
|
|
|
161
|
-
static std::
|
|
185
|
+
static std::string* RangeOption (napi_env env, napi_value opts, const std::string& name) {
|
|
162
186
|
if (HasProperty(env, opts, name)) {
|
|
163
187
|
const auto value = GetProperty(env, opts, name);
|
|
164
|
-
|
|
165
|
-
if (StringOrBufferLength(env, value) > 0) {
|
|
166
|
-
return ToString(env, value);
|
|
167
|
-
}
|
|
188
|
+
return new std::string(ToString(env, value));
|
|
168
189
|
}
|
|
169
190
|
|
|
170
|
-
return
|
|
191
|
+
return nullptr;
|
|
171
192
|
}
|
|
172
193
|
|
|
173
194
|
static std::vector<std::string> KeyArray (napi_env env, napi_value arr) {
|
|
@@ -199,13 +220,12 @@ static napi_status CallFunction (napi_env env,
|
|
|
199
220
|
return napi_call_function(env, global, callback, argc, argv, nullptr);
|
|
200
221
|
}
|
|
201
222
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
napi_create_buffer_copy(env, s->size(), s->data(), nullptr, &result);
|
|
223
|
+
template <typename T>
|
|
224
|
+
void Convert (napi_env env, const T& s, bool asBuffer, napi_value& result) {
|
|
225
|
+
if (asBuffer) {
|
|
226
|
+
napi_create_buffer_copy(env, s.size(), s.data(), nullptr, &result);
|
|
207
227
|
} else {
|
|
208
|
-
napi_create_string_utf8(env, s
|
|
228
|
+
napi_create_string_utf8(env, s.data(), s.size(), &result);
|
|
209
229
|
}
|
|
210
230
|
}
|
|
211
231
|
|
|
@@ -247,8 +267,9 @@ struct BaseWorker {
|
|
|
247
267
|
self->DoExecute();
|
|
248
268
|
}
|
|
249
269
|
|
|
250
|
-
|
|
270
|
+
bool SetStatus (const leveldb::Status& status) {
|
|
251
271
|
status_ = status;
|
|
272
|
+
return status.ok();
|
|
252
273
|
}
|
|
253
274
|
|
|
254
275
|
virtual void DoExecute () = 0;
|
|
@@ -278,7 +299,28 @@ struct BaseWorker {
|
|
|
278
299
|
}
|
|
279
300
|
|
|
280
301
|
virtual void HandleErrorCallback (napi_env env, napi_value callback) {
|
|
281
|
-
|
|
302
|
+
napi_value argv;
|
|
303
|
+
|
|
304
|
+
const auto msg = status_.ToString();
|
|
305
|
+
|
|
306
|
+
if (status_.IsNotFound()) {
|
|
307
|
+
argv = CreateCodeError(env, "LEVEL_NOT_FOUND", msg);
|
|
308
|
+
} else if (status_.IsCorruption()) {
|
|
309
|
+
argv = CreateCodeError(env, "LEVEL_CORRUPTION", msg);
|
|
310
|
+
} else if (status_.IsIOError()) {
|
|
311
|
+
if (msg.find("IO error: lock ") != std::string::npos) { // env_posix.cc
|
|
312
|
+
argv = CreateCodeError(env, "LEVEL_LOCKED", msg);
|
|
313
|
+
} else if (msg.find("IO error: LockFile ") != std::string::npos) { // env_win.cc
|
|
314
|
+
argv = CreateCodeError(env, "LEVEL_LOCKED", msg);
|
|
315
|
+
} else if (msg.find("IO error: While lock file") != std::string::npos) { // env_mac.cc
|
|
316
|
+
argv = CreateCodeError(env, "LEVEL_LOCKED", msg);
|
|
317
|
+
} else {
|
|
318
|
+
argv = CreateCodeError(env, "LEVEL_IO_ERROR", msg);
|
|
319
|
+
}
|
|
320
|
+
} else {
|
|
321
|
+
argv = CreateError(env, msg);
|
|
322
|
+
}
|
|
323
|
+
|
|
282
324
|
CallFunction(env, callback, 1, &argv);
|
|
283
325
|
}
|
|
284
326
|
|
|
@@ -333,18 +375,18 @@ struct Database {
|
|
|
333
375
|
leveldb::Status Put (const leveldb::WriteOptions& options,
|
|
334
376
|
const std::string& key,
|
|
335
377
|
const std::string& value) {
|
|
336
|
-
return db_->Put(options, key, value);
|
|
378
|
+
return db_->Put(options, db_->DefaultColumnFamily(), key, value);
|
|
337
379
|
}
|
|
338
380
|
|
|
339
381
|
leveldb::Status Get (const leveldb::ReadOptions& options,
|
|
340
382
|
const std::string& key,
|
|
341
|
-
|
|
342
|
-
return db_->Get(options, key, &value);
|
|
383
|
+
rocksdb::PinnableSlice& value) {
|
|
384
|
+
return db_->Get(options, db_->DefaultColumnFamily(), key, &value);
|
|
343
385
|
}
|
|
344
386
|
|
|
345
387
|
leveldb::Status Del (const leveldb::WriteOptions& options,
|
|
346
388
|
const std::string& key) {
|
|
347
|
-
return db_->Delete(options, key);
|
|
389
|
+
return db_->Delete(options, db_->DefaultColumnFamily(), key);
|
|
348
390
|
}
|
|
349
391
|
|
|
350
392
|
leveldb::Status WriteBatch (const leveldb::WriteOptions& options,
|
|
@@ -352,6 +394,18 @@ struct Database {
|
|
|
352
394
|
return db_->Write(options, batch);
|
|
353
395
|
}
|
|
354
396
|
|
|
397
|
+
uint64_t ApproximateSize (const leveldb::Range* range) {
|
|
398
|
+
uint64_t size = 0;
|
|
399
|
+
db_->GetApproximateSizes(range, 1, &size);
|
|
400
|
+
return size;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
void CompactRange (const leveldb::Slice* start,
|
|
404
|
+
const leveldb::Slice* end) {
|
|
405
|
+
rocksdb::CompactRangeOptions options;
|
|
406
|
+
db_->CompactRange(options, start, end);
|
|
407
|
+
}
|
|
408
|
+
|
|
355
409
|
void GetProperty (const std::string& property, std::string& value) {
|
|
356
410
|
db_->GetProperty(property, &value);
|
|
357
411
|
}
|
|
@@ -424,10 +478,10 @@ struct PriorityWorker : public BaseWorker {
|
|
|
424
478
|
struct BaseIterator {
|
|
425
479
|
BaseIterator(Database* database,
|
|
426
480
|
const bool reverse,
|
|
427
|
-
const std::
|
|
428
|
-
const std::
|
|
429
|
-
const std::
|
|
430
|
-
const std::
|
|
481
|
+
const std::string* lt,
|
|
482
|
+
const std::string* lte,
|
|
483
|
+
const std::string* gt,
|
|
484
|
+
const std::string* gte,
|
|
431
485
|
const int limit,
|
|
432
486
|
const bool fillCache)
|
|
433
487
|
: database_(database),
|
|
@@ -451,6 +505,11 @@ struct BaseIterator {
|
|
|
451
505
|
|
|
452
506
|
virtual ~BaseIterator () {
|
|
453
507
|
assert(!dbIterator_);
|
|
508
|
+
|
|
509
|
+
delete lt_;
|
|
510
|
+
delete lte_;
|
|
511
|
+
delete gt_;
|
|
512
|
+
delete gte_;
|
|
454
513
|
}
|
|
455
514
|
|
|
456
515
|
bool DidSeek () const {
|
|
@@ -571,10 +630,19 @@ struct BaseIterator {
|
|
|
571
630
|
}
|
|
572
631
|
|
|
573
632
|
bool OutOfRange (const leveldb::Slice& target) const {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
633
|
+
if (lte_) {
|
|
634
|
+
if (target.compare(*lte_) > 0) return true;
|
|
635
|
+
} else if (lt_) {
|
|
636
|
+
if (target.compare(*lt_) >= 0) return true;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (gte_) {
|
|
640
|
+
if (target.compare(*gte_) < 0) return true;
|
|
641
|
+
} else if (gt_) {
|
|
642
|
+
if (target.compare(*gt_) <= 0) return true;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return false;
|
|
578
646
|
}
|
|
579
647
|
|
|
580
648
|
Database* database_;
|
|
@@ -584,10 +652,10 @@ private:
|
|
|
584
652
|
leveldb::Iterator* dbIterator_;
|
|
585
653
|
bool didSeek_;
|
|
586
654
|
const bool reverse_;
|
|
587
|
-
const std::
|
|
588
|
-
const std::
|
|
589
|
-
const std::
|
|
590
|
-
const std::
|
|
655
|
+
const std::string* lt_;
|
|
656
|
+
const std::string* lte_;
|
|
657
|
+
const std::string* gt_;
|
|
658
|
+
const std::string* gte_;
|
|
591
659
|
const int limit_;
|
|
592
660
|
int count_;
|
|
593
661
|
};
|
|
@@ -598,21 +666,21 @@ struct Iterator final : public BaseIterator {
|
|
|
598
666
|
const bool keys,
|
|
599
667
|
const bool values,
|
|
600
668
|
const int limit,
|
|
601
|
-
const std::
|
|
602
|
-
const std::
|
|
603
|
-
const std::
|
|
604
|
-
const std::
|
|
669
|
+
const std::string* lt,
|
|
670
|
+
const std::string* lte,
|
|
671
|
+
const std::string* gt,
|
|
672
|
+
const std::string* gte,
|
|
605
673
|
const bool fillCache,
|
|
606
674
|
const bool keyAsBuffer,
|
|
607
675
|
const bool valueAsBuffer,
|
|
608
|
-
const uint32_t
|
|
676
|
+
const uint32_t highWaterMarkBytes)
|
|
609
677
|
: BaseIterator(database, reverse, lt, lte, gt, gte, limit, fillCache),
|
|
610
678
|
keys_(keys),
|
|
611
679
|
values_(values),
|
|
612
680
|
keyAsBuffer_(keyAsBuffer),
|
|
613
681
|
valueAsBuffer_(valueAsBuffer),
|
|
614
|
-
|
|
615
|
-
|
|
682
|
+
highWaterMarkBytes_(highWaterMarkBytes),
|
|
683
|
+
first_(true),
|
|
616
684
|
nexting_(false),
|
|
617
685
|
isClosing_(false),
|
|
618
686
|
closeWorker_(nullptr),
|
|
@@ -631,34 +699,34 @@ struct Iterator final : public BaseIterator {
|
|
|
631
699
|
|
|
632
700
|
bool ReadMany (uint32_t size) {
|
|
633
701
|
cache_.clear();
|
|
702
|
+
cache_.reserve(size * 2);
|
|
634
703
|
size_t bytesRead = 0;
|
|
635
704
|
|
|
636
705
|
while (true) {
|
|
637
|
-
if (
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
if (keys_) {
|
|
641
|
-
const auto& slice = CurrentKey();
|
|
642
|
-
cache_.emplace_back(slice.data(), slice.size());
|
|
643
|
-
bytesRead += slice.size();
|
|
644
|
-
} else {
|
|
645
|
-
cache_.emplace_back("");
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
if (values_) {
|
|
649
|
-
const auto& slice = CurrentValue();
|
|
650
|
-
cache_.emplace_back(slice.data(), slice.size());
|
|
651
|
-
bytesRead += slice.size();
|
|
652
|
-
} else {
|
|
653
|
-
cache_.emplace_back("");
|
|
654
|
-
}
|
|
706
|
+
if (!first_) Next();
|
|
707
|
+
else first_ = false;
|
|
655
708
|
|
|
656
|
-
if (!
|
|
657
|
-
|
|
658
|
-
|
|
709
|
+
if (!Valid() || !Increment()) break;
|
|
710
|
+
|
|
711
|
+
if (keys_ && values_) {
|
|
712
|
+
auto k = CurrentKey();
|
|
713
|
+
auto v = CurrentValue();
|
|
714
|
+
cache_.emplace_back(k.data(), k.size());
|
|
715
|
+
cache_.emplace_back(v.data(), v.size());
|
|
716
|
+
bytesRead += k.size() + v.size();
|
|
717
|
+
} else if (keys_) {
|
|
718
|
+
auto k = CurrentKey();
|
|
719
|
+
cache_.emplace_back(k.data(), k.size());
|
|
720
|
+
cache_.push_back({});
|
|
721
|
+
bytesRead += k.size();
|
|
722
|
+
} else if (values_) {
|
|
723
|
+
auto v = CurrentValue();
|
|
724
|
+
cache_.push_back({});
|
|
725
|
+
cache_.emplace_back(v.data(), v.size());
|
|
726
|
+
bytesRead += v.size();
|
|
659
727
|
}
|
|
660
728
|
|
|
661
|
-
if (bytesRead >
|
|
729
|
+
if (bytesRead > highWaterMarkBytes_ || cache_.size() / 2 >= size) {
|
|
662
730
|
return true;
|
|
663
731
|
}
|
|
664
732
|
}
|
|
@@ -670,8 +738,8 @@ struct Iterator final : public BaseIterator {
|
|
|
670
738
|
const bool values_;
|
|
671
739
|
const bool keyAsBuffer_;
|
|
672
740
|
const bool valueAsBuffer_;
|
|
673
|
-
const uint32_t
|
|
674
|
-
bool
|
|
741
|
+
const uint32_t highWaterMarkBytes_;
|
|
742
|
+
bool first_;
|
|
675
743
|
bool nexting_;
|
|
676
744
|
bool isClosing_;
|
|
677
745
|
BaseWorker* closeWorker_;
|
|
@@ -687,7 +755,7 @@ private:
|
|
|
687
755
|
* the guarantee that no db operations will be in-flight at this time.
|
|
688
756
|
*/
|
|
689
757
|
static void env_cleanup_hook (void* arg) {
|
|
690
|
-
Database* database = (
|
|
758
|
+
Database* database = reinterpret_cast<Database*>(arg);
|
|
691
759
|
|
|
692
760
|
// Do everything that db_close() does but synchronously. We're expecting that GC
|
|
693
761
|
// did not (yet) collect the database because that would be a user mistake (not
|
|
@@ -697,8 +765,8 @@ static void env_cleanup_hook (void* arg) {
|
|
|
697
765
|
// be a safe noop if called before db_open() or after db_close().
|
|
698
766
|
if (database && database->db_) {
|
|
699
767
|
// TODO: does not do `napi_delete_reference(env, iterator->ref_)`. Problem?
|
|
700
|
-
for (auto it
|
|
701
|
-
|
|
768
|
+
for (auto it : database->iterators_) {
|
|
769
|
+
it->Close();
|
|
702
770
|
}
|
|
703
771
|
|
|
704
772
|
// Having closed the iterators (and released snapshots) we can safely close.
|
|
@@ -866,8 +934,8 @@ NAPI_METHOD(db_close) {
|
|
|
866
934
|
napi_value noop;
|
|
867
935
|
napi_create_function(env, nullptr, 0, noop_callback, nullptr, &noop);
|
|
868
936
|
|
|
869
|
-
for (auto it
|
|
870
|
-
iterator_do_close(env,
|
|
937
|
+
for (auto it : database->iterators_) {
|
|
938
|
+
iterator_do_close(env, it, noop);
|
|
871
939
|
}
|
|
872
940
|
|
|
873
941
|
auto worker = new CloseWorker(env, database, callback);
|
|
@@ -881,6 +949,90 @@ NAPI_METHOD(db_close) {
|
|
|
881
949
|
return 0;
|
|
882
950
|
}
|
|
883
951
|
|
|
952
|
+
struct PutWorker final : public PriorityWorker {
|
|
953
|
+
PutWorker (napi_env env,
|
|
954
|
+
Database* database,
|
|
955
|
+
napi_value callback,
|
|
956
|
+
const std::string& key,
|
|
957
|
+
const std::string& value,
|
|
958
|
+
bool sync)
|
|
959
|
+
: PriorityWorker(env, database, callback, "rocks_level.db.put"),
|
|
960
|
+
key_(key), value_(value), sync_(sync) {
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
void DoExecute () override {
|
|
964
|
+
leveldb::WriteOptions options;
|
|
965
|
+
options.sync = sync_;
|
|
966
|
+
SetStatus(database_->Put(options, key_, value_));
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
const std::string key_;
|
|
970
|
+
const std::string value_;
|
|
971
|
+
const bool sync_;
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
NAPI_METHOD(db_put) {
|
|
975
|
+
NAPI_ARGV(5);
|
|
976
|
+
NAPI_DB_CONTEXT();
|
|
977
|
+
|
|
978
|
+
const auto key = ToString(env, argv[1]);
|
|
979
|
+
const auto value = ToString(env, argv[2]);
|
|
980
|
+
const auto sync = BooleanProperty(env, argv[3], "sync", false);
|
|
981
|
+
const auto callback = argv[4];
|
|
982
|
+
|
|
983
|
+
auto worker = new PutWorker(env, database, callback, key, value, sync);
|
|
984
|
+
worker->Queue(env);
|
|
985
|
+
|
|
986
|
+
return 0;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
struct GetWorker final : public PriorityWorker {
|
|
990
|
+
GetWorker (napi_env env,
|
|
991
|
+
Database* database,
|
|
992
|
+
napi_value callback,
|
|
993
|
+
const std::string& key,
|
|
994
|
+
const bool asBuffer,
|
|
995
|
+
const bool fillCache)
|
|
996
|
+
: PriorityWorker(env, database, callback, "rocks_level.db.get"),
|
|
997
|
+
key_(key), asBuffer_(asBuffer), fillCache_(fillCache) {
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
void DoExecute () override {
|
|
1001
|
+
leveldb::ReadOptions options;
|
|
1002
|
+
options.fill_cache = fillCache_;
|
|
1003
|
+
SetStatus(database_->Get(options, key_, value_));
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
void HandleOKCallback (napi_env env, napi_value callback) override {
|
|
1007
|
+
napi_value argv[2];
|
|
1008
|
+
napi_get_null(env, &argv[0]);
|
|
1009
|
+
Convert(env, std::move(value_), asBuffer_, argv[1]);
|
|
1010
|
+
CallFunction(env, callback, 2, argv);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
private:
|
|
1014
|
+
const std::string key_;
|
|
1015
|
+
rocksdb::PinnableSlice value_;
|
|
1016
|
+
const bool asBuffer_;
|
|
1017
|
+
const bool fillCache_;
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
NAPI_METHOD(db_get) {
|
|
1021
|
+
NAPI_ARGV(4);
|
|
1022
|
+
NAPI_DB_CONTEXT();
|
|
1023
|
+
|
|
1024
|
+
const auto key = ToString(env, argv[1]);
|
|
1025
|
+
const auto options = argv[2];
|
|
1026
|
+
const auto asBuffer = EncodingIsBuffer(env, options, "valueEncoding");
|
|
1027
|
+
const auto fillCache = BooleanProperty(env, options, "fillCache", true);
|
|
1028
|
+
const auto callback = argv[3];
|
|
1029
|
+
|
|
1030
|
+
auto worker = new GetWorker(env, database, callback, key, asBuffer, fillCache);
|
|
1031
|
+
worker->Queue(env);
|
|
1032
|
+
|
|
1033
|
+
return 0;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
884
1036
|
struct GetManyWorker final : public PriorityWorker {
|
|
885
1037
|
GetManyWorker (napi_env env,
|
|
886
1038
|
Database* database,
|
|
@@ -907,18 +1059,21 @@ struct GetManyWorker final : public PriorityWorker {
|
|
|
907
1059
|
options.snapshot = snapshot_;
|
|
908
1060
|
options.fill_cache = fillCache_;
|
|
909
1061
|
|
|
1062
|
+
rocksdb::PinnableSlice value;
|
|
1063
|
+
|
|
910
1064
|
for (const auto& key: keys_) {
|
|
911
|
-
std::string value;
|
|
912
1065
|
const auto status = database_->Get(options, key, value);
|
|
913
1066
|
|
|
914
1067
|
if (status.ok()) {
|
|
915
|
-
cache_.
|
|
1068
|
+
cache_.emplace_back(std::move(value));
|
|
916
1069
|
} else if (status.IsNotFound()) {
|
|
917
|
-
cache_.
|
|
1070
|
+
cache_.emplace_back(nullptr);
|
|
918
1071
|
} else {
|
|
919
1072
|
SetStatus(status);
|
|
920
1073
|
break;
|
|
921
1074
|
}
|
|
1075
|
+
|
|
1076
|
+
value.Reset();
|
|
922
1077
|
}
|
|
923
1078
|
|
|
924
1079
|
database_->ReleaseSnapshot(snapshot_);
|
|
@@ -933,7 +1088,11 @@ struct GetManyWorker final : public PriorityWorker {
|
|
|
933
1088
|
|
|
934
1089
|
for (size_t idx = 0; idx < size; idx++) {
|
|
935
1090
|
napi_value element;
|
|
936
|
-
|
|
1091
|
+
if (cache_[idx].GetSelf() != nullptr) {
|
|
1092
|
+
Convert(env, cache_[idx], valueAsBuffer_, element);
|
|
1093
|
+
} else {
|
|
1094
|
+
napi_get_undefined(env, &element);
|
|
1095
|
+
}
|
|
937
1096
|
napi_set_element(env, array, static_cast<uint32_t>(idx), element);
|
|
938
1097
|
}
|
|
939
1098
|
|
|
@@ -946,7 +1105,7 @@ struct GetManyWorker final : public PriorityWorker {
|
|
|
946
1105
|
private:
|
|
947
1106
|
const std::vector<std::string> keys_;
|
|
948
1107
|
const bool valueAsBuffer_;
|
|
949
|
-
std::vector<
|
|
1108
|
+
std::vector<rocksdb::PinnableSlice> cache_;
|
|
950
1109
|
const bool fillCache_;
|
|
951
1110
|
const leveldb::Snapshot* snapshot_;
|
|
952
1111
|
};
|
|
@@ -957,7 +1116,7 @@ NAPI_METHOD(db_get_many) {
|
|
|
957
1116
|
|
|
958
1117
|
const auto keys = KeyArray(env, argv[1]);
|
|
959
1118
|
const auto options = argv[2];
|
|
960
|
-
const bool asBuffer =
|
|
1119
|
+
const bool asBuffer = EncodingIsBuffer(env, options, "valueEncoding");
|
|
961
1120
|
const bool fillCache = BooleanProperty(env, options, "fillCache", true);
|
|
962
1121
|
const auto callback = argv[3];
|
|
963
1122
|
|
|
@@ -967,6 +1126,257 @@ NAPI_METHOD(db_get_many) {
|
|
|
967
1126
|
return 0;
|
|
968
1127
|
}
|
|
969
1128
|
|
|
1129
|
+
struct DelWorker final : public PriorityWorker {
|
|
1130
|
+
DelWorker (napi_env env,
|
|
1131
|
+
Database* database,
|
|
1132
|
+
napi_value callback,
|
|
1133
|
+
const std::string& key,
|
|
1134
|
+
bool sync)
|
|
1135
|
+
: PriorityWorker(env, database, callback, "rocks_level.db.del"),
|
|
1136
|
+
key_(key), sync_(sync) {
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
void DoExecute () override {
|
|
1140
|
+
leveldb::WriteOptions options;
|
|
1141
|
+
options.sync = sync_;
|
|
1142
|
+
SetStatus(database_->Del(options, key_));
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
const std::string key_;
|
|
1146
|
+
const bool sync_;
|
|
1147
|
+
};
|
|
1148
|
+
|
|
1149
|
+
NAPI_METHOD(db_del) {
|
|
1150
|
+
NAPI_ARGV(4);
|
|
1151
|
+
NAPI_DB_CONTEXT();
|
|
1152
|
+
|
|
1153
|
+
const auto key = ToString(env, argv[1]);
|
|
1154
|
+
const auto sync = BooleanProperty(env, argv[2], "sync", false);
|
|
1155
|
+
const auto callback = argv[3];
|
|
1156
|
+
|
|
1157
|
+
auto worker = new DelWorker(env, database, callback, key, sync);
|
|
1158
|
+
worker->Queue(env);
|
|
1159
|
+
|
|
1160
|
+
return 0;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
struct ClearWorker final : public PriorityWorker {
|
|
1164
|
+
ClearWorker (napi_env env,
|
|
1165
|
+
Database* database,
|
|
1166
|
+
napi_value callback,
|
|
1167
|
+
const bool reverse,
|
|
1168
|
+
const int limit,
|
|
1169
|
+
const std::string* lt,
|
|
1170
|
+
const std::string* lte,
|
|
1171
|
+
const std::string* gt,
|
|
1172
|
+
const std::string* gte)
|
|
1173
|
+
: PriorityWorker(env, database, callback, "rocks_level.db.clear"),
|
|
1174
|
+
iterator_(database, reverse, lt, lte, gt, gte, limit, false) {
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
void DoExecute () override {
|
|
1178
|
+
iterator_.SeekToRange();
|
|
1179
|
+
|
|
1180
|
+
// TODO: add option
|
|
1181
|
+
const uint32_t hwm = 16 * 1024;
|
|
1182
|
+
leveldb::WriteBatch batch;
|
|
1183
|
+
|
|
1184
|
+
leveldb::WriteOptions options;
|
|
1185
|
+
options.sync = false;
|
|
1186
|
+
|
|
1187
|
+
while (true) {
|
|
1188
|
+
size_t bytesRead = 0;
|
|
1189
|
+
|
|
1190
|
+
while (bytesRead <= hwm && iterator_.Valid() && iterator_.Increment()) {
|
|
1191
|
+
const auto key = iterator_.CurrentKey();
|
|
1192
|
+
batch.Delete(key);
|
|
1193
|
+
bytesRead += key.size();
|
|
1194
|
+
iterator_.Next();
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
if (!SetStatus(iterator_.Status()) || bytesRead == 0) {
|
|
1198
|
+
break;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
if (!SetStatus(database_->WriteBatch(options, &batch))) {
|
|
1202
|
+
break;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
batch.Clear();
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
iterator_.Close();
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
private:
|
|
1212
|
+
BaseIterator iterator_;
|
|
1213
|
+
};
|
|
1214
|
+
|
|
1215
|
+
NAPI_METHOD(db_clear) {
|
|
1216
|
+
NAPI_ARGV(3);
|
|
1217
|
+
NAPI_DB_CONTEXT();
|
|
1218
|
+
|
|
1219
|
+
napi_value options = argv[1];
|
|
1220
|
+
napi_value callback = argv[2];
|
|
1221
|
+
|
|
1222
|
+
const auto reverse = BooleanProperty(env, options, "reverse", false);
|
|
1223
|
+
const auto limit = Int32Property(env, options, "limit", -1);
|
|
1224
|
+
|
|
1225
|
+
const auto lt = RangeOption(env, options, "lt");
|
|
1226
|
+
const auto lte = RangeOption(env, options, "lte");
|
|
1227
|
+
const auto gt = RangeOption(env, options, "gt");
|
|
1228
|
+
const auto gte = RangeOption(env, options, "gte");
|
|
1229
|
+
|
|
1230
|
+
auto worker = new ClearWorker(env, database, callback, reverse, limit, lt, lte, gt, gte);
|
|
1231
|
+
worker->Queue(env);
|
|
1232
|
+
|
|
1233
|
+
return 0;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
struct ApproximateSizeWorker final : public PriorityWorker {
|
|
1237
|
+
ApproximateSizeWorker (napi_env env,
|
|
1238
|
+
Database* database,
|
|
1239
|
+
napi_value callback,
|
|
1240
|
+
const std::string& start,
|
|
1241
|
+
const std::string& end)
|
|
1242
|
+
: PriorityWorker(env, database, callback, "rocks_level.db.approximate_size"),
|
|
1243
|
+
start_(start), end_(end) {}
|
|
1244
|
+
|
|
1245
|
+
void DoExecute () override {
|
|
1246
|
+
leveldb::Range range(start_, end_);
|
|
1247
|
+
size_ = database_->ApproximateSize(&range);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
void HandleOKCallback (napi_env env, napi_value callback) override {
|
|
1251
|
+
napi_value argv[2];
|
|
1252
|
+
napi_get_null(env, &argv[0]);
|
|
1253
|
+
napi_create_int64(env, size_, &argv[1]);
|
|
1254
|
+
CallFunction(env, callback, 2, argv);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
std::string start_;
|
|
1258
|
+
std::string end_;
|
|
1259
|
+
uint64_t size_;
|
|
1260
|
+
};
|
|
1261
|
+
|
|
1262
|
+
NAPI_METHOD(db_approximate_size) {
|
|
1263
|
+
NAPI_ARGV(4);
|
|
1264
|
+
NAPI_DB_CONTEXT();
|
|
1265
|
+
|
|
1266
|
+
const auto start = ToString(env, argv[1]);
|
|
1267
|
+
const auto end = ToString(env, argv[2]);
|
|
1268
|
+
const auto callback = argv[3];
|
|
1269
|
+
|
|
1270
|
+
auto worker = new ApproximateSizeWorker(env, database, callback, start, end);
|
|
1271
|
+
worker->Queue(env);
|
|
1272
|
+
|
|
1273
|
+
return 0;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
struct CompactRangeWorker final : public PriorityWorker {
|
|
1277
|
+
CompactRangeWorker (napi_env env,
|
|
1278
|
+
Database* database,
|
|
1279
|
+
napi_value callback,
|
|
1280
|
+
const std::string& start,
|
|
1281
|
+
const std::string& end)
|
|
1282
|
+
: PriorityWorker(env, database, callback, "rocks_level.db.compact_range"),
|
|
1283
|
+
start_(start), end_(end) {}
|
|
1284
|
+
|
|
1285
|
+
void DoExecute () override {
|
|
1286
|
+
leveldb::Slice start = start_;
|
|
1287
|
+
leveldb::Slice end = end_;
|
|
1288
|
+
database_->CompactRange(&start, &end);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
const std::string start_;
|
|
1292
|
+
const std::string end_;
|
|
1293
|
+
};
|
|
1294
|
+
|
|
1295
|
+
NAPI_METHOD(db_compact_range) {
|
|
1296
|
+
NAPI_ARGV(4);
|
|
1297
|
+
NAPI_DB_CONTEXT();
|
|
1298
|
+
|
|
1299
|
+
const auto start = ToString(env, argv[1]);
|
|
1300
|
+
const auto end = ToString(env, argv[2]);
|
|
1301
|
+
const auto callback = argv[3];
|
|
1302
|
+
|
|
1303
|
+
auto worker = new CompactRangeWorker(env, database, callback, start, end);
|
|
1304
|
+
worker->Queue(env);
|
|
1305
|
+
|
|
1306
|
+
return 0;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
NAPI_METHOD(db_get_property) {
|
|
1310
|
+
NAPI_ARGV(2);
|
|
1311
|
+
NAPI_DB_CONTEXT();
|
|
1312
|
+
|
|
1313
|
+
const auto property = ToString(env, argv[1]);
|
|
1314
|
+
|
|
1315
|
+
std::string value;
|
|
1316
|
+
database->GetProperty(property, value);
|
|
1317
|
+
|
|
1318
|
+
napi_value result;
|
|
1319
|
+
napi_create_string_utf8(env, value.data(), value.size(), &result);
|
|
1320
|
+
|
|
1321
|
+
return result;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
struct DestroyWorker final : public BaseWorker {
|
|
1325
|
+
DestroyWorker (napi_env env,
|
|
1326
|
+
const std::string& location,
|
|
1327
|
+
napi_value callback)
|
|
1328
|
+
: BaseWorker(env, nullptr, callback, "rocks_level.destroy_db"),
|
|
1329
|
+
location_(location) {}
|
|
1330
|
+
|
|
1331
|
+
~DestroyWorker () {}
|
|
1332
|
+
|
|
1333
|
+
void DoExecute () override {
|
|
1334
|
+
leveldb::Options options;
|
|
1335
|
+
SetStatus(leveldb::DestroyDB(location_, options));
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
const std::string location_;
|
|
1339
|
+
};
|
|
1340
|
+
|
|
1341
|
+
NAPI_METHOD(destroy_db) {
|
|
1342
|
+
NAPI_ARGV(2);
|
|
1343
|
+
|
|
1344
|
+
const auto location = ToString(env, argv[0]);
|
|
1345
|
+
const auto callback = argv[1];
|
|
1346
|
+
|
|
1347
|
+
auto worker = new DestroyWorker(env, location, callback);
|
|
1348
|
+
worker->Queue(env);
|
|
1349
|
+
|
|
1350
|
+
return 0;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
struct RepairWorker final : public BaseWorker {
|
|
1354
|
+
RepairWorker (napi_env env,
|
|
1355
|
+
const std::string& location,
|
|
1356
|
+
napi_value callback)
|
|
1357
|
+
: BaseWorker(env, nullptr, callback, "rocks_level.repair_db"),
|
|
1358
|
+
location_(location) {}
|
|
1359
|
+
|
|
1360
|
+
void DoExecute () override {
|
|
1361
|
+
leveldb::Options options;
|
|
1362
|
+
SetStatus(leveldb::RepairDB(location_, options));
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
const std::string location_;
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1368
|
+
NAPI_METHOD(repair_db) {
|
|
1369
|
+
NAPI_ARGV(2);
|
|
1370
|
+
|
|
1371
|
+
const auto location = ToString(env, argv[1]);
|
|
1372
|
+
const auto callback = argv[1];
|
|
1373
|
+
|
|
1374
|
+
auto worker = new RepairWorker(env, location, callback);
|
|
1375
|
+
worker->Queue(env);
|
|
1376
|
+
|
|
1377
|
+
return 0;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
970
1380
|
static void FinalizeIterator (napi_env env, void* data, void* hint) {
|
|
971
1381
|
if (data) {
|
|
972
1382
|
delete reinterpret_cast<Iterator*>(data);
|
|
@@ -982,10 +1392,10 @@ NAPI_METHOD(iterator_init) {
|
|
|
982
1392
|
const auto keys = BooleanProperty(env, options, "keys", true);
|
|
983
1393
|
const auto values = BooleanProperty(env, options, "values", true);
|
|
984
1394
|
const auto fillCache = BooleanProperty(env, options, "fillCache", false);
|
|
985
|
-
const
|
|
986
|
-
const
|
|
1395
|
+
const bool keyAsBuffer = EncodingIsBuffer(env, options, "keyEncoding");
|
|
1396
|
+
const bool valueAsBuffer = EncodingIsBuffer(env, options, "valueEncoding");
|
|
987
1397
|
const auto limit = Int32Property(env, options, "limit", -1);
|
|
988
|
-
const auto
|
|
1398
|
+
const auto highWaterMarkBytes = Uint32Property(env, options, "highWaterMarkBytes", 16 * 1024);
|
|
989
1399
|
|
|
990
1400
|
const auto lt = RangeOption(env, options, "lt");
|
|
991
1401
|
const auto lte = RangeOption(env, options, "lte");
|
|
@@ -994,7 +1404,7 @@ NAPI_METHOD(iterator_init) {
|
|
|
994
1404
|
|
|
995
1405
|
auto iterator = new Iterator(database, reverse, keys,
|
|
996
1406
|
values, limit, lt, lte, gt, gte, fillCache,
|
|
997
|
-
keyAsBuffer, valueAsBuffer,
|
|
1407
|
+
keyAsBuffer, valueAsBuffer, highWaterMarkBytes);
|
|
998
1408
|
napi_value result;
|
|
999
1409
|
|
|
1000
1410
|
NAPI_STATUS_THROWS(napi_create_external(env, iterator,
|
|
@@ -1017,7 +1427,7 @@ NAPI_METHOD(iterator_seek) {
|
|
|
1017
1427
|
}
|
|
1018
1428
|
|
|
1019
1429
|
const auto target = ToString(env, argv[1]);
|
|
1020
|
-
iterator->
|
|
1430
|
+
iterator->first_ = true;
|
|
1021
1431
|
iterator->Seek(target);
|
|
1022
1432
|
|
|
1023
1433
|
return 0;
|
|
@@ -1104,8 +1514,8 @@ struct NextWorker final : public BaseWorker {
|
|
|
1104
1514
|
Convert(env, iterator_->cache_[idx + 0], iterator_->keyAsBuffer_, key);
|
|
1105
1515
|
Convert(env, iterator_->cache_[idx + 1], iterator_->valueAsBuffer_, val);
|
|
1106
1516
|
|
|
1107
|
-
napi_set_element(env, result, static_cast<int>(
|
|
1108
|
-
napi_set_element(env, result, static_cast<int>(
|
|
1517
|
+
napi_set_element(env, result, static_cast<int>(idx + 0), key);
|
|
1518
|
+
napi_set_element(env, result, static_cast<int>(idx + 1), val);
|
|
1109
1519
|
}
|
|
1110
1520
|
|
|
1111
1521
|
iterator_->cache_.clear();
|
|
@@ -1146,9 +1556,8 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1146
1556
|
const auto callback = argv[2];
|
|
1147
1557
|
|
|
1148
1558
|
if (iterator->isClosing_) {
|
|
1149
|
-
|
|
1150
|
-
CallFunction(env, callback, 1, &argv);
|
|
1151
|
-
|
|
1559
|
+
napi_value argv = CreateCodeError(env, "LEVEL_ITERATOR_NOT_OPEN", "Iterator is not open");
|
|
1560
|
+
NAPI_STATUS_THROWS(CallFunction(env, callback, 1, &argv));
|
|
1152
1561
|
return 0;
|
|
1153
1562
|
}
|
|
1154
1563
|
|
|
@@ -1159,6 +1568,83 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1159
1568
|
return 0;
|
|
1160
1569
|
}
|
|
1161
1570
|
|
|
1571
|
+
/**
|
|
1572
|
+
* Worker class for batch write operation.
|
|
1573
|
+
*/
|
|
1574
|
+
struct BatchWorker final : public PriorityWorker {
|
|
1575
|
+
BatchWorker (napi_env env,
|
|
1576
|
+
Database* database,
|
|
1577
|
+
napi_value callback,
|
|
1578
|
+
leveldb::WriteBatch* batch,
|
|
1579
|
+
const bool sync,
|
|
1580
|
+
const bool hasData)
|
|
1581
|
+
: PriorityWorker(env, database, callback, "rocks_level.batch.do"),
|
|
1582
|
+
batch_(batch), hasData_(hasData) {
|
|
1583
|
+
options_.sync = sync;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
~BatchWorker () {
|
|
1587
|
+
delete batch_;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
void DoExecute () override {
|
|
1591
|
+
if (hasData_) {
|
|
1592
|
+
SetStatus(database_->WriteBatch(options_, batch_));
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
private:
|
|
1597
|
+
leveldb::WriteOptions options_;
|
|
1598
|
+
leveldb::WriteBatch* batch_;
|
|
1599
|
+
const bool hasData_;
|
|
1600
|
+
};
|
|
1601
|
+
|
|
1602
|
+
NAPI_METHOD(batch_do) {
|
|
1603
|
+
NAPI_ARGV(4);
|
|
1604
|
+
NAPI_DB_CONTEXT();
|
|
1605
|
+
|
|
1606
|
+
const auto array = argv[1];
|
|
1607
|
+
const auto sync = BooleanProperty(env, argv[2], "sync", false);
|
|
1608
|
+
const auto callback = argv[3];
|
|
1609
|
+
|
|
1610
|
+
uint32_t length;
|
|
1611
|
+
napi_get_array_length(env, array, &length);
|
|
1612
|
+
|
|
1613
|
+
leveldb::WriteBatch* batch = new leveldb::WriteBatch();
|
|
1614
|
+
bool hasData = false;
|
|
1615
|
+
|
|
1616
|
+
for (uint32_t i = 0; i < length; i++) {
|
|
1617
|
+
napi_value element;
|
|
1618
|
+
napi_get_element(env, array, i, &element);
|
|
1619
|
+
|
|
1620
|
+
if (!IsObject(env, element)) continue;
|
|
1621
|
+
|
|
1622
|
+
std::string type = StringProperty(env, element, "type");
|
|
1623
|
+
|
|
1624
|
+
if (type == "del") {
|
|
1625
|
+
if (!HasProperty(env, element, "key")) continue;
|
|
1626
|
+
const auto key = ToString(env, GetProperty(env, element, "key"));
|
|
1627
|
+
|
|
1628
|
+
batch->Delete(key);
|
|
1629
|
+
if (!hasData) hasData = true;
|
|
1630
|
+
} else if (type == "put") {
|
|
1631
|
+
if (!HasProperty(env, element, "key")) continue;
|
|
1632
|
+
if (!HasProperty(env, element, "value")) continue;
|
|
1633
|
+
|
|
1634
|
+
const auto key = ToString(env, GetProperty(env, element, "key"));
|
|
1635
|
+
const auto value = ToString(env, GetProperty(env, element, "value"));
|
|
1636
|
+
|
|
1637
|
+
batch->Put(key, value);
|
|
1638
|
+
if (!hasData) hasData = true;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
auto worker = new BatchWorker(env, database, callback, batch, sync, hasData);
|
|
1643
|
+
worker->Queue(env);
|
|
1644
|
+
|
|
1645
|
+
return 0;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1162
1648
|
static void FinalizeBatch (napi_env env, void* data, void* hint) {
|
|
1163
1649
|
if (data) {
|
|
1164
1650
|
delete reinterpret_cast<leveldb::WriteBatch*>(data);
|
|
@@ -1261,13 +1747,24 @@ NAPI_INIT() {
|
|
|
1261
1747
|
NAPI_EXPORT_FUNCTION(db_init);
|
|
1262
1748
|
NAPI_EXPORT_FUNCTION(db_open);
|
|
1263
1749
|
NAPI_EXPORT_FUNCTION(db_close);
|
|
1750
|
+
NAPI_EXPORT_FUNCTION(db_put);
|
|
1751
|
+
NAPI_EXPORT_FUNCTION(db_get);
|
|
1264
1752
|
NAPI_EXPORT_FUNCTION(db_get_many);
|
|
1753
|
+
NAPI_EXPORT_FUNCTION(db_del);
|
|
1754
|
+
NAPI_EXPORT_FUNCTION(db_clear);
|
|
1755
|
+
NAPI_EXPORT_FUNCTION(db_approximate_size);
|
|
1756
|
+
NAPI_EXPORT_FUNCTION(db_compact_range);
|
|
1757
|
+
NAPI_EXPORT_FUNCTION(db_get_property);
|
|
1758
|
+
|
|
1759
|
+
NAPI_EXPORT_FUNCTION(destroy_db);
|
|
1760
|
+
NAPI_EXPORT_FUNCTION(repair_db);
|
|
1265
1761
|
|
|
1266
1762
|
NAPI_EXPORT_FUNCTION(iterator_init);
|
|
1267
1763
|
NAPI_EXPORT_FUNCTION(iterator_seek);
|
|
1268
1764
|
NAPI_EXPORT_FUNCTION(iterator_close);
|
|
1269
1765
|
NAPI_EXPORT_FUNCTION(iterator_nextv);
|
|
1270
1766
|
|
|
1767
|
+
NAPI_EXPORT_FUNCTION(batch_do);
|
|
1271
1768
|
NAPI_EXPORT_FUNCTION(batch_init);
|
|
1272
1769
|
NAPI_EXPORT_FUNCTION(batch_put);
|
|
1273
1770
|
NAPI_EXPORT_FUNCTION(batch_del);
|