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