@nxtedition/rocksdb 5.2.26 → 5.2.29
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 +436 -870
- package/binding.gyp +1 -1
- package/chained-batch.js +1 -2
- package/deps/rocksdb/rocksdb/cmake/modules/CxxFlags.cmake +7 -0
- package/deps/rocksdb/rocksdb/cmake/modules/FindJeMalloc.cmake +29 -0
- package/deps/rocksdb/rocksdb/cmake/modules/FindNUMA.cmake +29 -0
- package/deps/rocksdb/rocksdb/cmake/modules/FindSnappy.cmake +29 -0
- package/deps/rocksdb/rocksdb/cmake/modules/FindTBB.cmake +33 -0
- package/deps/rocksdb/rocksdb/cmake/modules/Findgflags.cmake +29 -0
- package/deps/rocksdb/rocksdb/cmake/modules/Findlz4.cmake +29 -0
- package/deps/rocksdb/rocksdb/cmake/modules/Finduring.cmake +26 -0
- package/deps/rocksdb/rocksdb/cmake/modules/Findzstd.cmake +29 -0
- package/deps/rocksdb/rocksdb/cmake/modules/ReadVersion.cmake +10 -0
- package/deps/rocksdb/rocksdb.gyp +26 -26
- package/index.js +5 -87
- package/package-lock.json +23687 -0
- package/package.json +1 -2
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/{darwin-x86 → darwin-x64}/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.node +0 -0
- package/deps/rocksdb/rocksdb/README.md +0 -32
- package/deps/rocksdb/rocksdb/microbench/README.md +0 -60
- package/deps/rocksdb/rocksdb/plugin/README.md +0 -43
- package/deps/rocksdb/rocksdb/port/README +0 -10
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_tree/lib/README +0 -13
- package/deps/snappy/snappy-1.1.7/README.md +0 -149
package/binding.cc
CHANGED
|
@@ -1,28 +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>
|
|
14
|
+
#include <rocksdb/write_batch.h>
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
#include <set>
|
|
16
|
+
#include <array>
|
|
20
17
|
#include <memory>
|
|
18
|
+
#include <optional>
|
|
19
|
+
#include <set>
|
|
21
20
|
#include <string>
|
|
22
21
|
#include <vector>
|
|
23
22
|
|
|
24
23
|
class NullLogger : public rocksdb::Logger {
|
|
25
|
-
public:
|
|
24
|
+
public:
|
|
26
25
|
using rocksdb::Logger::Logv;
|
|
27
26
|
virtual void Logv(const char* format, va_list ap) override {}
|
|
28
27
|
virtual size_t GetLogFileSize() const override { return 0; }
|
|
@@ -31,7 +30,7 @@ public:
|
|
|
31
30
|
struct Database;
|
|
32
31
|
struct Iterator;
|
|
33
32
|
|
|
34
|
-
#define NAPI_DB_CONTEXT()
|
|
33
|
+
#define NAPI_DB_CONTEXT() \
|
|
35
34
|
Database* database = nullptr; \
|
|
36
35
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
|
|
37
36
|
|
|
@@ -39,29 +38,29 @@ struct Iterator;
|
|
|
39
38
|
Iterator* iterator = nullptr; \
|
|
40
39
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
|
|
41
40
|
|
|
42
|
-
#define NAPI_BATCH_CONTEXT()
|
|
41
|
+
#define NAPI_BATCH_CONTEXT() \
|
|
43
42
|
rocksdb::WriteBatch* batch = nullptr; \
|
|
44
43
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&batch));
|
|
45
44
|
|
|
46
|
-
static bool IsString
|
|
45
|
+
static bool IsString(napi_env env, napi_value value) {
|
|
47
46
|
napi_valuetype type;
|
|
48
47
|
napi_typeof(env, value, &type);
|
|
49
48
|
return type == napi_string;
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
static bool IsBuffer
|
|
51
|
+
static bool IsBuffer(napi_env env, napi_value value) {
|
|
53
52
|
bool isBuffer;
|
|
54
53
|
napi_is_buffer(env, value, &isBuffer);
|
|
55
54
|
return isBuffer;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
static bool IsObject
|
|
57
|
+
static bool IsObject(napi_env env, napi_value value) {
|
|
59
58
|
napi_valuetype type;
|
|
60
59
|
napi_typeof(env, value, &type);
|
|
61
60
|
return type == napi_object;
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
static napi_value CreateError
|
|
63
|
+
static napi_value CreateError(napi_env env, const std::string_view& str) {
|
|
65
64
|
napi_value msg;
|
|
66
65
|
napi_create_string_utf8(env, str.data(), str.size(), &msg);
|
|
67
66
|
napi_value error;
|
|
@@ -69,7 +68,7 @@ static napi_value CreateError (napi_env env, const std::string& str) {
|
|
|
69
68
|
return error;
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
static napi_value CreateCodeError
|
|
71
|
+
static napi_value CreateCodeError(napi_env env, const std::string_view& code, const std::string_view& msg) {
|
|
73
72
|
napi_value codeValue;
|
|
74
73
|
napi_create_string_utf8(env, code.data(), code.size(), &codeValue);
|
|
75
74
|
napi_value msgValue;
|
|
@@ -79,19 +78,19 @@ static napi_value CreateCodeError (napi_env env, const std::string& code, const
|
|
|
79
78
|
return error;
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
static bool HasProperty
|
|
81
|
+
static bool HasProperty(napi_env env, napi_value obj, const std::string_view& key) {
|
|
83
82
|
bool has = false;
|
|
84
83
|
napi_has_named_property(env, obj, key.data(), &has);
|
|
85
84
|
return has;
|
|
86
85
|
}
|
|
87
86
|
|
|
88
|
-
static napi_value GetProperty
|
|
87
|
+
static napi_value GetProperty(napi_env env, napi_value obj, const std::string_view& key) {
|
|
89
88
|
napi_value value;
|
|
90
89
|
napi_get_named_property(env, obj, key.data(), &value);
|
|
91
90
|
return value;
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
static bool BooleanProperty
|
|
93
|
+
static bool BooleanProperty(napi_env env, napi_value obj, const std::string_view& key, bool defaultValue) {
|
|
95
94
|
if (HasProperty(env, obj, key.data())) {
|
|
96
95
|
const auto value = GetProperty(env, obj, key.data());
|
|
97
96
|
bool result;
|
|
@@ -102,12 +101,12 @@ static bool BooleanProperty (napi_env env, napi_value obj, const std::string& ke
|
|
|
102
101
|
return defaultValue;
|
|
103
102
|
}
|
|
104
103
|
|
|
105
|
-
static bool EncodingIsBuffer
|
|
104
|
+
static bool EncodingIsBuffer(napi_env env, napi_value obj, const std::string_view& option) {
|
|
106
105
|
napi_value value;
|
|
107
106
|
size_t size;
|
|
108
107
|
|
|
109
108
|
if (napi_get_named_property(env, obj, option.data(), &value) == napi_ok &&
|
|
110
|
-
|
|
109
|
+
napi_get_value_string_utf8(env, value, nullptr, 0, &size) == napi_ok) {
|
|
111
110
|
// Value is either "buffer" or "utf8" so we can tell them apart just by size
|
|
112
111
|
return size == 6;
|
|
113
112
|
}
|
|
@@ -115,7 +114,7 @@ static bool EncodingIsBuffer (napi_env env, napi_value obj, const std::string& o
|
|
|
115
114
|
return false;
|
|
116
115
|
}
|
|
117
116
|
|
|
118
|
-
static uint32_t Uint32Property
|
|
117
|
+
static uint32_t Uint32Property(napi_env env, napi_value obj, const std::string_view& key, uint32_t defaultValue) {
|
|
119
118
|
if (HasProperty(env, obj, key.data())) {
|
|
120
119
|
const auto value = GetProperty(env, obj, key.data());
|
|
121
120
|
uint32_t result;
|
|
@@ -126,7 +125,7 @@ static uint32_t Uint32Property (napi_env env, napi_value obj, const std::string&
|
|
|
126
125
|
return defaultValue;
|
|
127
126
|
}
|
|
128
127
|
|
|
129
|
-
static int Int32Property
|
|
128
|
+
static int Int32Property(napi_env env, napi_value obj, const std::string_view& key, int defaultValue) {
|
|
130
129
|
if (HasProperty(env, obj, key.data())) {
|
|
131
130
|
const auto value = GetProperty(env, obj, key.data());
|
|
132
131
|
int result;
|
|
@@ -137,24 +136,27 @@ static int Int32Property (napi_env env, napi_value obj, const std::string& key,
|
|
|
137
136
|
return defaultValue;
|
|
138
137
|
}
|
|
139
138
|
|
|
140
|
-
static std::string ToString
|
|
139
|
+
static std::string ToString(napi_env env, napi_value from, const std::string& defaultValue = "") {
|
|
141
140
|
if (IsString(env, from)) {
|
|
142
141
|
size_t length = 0;
|
|
143
142
|
napi_get_value_string_utf8(env, from, nullptr, 0, &length);
|
|
144
143
|
std::string value(length, '\0');
|
|
145
|
-
napi_get_value_string_utf8(
|
|
144
|
+
napi_get_value_string_utf8(env, from, &value[0], value.length() + 1, &length);
|
|
146
145
|
return value;
|
|
147
146
|
} else if (IsBuffer(env, from)) {
|
|
148
147
|
char* buf = nullptr;
|
|
149
148
|
size_t length = 0;
|
|
150
|
-
napi_get_buffer_info(env, from, reinterpret_cast<void
|
|
149
|
+
napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length);
|
|
151
150
|
return std::string(buf, length);
|
|
152
151
|
}
|
|
153
152
|
|
|
154
153
|
return defaultValue;
|
|
155
154
|
}
|
|
156
155
|
|
|
157
|
-
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 = "") {
|
|
158
160
|
if (HasProperty(env, obj, key)) {
|
|
159
161
|
napi_value value = GetProperty(env, obj, key);
|
|
160
162
|
if (IsString(env, value)) {
|
|
@@ -165,56 +167,49 @@ static std::string StringProperty (napi_env env, napi_value obj, const std::stri
|
|
|
165
167
|
return defaultValue;
|
|
166
168
|
}
|
|
167
169
|
|
|
168
|
-
static
|
|
169
|
-
size_t size = 0;
|
|
170
|
-
|
|
171
|
-
if (IsString(env, value)) {
|
|
172
|
-
napi_get_value_string_utf8(env, value, nullptr, 0, &size);
|
|
173
|
-
} else if (IsBuffer(env, value)) {
|
|
174
|
-
char* buf = nullptr;
|
|
175
|
-
napi_get_buffer_info(env, value, (void **)&buf, &size);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return size;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
static std::string* RangeOption (napi_env env, napi_value opts, const std::string& name) {
|
|
170
|
+
static std::optional<std::string> RangeOption(napi_env env, napi_value opts, const std::string_view& name) {
|
|
182
171
|
if (HasProperty(env, opts, name)) {
|
|
183
172
|
const auto value = GetProperty(env, opts, name);
|
|
184
|
-
return
|
|
173
|
+
return ToString(env, value);
|
|
185
174
|
}
|
|
186
175
|
|
|
187
|
-
return
|
|
176
|
+
return {};
|
|
188
177
|
}
|
|
189
178
|
|
|
190
|
-
static
|
|
191
|
-
|
|
192
|
-
|
|
179
|
+
static napi_status CallFunction(napi_env env, napi_value callback, const int argc, napi_value* argv) {
|
|
180
|
+
napi_value global;
|
|
181
|
+
napi_get_global(env, &global);
|
|
182
|
+
return napi_call_function(env, global, callback, argc, argv, nullptr);
|
|
183
|
+
}
|
|
193
184
|
|
|
194
|
-
|
|
195
|
-
|
|
185
|
+
static napi_value ToError(napi_env env, const rocksdb::Status& status) {
|
|
186
|
+
if (status.ok()) {
|
|
187
|
+
return 0;
|
|
188
|
+
}
|
|
196
189
|
|
|
197
|
-
|
|
198
|
-
napi_value element;
|
|
190
|
+
const auto msg = status.ToString();
|
|
199
191
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
192
|
+
if (status.IsNotFound()) {
|
|
193
|
+
return CreateCodeError(env, "LEVEL_NOT_FOUND", msg);
|
|
194
|
+
} else if (status.IsCorruption()) {
|
|
195
|
+
return CreateCodeError(env, "LEVEL_CORRUPTION", msg);
|
|
196
|
+
} else if (status.IsIOError()) {
|
|
197
|
+
if (msg.find("IO error: lock ") != std::string::npos) { // env_posix.cc
|
|
198
|
+
return CreateCodeError(env, "LEVEL_LOCKED", msg);
|
|
199
|
+
} else if (msg.find("IO error: LockFile ") != std::string::npos) { // env_win.cc
|
|
200
|
+
return CreateCodeError(env, "LEVEL_LOCKED", msg);
|
|
201
|
+
} else if (msg.find("IO error: While lock file") != std::string::npos) { // env_mac.cc
|
|
202
|
+
return CreateCodeError(env, "LEVEL_LOCKED", msg);
|
|
203
|
+
} else {
|
|
204
|
+
return CreateCodeError(env, "LEVEL_IO_ERROR", msg);
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
207
|
|
|
207
|
-
return
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
static napi_status CallFunction (napi_env env, napi_value callback, const int argc, napi_value* argv) {
|
|
211
|
-
napi_value global;
|
|
212
|
-
napi_get_global(env, &global);
|
|
213
|
-
return napi_call_function(env, global, callback, argc, argv, nullptr);
|
|
208
|
+
return CreateError(env, msg);
|
|
214
209
|
}
|
|
215
210
|
|
|
216
211
|
template <typename T>
|
|
217
|
-
void Convert
|
|
212
|
+
void Convert(napi_env env, const T& s, bool asBuffer, napi_value& result) {
|
|
218
213
|
if (asBuffer) {
|
|
219
214
|
napi_create_buffer_copy(env, s.size(), s.data(), nullptr, &result);
|
|
220
215
|
} else {
|
|
@@ -222,112 +217,101 @@ void Convert (napi_env env, const T& s, bool asBuffer, napi_value& result) {
|
|
|
222
217
|
}
|
|
223
218
|
}
|
|
224
219
|
|
|
220
|
+
struct NapiSlice : public rocksdb::Slice {
|
|
221
|
+
NapiSlice(napi_env env, napi_value from) {
|
|
222
|
+
if (IsString(env, from)) {
|
|
223
|
+
napi_get_value_string_utf8(env, from, nullptr, 0, &size_);
|
|
224
|
+
char* data;
|
|
225
|
+
if (size_ + 1 < stack_.size()) {
|
|
226
|
+
data = stack_.data();
|
|
227
|
+
} else {
|
|
228
|
+
heap_.reset(new char[size_ + 1]);
|
|
229
|
+
data = heap_.get();
|
|
230
|
+
}
|
|
231
|
+
data[size_] = 0;
|
|
232
|
+
napi_get_value_string_utf8(env, from, data, size_ + 1, &size_);
|
|
233
|
+
data_ = data;
|
|
234
|
+
} else if (IsBuffer(env, from)) {
|
|
235
|
+
void* data;
|
|
236
|
+
napi_get_buffer_info(env, from, &data, &size_);
|
|
237
|
+
data_ = static_cast<char*>(data);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
std::unique_ptr<char[]> heap_;
|
|
242
|
+
std::array<char, 8192> stack_;
|
|
243
|
+
};
|
|
244
|
+
|
|
225
245
|
/**
|
|
226
246
|
* Base worker class. Handles the async work. Derived classes can override the
|
|
227
247
|
* following virtual methods (listed in the order in which they're called):
|
|
228
248
|
*
|
|
229
249
|
* - Execute (abstract, worker pool thread): main work
|
|
230
|
-
* -
|
|
231
|
-
* -
|
|
232
|
-
* -
|
|
250
|
+
* - OnOk (main thread): call JS callback on success
|
|
251
|
+
* - OnError (main thread): call JS callback on error
|
|
252
|
+
* - Destroy (main thread): do cleanup regardless of success
|
|
233
253
|
*/
|
|
234
|
-
struct
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
napi_value callback,
|
|
238
|
-
const std::string& resourceName)
|
|
239
|
-
: database_(database) {
|
|
254
|
+
struct Worker {
|
|
255
|
+
Worker(napi_env env, Database* database, napi_value callback, const std::string& resourceName)
|
|
256
|
+
: database_(database) {
|
|
240
257
|
NAPI_STATUS_THROWS_VOID(napi_create_reference(env, callback, 1, &callbackRef_));
|
|
241
258
|
napi_value asyncResourceName;
|
|
242
|
-
NAPI_STATUS_THROWS_VOID(napi_create_string_utf8(env, resourceName.data(),
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
NAPI_STATUS_THROWS_VOID(napi_create_async_work(env, callback,
|
|
246
|
-
asyncResourceName,
|
|
247
|
-
BaseWorker::Execute,
|
|
248
|
-
BaseWorker::Complete,
|
|
249
|
-
this, &asyncWork_));
|
|
259
|
+
NAPI_STATUS_THROWS_VOID(napi_create_string_utf8(env, resourceName.data(), resourceName.size(), &asyncResourceName));
|
|
260
|
+
NAPI_STATUS_THROWS_VOID(napi_create_async_work(env, callback, asyncResourceName, Worker::Execute,
|
|
261
|
+
Worker::Complete, this, &asyncWork_));
|
|
250
262
|
}
|
|
251
263
|
|
|
252
|
-
virtual ~
|
|
264
|
+
virtual ~Worker() {}
|
|
253
265
|
|
|
254
|
-
static void Execute
|
|
255
|
-
auto self = reinterpret_cast<
|
|
256
|
-
self->status_ = self->Execute();
|
|
266
|
+
static void Execute(napi_env env, void* data) {
|
|
267
|
+
auto self = reinterpret_cast<Worker*>(data);
|
|
268
|
+
self->status_ = self->Execute(*self->database_);
|
|
257
269
|
}
|
|
258
270
|
|
|
259
|
-
static void Complete
|
|
260
|
-
auto self = reinterpret_cast<
|
|
271
|
+
static void Complete(napi_env env, napi_status status, void* data) {
|
|
272
|
+
auto self = reinterpret_cast<Worker*>(data);
|
|
261
273
|
|
|
262
274
|
napi_value callback;
|
|
263
275
|
napi_get_reference_value(env, self->callbackRef_, &callback);
|
|
264
276
|
|
|
265
277
|
if (self->status_.ok()) {
|
|
266
|
-
self->
|
|
278
|
+
self->OnOk(env, callback);
|
|
267
279
|
} else {
|
|
268
|
-
self->
|
|
280
|
+
self->OnError(env, callback, ToError(env, self->status_));
|
|
269
281
|
}
|
|
270
282
|
|
|
271
|
-
self->
|
|
272
|
-
}
|
|
283
|
+
self->Destroy(env);
|
|
273
284
|
|
|
274
|
-
|
|
285
|
+
napi_delete_reference(env, self->callbackRef_);
|
|
286
|
+
napi_delete_async_work(env, self->asyncWork_);
|
|
275
287
|
|
|
276
|
-
|
|
277
|
-
napi_value argv;
|
|
278
|
-
napi_get_null(env, &argv);
|
|
279
|
-
CallFunction(env, callback, 1, &argv);
|
|
288
|
+
delete self;
|
|
280
289
|
}
|
|
281
290
|
|
|
282
|
-
virtual
|
|
283
|
-
napi_value argv;
|
|
284
|
-
|
|
285
|
-
const auto msg = status_.ToString();
|
|
286
|
-
|
|
287
|
-
if (status_.IsNotFound()) {
|
|
288
|
-
argv = CreateCodeError(env, "LEVEL_NOT_FOUND", msg);
|
|
289
|
-
} else if (status_.IsCorruption()) {
|
|
290
|
-
argv = CreateCodeError(env, "LEVEL_CORRUPTION", msg);
|
|
291
|
-
} else if (status_.IsIOError()) {
|
|
292
|
-
if (msg.find("IO error: lock ") != std::string::npos) { // env_posix.cc
|
|
293
|
-
argv = CreateCodeError(env, "LEVEL_LOCKED", msg);
|
|
294
|
-
} else if (msg.find("IO error: LockFile ") != std::string::npos) { // env_win.cc
|
|
295
|
-
argv = CreateCodeError(env, "LEVEL_LOCKED", msg);
|
|
296
|
-
} else if (msg.find("IO error: While lock file") != std::string::npos) { // env_mac.cc
|
|
297
|
-
argv = CreateCodeError(env, "LEVEL_LOCKED", msg);
|
|
298
|
-
} else {
|
|
299
|
-
argv = CreateCodeError(env, "LEVEL_IO_ERROR", msg);
|
|
300
|
-
}
|
|
301
|
-
} else {
|
|
302
|
-
argv = CreateError(env, msg);
|
|
303
|
-
}
|
|
291
|
+
virtual rocksdb::Status Execute(Database& database) = 0;
|
|
304
292
|
|
|
293
|
+
virtual void OnOk(napi_env env, napi_value callback) {
|
|
294
|
+
napi_value argv;
|
|
295
|
+
napi_get_null(env, &argv);
|
|
305
296
|
CallFunction(env, callback, 1, &argv);
|
|
306
297
|
}
|
|
307
298
|
|
|
308
|
-
virtual void
|
|
309
|
-
napi_delete_reference(env, callbackRef_);
|
|
310
|
-
napi_delete_async_work(env, asyncWork_);
|
|
299
|
+
virtual void OnError(napi_env env, napi_value callback, napi_value err) { CallFunction(env, callback, 1, &err); }
|
|
311
300
|
|
|
312
|
-
|
|
313
|
-
}
|
|
301
|
+
virtual void Destroy(napi_env env) {}
|
|
314
302
|
|
|
315
|
-
void Queue
|
|
316
|
-
napi_queue_async_work(env, asyncWork_);
|
|
317
|
-
}
|
|
303
|
+
void Queue(napi_env env) { napi_queue_async_work(env, asyncWork_); }
|
|
318
304
|
|
|
319
305
|
Database* database_;
|
|
320
306
|
|
|
321
|
-
private:
|
|
307
|
+
private:
|
|
322
308
|
napi_ref callbackRef_;
|
|
323
309
|
napi_async_work asyncWork_;
|
|
324
310
|
rocksdb::Status status_;
|
|
325
311
|
};
|
|
326
312
|
|
|
327
313
|
struct Database {
|
|
328
|
-
rocksdb::Status Open
|
|
329
|
-
const bool readOnly,
|
|
330
|
-
const char* location) {
|
|
314
|
+
rocksdb::Status Open(const rocksdb::Options& options, const bool readOnly, const char* location) {
|
|
331
315
|
if (readOnly) {
|
|
332
316
|
rocksdb::DB* db = nullptr;
|
|
333
317
|
const auto status = rocksdb::DB::OpenForReadOnly(options, location, &db);
|
|
@@ -341,75 +325,19 @@ struct Database {
|
|
|
341
325
|
}
|
|
342
326
|
}
|
|
343
327
|
|
|
344
|
-
void
|
|
345
|
-
db_.reset();
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
rocksdb::Status Put (const rocksdb::WriteOptions& options,
|
|
349
|
-
const std::string& key,
|
|
350
|
-
const std::string& value) {
|
|
351
|
-
return db_->Put(options, db_->DefaultColumnFamily(), key, value);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
rocksdb::Status Get (const rocksdb::ReadOptions& options,
|
|
355
|
-
const std::string& key,
|
|
356
|
-
rocksdb::PinnableSlice& value) {
|
|
357
|
-
return db_->Get(options, db_->DefaultColumnFamily(), key, &value);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
rocksdb::Status Del (const rocksdb::WriteOptions& options,
|
|
361
|
-
const std::string& key) {
|
|
362
|
-
return db_->Delete(options, db_->DefaultColumnFamily(), key);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
rocksdb::Status WriteBatch (const rocksdb::WriteOptions& options,
|
|
366
|
-
rocksdb::WriteBatch* batch) {
|
|
367
|
-
return db_->Write(options, batch);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
uint64_t ApproximateSize (const rocksdb::Range* range) {
|
|
371
|
-
uint64_t size = 0;
|
|
372
|
-
db_->GetApproximateSizes(range, 1, &size);
|
|
373
|
-
return size;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
void CompactRange (const rocksdb::Slice* start,
|
|
377
|
-
const rocksdb::Slice* end) {
|
|
378
|
-
rocksdb::CompactRangeOptions options;
|
|
379
|
-
db_->CompactRange(options, start, end);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
void GetProperty (const std::string& property, std::string& value) {
|
|
383
|
-
db_->GetProperty(property, &value);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
const rocksdb::Snapshot* NewSnapshot () {
|
|
387
|
-
return db_->GetSnapshot();
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
rocksdb::Iterator* NewIterator (const rocksdb::ReadOptions& options) {
|
|
391
|
-
return db_->NewIterator(options);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
void ReleaseSnapshot (const rocksdb::Snapshot* snapshot) {
|
|
395
|
-
return db_->ReleaseSnapshot(snapshot);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
void AttachIterator (napi_env env, Iterator* iterator) {
|
|
328
|
+
void AttachIterator(napi_env env, Iterator* iterator) {
|
|
399
329
|
iterators_.insert(iterator);
|
|
400
330
|
IncrementPriorityWork(env);
|
|
401
331
|
}
|
|
402
332
|
|
|
403
|
-
void DetachIterator
|
|
333
|
+
void DetachIterator(napi_env env, Iterator* iterator) {
|
|
404
334
|
iterators_.erase(iterator);
|
|
405
335
|
DecrementPriorityWork(env);
|
|
406
336
|
}
|
|
407
337
|
|
|
408
|
-
void IncrementPriorityWork
|
|
409
|
-
napi_reference_ref(env, prioritRef_, &priorityWork_);
|
|
410
|
-
}
|
|
338
|
+
void IncrementPriorityWork(napi_env env) { napi_reference_ref(env, prioritRef_, &priorityWork_); }
|
|
411
339
|
|
|
412
|
-
void DecrementPriorityWork
|
|
340
|
+
void DecrementPriorityWork(napi_env env) {
|
|
413
341
|
napi_reference_unref(env, prioritRef_, &priorityWork_);
|
|
414
342
|
|
|
415
343
|
if (priorityWork_ == 0 && pendingCloseWorker_) {
|
|
@@ -418,208 +346,106 @@ struct Database {
|
|
|
418
346
|
}
|
|
419
347
|
}
|
|
420
348
|
|
|
421
|
-
bool HasPriorityWork
|
|
422
|
-
return priorityWork_ > 0;
|
|
423
|
-
}
|
|
349
|
+
bool HasPriorityWork() const { return priorityWork_ > 0; }
|
|
424
350
|
|
|
425
351
|
std::unique_ptr<rocksdb::DB> db_;
|
|
426
|
-
|
|
352
|
+
Worker* pendingCloseWorker_;
|
|
427
353
|
std::set<Iterator*> iterators_;
|
|
428
354
|
napi_ref prioritRef_;
|
|
429
355
|
|
|
430
|
-
private:
|
|
356
|
+
private:
|
|
431
357
|
uint32_t priorityWork_ = 0;
|
|
432
358
|
};
|
|
433
359
|
|
|
434
|
-
/**
|
|
435
|
-
* Base worker class for doing async work that defers closing the database.
|
|
436
|
-
*/
|
|
437
|
-
struct PriorityWorker : public BaseWorker {
|
|
438
|
-
PriorityWorker (napi_env env, Database* database, napi_value callback, const char* resourceName)
|
|
439
|
-
: BaseWorker(env, database, callback, resourceName) {
|
|
440
|
-
database_->IncrementPriorityWork(env);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
virtual ~PriorityWorker () {}
|
|
444
|
-
|
|
445
|
-
void Finally (napi_env env) override {
|
|
446
|
-
database_->DecrementPriorityWork(env);
|
|
447
|
-
BaseWorker::Finally(env);
|
|
448
|
-
}
|
|
449
|
-
};
|
|
450
|
-
|
|
451
360
|
struct BaseIterator {
|
|
452
361
|
BaseIterator(Database* database,
|
|
453
362
|
const bool reverse,
|
|
454
|
-
const std::string
|
|
455
|
-
const std::string
|
|
456
|
-
const std::string
|
|
457
|
-
const std::string
|
|
363
|
+
const std::optional<std::string>& lt,
|
|
364
|
+
const std::optional<std::string>& lte,
|
|
365
|
+
const std::optional<std::string>& gt,
|
|
366
|
+
const std::optional<std::string>& gte,
|
|
458
367
|
const int limit,
|
|
459
368
|
const bool fillCache)
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
options.
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
assert(!iterator_);
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
bool DidSeek () const {
|
|
491
|
-
return didSeek_;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
void SeekToRange () {
|
|
369
|
+
: database_(database),
|
|
370
|
+
lt_(!lte ? lt : *lte + '\0'),
|
|
371
|
+
gte_(gte ? gte : (gt ? std::optional<std::string>(*gt + '\0') : std::nullopt)),
|
|
372
|
+
snapshot_(database_->db_->GetSnapshot(),
|
|
373
|
+
[this](const rocksdb::Snapshot* ptr) { database_->db_->ReleaseSnapshot(ptr); }),
|
|
374
|
+
iterator_(database->db_->NewIterator([&] {
|
|
375
|
+
rocksdb::ReadOptions options;
|
|
376
|
+
if (lt_) {
|
|
377
|
+
upper_bound_ = rocksdb::Slice(lt_->data(), lt_->size());
|
|
378
|
+
options.iterate_upper_bound = &upper_bound_;
|
|
379
|
+
}
|
|
380
|
+
if (gte_) {
|
|
381
|
+
lower_bound_ = rocksdb::Slice(gte_->data(), gte_->size());
|
|
382
|
+
options.iterate_lower_bound = &lower_bound_;
|
|
383
|
+
}
|
|
384
|
+
options.fill_cache = fillCache;
|
|
385
|
+
options.snapshot = snapshot_.get();
|
|
386
|
+
return options;
|
|
387
|
+
}())),
|
|
388
|
+
reverse_(reverse),
|
|
389
|
+
limit_(limit) {}
|
|
390
|
+
|
|
391
|
+
virtual ~BaseIterator() { assert(!iterator_); }
|
|
392
|
+
|
|
393
|
+
bool DidSeek() const { return didSeek_; }
|
|
394
|
+
|
|
395
|
+
void SeekToRange() {
|
|
495
396
|
didSeek_ = true;
|
|
496
397
|
|
|
497
|
-
if (
|
|
498
|
-
iterator_->Seek(*gt_);
|
|
499
|
-
|
|
500
|
-
if (iterator_->Valid() && iterator_->key().compare(*gt_) == 0) {
|
|
501
|
-
iterator_->Next();
|
|
502
|
-
}
|
|
503
|
-
} else if (reverse_ && lte_) {
|
|
504
|
-
iterator_->Seek(*lte_);
|
|
505
|
-
|
|
506
|
-
if (!iterator_->Valid()) {
|
|
507
|
-
iterator_->SeekToLast();
|
|
508
|
-
} else if (iterator_->key().compare(*lte_) > 0) {
|
|
509
|
-
iterator_->Prev();
|
|
510
|
-
}
|
|
511
|
-
} else if (reverse_) {
|
|
398
|
+
if (reverse_) {
|
|
512
399
|
iterator_->SeekToLast();
|
|
513
400
|
} else {
|
|
514
401
|
iterator_->SeekToFirst();
|
|
515
402
|
}
|
|
516
403
|
}
|
|
517
404
|
|
|
518
|
-
void Seek
|
|
405
|
+
void Seek(const std::string& target) {
|
|
519
406
|
didSeek_ = true;
|
|
520
407
|
|
|
521
|
-
if (
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
iterator_->Seek(target);
|
|
526
|
-
|
|
527
|
-
if (iterator_->Valid()) {
|
|
528
|
-
const auto cmp = iterator_->key().compare(target);
|
|
529
|
-
if (reverse_ ? cmp > 0 : cmp < 0) {
|
|
530
|
-
Next();
|
|
531
|
-
}
|
|
532
|
-
} else {
|
|
533
|
-
SeekToFirst();
|
|
408
|
+
if ((lt_ && target.compare(*lt_) >= 0) || (gte_ && target.compare(*gte_) < 0)) {
|
|
409
|
+
// TODO (fix): Why is this required? Seek should handle it?
|
|
410
|
+
// https://github.com/facebook/rocksdb/issues/9904
|
|
411
|
+
iterator_->SeekToLast();
|
|
534
412
|
if (iterator_->Valid()) {
|
|
535
|
-
|
|
536
|
-
if (reverse_ ? cmp > 0 : cmp < 0) {
|
|
537
|
-
SeekToEnd();
|
|
538
|
-
}
|
|
413
|
+
iterator_->Next();
|
|
539
414
|
}
|
|
415
|
+
} else if (reverse_) {
|
|
416
|
+
iterator_->SeekForPrev(target);
|
|
417
|
+
} else {
|
|
418
|
+
iterator_->Seek(target);
|
|
540
419
|
}
|
|
541
420
|
}
|
|
542
421
|
|
|
543
|
-
void Close
|
|
422
|
+
void Close() {
|
|
544
423
|
snapshot_.reset();
|
|
545
424
|
iterator_.reset();
|
|
546
425
|
}
|
|
547
426
|
|
|
548
|
-
bool Valid
|
|
549
|
-
if (!iterator_->Valid()) {
|
|
550
|
-
return false;
|
|
551
|
-
}
|
|
427
|
+
bool Valid() const { return iterator_->Valid(); }
|
|
552
428
|
|
|
553
|
-
|
|
554
|
-
return false;
|
|
555
|
-
}
|
|
429
|
+
bool Increment() { return limit_ < 0 || ++count_ <= limit_; }
|
|
556
430
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
431
|
+
void Next() {
|
|
432
|
+
if (reverse_)
|
|
433
|
+
iterator_->Prev();
|
|
434
|
+
else
|
|
435
|
+
iterator_->Next();
|
|
562
436
|
}
|
|
563
437
|
|
|
564
|
-
|
|
565
|
-
return limit_ < 0 || ++count_ <= limit_;
|
|
566
|
-
}
|
|
438
|
+
rocksdb::Slice CurrentKey() const { return iterator_->key(); }
|
|
567
439
|
|
|
568
|
-
|
|
569
|
-
if (reverse_) iterator_->Prev();
|
|
570
|
-
else iterator_->Next();
|
|
571
|
-
}
|
|
440
|
+
rocksdb::Slice CurrentValue() const { return iterator_->value(); }
|
|
572
441
|
|
|
573
|
-
|
|
574
|
-
if (reverse_) iterator_->SeekToLast();
|
|
575
|
-
else iterator_->SeekToFirst();
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
void SeekToLast () {
|
|
579
|
-
if (reverse_) iterator_->SeekToFirst();
|
|
580
|
-
else iterator_->SeekToLast();
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
void SeekToEnd () {
|
|
584
|
-
SeekToLast();
|
|
585
|
-
Next();
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
rocksdb::Slice CurrentKey () const {
|
|
589
|
-
return iterator_->key();
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
rocksdb::Slice CurrentValue () const {
|
|
593
|
-
return iterator_->value();
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
rocksdb::Status Status () const {
|
|
597
|
-
return iterator_->status();
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
bool OutOfRange (const rocksdb::Slice& target) const {
|
|
601
|
-
if (lte_) {
|
|
602
|
-
if (target.compare(*lte_) > 0) return true;
|
|
603
|
-
} else if (lt_) {
|
|
604
|
-
if (target.compare(*lt_) >= 0) return true;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
if (gte_) {
|
|
608
|
-
if (target.compare(*gte_) < 0) return true;
|
|
609
|
-
} else if (gt_) {
|
|
610
|
-
if (target.compare(*gt_) <= 0) return true;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
return false;
|
|
614
|
-
}
|
|
442
|
+
rocksdb::Status Status() const { return iterator_->status(); }
|
|
615
443
|
|
|
616
444
|
Database* database_;
|
|
617
445
|
|
|
618
|
-
private:
|
|
619
|
-
const std::
|
|
620
|
-
const std::
|
|
621
|
-
const std::unique_ptr<const std::string> gt_;
|
|
622
|
-
const std::unique_ptr<const std::string> gte_;
|
|
446
|
+
private:
|
|
447
|
+
const std::optional<std::string> lt_;
|
|
448
|
+
const std::optional<std::string> gte_;
|
|
623
449
|
rocksdb::Slice lower_bound_;
|
|
624
450
|
rocksdb::Slice upper_bound_;
|
|
625
451
|
std::shared_ptr<const rocksdb::Snapshot> snapshot_;
|
|
@@ -631,37 +457,38 @@ private:
|
|
|
631
457
|
};
|
|
632
458
|
|
|
633
459
|
struct Iterator final : public BaseIterator {
|
|
634
|
-
Iterator
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
void Attach (napi_env env, napi_value context) {
|
|
460
|
+
Iterator(Database* database,
|
|
461
|
+
const bool reverse,
|
|
462
|
+
const bool keys,
|
|
463
|
+
const bool values,
|
|
464
|
+
const int limit,
|
|
465
|
+
const std::optional<std::string>& lt,
|
|
466
|
+
const std::optional<std::string>& lte,
|
|
467
|
+
const std::optional<std::string>& gt,
|
|
468
|
+
const std::optional<std::string>& gte,
|
|
469
|
+
const bool fillCache,
|
|
470
|
+
const bool keyAsBuffer,
|
|
471
|
+
const bool valueAsBuffer,
|
|
472
|
+
const uint32_t highWaterMarkBytes)
|
|
473
|
+
: BaseIterator(database, reverse, lt, lte, gt, gte, limit, fillCache),
|
|
474
|
+
keys_(keys),
|
|
475
|
+
values_(values),
|
|
476
|
+
keyAsBuffer_(keyAsBuffer),
|
|
477
|
+
valueAsBuffer_(valueAsBuffer),
|
|
478
|
+
highWaterMarkBytes_(highWaterMarkBytes),
|
|
479
|
+
first_(true),
|
|
480
|
+
ref_(nullptr) {}
|
|
481
|
+
|
|
482
|
+
void Attach(napi_env env, napi_value context) {
|
|
658
483
|
napi_create_reference(env, context, 1, &ref_);
|
|
659
484
|
database_->AttachIterator(env, this);
|
|
660
485
|
}
|
|
661
486
|
|
|
662
|
-
void Detach
|
|
487
|
+
void Detach(napi_env env) {
|
|
663
488
|
database_->DetachIterator(env, this);
|
|
664
|
-
if (ref_)
|
|
489
|
+
if (ref_) {
|
|
490
|
+
napi_delete_reference(env, ref_);
|
|
491
|
+
}
|
|
665
492
|
}
|
|
666
493
|
|
|
667
494
|
const bool keys_;
|
|
@@ -671,7 +498,7 @@ struct Iterator final : public BaseIterator {
|
|
|
671
498
|
const uint32_t highWaterMarkBytes_;
|
|
672
499
|
bool first_;
|
|
673
500
|
|
|
674
|
-
private:
|
|
501
|
+
private:
|
|
675
502
|
napi_ref ref_;
|
|
676
503
|
};
|
|
677
504
|
|
|
@@ -680,15 +507,16 @@ private:
|
|
|
680
507
|
* already-scheduled napi_async_work items have finished, which gives us
|
|
681
508
|
* the guarantee that no db operations will be in-flight at this time.
|
|
682
509
|
*/
|
|
683
|
-
static void env_cleanup_hook
|
|
510
|
+
static void env_cleanup_hook(void* arg) {
|
|
684
511
|
auto database = reinterpret_cast<Database*>(arg);
|
|
685
512
|
|
|
686
|
-
// Do everything that db_close() does but synchronously. We're expecting that
|
|
687
|
-
// did not (yet) collect the database because that would be a user mistake
|
|
688
|
-
// closing their db) made during the lifetime of the environment. That's
|
|
689
|
-
// from an environment being torn down (like the main process or a
|
|
690
|
-
// where it's our responsibility to clean up. Note also, the
|
|
691
|
-
// be a safe noop if called before db_open() or after
|
|
513
|
+
// Do everything that db_close() does but synchronously. We're expecting that
|
|
514
|
+
// GC did not (yet) collect the database because that would be a user mistake
|
|
515
|
+
// (not closing their db) made during the lifetime of the environment. That's
|
|
516
|
+
// different from an environment being torn down (like the main process or a
|
|
517
|
+
// worker thread) where it's our responsibility to clean up. Note also, the
|
|
518
|
+
// following code must be a safe noop if called before db_open() or after
|
|
519
|
+
// db_close().
|
|
692
520
|
if (database && database->db_) {
|
|
693
521
|
// TODO: does not do `napi_delete_reference(env, iterator->ref_)`. Problem?
|
|
694
522
|
for (auto it : database->iterators_) {
|
|
@@ -696,15 +524,16 @@ static void env_cleanup_hook (void* arg) {
|
|
|
696
524
|
}
|
|
697
525
|
|
|
698
526
|
// Having closed the iterators (and released snapshots) we can safely close.
|
|
699
|
-
database->
|
|
527
|
+
database->db_->Close();
|
|
700
528
|
}
|
|
701
529
|
}
|
|
702
530
|
|
|
703
|
-
static void FinalizeDatabase
|
|
531
|
+
static void FinalizeDatabase(napi_env env, void* data, void* hint) {
|
|
704
532
|
if (data) {
|
|
705
533
|
auto database = reinterpret_cast<Database*>(data);
|
|
706
534
|
napi_remove_env_cleanup_hook(env, env_cleanup_hook, database);
|
|
707
|
-
if (database->prioritRef_)
|
|
535
|
+
if (database->prioritRef_)
|
|
536
|
+
napi_delete_reference(env, database->prioritRef_);
|
|
708
537
|
delete database;
|
|
709
538
|
}
|
|
710
539
|
}
|
|
@@ -714,39 +543,33 @@ NAPI_METHOD(db_init) {
|
|
|
714
543
|
napi_add_env_cleanup_hook(env, env_cleanup_hook, database);
|
|
715
544
|
|
|
716
545
|
napi_value result;
|
|
717
|
-
NAPI_STATUS_THROWS(napi_create_external(env, database,
|
|
718
|
-
FinalizeDatabase,
|
|
719
|
-
nullptr, &result));
|
|
546
|
+
NAPI_STATUS_THROWS(napi_create_external(env, database, FinalizeDatabase, nullptr, &result));
|
|
720
547
|
|
|
721
548
|
NAPI_STATUS_THROWS(napi_create_reference(env, result, 0, &database->prioritRef_));
|
|
722
549
|
|
|
723
550
|
return result;
|
|
724
551
|
}
|
|
725
552
|
|
|
726
|
-
struct OpenWorker final : public
|
|
727
|
-
OpenWorker
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
readOnly_(readOnly),
|
|
744
|
-
location_(location) {
|
|
553
|
+
struct OpenWorker final : public Worker {
|
|
554
|
+
OpenWorker(napi_env env,
|
|
555
|
+
Database* database,
|
|
556
|
+
napi_value callback,
|
|
557
|
+
const std::string& location,
|
|
558
|
+
const bool createIfMissing,
|
|
559
|
+
const bool errorIfExists,
|
|
560
|
+
const bool compression,
|
|
561
|
+
const uint32_t writeBufferSize,
|
|
562
|
+
const uint32_t blockSize,
|
|
563
|
+
const uint32_t maxOpenFiles,
|
|
564
|
+
const uint32_t blockRestartInterval,
|
|
565
|
+
const uint32_t maxFileSize,
|
|
566
|
+
const uint32_t cacheSize,
|
|
567
|
+
const std::string& infoLogLevel,
|
|
568
|
+
const bool readOnly)
|
|
569
|
+
: Worker(env, database, callback, "leveldown.db.open"), readOnly_(readOnly), location_(location) {
|
|
745
570
|
options_.create_if_missing = createIfMissing;
|
|
746
571
|
options_.error_if_exists = errorIfExists;
|
|
747
|
-
options_.compression = compression
|
|
748
|
-
? rocksdb::kSnappyCompression
|
|
749
|
-
: rocksdb::kNoCompression;
|
|
572
|
+
options_.compression = compression ? rocksdb::kSnappyCompression : rocksdb::kNoCompression;
|
|
750
573
|
options_.write_buffer_size = writeBufferSize;
|
|
751
574
|
options_.max_open_files = maxOpenFiles;
|
|
752
575
|
options_.max_log_file_size = maxFileSize;
|
|
@@ -755,13 +578,20 @@ struct OpenWorker final : public PriorityWorker {
|
|
|
755
578
|
if (infoLogLevel.size() > 0) {
|
|
756
579
|
rocksdb::InfoLogLevel lvl = {};
|
|
757
580
|
|
|
758
|
-
if (infoLogLevel == "debug")
|
|
759
|
-
|
|
760
|
-
else if (infoLogLevel == "
|
|
761
|
-
|
|
762
|
-
else if (infoLogLevel == "
|
|
763
|
-
|
|
764
|
-
else
|
|
581
|
+
if (infoLogLevel == "debug")
|
|
582
|
+
lvl = rocksdb::InfoLogLevel::DEBUG_LEVEL;
|
|
583
|
+
else if (infoLogLevel == "info")
|
|
584
|
+
lvl = rocksdb::InfoLogLevel::INFO_LEVEL;
|
|
585
|
+
else if (infoLogLevel == "warn")
|
|
586
|
+
lvl = rocksdb::InfoLogLevel::WARN_LEVEL;
|
|
587
|
+
else if (infoLogLevel == "error")
|
|
588
|
+
lvl = rocksdb::InfoLogLevel::ERROR_LEVEL;
|
|
589
|
+
else if (infoLogLevel == "fatal")
|
|
590
|
+
lvl = rocksdb::InfoLogLevel::FATAL_LEVEL;
|
|
591
|
+
else if (infoLogLevel == "header")
|
|
592
|
+
lvl = rocksdb::InfoLogLevel::HEADER_LEVEL;
|
|
593
|
+
else
|
|
594
|
+
napi_throw_error(env, nullptr, "invalid log level");
|
|
765
595
|
|
|
766
596
|
options_.info_log_level = lvl;
|
|
767
597
|
} else {
|
|
@@ -785,14 +615,10 @@ struct OpenWorker final : public PriorityWorker {
|
|
|
785
615
|
tableOptions.format_version = 5;
|
|
786
616
|
tableOptions.checksum = rocksdb::kxxHash64;
|
|
787
617
|
|
|
788
|
-
options_.table_factory.reset(
|
|
789
|
-
rocksdb::NewBlockBasedTableFactory(tableOptions)
|
|
790
|
-
);
|
|
618
|
+
options_.table_factory.reset(rocksdb::NewBlockBasedTableFactory(tableOptions));
|
|
791
619
|
}
|
|
792
620
|
|
|
793
|
-
rocksdb::Status Execute
|
|
794
|
-
return database_->Open(options_, readOnly_, location_.c_str());
|
|
795
|
-
}
|
|
621
|
+
rocksdb::Status Execute(Database& database) override { return database.Open(options_, readOnly_, location_.c_str()); }
|
|
796
622
|
|
|
797
623
|
rocksdb::Options options_;
|
|
798
624
|
const bool readOnly_;
|
|
@@ -813,39 +639,30 @@ NAPI_METHOD(db_open) {
|
|
|
813
639
|
const auto infoLogLevel = StringProperty(env, options, "infoLogLevel");
|
|
814
640
|
|
|
815
641
|
const auto cacheSize = Uint32Property(env, options, "cacheSize", 8 << 20);
|
|
816
|
-
const auto writeBufferSize = Uint32Property(env, options
|
|
642
|
+
const auto writeBufferSize = Uint32Property(env, options, "writeBufferSize", 4 << 20);
|
|
817
643
|
const auto blockSize = Uint32Property(env, options, "blockSize", 4096);
|
|
818
644
|
const auto maxOpenFiles = Uint32Property(env, options, "maxOpenFiles", 1000);
|
|
819
|
-
const auto blockRestartInterval = Uint32Property(env, options,
|
|
820
|
-
"blockRestartInterval", 16);
|
|
645
|
+
const auto blockRestartInterval = Uint32Property(env, options, "blockRestartInterval", 16);
|
|
821
646
|
const auto maxFileSize = Uint32Property(env, options, "maxFileSize", 2 << 20);
|
|
822
647
|
|
|
823
648
|
const auto callback = argv[3];
|
|
824
649
|
|
|
825
|
-
auto worker =
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
maxOpenFiles, blockRestartInterval,
|
|
829
|
-
maxFileSize, cacheSize,
|
|
830
|
-
infoLogLevel, readOnly);
|
|
650
|
+
auto worker =
|
|
651
|
+
new OpenWorker(env, database, callback, location, createIfMissing, errorIfExists, compression, writeBufferSize,
|
|
652
|
+
blockSize, maxOpenFiles, blockRestartInterval, maxFileSize, cacheSize, infoLogLevel, readOnly);
|
|
831
653
|
worker->Queue(env);
|
|
832
654
|
|
|
833
655
|
return 0;
|
|
834
656
|
}
|
|
835
657
|
|
|
836
|
-
struct CloseWorker final : public
|
|
837
|
-
CloseWorker
|
|
838
|
-
|
|
839
|
-
napi_value callback)
|
|
840
|
-
: BaseWorker(env, database, callback, "leveldown.db.close") {}
|
|
658
|
+
struct CloseWorker final : public Worker {
|
|
659
|
+
CloseWorker(napi_env env, Database* database, napi_value callback)
|
|
660
|
+
: Worker(env, database, callback, "leveldown.db.close") {}
|
|
841
661
|
|
|
842
|
-
rocksdb::Status Execute
|
|
843
|
-
database_->CloseDatabase();
|
|
844
|
-
return rocksdb::Status::OK();
|
|
845
|
-
}
|
|
662
|
+
rocksdb::Status Execute(Database& database) override { return database.db_->Close(); }
|
|
846
663
|
};
|
|
847
664
|
|
|
848
|
-
napi_value noop_callback
|
|
665
|
+
napi_value noop_callback(napi_env env, napi_callback_info info) {
|
|
849
666
|
return 0;
|
|
850
667
|
}
|
|
851
668
|
|
|
@@ -866,72 +683,62 @@ NAPI_METHOD(db_close) {
|
|
|
866
683
|
return 0;
|
|
867
684
|
}
|
|
868
685
|
|
|
869
|
-
struct PutWorker final : public PriorityWorker {
|
|
870
|
-
PutWorker (napi_env env,
|
|
871
|
-
Database* database,
|
|
872
|
-
napi_value callback,
|
|
873
|
-
const std::string& key,
|
|
874
|
-
const std::string& value,
|
|
875
|
-
bool sync)
|
|
876
|
-
: PriorityWorker(env, database, callback, "rocks_level.db.put"),
|
|
877
|
-
key_(key), value_(value), sync_(sync) {
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
rocksdb::Status Execute () override {
|
|
881
|
-
rocksdb::WriteOptions options;
|
|
882
|
-
options.sync = sync_;
|
|
883
|
-
return database_->Put(options, key_, value_);
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
const std::string key_;
|
|
887
|
-
const std::string value_;
|
|
888
|
-
const bool sync_;
|
|
889
|
-
};
|
|
890
|
-
|
|
891
686
|
NAPI_METHOD(db_put) {
|
|
892
|
-
NAPI_ARGV(
|
|
687
|
+
NAPI_ARGV(4);
|
|
893
688
|
NAPI_DB_CONTEXT();
|
|
894
689
|
|
|
895
690
|
const auto key = ToString(env, argv[1]);
|
|
896
691
|
const auto value = ToString(env, argv[2]);
|
|
897
|
-
const auto sync = BooleanProperty(env, argv[3], "sync", false);
|
|
898
|
-
const auto callback = argv[4];
|
|
899
|
-
|
|
900
|
-
auto worker = new PutWorker(env, database, callback, key, value, sync);
|
|
901
|
-
worker->Queue(env);
|
|
902
692
|
|
|
903
|
-
|
|
693
|
+
rocksdb::WriteOptions options;
|
|
694
|
+
return ToError(env, database->db_->Put(options, key, value));
|
|
904
695
|
}
|
|
905
696
|
|
|
906
|
-
struct GetWorker final : public
|
|
907
|
-
GetWorker
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
697
|
+
struct GetWorker final : public Worker {
|
|
698
|
+
GetWorker(napi_env env,
|
|
699
|
+
Database* database,
|
|
700
|
+
napi_value callback,
|
|
701
|
+
const std::string& key,
|
|
702
|
+
const bool asBuffer,
|
|
703
|
+
const bool fillCache)
|
|
704
|
+
: Worker(env, database, callback, "rocks_level.db.get"),
|
|
705
|
+
key_(key),
|
|
706
|
+
asBuffer_(asBuffer),
|
|
707
|
+
fillCache_(fillCache),
|
|
708
|
+
snapshot_(database_->db_->GetSnapshot(),
|
|
709
|
+
[this](const rocksdb::Snapshot* ptr) { database_->db_->ReleaseSnapshot(ptr); }) {
|
|
710
|
+
database_->IncrementPriorityWork(env);
|
|
915
711
|
}
|
|
916
712
|
|
|
917
|
-
rocksdb::Status Execute
|
|
713
|
+
rocksdb::Status Execute(Database& database) override {
|
|
918
714
|
rocksdb::ReadOptions options;
|
|
919
715
|
options.fill_cache = fillCache_;
|
|
920
|
-
|
|
716
|
+
options.snapshot = snapshot_.get();
|
|
717
|
+
|
|
718
|
+
auto status = database.db_->Get(options, database.db_->DefaultColumnFamily(), key_, &value_);
|
|
719
|
+
snapshot_ = nullptr;
|
|
720
|
+
|
|
721
|
+
return status;
|
|
921
722
|
}
|
|
922
723
|
|
|
923
|
-
void
|
|
724
|
+
void OnOk(napi_env env, napi_value callback) override {
|
|
924
725
|
napi_value argv[2];
|
|
925
726
|
napi_get_null(env, &argv[0]);
|
|
926
727
|
Convert(env, std::move(value_), asBuffer_, argv[1]);
|
|
927
728
|
CallFunction(env, callback, 2, argv);
|
|
928
729
|
}
|
|
929
730
|
|
|
930
|
-
|
|
731
|
+
void Destroy(napi_env env) override {
|
|
732
|
+
database_->DecrementPriorityWork(env);
|
|
733
|
+
Worker::Destroy(env);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
private:
|
|
931
737
|
const std::string key_;
|
|
932
738
|
rocksdb::PinnableSlice value_;
|
|
933
739
|
const bool asBuffer_;
|
|
934
740
|
const bool fillCache_;
|
|
741
|
+
std::shared_ptr<const rocksdb::Snapshot> snapshot_;
|
|
935
742
|
};
|
|
936
743
|
|
|
937
744
|
NAPI_METHOD(db_get) {
|
|
@@ -950,37 +757,28 @@ NAPI_METHOD(db_get) {
|
|
|
950
757
|
return 0;
|
|
951
758
|
}
|
|
952
759
|
|
|
953
|
-
struct GetManyWorker final : public
|
|
954
|
-
GetManyWorker
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
database_->ReleaseSnapshot(snapshot_);
|
|
968
|
-
snapshot_ = nullptr;
|
|
969
|
-
}
|
|
760
|
+
struct GetManyWorker final : public Worker {
|
|
761
|
+
GetManyWorker(napi_env env,
|
|
762
|
+
Database* database,
|
|
763
|
+
const std::vector<std::string>& keys,
|
|
764
|
+
napi_value callback,
|
|
765
|
+
const bool valueAsBuffer,
|
|
766
|
+
const bool fillCache)
|
|
767
|
+
: Worker(env, database, callback, "leveldown.get.many"),
|
|
768
|
+
keys_(keys),
|
|
769
|
+
valueAsBuffer_(valueAsBuffer),
|
|
770
|
+
fillCache_(fillCache),
|
|
771
|
+
snapshot_(database_->db_->GetSnapshot(),
|
|
772
|
+
[this](const rocksdb::Snapshot* ptr) { database_->db_->ReleaseSnapshot(ptr); }) {
|
|
773
|
+
database_->IncrementPriorityWork(env);
|
|
970
774
|
}
|
|
971
775
|
|
|
972
|
-
rocksdb::Status Execute
|
|
776
|
+
rocksdb::Status Execute(Database& database) override {
|
|
973
777
|
rocksdb::ReadOptions options;
|
|
974
|
-
options.snapshot = snapshot_;
|
|
975
778
|
options.fill_cache = fillCache_;
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
std::vector<rocksdb::Slice>(keys_.begin(), keys_.end()),
|
|
980
|
-
&values_
|
|
981
|
-
);
|
|
982
|
-
|
|
983
|
-
database_->ReleaseSnapshot(snapshot_);
|
|
779
|
+
options.snapshot = snapshot_.get();
|
|
780
|
+
|
|
781
|
+
status_ = database.db_->MultiGet(options, std::vector<rocksdb::Slice>(keys_.begin(), keys_.end()), &values_);
|
|
984
782
|
snapshot_ = nullptr;
|
|
985
783
|
|
|
986
784
|
for (auto status : status_) {
|
|
@@ -992,7 +790,7 @@ struct GetManyWorker final : public PriorityWorker {
|
|
|
992
790
|
return rocksdb::Status::OK();
|
|
993
791
|
}
|
|
994
792
|
|
|
995
|
-
void
|
|
793
|
+
void OnOk(napi_env env, napi_value callback) override {
|
|
996
794
|
const auto size = values_.size();
|
|
997
795
|
|
|
998
796
|
napi_value array;
|
|
@@ -1014,20 +812,39 @@ struct GetManyWorker final : public PriorityWorker {
|
|
|
1014
812
|
CallFunction(env, callback, 2, argv);
|
|
1015
813
|
}
|
|
1016
814
|
|
|
1017
|
-
|
|
815
|
+
void Destroy(napi_env env) override {
|
|
816
|
+
database_->DecrementPriorityWork(env);
|
|
817
|
+
Worker::Destroy(env);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
private:
|
|
1018
821
|
const std::vector<std::string> keys_;
|
|
1019
822
|
std::vector<std::string> values_;
|
|
1020
823
|
std::vector<rocksdb::Status> status_;
|
|
1021
824
|
const bool valueAsBuffer_;
|
|
1022
825
|
const bool fillCache_;
|
|
1023
|
-
const rocksdb::Snapshot
|
|
826
|
+
std::shared_ptr<const rocksdb::Snapshot> snapshot_;
|
|
1024
827
|
};
|
|
1025
828
|
|
|
1026
829
|
NAPI_METHOD(db_get_many) {
|
|
1027
830
|
NAPI_ARGV(4);
|
|
1028
831
|
NAPI_DB_CONTEXT();
|
|
1029
832
|
|
|
1030
|
-
|
|
833
|
+
std::vector<std::string> keys;
|
|
834
|
+
{
|
|
835
|
+
uint32_t length;
|
|
836
|
+
NAPI_STATUS_THROWS(napi_get_array_length(env, argv[1], &length));
|
|
837
|
+
|
|
838
|
+
keys.reserve(length);
|
|
839
|
+
|
|
840
|
+
for (uint32_t i = 0; i < length; i++) {
|
|
841
|
+
napi_value element;
|
|
842
|
+
|
|
843
|
+
NAPI_STATUS_THROWS(napi_get_element(env, argv[1], i, &element));
|
|
844
|
+
keys.push_back(ToString(env, element));
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
1031
848
|
const auto options = argv[2];
|
|
1032
849
|
const bool asBuffer = EncodingIsBuffer(env, options, "valueEncoding");
|
|
1033
850
|
const bool fillCache = BooleanProperty(env, options, "fillCache", true);
|
|
@@ -1039,190 +856,67 @@ NAPI_METHOD(db_get_many) {
|
|
|
1039
856
|
return 0;
|
|
1040
857
|
}
|
|
1041
858
|
|
|
1042
|
-
struct DelWorker final : public PriorityWorker {
|
|
1043
|
-
DelWorker (napi_env env,
|
|
1044
|
-
Database* database,
|
|
1045
|
-
napi_value callback,
|
|
1046
|
-
const std::string& key,
|
|
1047
|
-
bool sync)
|
|
1048
|
-
: PriorityWorker(env, database, callback, "rocks_level.db.del"),
|
|
1049
|
-
key_(key), sync_(sync) {
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
rocksdb::Status Execute () override {
|
|
1053
|
-
rocksdb::WriteOptions options;
|
|
1054
|
-
options.sync = sync_;
|
|
1055
|
-
return database_->Del(options, key_);
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
const std::string key_;
|
|
1059
|
-
const bool sync_;
|
|
1060
|
-
};
|
|
1061
|
-
|
|
1062
859
|
NAPI_METHOD(db_del) {
|
|
1063
|
-
NAPI_ARGV(
|
|
860
|
+
NAPI_ARGV(3);
|
|
1064
861
|
NAPI_DB_CONTEXT();
|
|
1065
862
|
|
|
1066
863
|
const auto key = ToString(env, argv[1]);
|
|
1067
|
-
const auto sync = BooleanProperty(env, argv[2], "sync", false);
|
|
1068
|
-
const auto callback = argv[3];
|
|
1069
864
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
return 0;
|
|
865
|
+
rocksdb::WriteOptions options;
|
|
866
|
+
return ToError(env, database->db_->Delete(options, key));
|
|
1074
867
|
}
|
|
1075
868
|
|
|
1076
|
-
struct ClearWorker final : public PriorityWorker {
|
|
1077
|
-
ClearWorker (napi_env env,
|
|
1078
|
-
Database* database,
|
|
1079
|
-
napi_value callback,
|
|
1080
|
-
const bool reverse,
|
|
1081
|
-
const int limit,
|
|
1082
|
-
const std::string* lt,
|
|
1083
|
-
const std::string* lte,
|
|
1084
|
-
const std::string* gt,
|
|
1085
|
-
const std::string* gte)
|
|
1086
|
-
: PriorityWorker(env, database, callback, "rocks_level.db.clear"),
|
|
1087
|
-
iterator_(database, reverse, lt, lte, gt, gte, limit, false) {
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
rocksdb::Status Execute () override {
|
|
1091
|
-
iterator_.SeekToRange();
|
|
1092
|
-
|
|
1093
|
-
// TODO: add option
|
|
1094
|
-
const uint32_t hwm = 16 * 1024;
|
|
1095
|
-
|
|
1096
|
-
rocksdb::WriteBatch batch;
|
|
1097
|
-
rocksdb::WriteOptions options;
|
|
1098
|
-
rocksdb::Status status;
|
|
1099
|
-
|
|
1100
|
-
while (true) {
|
|
1101
|
-
size_t bytesRead = 0;
|
|
1102
|
-
|
|
1103
|
-
while (bytesRead <= hwm && iterator_.Valid() && iterator_.Increment()) {
|
|
1104
|
-
const auto key = iterator_.CurrentKey();
|
|
1105
|
-
batch.Delete(key);
|
|
1106
|
-
bytesRead += key.size();
|
|
1107
|
-
iterator_.Next();
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
status = iterator_.Status();
|
|
1111
|
-
if (!status.ok() || bytesRead == 0) {
|
|
1112
|
-
break;
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
status = database_->WriteBatch(options, &batch);
|
|
1116
|
-
if (!status.ok()) {
|
|
1117
|
-
break;
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
batch.Clear();
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
iterator_.Close();
|
|
1124
|
-
|
|
1125
|
-
return status;
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
private:
|
|
1129
|
-
BaseIterator iterator_;
|
|
1130
|
-
};
|
|
1131
|
-
|
|
1132
869
|
NAPI_METHOD(db_clear) {
|
|
1133
|
-
NAPI_ARGV(
|
|
870
|
+
NAPI_ARGV(2);
|
|
1134
871
|
NAPI_DB_CONTEXT();
|
|
1135
872
|
|
|
1136
|
-
|
|
1137
|
-
|
|
873
|
+
const auto reverse = BooleanProperty(env, argv[1], "reverse", false);
|
|
874
|
+
const auto limit = Int32Property(env, argv[1], "limit", -1);
|
|
1138
875
|
|
|
1139
|
-
const auto
|
|
1140
|
-
const auto
|
|
1141
|
-
|
|
1142
|
-
const auto
|
|
1143
|
-
const auto lte = RangeOption(env, options, "lte");
|
|
1144
|
-
const auto gt = RangeOption(env, options, "gt");
|
|
1145
|
-
const auto gte = RangeOption(env, options, "gte");
|
|
876
|
+
const auto lt = RangeOption(env, argv[1], "lt");
|
|
877
|
+
const auto lte = RangeOption(env, argv[1], "lte");
|
|
878
|
+
const auto gt = RangeOption(env, argv[1], "gt");
|
|
879
|
+
const auto gte = RangeOption(env, argv[1], "gte");
|
|
1146
880
|
|
|
1147
|
-
|
|
1148
|
-
worker->Queue(env);
|
|
881
|
+
// TODO (perf): Use DeleteRange.
|
|
1149
882
|
|
|
1150
|
-
|
|
1151
|
-
}
|
|
883
|
+
BaseIterator it(database, reverse, lt, lte, gt, gte, limit, false);
|
|
1152
884
|
|
|
1153
|
-
|
|
1154
|
-
ApproximateSizeWorker (napi_env env,
|
|
1155
|
-
Database* database,
|
|
1156
|
-
napi_value callback,
|
|
1157
|
-
const std::string& start,
|
|
1158
|
-
const std::string& end)
|
|
1159
|
-
: PriorityWorker(env, database, callback, "rocks_level.db.approximate_size"),
|
|
1160
|
-
start_(start), end_(end) {}
|
|
1161
|
-
|
|
1162
|
-
rocksdb::Status Execute () override {
|
|
1163
|
-
rocksdb::Range range(start_, end_);
|
|
1164
|
-
size_ = database_->ApproximateSize(&range);
|
|
1165
|
-
return rocksdb::Status::OK();
|
|
1166
|
-
}
|
|
885
|
+
it.SeekToRange();
|
|
1167
886
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
napi_get_null(env, &argv[0]);
|
|
1171
|
-
napi_create_int64(env, size_, &argv[1]);
|
|
1172
|
-
CallFunction(env, callback, 2, argv);
|
|
1173
|
-
}
|
|
887
|
+
// TODO: add option
|
|
888
|
+
const uint32_t hwm = 16 * 1024;
|
|
1174
889
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
};
|
|
890
|
+
rocksdb::WriteBatch batch;
|
|
891
|
+
rocksdb::WriteOptions options;
|
|
892
|
+
rocksdb::Status status;
|
|
1179
893
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
NAPI_DB_CONTEXT();
|
|
894
|
+
while (true) {
|
|
895
|
+
size_t bytesRead = 0;
|
|
1183
896
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
897
|
+
while (bytesRead <= hwm && it.Valid() && it.Increment()) {
|
|
898
|
+
const auto key = it.CurrentKey();
|
|
899
|
+
batch.Delete(key);
|
|
900
|
+
bytesRead += key.size();
|
|
901
|
+
it.Next();
|
|
902
|
+
}
|
|
1187
903
|
|
|
1188
|
-
|
|
1189
|
-
|
|
904
|
+
status = it.Status();
|
|
905
|
+
if (!status.ok() || bytesRead == 0) {
|
|
906
|
+
break;
|
|
907
|
+
}
|
|
1190
908
|
|
|
1191
|
-
|
|
1192
|
-
|
|
909
|
+
status = database->db_->Write(options, &batch);
|
|
910
|
+
if (!status.ok()) {
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
1193
913
|
|
|
1194
|
-
|
|
1195
|
-
CompactRangeWorker (napi_env env,
|
|
1196
|
-
Database* database,
|
|
1197
|
-
napi_value callback,
|
|
1198
|
-
const std::string& start,
|
|
1199
|
-
const std::string& end)
|
|
1200
|
-
: PriorityWorker(env, database, callback, "rocks_level.db.compact_range"),
|
|
1201
|
-
start_(start), end_(end) {}
|
|
1202
|
-
|
|
1203
|
-
rocksdb::Status Execute () override {
|
|
1204
|
-
rocksdb::Slice start = start_;
|
|
1205
|
-
rocksdb::Slice end = end_;
|
|
1206
|
-
database_->CompactRange(&start, &end);
|
|
1207
|
-
return rocksdb::Status::OK();
|
|
914
|
+
batch.Clear();
|
|
1208
915
|
}
|
|
1209
916
|
|
|
1210
|
-
|
|
1211
|
-
const std::string end_;
|
|
1212
|
-
};
|
|
1213
|
-
|
|
1214
|
-
NAPI_METHOD(db_compact_range) {
|
|
1215
|
-
NAPI_ARGV(4);
|
|
1216
|
-
NAPI_DB_CONTEXT();
|
|
1217
|
-
|
|
1218
|
-
const auto start = ToString(env, argv[1]);
|
|
1219
|
-
const auto end = ToString(env, argv[2]);
|
|
1220
|
-
const auto callback = argv[3];
|
|
1221
|
-
|
|
1222
|
-
auto worker = new CompactRangeWorker(env, database, callback, start, end);
|
|
1223
|
-
worker->Queue(env);
|
|
917
|
+
it.Close();
|
|
1224
918
|
|
|
1225
|
-
return
|
|
919
|
+
return ToError(env, status);
|
|
1226
920
|
}
|
|
1227
921
|
|
|
1228
922
|
NAPI_METHOD(db_get_property) {
|
|
@@ -1232,7 +926,7 @@ NAPI_METHOD(db_get_property) {
|
|
|
1232
926
|
const auto property = ToString(env, argv[1]);
|
|
1233
927
|
|
|
1234
928
|
std::string value;
|
|
1235
|
-
database->GetProperty(property, value);
|
|
929
|
+
database->db_->GetProperty(property, &value);
|
|
1236
930
|
|
|
1237
931
|
napi_value result;
|
|
1238
932
|
napi_create_string_utf8(env, value.data(), value.size(), &result);
|
|
@@ -1240,63 +934,7 @@ NAPI_METHOD(db_get_property) {
|
|
|
1240
934
|
return result;
|
|
1241
935
|
}
|
|
1242
936
|
|
|
1243
|
-
|
|
1244
|
-
DestroyWorker (napi_env env,
|
|
1245
|
-
const std::string& location,
|
|
1246
|
-
napi_value callback)
|
|
1247
|
-
: BaseWorker(env, nullptr, callback, "rocks_level.destroy_db"),
|
|
1248
|
-
location_(location) {}
|
|
1249
|
-
|
|
1250
|
-
~DestroyWorker () {}
|
|
1251
|
-
|
|
1252
|
-
rocksdb::Status Execute () override {
|
|
1253
|
-
rocksdb::Options options;
|
|
1254
|
-
return rocksdb::DestroyDB(location_, options);
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
const std::string location_;
|
|
1258
|
-
};
|
|
1259
|
-
|
|
1260
|
-
NAPI_METHOD(destroy_db) {
|
|
1261
|
-
NAPI_ARGV(2);
|
|
1262
|
-
|
|
1263
|
-
const auto location = ToString(env, argv[0]);
|
|
1264
|
-
const auto callback = argv[1];
|
|
1265
|
-
|
|
1266
|
-
auto worker = new DestroyWorker(env, location, callback);
|
|
1267
|
-
worker->Queue(env);
|
|
1268
|
-
|
|
1269
|
-
return 0;
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
struct RepairWorker final : public BaseWorker {
|
|
1273
|
-
RepairWorker (napi_env env,
|
|
1274
|
-
const std::string& location,
|
|
1275
|
-
napi_value callback)
|
|
1276
|
-
: BaseWorker(env, nullptr, callback, "rocks_level.repair_db"),
|
|
1277
|
-
location_(location) {}
|
|
1278
|
-
|
|
1279
|
-
rocksdb::Status Execute () override {
|
|
1280
|
-
rocksdb::Options options;
|
|
1281
|
-
return rocksdb::RepairDB(location_, options);
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
const std::string location_;
|
|
1285
|
-
};
|
|
1286
|
-
|
|
1287
|
-
NAPI_METHOD(repair_db) {
|
|
1288
|
-
NAPI_ARGV(2);
|
|
1289
|
-
|
|
1290
|
-
const auto location = ToString(env, argv[1]);
|
|
1291
|
-
const auto callback = argv[1];
|
|
1292
|
-
|
|
1293
|
-
auto worker = new RepairWorker(env, location, callback);
|
|
1294
|
-
worker->Queue(env);
|
|
1295
|
-
|
|
1296
|
-
return 0;
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
static void FinalizeIterator (napi_env env, void* data, void* hint) {
|
|
937
|
+
static void FinalizeIterator(napi_env env, void* data, void* hint) {
|
|
1300
938
|
if (data) {
|
|
1301
939
|
delete reinterpret_cast<Iterator*>(data);
|
|
1302
940
|
}
|
|
@@ -1321,14 +959,11 @@ NAPI_METHOD(iterator_init) {
|
|
|
1321
959
|
const auto gt = RangeOption(env, options, "gt");
|
|
1322
960
|
const auto gte = RangeOption(env, options, "gte");
|
|
1323
961
|
|
|
1324
|
-
auto iterator = new Iterator(database, reverse, keys,
|
|
1325
|
-
|
|
1326
|
-
keyAsBuffer, valueAsBuffer, highWaterMarkBytes);
|
|
962
|
+
auto iterator = new Iterator(database, reverse, keys, values, limit, lt, lte, gt, gte, fillCache, keyAsBuffer,
|
|
963
|
+
valueAsBuffer, highWaterMarkBytes);
|
|
1327
964
|
napi_value result;
|
|
1328
965
|
|
|
1329
|
-
NAPI_STATUS_THROWS(napi_create_external(env, iterator,
|
|
1330
|
-
FinalizeIterator,
|
|
1331
|
-
nullptr, &result));
|
|
966
|
+
NAPI_STATUS_THROWS(napi_create_external(env, iterator, FinalizeIterator, nullptr, &result));
|
|
1332
967
|
|
|
1333
968
|
// Prevent GC of JS object before the iterator is closed (explicitly or on
|
|
1334
969
|
// db close) and keep track of non-closed iterators to end them on db close.
|
|
@@ -1348,24 +983,21 @@ NAPI_METHOD(iterator_seek) {
|
|
|
1348
983
|
return 0;
|
|
1349
984
|
}
|
|
1350
985
|
|
|
1351
|
-
struct CloseIteratorWorker final : public
|
|
1352
|
-
CloseIteratorWorker
|
|
1353
|
-
|
|
1354
|
-
napi_value callback)
|
|
1355
|
-
: BaseWorker(env, iterator->database_, callback, "leveldown.iterator.end"),
|
|
1356
|
-
iterator_(iterator) {}
|
|
986
|
+
struct CloseIteratorWorker final : public Worker {
|
|
987
|
+
CloseIteratorWorker(napi_env env, Iterator* iterator, napi_value callback)
|
|
988
|
+
: Worker(env, iterator->database_, callback, "leveldown.iterator.end"), iterator_(iterator) {}
|
|
1357
989
|
|
|
1358
|
-
rocksdb::Status Execute
|
|
990
|
+
rocksdb::Status Execute(Database& database) override {
|
|
1359
991
|
iterator_->Close();
|
|
1360
992
|
return rocksdb::Status::OK();
|
|
1361
993
|
}
|
|
1362
994
|
|
|
1363
|
-
void
|
|
995
|
+
void Destroy(napi_env env) override {
|
|
1364
996
|
iterator_->Detach(env);
|
|
1365
|
-
|
|
997
|
+
Worker::Destroy(env);
|
|
1366
998
|
}
|
|
1367
999
|
|
|
1368
|
-
private:
|
|
1000
|
+
private:
|
|
1369
1001
|
Iterator* iterator_;
|
|
1370
1002
|
};
|
|
1371
1003
|
|
|
@@ -1381,16 +1013,11 @@ NAPI_METHOD(iterator_close) {
|
|
|
1381
1013
|
return 0;
|
|
1382
1014
|
}
|
|
1383
1015
|
|
|
1384
|
-
struct NextWorker final : public
|
|
1385
|
-
NextWorker
|
|
1386
|
-
|
|
1387
|
-
uint32_t size,
|
|
1388
|
-
napi_value callback)
|
|
1389
|
-
: BaseWorker(env, iterator->database_, callback,
|
|
1390
|
-
"leveldown.iterator.next"),
|
|
1391
|
-
iterator_(iterator), size_(size) {}
|
|
1016
|
+
struct NextWorker final : public Worker {
|
|
1017
|
+
NextWorker(napi_env env, Iterator* iterator, uint32_t size, napi_value callback)
|
|
1018
|
+
: Worker(env, iterator->database_, callback, "leveldown.iterator.next"), iterator_(iterator), size_(size) {}
|
|
1392
1019
|
|
|
1393
|
-
rocksdb::Status Execute
|
|
1020
|
+
rocksdb::Status Execute(Database& database) override {
|
|
1394
1021
|
if (!iterator_->DidSeek()) {
|
|
1395
1022
|
iterator_->SeekToRange();
|
|
1396
1023
|
}
|
|
@@ -1398,16 +1025,18 @@ struct NextWorker final : public BaseWorker {
|
|
|
1398
1025
|
// Limit the size of the cache to prevent starving the event loop
|
|
1399
1026
|
// in JS-land while we're recursively calling process.nextTick().
|
|
1400
1027
|
|
|
1401
|
-
finished_ = false;
|
|
1402
1028
|
cache_.reserve(size_ * 2);
|
|
1403
1029
|
size_t bytesRead = 0;
|
|
1404
1030
|
|
|
1405
1031
|
while (true) {
|
|
1406
|
-
if (!iterator_->first_)
|
|
1407
|
-
|
|
1032
|
+
if (!iterator_->first_)
|
|
1033
|
+
iterator_->Next();
|
|
1034
|
+
else
|
|
1035
|
+
iterator_->first_ = false;
|
|
1036
|
+
|
|
1037
|
+
if (!iterator_->Valid() || !iterator_->Increment())
|
|
1038
|
+
break;
|
|
1408
1039
|
|
|
1409
|
-
if (!iterator_->Valid() || !iterator_->Increment()) break;
|
|
1410
|
-
|
|
1411
1040
|
if (iterator_->keys_ && iterator_->values_) {
|
|
1412
1041
|
auto k = iterator_->CurrentKey();
|
|
1413
1042
|
auto v = iterator_->CurrentValue();
|
|
@@ -1435,7 +1064,7 @@ struct NextWorker final : public BaseWorker {
|
|
|
1435
1064
|
return iterator_->Status();
|
|
1436
1065
|
}
|
|
1437
1066
|
|
|
1438
|
-
void
|
|
1067
|
+
void OnOk(napi_env env, napi_value callback) override {
|
|
1439
1068
|
const auto size = cache_.size();
|
|
1440
1069
|
napi_value result;
|
|
1441
1070
|
napi_create_array_with_length(env, size, &result);
|
|
@@ -1460,7 +1089,7 @@ struct NextWorker final : public BaseWorker {
|
|
|
1460
1089
|
CallFunction(env, callback, 3, argv);
|
|
1461
1090
|
}
|
|
1462
1091
|
|
|
1463
|
-
private:
|
|
1092
|
+
private:
|
|
1464
1093
|
std::vector<std::string> cache_;
|
|
1465
1094
|
Iterator* iterator_ = nullptr;
|
|
1466
1095
|
uint32_t size_ = 0;
|
|
@@ -1473,7 +1102,8 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1473
1102
|
|
|
1474
1103
|
uint32_t size;
|
|
1475
1104
|
NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &size));
|
|
1476
|
-
if (size == 0)
|
|
1105
|
+
if (size == 0)
|
|
1106
|
+
size = 1;
|
|
1477
1107
|
|
|
1478
1108
|
const auto callback = argv[2];
|
|
1479
1109
|
|
|
@@ -1483,74 +1113,51 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1483
1113
|
return 0;
|
|
1484
1114
|
}
|
|
1485
1115
|
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
napi_value callback,
|
|
1490
|
-
napi_value array,
|
|
1491
|
-
const bool sync)
|
|
1492
|
-
: PriorityWorker(env, database, callback, "rocks_level.batch.do"), sync_(sync) {
|
|
1493
|
-
uint32_t length;
|
|
1494
|
-
NAPI_STATUS_THROWS_VOID(napi_get_array_length(env, array, &length));
|
|
1495
|
-
|
|
1496
|
-
for (uint32_t i = 0; i < length; i++) {
|
|
1497
|
-
napi_value element;
|
|
1498
|
-
NAPI_STATUS_THROWS_VOID(napi_get_element(env, array, i, &element));
|
|
1116
|
+
NAPI_METHOD(batch_do) {
|
|
1117
|
+
NAPI_ARGV(3);
|
|
1118
|
+
NAPI_DB_CONTEXT();
|
|
1499
1119
|
|
|
1500
|
-
|
|
1120
|
+
const auto operations = argv[1];
|
|
1501
1121
|
|
|
1502
|
-
|
|
1122
|
+
rocksdb::WriteBatch batch;
|
|
1503
1123
|
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
const auto key = ToString(env, GetProperty(env, element, "key"));
|
|
1124
|
+
uint32_t length;
|
|
1125
|
+
NAPI_STATUS_THROWS(napi_get_array_length(env, operations, &length));
|
|
1507
1126
|
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
if (!HasProperty(env, element, "key")) continue;
|
|
1512
|
-
if (!HasProperty(env, element, "value")) continue;
|
|
1127
|
+
for (uint32_t i = 0; i < length; i++) {
|
|
1128
|
+
napi_value element;
|
|
1129
|
+
NAPI_STATUS_THROWS(napi_get_element(env, operations, i, &element));
|
|
1513
1130
|
|
|
1514
|
-
|
|
1515
|
-
|
|
1131
|
+
if (!IsObject(env, element))
|
|
1132
|
+
continue;
|
|
1516
1133
|
|
|
1517
|
-
|
|
1518
|
-
if (!hasData_) hasData_ = true;
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1134
|
+
const auto type = StringProperty(env, element, "type");
|
|
1522
1135
|
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
}
|
|
1136
|
+
if (type == "del") {
|
|
1137
|
+
if (!HasProperty(env, element, "key"))
|
|
1138
|
+
continue;
|
|
1527
1139
|
|
|
1528
|
-
|
|
1529
|
-
options.sync = sync_;
|
|
1530
|
-
return database_->WriteBatch(options, &batch_);
|
|
1531
|
-
}
|
|
1140
|
+
const auto key = NapiSlice(env, GetProperty(env, element, "key"));
|
|
1532
1141
|
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
NAPI_METHOD(batch_do) {
|
|
1540
|
-
NAPI_ARGV(4);
|
|
1541
|
-
NAPI_DB_CONTEXT();
|
|
1142
|
+
batch.Delete(key);
|
|
1143
|
+
} else if (type == "put") {
|
|
1144
|
+
if (!HasProperty(env, element, "key"))
|
|
1145
|
+
continue;
|
|
1146
|
+
if (!HasProperty(env, element, "value"))
|
|
1147
|
+
continue;
|
|
1542
1148
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
const auto callback = argv[3];
|
|
1149
|
+
const auto key = NapiSlice(env, GetProperty(env, element, "key"));
|
|
1150
|
+
const auto value = NapiSlice(env, GetProperty(env, element, "value"));
|
|
1546
1151
|
|
|
1547
|
-
|
|
1548
|
-
|
|
1152
|
+
batch.Put(key, value);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1549
1155
|
|
|
1550
|
-
|
|
1156
|
+
rocksdb::WriteOptions options;
|
|
1157
|
+
return ToError(env, database->db_->Write(options, &batch));
|
|
1551
1158
|
}
|
|
1552
1159
|
|
|
1553
|
-
static void FinalizeBatch
|
|
1160
|
+
static void FinalizeBatch(napi_env env, void* data, void* hint) {
|
|
1554
1161
|
if (data) {
|
|
1555
1162
|
delete reinterpret_cast<rocksdb::WriteBatch*>(data);
|
|
1556
1163
|
}
|
|
@@ -1571,8 +1178,8 @@ NAPI_METHOD(batch_put) {
|
|
|
1571
1178
|
NAPI_ARGV(3);
|
|
1572
1179
|
NAPI_BATCH_CONTEXT();
|
|
1573
1180
|
|
|
1574
|
-
const auto key =
|
|
1575
|
-
const auto value =
|
|
1181
|
+
const auto key = NapiSlice(env, argv[1]);
|
|
1182
|
+
const auto value = NapiSlice(env, argv[2]);
|
|
1576
1183
|
|
|
1577
1184
|
batch->Put(key, value);
|
|
1578
1185
|
|
|
@@ -1583,7 +1190,7 @@ NAPI_METHOD(batch_del) {
|
|
|
1583
1190
|
NAPI_ARGV(2);
|
|
1584
1191
|
NAPI_BATCH_CONTEXT();
|
|
1585
1192
|
|
|
1586
|
-
const auto key =
|
|
1193
|
+
const auto key = NapiSlice(env, argv[1]);
|
|
1587
1194
|
|
|
1588
1195
|
batch->Delete(key);
|
|
1589
1196
|
|
|
@@ -1599,51 +1206,15 @@ NAPI_METHOD(batch_clear) {
|
|
|
1599
1206
|
return 0;
|
|
1600
1207
|
}
|
|
1601
1208
|
|
|
1602
|
-
struct BatchWriteWorker final : public PriorityWorker {
|
|
1603
|
-
BatchWriteWorker (napi_env env,
|
|
1604
|
-
Database* database,
|
|
1605
|
-
napi_value batch,
|
|
1606
|
-
napi_value callback,
|
|
1607
|
-
const bool sync)
|
|
1608
|
-
: PriorityWorker(env, database, callback, "leveldown.batch.write"),
|
|
1609
|
-
sync_(sync) {
|
|
1610
|
-
|
|
1611
|
-
NAPI_STATUS_THROWS_VOID(napi_get_value_external(env, batch, reinterpret_cast<void**>(&batch_)));
|
|
1612
|
-
|
|
1613
|
-
// Prevent GC of batch object before we execute
|
|
1614
|
-
NAPI_STATUS_THROWS_VOID(napi_create_reference(env, batch, 1, &batchRef_));
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
rocksdb::Status Execute () override {
|
|
1618
|
-
rocksdb::WriteOptions options;
|
|
1619
|
-
options.sync = sync_;
|
|
1620
|
-
return database_->WriteBatch(options, batch_);
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
void Finally (napi_env env) override {
|
|
1624
|
-
napi_delete_reference(env, batchRef_);
|
|
1625
|
-
PriorityWorker::Finally(env);
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
private:
|
|
1629
|
-
rocksdb::WriteBatch* batch_;
|
|
1630
|
-
const bool sync_;
|
|
1631
|
-
napi_ref batchRef_;
|
|
1632
|
-
};
|
|
1633
|
-
|
|
1634
1209
|
NAPI_METHOD(batch_write) {
|
|
1635
|
-
NAPI_ARGV(
|
|
1210
|
+
NAPI_ARGV(3);
|
|
1636
1211
|
NAPI_DB_CONTEXT();
|
|
1637
1212
|
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
const auto sync = BooleanProperty(env, options, "sync", false);
|
|
1641
|
-
const auto callback = argv[3];
|
|
1642
|
-
|
|
1643
|
-
auto worker = new BatchWriteWorker(env, database, batch, callback, sync);
|
|
1644
|
-
worker->Queue(env);
|
|
1213
|
+
rocksdb::WriteBatch* batch;
|
|
1214
|
+
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
|
|
1645
1215
|
|
|
1646
|
-
|
|
1216
|
+
rocksdb::WriteOptions options;
|
|
1217
|
+
return ToError(env, database->db_->Write(options, batch));
|
|
1647
1218
|
}
|
|
1648
1219
|
|
|
1649
1220
|
NAPI_INIT() {
|
|
@@ -1655,13 +1226,8 @@ NAPI_INIT() {
|
|
|
1655
1226
|
NAPI_EXPORT_FUNCTION(db_get_many);
|
|
1656
1227
|
NAPI_EXPORT_FUNCTION(db_del);
|
|
1657
1228
|
NAPI_EXPORT_FUNCTION(db_clear);
|
|
1658
|
-
NAPI_EXPORT_FUNCTION(db_approximate_size);
|
|
1659
|
-
NAPI_EXPORT_FUNCTION(db_compact_range);
|
|
1660
1229
|
NAPI_EXPORT_FUNCTION(db_get_property);
|
|
1661
1230
|
|
|
1662
|
-
NAPI_EXPORT_FUNCTION(destroy_db);
|
|
1663
|
-
NAPI_EXPORT_FUNCTION(repair_db);
|
|
1664
|
-
|
|
1665
1231
|
NAPI_EXPORT_FUNCTION(iterator_init);
|
|
1666
1232
|
NAPI_EXPORT_FUNCTION(iterator_seek);
|
|
1667
1233
|
NAPI_EXPORT_FUNCTION(iterator_close);
|