@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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
186
|
+
return ToString(env, value);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
return {};
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
static
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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
|
|
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
|
|
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
|
|
288
|
-
|
|
289
|
-
|
|
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
|
-
|
|
297
|
-
|
|
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 ~
|
|
277
|
+
virtual ~Worker() {}
|
|
306
278
|
|
|
307
|
-
static void Execute
|
|
308
|
-
auto self = reinterpret_cast<
|
|
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
|
|
313
|
-
auto self = reinterpret_cast<
|
|
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
|
|
304
|
+
virtual rocksdb::Status Execute(Database& database) = 0;
|
|
333
305
|
|
|
334
|
-
virtual void OnOk
|
|
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
|
|
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
|
|
345
|
-
}
|
|
314
|
+
virtual void Destroy(napi_env env) {}
|
|
346
315
|
|
|
347
|
-
void Queue
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
346
|
+
void DetachIterator(napi_env env, Iterator* iterator) {
|
|
385
347
|
iterators_.erase(iterator);
|
|
386
348
|
DecrementPriorityWork(env);
|
|
387
349
|
}
|
|
388
350
|
|
|
389
|
-
void IncrementPriorityWork
|
|
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
|
|
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
|
|
403
|
-
return priorityWork_ > 0;
|
|
404
|
-
}
|
|
362
|
+
bool HasPriorityWork() const { return priorityWork_ > 0; }
|
|
405
363
|
|
|
406
364
|
std::unique_ptr<rocksdb::DB> db_;
|
|
407
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
options.
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
|
|
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 (
|
|
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
|
|
418
|
+
void Seek(const std::string& target) {
|
|
494
419
|
didSeek_ = true;
|
|
495
420
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
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
|
|
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
|
-
|
|
554
|
-
return iterator_->value();
|
|
555
|
-
}
|
|
442
|
+
bool Increment() { return limit_ < 0 || ++count_ <= limit_; }
|
|
556
443
|
|
|
557
|
-
|
|
558
|
-
|
|
444
|
+
void Next() {
|
|
445
|
+
if (reverse_)
|
|
446
|
+
iterator_->Prev();
|
|
447
|
+
else
|
|
448
|
+
iterator_->Next();
|
|
559
449
|
}
|
|
560
450
|
|
|
561
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
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
|
|
500
|
+
void Detach(napi_env env) {
|
|
624
501
|
database_->DetachIterator(env, this);
|
|
625
|
-
if (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
|
|
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
|
|
648
|
-
// did not (yet) collect the database because that would be a user mistake
|
|
649
|
-
// closing their db) made during the lifetime of the environment. That's
|
|
650
|
-
// from an environment being torn down (like the main process or a
|
|
651
|
-
// where it's our responsibility to clean up. Note also, the
|
|
652
|
-
// be a safe noop if called before db_open() or after
|
|
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->
|
|
540
|
+
database->db_->Close();
|
|
661
541
|
}
|
|
662
542
|
}
|
|
663
543
|
|
|
664
|
-
static void FinalizeDatabase
|
|
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_)
|
|
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
|
|
688
|
-
OpenWorker
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
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")
|
|
720
|
-
|
|
721
|
-
else if (infoLogLevel == "
|
|
722
|
-
|
|
723
|
-
else if (infoLogLevel == "
|
|
724
|
-
|
|
725
|
-
else
|
|
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
|
|
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
|
|
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 =
|
|
787
|
-
|
|
788
|
-
|
|
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
|
|
798
|
-
CloseWorker
|
|
799
|
-
|
|
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
|
|
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
|
|
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
|
|
841
|
-
GetWorker
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
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
|
|
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_
|
|
732
|
+
snapshot_ = nullptr;
|
|
733
|
+
|
|
860
734
|
return status;
|
|
861
735
|
}
|
|
862
736
|
|
|
863
|
-
void OnOk
|
|
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
|
-
|
|
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
|
|
895
|
-
GetManyWorker
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
1103
|
-
CloseIteratorWorker
|
|
1104
|
-
|
|
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
|
|
1003
|
+
rocksdb::Status Execute(Database& database) override {
|
|
1110
1004
|
iterator_->Close();
|
|
1111
1005
|
return rocksdb::Status::OK();
|
|
1112
1006
|
}
|
|
1113
1007
|
|
|
1114
|
-
void Destroy
|
|
1008
|
+
void Destroy(napi_env env) override {
|
|
1115
1009
|
iterator_->Detach(env);
|
|
1116
|
-
|
|
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
|
|
1136
|
-
NextWorker
|
|
1137
|
-
|
|
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
|
|
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_)
|
|
1157
|
-
|
|
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
|
|
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)
|
|
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))
|
|
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"))
|
|
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"))
|
|
1263
|
-
|
|
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
|
|
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(
|
|
1223
|
+
NAPI_ARGV(3);
|
|
1327
1224
|
NAPI_DB_CONTEXT();
|
|
1328
1225
|
|
|
1329
1226
|
rocksdb::WriteBatch* batch;
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|