@nxtedition/rocksdb 5.2.33 → 5.2.36
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 +303 -296
- package/binding.gyp +1 -1
- package/deps/rocksdb/rocksdb/README.md +32 -0
- package/deps/rocksdb/rocksdb/microbench/README.md +60 -0
- package/deps/rocksdb/rocksdb/plugin/README.md +43 -0
- package/deps/rocksdb/rocksdb/port/README +10 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_tree/lib/README +13 -0
- package/deps/rocksdb/rocksdb.gyp +1 -1
- package/deps/snappy/snappy-1.1.7/README.md +149 -0
- package/iterator.js +1 -1
- package/package.json +8 -8
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/{darwin-x64+arm64 → darwin-x64}/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.node +0 -0
- package/deps/rocksdb/rocksdb/cmake/modules/CxxFlags.cmake +0 -7
- package/deps/rocksdb/rocksdb/cmake/modules/FindJeMalloc.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/FindNUMA.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/FindSnappy.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/FindTBB.cmake +0 -33
- package/deps/rocksdb/rocksdb/cmake/modules/Findgflags.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/Findlz4.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/Finduring.cmake +0 -26
- package/deps/rocksdb/rocksdb/cmake/modules/Findzstd.cmake +0 -29
- package/deps/rocksdb/rocksdb/cmake/modules/ReadVersion.cmake +0 -10
- package/package-lock.json +0 -23687
- package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
package/binding.cc
CHANGED
|
@@ -30,6 +30,23 @@ class NullLogger : public rocksdb::Logger {
|
|
|
30
30
|
struct Database;
|
|
31
31
|
struct Iterator;
|
|
32
32
|
|
|
33
|
+
#define NAPI_STATUS_RETURN(call) \
|
|
34
|
+
{ \
|
|
35
|
+
const auto status = (call); \
|
|
36
|
+
if (status != napi_ok) { \
|
|
37
|
+
return status; \
|
|
38
|
+
} \
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#define NAPI_PENDING_EXCEPTION() \
|
|
42
|
+
{ \
|
|
43
|
+
bool result; \
|
|
44
|
+
NAPI_STATUS_THROWS(napi_is_exception_pending(env, &result)); \
|
|
45
|
+
if (result) { \
|
|
46
|
+
return nullptr; \
|
|
47
|
+
} \
|
|
48
|
+
}
|
|
49
|
+
|
|
33
50
|
#define NAPI_DB_CONTEXT() \
|
|
34
51
|
Database* database = nullptr; \
|
|
35
52
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
|
|
@@ -60,21 +77,15 @@ static bool IsObject(napi_env env, napi_value value) {
|
|
|
60
77
|
return type == napi_object;
|
|
61
78
|
}
|
|
62
79
|
|
|
63
|
-
static napi_value CreateError(napi_env env, const std::string_view&
|
|
64
|
-
napi_value
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return error;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
static napi_value CreateCodeError(napi_env env, const std::string_view& code, const std::string_view& msg) {
|
|
72
|
-
napi_value codeValue;
|
|
73
|
-
napi_create_string_utf8(env, code.data(), code.size(), &codeValue);
|
|
80
|
+
static napi_value CreateError(napi_env env, const std::optional<std::string_view>& code, const std::string_view& msg) {
|
|
81
|
+
napi_value codeValue = nullptr;
|
|
82
|
+
if (code) {
|
|
83
|
+
NAPI_STATUS_THROWS(napi_create_string_utf8(env, code->data(), code->size(), &codeValue));
|
|
84
|
+
}
|
|
74
85
|
napi_value msgValue;
|
|
75
|
-
napi_create_string_utf8(env, msg.data(), msg.size(), &msgValue);
|
|
86
|
+
NAPI_STATUS_THROWS(napi_create_string_utf8(env, msg.data(), msg.size(), &msgValue));
|
|
76
87
|
napi_value error;
|
|
77
|
-
napi_create_error(env, codeValue, msgValue, &error);
|
|
88
|
+
NAPI_STATUS_THROWS(napi_create_error(env, codeValue, msgValue, &error));
|
|
78
89
|
return error;
|
|
79
90
|
}
|
|
80
91
|
|
|
@@ -90,7 +101,7 @@ static napi_value GetProperty(napi_env env, napi_value obj, const std::string_vi
|
|
|
90
101
|
return value;
|
|
91
102
|
}
|
|
92
103
|
|
|
93
|
-
static bool BooleanProperty(napi_env env, napi_value obj, const std::string_view& key
|
|
104
|
+
static std::optional<bool> BooleanProperty(napi_env env, napi_value obj, const std::string_view& key) {
|
|
94
105
|
if (HasProperty(env, obj, key.data())) {
|
|
95
106
|
const auto value = GetProperty(env, obj, key.data());
|
|
96
107
|
bool result;
|
|
@@ -98,7 +109,7 @@ static bool BooleanProperty(napi_env env, napi_value obj, const std::string_view
|
|
|
98
109
|
return result;
|
|
99
110
|
}
|
|
100
111
|
|
|
101
|
-
return
|
|
112
|
+
return {};
|
|
102
113
|
}
|
|
103
114
|
|
|
104
115
|
static bool EncodingIsBuffer(napi_env env, napi_value obj, const std::string_view& option) {
|
|
@@ -114,7 +125,7 @@ static bool EncodingIsBuffer(napi_env env, napi_value obj, const std::string_vie
|
|
|
114
125
|
return false;
|
|
115
126
|
}
|
|
116
127
|
|
|
117
|
-
static uint32_t Uint32Property(napi_env env, napi_value obj, const std::string_view& key
|
|
128
|
+
static std::optional<uint32_t> Uint32Property(napi_env env, napi_value obj, const std::string_view& key) {
|
|
118
129
|
if (HasProperty(env, obj, key.data())) {
|
|
119
130
|
const auto value = GetProperty(env, obj, key.data());
|
|
120
131
|
uint32_t result;
|
|
@@ -122,10 +133,10 @@ static uint32_t Uint32Property(napi_env env, napi_value obj, const std::string_v
|
|
|
122
133
|
return result;
|
|
123
134
|
}
|
|
124
135
|
|
|
125
|
-
return
|
|
136
|
+
return {};
|
|
126
137
|
}
|
|
127
138
|
|
|
128
|
-
static int Int32Property(napi_env env, napi_value obj, const std::string_view& key
|
|
139
|
+
static std::optional<int> Int32Property(napi_env env, napi_value obj, const std::string_view& key) {
|
|
129
140
|
if (HasProperty(env, obj, key.data())) {
|
|
130
141
|
const auto value = GetProperty(env, obj, key.data());
|
|
131
142
|
int result;
|
|
@@ -133,7 +144,7 @@ static int Int32Property(napi_env env, napi_value obj, const std::string_view& k
|
|
|
133
144
|
return result;
|
|
134
145
|
}
|
|
135
146
|
|
|
136
|
-
return
|
|
147
|
+
return {};
|
|
137
148
|
}
|
|
138
149
|
|
|
139
150
|
static std::string ToString(napi_env env, napi_value from, const std::string& defaultValue = "") {
|
|
@@ -153,42 +164,19 @@ static std::string ToString(napi_env env, napi_value from, const std::string& de
|
|
|
153
164
|
return defaultValue;
|
|
154
165
|
}
|
|
155
166
|
|
|
156
|
-
static std::string StringProperty(napi_env env,
|
|
157
|
-
napi_value obj,
|
|
158
|
-
const std::string_view& key,
|
|
159
|
-
const std::string& defaultValue = "") {
|
|
160
|
-
if (HasProperty(env, obj, key)) {
|
|
161
|
-
napi_value value = GetProperty(env, obj, key);
|
|
162
|
-
if (IsString(env, value)) {
|
|
163
|
-
return ToString(env, value);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return defaultValue;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
static std::optional<std::string> RangeOption(napi_env env, napi_value opts, const std::string_view& name) {
|
|
167
|
+
static std::optional<std::string> StringProperty(napi_env env, napi_value opts, const std::string_view& name) {
|
|
171
168
|
if (HasProperty(env, opts, name)) {
|
|
172
169
|
const auto value = GetProperty(env, opts, name);
|
|
173
170
|
return ToString(env, value);
|
|
174
171
|
}
|
|
175
|
-
|
|
176
172
|
return {};
|
|
177
173
|
}
|
|
178
174
|
|
|
179
175
|
static napi_status CallFunction(napi_env env, napi_value callback, const int argc, napi_value* argv) {
|
|
180
|
-
napi_status status;
|
|
181
176
|
napi_value global;
|
|
182
177
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return status;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
status = napi_call_function(env, global, callback, argc, argv, nullptr);
|
|
189
|
-
if (status != napi_ok) {
|
|
190
|
-
return status;
|
|
191
|
-
}
|
|
178
|
+
NAPI_STATUS_RETURN(napi_get_global(env, &global));
|
|
179
|
+
NAPI_STATUS_RETURN(napi_call_function(env, global, callback, argc, argv, nullptr));
|
|
192
180
|
|
|
193
181
|
return napi_ok;
|
|
194
182
|
}
|
|
@@ -201,28 +189,45 @@ static napi_value ToError(napi_env env, const rocksdb::Status& status) {
|
|
|
201
189
|
const auto msg = status.ToString();
|
|
202
190
|
|
|
203
191
|
if (status.IsNotFound()) {
|
|
204
|
-
return
|
|
192
|
+
return CreateError(env, "LEVEL_NOT_FOUND", msg);
|
|
205
193
|
} else if (status.IsCorruption()) {
|
|
206
|
-
return
|
|
194
|
+
return CreateError(env, "LEVEL_CORRUPTION", msg);
|
|
207
195
|
} else if (status.IsIOError()) {
|
|
208
196
|
if (msg.find("IO error: lock ") != std::string::npos) { // env_posix.cc
|
|
209
|
-
return
|
|
197
|
+
return CreateError(env, "LEVEL_LOCKED", msg);
|
|
210
198
|
} else if (msg.find("IO error: LockFile ") != std::string::npos) { // env_win.cc
|
|
211
|
-
return
|
|
199
|
+
return CreateError(env, "LEVEL_LOCKED", msg);
|
|
212
200
|
} else if (msg.find("IO error: While lock file") != std::string::npos) { // env_mac.cc
|
|
213
|
-
return
|
|
201
|
+
return CreateError(env, "LEVEL_LOCKED", msg);
|
|
214
202
|
} else {
|
|
215
|
-
return
|
|
203
|
+
return CreateError(env, "LEVEL_IO_ERROR", msg);
|
|
216
204
|
}
|
|
217
205
|
}
|
|
218
206
|
|
|
219
|
-
return CreateError(env, msg);
|
|
207
|
+
return CreateError(env, {}, msg);
|
|
220
208
|
}
|
|
221
209
|
|
|
222
210
|
template <typename T>
|
|
223
|
-
|
|
211
|
+
static void Finalize(napi_env env, void* data, void* hint) {
|
|
212
|
+
if (hint) {
|
|
213
|
+
delete reinterpret_cast<T*>(hint);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
napi_status Convert(napi_env env, std::string s, bool asBuffer, napi_value& result) {
|
|
218
|
+
if (asBuffer) {
|
|
219
|
+
auto ptr = new std::string(std::move(s));
|
|
220
|
+
return napi_create_external_buffer(env, ptr->size(), ptr->data(), Finalize<std::string>, ptr, &result);
|
|
221
|
+
} else {
|
|
222
|
+
return napi_create_string_utf8(env, s.data(), s.size(), &result);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
napi_status Convert(napi_env env, rocksdb::PinnableSlice s, bool asBuffer, napi_value& result) {
|
|
224
227
|
if (asBuffer) {
|
|
225
|
-
|
|
228
|
+
auto ptr = new rocksdb::PinnableSlice(std::move(s));
|
|
229
|
+
return napi_create_external_buffer(env, ptr->size(), const_cast<char*>(ptr->data()), Finalize<std::string>, ptr,
|
|
230
|
+
&result);
|
|
226
231
|
} else {
|
|
227
232
|
return napi_create_string_utf8(env, s.data(), s.size(), &result);
|
|
228
233
|
}
|
|
@@ -231,7 +236,7 @@ napi_status Convert(napi_env env, const T& s, bool asBuffer, napi_value& result)
|
|
|
231
236
|
struct NapiSlice : public rocksdb::Slice {
|
|
232
237
|
NapiSlice(napi_env env, napi_value from) {
|
|
233
238
|
if (IsString(env, from)) {
|
|
234
|
-
napi_get_value_string_utf8(env, from, nullptr, 0, &size_);
|
|
239
|
+
NAPI_STATUS_THROWS_VOID(napi_get_value_string_utf8(env, from, nullptr, 0, &size_));
|
|
235
240
|
char* data;
|
|
236
241
|
if (size_ + 1 < stack_.size()) {
|
|
237
242
|
data = stack_.data();
|
|
@@ -240,17 +245,17 @@ struct NapiSlice : public rocksdb::Slice {
|
|
|
240
245
|
data = heap_.get();
|
|
241
246
|
}
|
|
242
247
|
data[size_] = 0;
|
|
243
|
-
napi_get_value_string_utf8(env, from, data, size_ + 1, &size_);
|
|
248
|
+
NAPI_STATUS_THROWS_VOID(napi_get_value_string_utf8(env, from, data, size_ + 1, &size_));
|
|
244
249
|
data_ = data;
|
|
245
250
|
} else if (IsBuffer(env, from)) {
|
|
246
251
|
void* data;
|
|
247
|
-
napi_get_buffer_info(env, from, &data, &size_);
|
|
252
|
+
NAPI_STATUS_THROWS_VOID(napi_get_buffer_info(env, from, &data, &size_));
|
|
248
253
|
data_ = static_cast<char*>(data);
|
|
249
254
|
}
|
|
250
255
|
}
|
|
251
256
|
|
|
252
257
|
std::unique_ptr<char[]> heap_;
|
|
253
|
-
std::array<char,
|
|
258
|
+
std::array<char, 1024> stack_;
|
|
254
259
|
};
|
|
255
260
|
|
|
256
261
|
/**
|
|
@@ -263,13 +268,12 @@ struct NapiSlice : public rocksdb::Slice {
|
|
|
263
268
|
* - Destroy (main thread): do cleanup regardless of success
|
|
264
269
|
*/
|
|
265
270
|
struct Worker {
|
|
266
|
-
Worker(napi_env env, Database* database, napi_value callback, const std::string& resourceName)
|
|
267
|
-
: database_(database) {
|
|
271
|
+
Worker(napi_env env, Database* database, napi_value callback, const std::string& resourceName) : database_(database) {
|
|
268
272
|
NAPI_STATUS_THROWS_VOID(napi_create_reference(env, callback, 1, &callbackRef_));
|
|
269
273
|
napi_value asyncResourceName;
|
|
270
274
|
NAPI_STATUS_THROWS_VOID(napi_create_string_utf8(env, resourceName.data(), resourceName.size(), &asyncResourceName));
|
|
271
|
-
NAPI_STATUS_THROWS_VOID(
|
|
272
|
-
|
|
275
|
+
NAPI_STATUS_THROWS_VOID(
|
|
276
|
+
napi_create_async_work(env, callback, asyncResourceName, Worker::Execute, Worker::Complete, this, &asyncWork_));
|
|
273
277
|
}
|
|
274
278
|
|
|
275
279
|
virtual ~Worker() {}
|
|
@@ -282,6 +286,8 @@ struct Worker {
|
|
|
282
286
|
static void Complete(napi_env env, napi_status status, void* data) {
|
|
283
287
|
auto self = reinterpret_cast<Worker*>(data);
|
|
284
288
|
|
|
289
|
+
// TODO (fix): napi status handling...
|
|
290
|
+
|
|
285
291
|
napi_value callback;
|
|
286
292
|
napi_get_reference_value(env, self->callbackRef_, &callback);
|
|
287
293
|
|
|
@@ -301,13 +307,15 @@ struct Worker {
|
|
|
301
307
|
|
|
302
308
|
virtual rocksdb::Status Execute(Database& database) = 0;
|
|
303
309
|
|
|
304
|
-
virtual
|
|
310
|
+
virtual napi_status OnOk(napi_env env, napi_value callback) {
|
|
305
311
|
napi_value argv;
|
|
306
|
-
napi_get_null(env, &argv);
|
|
307
|
-
CallFunction(env, callback, 1, &argv);
|
|
312
|
+
NAPI_STATUS_RETURN(napi_get_null(env, &argv));
|
|
313
|
+
return CallFunction(env, callback, 1, &argv);
|
|
308
314
|
}
|
|
309
315
|
|
|
310
|
-
virtual
|
|
316
|
+
virtual napi_status OnError(napi_env env, napi_value callback, napi_value err) {
|
|
317
|
+
return CallFunction(env, callback, 1, &err);
|
|
318
|
+
}
|
|
311
319
|
|
|
312
320
|
virtual void Destroy(napi_env env) {}
|
|
313
321
|
|
|
@@ -322,20 +330,6 @@ struct Worker {
|
|
|
322
330
|
};
|
|
323
331
|
|
|
324
332
|
struct Database {
|
|
325
|
-
rocksdb::Status Open(const rocksdb::Options& options, const bool readOnly, const char* location) {
|
|
326
|
-
if (readOnly) {
|
|
327
|
-
rocksdb::DB* db = nullptr;
|
|
328
|
-
const auto status = rocksdb::DB::OpenForReadOnly(options, location, &db);
|
|
329
|
-
db_.reset(db);
|
|
330
|
-
return status;
|
|
331
|
-
} else {
|
|
332
|
-
rocksdb::DB* db = nullptr;
|
|
333
|
-
const auto status = rocksdb::DB::Open(options, location, &db);
|
|
334
|
-
db_.reset(db);
|
|
335
|
-
return status;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
333
|
void AttachIterator(napi_env env, Iterator* iterator) {
|
|
340
334
|
iterators_.insert(iterator);
|
|
341
335
|
IncrementPriorityWork(env);
|
|
@@ -346,10 +340,10 @@ struct Database {
|
|
|
346
340
|
DecrementPriorityWork(env);
|
|
347
341
|
}
|
|
348
342
|
|
|
349
|
-
void IncrementPriorityWork(napi_env env) { napi_reference_ref(env,
|
|
343
|
+
void IncrementPriorityWork(napi_env env) { napi_reference_ref(env, priorityRef_, &priorityWork_); }
|
|
350
344
|
|
|
351
345
|
void DecrementPriorityWork(napi_env env) {
|
|
352
|
-
napi_reference_unref(env,
|
|
346
|
+
napi_reference_unref(env, priorityRef_, &priorityWork_);
|
|
353
347
|
|
|
354
348
|
if (priorityWork_ == 0 && pendingCloseWorker_) {
|
|
355
349
|
pendingCloseWorker_->Queue(env);
|
|
@@ -362,7 +356,7 @@ struct Database {
|
|
|
362
356
|
std::unique_ptr<rocksdb::DB> db_;
|
|
363
357
|
Worker* pendingCloseWorker_;
|
|
364
358
|
std::set<Iterator*> iterators_;
|
|
365
|
-
napi_ref
|
|
359
|
+
napi_ref priorityRef_;
|
|
366
360
|
|
|
367
361
|
private:
|
|
368
362
|
uint32_t priorityWork_ = 0;
|
|
@@ -378,33 +372,40 @@ struct BaseIterator {
|
|
|
378
372
|
const int limit,
|
|
379
373
|
const bool fillCache)
|
|
380
374
|
: database_(database),
|
|
381
|
-
lt_(!lte ? lt : *lte + '\0'),
|
|
382
|
-
gte_(gte ? gte : (gt ? std::optional<std::string>(*gt + '\0') : std::nullopt)),
|
|
383
375
|
snapshot_(database_->db_->GetSnapshot(),
|
|
384
376
|
[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
377
|
reverse_(reverse),
|
|
400
|
-
limit_(limit)
|
|
378
|
+
limit_(limit),
|
|
379
|
+
fillCache_(fillCache) {
|
|
380
|
+
if (lte) {
|
|
381
|
+
upper_bound_ = rocksdb::PinnableSlice();
|
|
382
|
+
*upper_bound_->GetSelf() = std::move(*lte) + '\0';
|
|
383
|
+
upper_bound_->PinSelf();
|
|
384
|
+
} else if (lt) {
|
|
385
|
+
upper_bound_ = rocksdb::PinnableSlice();
|
|
386
|
+
*upper_bound_->GetSelf() = std::move(*lt);
|
|
387
|
+
upper_bound_->PinSelf();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (gte) {
|
|
391
|
+
lower_bound_ = rocksdb::PinnableSlice();
|
|
392
|
+
*lower_bound_->GetSelf() = std::move(*gte);
|
|
393
|
+
lower_bound_->PinSelf();
|
|
394
|
+
} else if (gt) {
|
|
395
|
+
lower_bound_ = rocksdb::PinnableSlice();
|
|
396
|
+
*lower_bound_->GetSelf() = std::move(*gt) + '\0';
|
|
397
|
+
lower_bound_->PinSelf();
|
|
398
|
+
}
|
|
399
|
+
}
|
|
401
400
|
|
|
402
401
|
virtual ~BaseIterator() { assert(!iterator_); }
|
|
403
402
|
|
|
404
|
-
bool DidSeek() const { return
|
|
403
|
+
bool DidSeek() const { return iterator_ != nullptr; }
|
|
405
404
|
|
|
406
405
|
void SeekToRange() {
|
|
407
|
-
|
|
406
|
+
if (!iterator_) {
|
|
407
|
+
Init();
|
|
408
|
+
}
|
|
408
409
|
|
|
409
410
|
if (reverse_) {
|
|
410
411
|
iterator_->SeekToLast();
|
|
@@ -413,10 +414,12 @@ struct BaseIterator {
|
|
|
413
414
|
}
|
|
414
415
|
}
|
|
415
416
|
|
|
416
|
-
void Seek(const
|
|
417
|
-
|
|
417
|
+
void Seek(const rocksdb::Slice& target) {
|
|
418
|
+
if (!iterator_) {
|
|
419
|
+
Init();
|
|
420
|
+
}
|
|
418
421
|
|
|
419
|
-
if ((
|
|
422
|
+
if ((upper_bound_ && target.compare(*upper_bound_) >= 0) || (lower_bound_ && target.compare(*lower_bound_) < 0)) {
|
|
420
423
|
// TODO (fix): Why is this required? Seek should handle it?
|
|
421
424
|
// https://github.com/facebook/rocksdb/issues/9904
|
|
422
425
|
iterator_->SeekToLast();
|
|
@@ -455,16 +458,28 @@ struct BaseIterator {
|
|
|
455
458
|
Database* database_;
|
|
456
459
|
|
|
457
460
|
private:
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
461
|
+
void Init() {
|
|
462
|
+
rocksdb::ReadOptions options;
|
|
463
|
+
if (upper_bound_) {
|
|
464
|
+
options.iterate_upper_bound = &*upper_bound_;
|
|
465
|
+
}
|
|
466
|
+
if (lower_bound_) {
|
|
467
|
+
options.iterate_lower_bound = &*lower_bound_;
|
|
468
|
+
}
|
|
469
|
+
options.fill_cache = fillCache_;
|
|
470
|
+
options.snapshot = snapshot_.get();
|
|
471
|
+
|
|
472
|
+
iterator_.reset(database_->db_->NewIterator(options));
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
std::optional<rocksdb::PinnableSlice> lower_bound_;
|
|
476
|
+
std::optional<rocksdb::PinnableSlice> upper_bound_;
|
|
462
477
|
std::shared_ptr<const rocksdb::Snapshot> snapshot_;
|
|
463
478
|
std::unique_ptr<rocksdb::Iterator> iterator_;
|
|
464
|
-
bool didSeek_ = false;
|
|
465
479
|
const bool reverse_;
|
|
466
480
|
const int limit_;
|
|
467
481
|
int count_ = 0;
|
|
482
|
+
const bool fillCache_;
|
|
468
483
|
};
|
|
469
484
|
|
|
470
485
|
struct Iterator final : public BaseIterator {
|
|
@@ -486,9 +501,7 @@ struct Iterator final : public BaseIterator {
|
|
|
486
501
|
values_(values),
|
|
487
502
|
keyAsBuffer_(keyAsBuffer),
|
|
488
503
|
valueAsBuffer_(valueAsBuffer),
|
|
489
|
-
highWaterMarkBytes_(highWaterMarkBytes)
|
|
490
|
-
first_(true),
|
|
491
|
-
ref_(nullptr) {}
|
|
504
|
+
highWaterMarkBytes_(highWaterMarkBytes) {}
|
|
492
505
|
|
|
493
506
|
void Attach(napi_env env, napi_value context) {
|
|
494
507
|
napi_create_reference(env, context, 1, &ref_);
|
|
@@ -507,10 +520,10 @@ struct Iterator final : public BaseIterator {
|
|
|
507
520
|
const bool keyAsBuffer_;
|
|
508
521
|
const bool valueAsBuffer_;
|
|
509
522
|
const uint32_t highWaterMarkBytes_;
|
|
510
|
-
bool first_;
|
|
523
|
+
bool first_ = true;
|
|
511
524
|
|
|
512
525
|
private:
|
|
513
|
-
napi_ref ref_;
|
|
526
|
+
napi_ref ref_ = nullptr;
|
|
514
527
|
};
|
|
515
528
|
|
|
516
529
|
/**
|
|
@@ -543,8 +556,8 @@ static void FinalizeDatabase(napi_env env, void* data, void* hint) {
|
|
|
543
556
|
if (data) {
|
|
544
557
|
auto database = reinterpret_cast<Database*>(data);
|
|
545
558
|
napi_remove_env_cleanup_hook(env, env_cleanup_hook, database);
|
|
546
|
-
if (database->
|
|
547
|
-
napi_delete_reference(env, database->
|
|
559
|
+
if (database->priorityRef_)
|
|
560
|
+
napi_delete_reference(env, database->priorityRef_);
|
|
548
561
|
delete database;
|
|
549
562
|
}
|
|
550
563
|
}
|
|
@@ -556,7 +569,7 @@ NAPI_METHOD(db_init) {
|
|
|
556
569
|
napi_value result;
|
|
557
570
|
NAPI_STATUS_THROWS(napi_create_external(env, database, FinalizeDatabase, nullptr, &result));
|
|
558
571
|
|
|
559
|
-
NAPI_STATUS_THROWS(napi_create_reference(env, result, 0, &database->
|
|
572
|
+
NAPI_STATUS_THROWS(napi_create_reference(env, result, 0, &database->priorityRef_));
|
|
560
573
|
|
|
561
574
|
return result;
|
|
562
575
|
}
|
|
@@ -566,71 +579,21 @@ struct OpenWorker final : public Worker {
|
|
|
566
579
|
Database* database,
|
|
567
580
|
napi_value callback,
|
|
568
581
|
const std::string& location,
|
|
569
|
-
|
|
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,
|
|
582
|
+
rocksdb::Options options,
|
|
579
583
|
const bool readOnly)
|
|
580
|
-
: Worker(env, database, callback, "leveldown.db.open"),
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
options_.write_buffer_size = writeBufferSize;
|
|
585
|
-
options_.max_open_files = maxOpenFiles;
|
|
586
|
-
options_.max_log_file_size = maxFileSize;
|
|
587
|
-
options_.use_adaptive_mutex = true;
|
|
588
|
-
|
|
589
|
-
if (infoLogLevel.size() > 0) {
|
|
590
|
-
rocksdb::InfoLogLevel lvl = {};
|
|
591
|
-
|
|
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");
|
|
606
|
-
|
|
607
|
-
options_.info_log_level = lvl;
|
|
608
|
-
} else {
|
|
609
|
-
// In some places RocksDB checks this option to see if it should prepare
|
|
610
|
-
// debug information (ahead of logging), so set it to the highest level.
|
|
611
|
-
options_.info_log_level = rocksdb::InfoLogLevel::HEADER_LEVEL;
|
|
612
|
-
options_.info_log.reset(new NullLogger());
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
rocksdb::BlockBasedTableOptions tableOptions;
|
|
616
|
-
|
|
617
|
-
if (cacheSize) {
|
|
618
|
-
tableOptions.block_cache = rocksdb::NewLRUCache(cacheSize);
|
|
619
|
-
} else {
|
|
620
|
-
tableOptions.no_block_cache = true;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
tableOptions.block_size = blockSize;
|
|
624
|
-
tableOptions.block_restart_interval = blockRestartInterval;
|
|
625
|
-
tableOptions.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10));
|
|
626
|
-
tableOptions.format_version = 5;
|
|
627
|
-
tableOptions.checksum = rocksdb::kxxHash64;
|
|
584
|
+
: Worker(env, database, callback, "leveldown.db.open"),
|
|
585
|
+
options_(options),
|
|
586
|
+
readOnly_(readOnly),
|
|
587
|
+
location_(location) {}
|
|
628
588
|
|
|
629
|
-
|
|
589
|
+
rocksdb::Status Execute(Database& database) override {
|
|
590
|
+
rocksdb::DB* db;
|
|
591
|
+
const auto status = readOnly_ ? rocksdb::DB::OpenForReadOnly(options_, location_, &db)
|
|
592
|
+
: rocksdb::DB::Open(options_, location_, &db);
|
|
593
|
+
database.db_.reset(db);
|
|
594
|
+
return status;
|
|
630
595
|
}
|
|
631
596
|
|
|
632
|
-
rocksdb::Status Execute(Database& database) override { return database.Open(options_, readOnly_, location_.c_str()); }
|
|
633
|
-
|
|
634
597
|
rocksdb::Options options_;
|
|
635
598
|
const bool readOnly_;
|
|
636
599
|
const std::string location_;
|
|
@@ -640,27 +603,68 @@ NAPI_METHOD(db_open) {
|
|
|
640
603
|
NAPI_ARGV(4);
|
|
641
604
|
NAPI_DB_CONTEXT();
|
|
642
605
|
|
|
606
|
+
rocksdb::Options options;
|
|
607
|
+
|
|
608
|
+
options.IncreaseParallelism(Uint32Property(env, argv[2], "parallelism").value_or(4));
|
|
609
|
+
|
|
643
610
|
const auto location = ToString(env, argv[1]);
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
611
|
+
options.create_if_missing = BooleanProperty(env, argv[2], "createIfMissing").value_or(true);
|
|
612
|
+
options.error_if_exists = BooleanProperty(env, argv[2], "errorIfExists").value_or(false);
|
|
613
|
+
options.compression = BooleanProperty(env, argv[2], "compression").value_or((true)) ? rocksdb::kSnappyCompression
|
|
614
|
+
: rocksdb::kNoCompression;
|
|
615
|
+
options.use_adaptive_mutex = true;
|
|
616
|
+
|
|
617
|
+
const auto infoLogLevel = StringProperty(env, argv[2], "infoLogLevel").value_or("");
|
|
618
|
+
if (infoLogLevel.size() > 0) {
|
|
619
|
+
rocksdb::InfoLogLevel lvl = {};
|
|
620
|
+
|
|
621
|
+
if (infoLogLevel == "debug")
|
|
622
|
+
lvl = rocksdb::InfoLogLevel::DEBUG_LEVEL;
|
|
623
|
+
else if (infoLogLevel == "info")
|
|
624
|
+
lvl = rocksdb::InfoLogLevel::INFO_LEVEL;
|
|
625
|
+
else if (infoLogLevel == "warn")
|
|
626
|
+
lvl = rocksdb::InfoLogLevel::WARN_LEVEL;
|
|
627
|
+
else if (infoLogLevel == "error")
|
|
628
|
+
lvl = rocksdb::InfoLogLevel::ERROR_LEVEL;
|
|
629
|
+
else if (infoLogLevel == "fatal")
|
|
630
|
+
lvl = rocksdb::InfoLogLevel::FATAL_LEVEL;
|
|
631
|
+
else if (infoLogLevel == "header")
|
|
632
|
+
lvl = rocksdb::InfoLogLevel::HEADER_LEVEL;
|
|
633
|
+
else
|
|
634
|
+
napi_throw_error(env, nullptr, "invalid log level");
|
|
649
635
|
|
|
650
|
-
|
|
636
|
+
options.info_log_level = lvl;
|
|
637
|
+
} else {
|
|
638
|
+
// In some places RocksDB checks this option to see if it should prepare
|
|
639
|
+
// debug information (ahead of logging), so set it to the highest level.
|
|
640
|
+
options.info_log_level = rocksdb::InfoLogLevel::HEADER_LEVEL;
|
|
641
|
+
options.info_log.reset(new NullLogger());
|
|
642
|
+
}
|
|
651
643
|
|
|
652
|
-
const auto
|
|
653
|
-
const auto
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
644
|
+
const auto readOnly = BooleanProperty(env, argv[2], "readOnly").value_or(false);
|
|
645
|
+
const auto cacheSize = Uint32Property(env, argv[2], "cacheSize").value_or(8 << 20);
|
|
646
|
+
|
|
647
|
+
rocksdb::BlockBasedTableOptions tableOptions;
|
|
648
|
+
|
|
649
|
+
if (cacheSize) {
|
|
650
|
+
tableOptions.block_cache = rocksdb::NewLRUCache(cacheSize);
|
|
651
|
+
} else {
|
|
652
|
+
tableOptions.no_block_cache = true;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
tableOptions.block_size = Uint32Property(env, argv[2], "blockSize").value_or(4096);
|
|
656
|
+
tableOptions.block_restart_interval = Uint32Property(env, argv[2], "blockRestartInterval").value_or(16);
|
|
657
|
+
tableOptions.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10));
|
|
658
|
+
tableOptions.format_version = 5;
|
|
659
|
+
tableOptions.checksum = rocksdb::kxxHash64;
|
|
660
|
+
|
|
661
|
+
options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(tableOptions));
|
|
658
662
|
|
|
659
663
|
const auto callback = argv[3];
|
|
660
664
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
665
|
+
NAPI_PENDING_EXCEPTION();
|
|
666
|
+
|
|
667
|
+
auto worker = new OpenWorker(env, database, callback, location, options, readOnly);
|
|
664
668
|
worker->Queue(env);
|
|
665
669
|
|
|
666
670
|
return 0;
|
|
@@ -698,11 +702,13 @@ NAPI_METHOD(db_put) {
|
|
|
698
702
|
NAPI_ARGV(4);
|
|
699
703
|
NAPI_DB_CONTEXT();
|
|
700
704
|
|
|
701
|
-
const auto key =
|
|
702
|
-
const auto
|
|
705
|
+
const auto key = NapiSlice(env, argv[1]);
|
|
706
|
+
const auto val = NapiSlice(env, argv[2]);
|
|
707
|
+
|
|
708
|
+
NAPI_PENDING_EXCEPTION();
|
|
703
709
|
|
|
704
710
|
rocksdb::WriteOptions options;
|
|
705
|
-
return ToError(env, database->db_->Put(options, key,
|
|
711
|
+
return ToError(env, database->db_->Put(options, key, val));
|
|
706
712
|
}
|
|
707
713
|
|
|
708
714
|
struct GetWorker final : public Worker {
|
|
@@ -726,17 +732,19 @@ struct GetWorker final : public Worker {
|
|
|
726
732
|
options.fill_cache = fillCache_;
|
|
727
733
|
options.snapshot = snapshot_.get();
|
|
728
734
|
|
|
729
|
-
auto status = database.db_->Get(options,
|
|
735
|
+
auto status = database.db_->Get(options, key_, &value_);
|
|
736
|
+
|
|
737
|
+
key_.clear();
|
|
730
738
|
snapshot_ = nullptr;
|
|
731
739
|
|
|
732
740
|
return status;
|
|
733
741
|
}
|
|
734
742
|
|
|
735
|
-
|
|
743
|
+
napi_status OnOk(napi_env env, napi_value callback) override {
|
|
736
744
|
napi_value argv[2];
|
|
737
|
-
napi_get_null(env, &argv[0]);
|
|
738
|
-
Convert(env, std::move(value_), asBuffer_, argv[1]);
|
|
739
|
-
CallFunction(env, callback, 2, argv);
|
|
745
|
+
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
746
|
+
NAPI_STATUS_RETURN(Convert(env, std::move(value_), asBuffer_, argv[1]));
|
|
747
|
+
return CallFunction(env, callback, 2, argv);
|
|
740
748
|
}
|
|
741
749
|
|
|
742
750
|
void Destroy(napi_env env) override {
|
|
@@ -745,8 +753,8 @@ struct GetWorker final : public Worker {
|
|
|
745
753
|
}
|
|
746
754
|
|
|
747
755
|
private:
|
|
748
|
-
|
|
749
|
-
|
|
756
|
+
std::string key_;
|
|
757
|
+
std::string value_;
|
|
750
758
|
const bool asBuffer_;
|
|
751
759
|
const bool fillCache_;
|
|
752
760
|
std::shared_ptr<const rocksdb::Snapshot> snapshot_;
|
|
@@ -759,9 +767,11 @@ NAPI_METHOD(db_get) {
|
|
|
759
767
|
const auto key = ToString(env, argv[1]);
|
|
760
768
|
const auto options = argv[2];
|
|
761
769
|
const auto asBuffer = EncodingIsBuffer(env, options, "valueEncoding");
|
|
762
|
-
const auto fillCache = BooleanProperty(env, options, "fillCache"
|
|
770
|
+
const auto fillCache = BooleanProperty(env, options, "fillCache").value_or(true);
|
|
763
771
|
const auto callback = argv[3];
|
|
764
772
|
|
|
773
|
+
NAPI_PENDING_EXCEPTION();
|
|
774
|
+
|
|
765
775
|
auto worker = new GetWorker(env, database, callback, key, asBuffer, fillCache);
|
|
766
776
|
worker->Queue(env);
|
|
767
777
|
|
|
@@ -789,10 +799,24 @@ struct GetManyWorker final : public Worker {
|
|
|
789
799
|
options.fill_cache = fillCache_;
|
|
790
800
|
options.snapshot = snapshot_.get();
|
|
791
801
|
|
|
792
|
-
|
|
802
|
+
const auto numKeys = keys_.size();
|
|
803
|
+
|
|
804
|
+
std::vector<rocksdb::Slice> keys;
|
|
805
|
+
keys.reserve(keys_.size());
|
|
806
|
+
for (const auto& key : keys_) {
|
|
807
|
+
keys.emplace_back(key);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
statuses_.resize(numKeys);
|
|
811
|
+
values_.resize(numKeys);
|
|
812
|
+
|
|
813
|
+
database.db_->MultiGet(options, database.db_->DefaultColumnFamily(), numKeys, keys.data(), values_.data(),
|
|
814
|
+
statuses_.data());
|
|
815
|
+
|
|
816
|
+
keys_.clear();
|
|
793
817
|
snapshot_ = nullptr;
|
|
794
818
|
|
|
795
|
-
for (auto status :
|
|
819
|
+
for (auto status : statuses_) {
|
|
796
820
|
if (!status.ok() && !status.IsNotFound()) {
|
|
797
821
|
return status;
|
|
798
822
|
}
|
|
@@ -801,26 +825,29 @@ struct GetManyWorker final : public Worker {
|
|
|
801
825
|
return rocksdb::Status::OK();
|
|
802
826
|
}
|
|
803
827
|
|
|
804
|
-
|
|
828
|
+
napi_status OnOk(napi_env env, napi_value callback) override {
|
|
805
829
|
const auto size = values_.size();
|
|
806
830
|
|
|
807
831
|
napi_value array;
|
|
808
|
-
napi_create_array_with_length(env, size, &array);
|
|
832
|
+
NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &array));
|
|
809
833
|
|
|
810
834
|
for (size_t idx = 0; idx < size; idx++) {
|
|
811
835
|
napi_value element;
|
|
812
|
-
if (
|
|
813
|
-
Convert(env, values_[idx], valueAsBuffer_, element);
|
|
836
|
+
if (statuses_[idx].ok()) {
|
|
837
|
+
NAPI_STATUS_RETURN(Convert(env, std::move(values_[idx]), valueAsBuffer_, element));
|
|
814
838
|
} else {
|
|
815
|
-
napi_get_undefined(env, &element);
|
|
839
|
+
NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
|
|
816
840
|
}
|
|
817
|
-
napi_set_element(env, array, static_cast<uint32_t>(idx), element);
|
|
841
|
+
NAPI_STATUS_RETURN(napi_set_element(env, array, static_cast<uint32_t>(idx), element));
|
|
818
842
|
}
|
|
819
843
|
|
|
844
|
+
values_.clear();
|
|
845
|
+
statuses_.clear();
|
|
846
|
+
|
|
820
847
|
napi_value argv[2];
|
|
821
|
-
napi_get_null(env, &argv[0]);
|
|
848
|
+
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
822
849
|
argv[1] = array;
|
|
823
|
-
CallFunction(env, callback, 2, argv);
|
|
850
|
+
return CallFunction(env, callback, 2, argv);
|
|
824
851
|
}
|
|
825
852
|
|
|
826
853
|
void Destroy(napi_env env) override {
|
|
@@ -829,9 +856,9 @@ struct GetManyWorker final : public Worker {
|
|
|
829
856
|
}
|
|
830
857
|
|
|
831
858
|
private:
|
|
832
|
-
|
|
833
|
-
std::vector<
|
|
834
|
-
std::vector<rocksdb::Status>
|
|
859
|
+
std::vector<std::string> keys_;
|
|
860
|
+
std::vector<rocksdb::PinnableSlice> values_;
|
|
861
|
+
std::vector<rocksdb::Status> statuses_;
|
|
835
862
|
const bool valueAsBuffer_;
|
|
836
863
|
const bool fillCache_;
|
|
837
864
|
std::shared_ptr<const rocksdb::Snapshot> snapshot_;
|
|
@@ -858,9 +885,11 @@ NAPI_METHOD(db_get_many) {
|
|
|
858
885
|
|
|
859
886
|
const auto options = argv[2];
|
|
860
887
|
const bool asBuffer = EncodingIsBuffer(env, options, "valueEncoding");
|
|
861
|
-
const bool fillCache = BooleanProperty(env, options, "fillCache"
|
|
888
|
+
const bool fillCache = BooleanProperty(env, options, "fillCache").value_or(true);
|
|
862
889
|
const auto callback = argv[3];
|
|
863
890
|
|
|
891
|
+
NAPI_PENDING_EXCEPTION();
|
|
892
|
+
|
|
864
893
|
auto worker = new GetManyWorker(env, database, keys, callback, asBuffer, fillCache);
|
|
865
894
|
worker->Queue(env);
|
|
866
895
|
|
|
@@ -871,7 +900,9 @@ NAPI_METHOD(db_del) {
|
|
|
871
900
|
NAPI_ARGV(3);
|
|
872
901
|
NAPI_DB_CONTEXT();
|
|
873
902
|
|
|
874
|
-
const auto key =
|
|
903
|
+
const auto key = NapiSlice(env, argv[1]);
|
|
904
|
+
|
|
905
|
+
NAPI_PENDING_EXCEPTION();
|
|
875
906
|
|
|
876
907
|
rocksdb::WriteOptions options;
|
|
877
908
|
return ToError(env, database->db_->Delete(options, key));
|
|
@@ -881,13 +912,13 @@ NAPI_METHOD(db_clear) {
|
|
|
881
912
|
NAPI_ARGV(2);
|
|
882
913
|
NAPI_DB_CONTEXT();
|
|
883
914
|
|
|
884
|
-
const auto reverse = BooleanProperty(env, argv[1], "reverse"
|
|
885
|
-
const auto limit = Int32Property(env, argv[1], "limit"
|
|
915
|
+
const auto reverse = BooleanProperty(env, argv[1], "reverse").value_or(false);
|
|
916
|
+
const auto limit = Int32Property(env, argv[1], "limit").value_or(-1);
|
|
886
917
|
|
|
887
|
-
const auto lt =
|
|
888
|
-
const auto lte =
|
|
889
|
-
const auto gt =
|
|
890
|
-
const auto gte =
|
|
918
|
+
const auto lt = StringProperty(env, argv[1], "lt");
|
|
919
|
+
const auto lte = StringProperty(env, argv[1], "lte");
|
|
920
|
+
const auto gt = StringProperty(env, argv[1], "gt");
|
|
921
|
+
const auto gte = StringProperty(env, argv[1], "gte");
|
|
891
922
|
|
|
892
923
|
// TODO (perf): Use DeleteRange.
|
|
893
924
|
|
|
@@ -934,51 +965,47 @@ NAPI_METHOD(db_get_property) {
|
|
|
934
965
|
NAPI_ARGV(2);
|
|
935
966
|
NAPI_DB_CONTEXT();
|
|
936
967
|
|
|
937
|
-
const auto property =
|
|
968
|
+
const auto property = NapiSlice(env, argv[1]);
|
|
969
|
+
|
|
970
|
+
NAPI_PENDING_EXCEPTION();
|
|
938
971
|
|
|
939
972
|
std::string value;
|
|
940
973
|
database->db_->GetProperty(property, &value);
|
|
941
974
|
|
|
942
975
|
napi_value result;
|
|
943
|
-
napi_create_string_utf8(env, value.data(), value.size(), &result);
|
|
976
|
+
NAPI_STATUS_THROWS(napi_create_string_utf8(env, value.data(), value.size(), &result));
|
|
944
977
|
|
|
945
978
|
return result;
|
|
946
979
|
}
|
|
947
980
|
|
|
948
|
-
static void FinalizeIterator(napi_env env, void* data, void* hint) {
|
|
949
|
-
if (data) {
|
|
950
|
-
delete reinterpret_cast<Iterator*>(data);
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
|
|
954
981
|
NAPI_METHOD(iterator_init) {
|
|
955
982
|
NAPI_ARGV(2);
|
|
956
983
|
NAPI_DB_CONTEXT();
|
|
957
984
|
|
|
958
985
|
const auto options = argv[1];
|
|
959
|
-
const auto reverse = BooleanProperty(env, options, "reverse"
|
|
960
|
-
const auto keys = BooleanProperty(env, options, "keys"
|
|
961
|
-
const auto values = BooleanProperty(env, options, "values"
|
|
962
|
-
const auto fillCache = BooleanProperty(env, options, "fillCache"
|
|
986
|
+
const auto reverse = BooleanProperty(env, options, "reverse").value_or(false);
|
|
987
|
+
const auto keys = BooleanProperty(env, options, "keys").value_or(true);
|
|
988
|
+
const auto values = BooleanProperty(env, options, "values").value_or(true);
|
|
989
|
+
const auto fillCache = BooleanProperty(env, options, "fillCache").value_or(false);
|
|
963
990
|
const bool keyAsBuffer = EncodingIsBuffer(env, options, "keyEncoding");
|
|
964
991
|
const bool valueAsBuffer = EncodingIsBuffer(env, options, "valueEncoding");
|
|
965
|
-
const auto limit = Int32Property(env, options, "limit"
|
|
966
|
-
const auto highWaterMarkBytes = Uint32Property(env, options, "highWaterMarkBytes"
|
|
992
|
+
const auto limit = Int32Property(env, options, "limit").value_or(-1);
|
|
993
|
+
const auto highWaterMarkBytes = Uint32Property(env, options, "highWaterMarkBytes").value_or(16 * 1024);
|
|
967
994
|
|
|
968
|
-
const auto lt =
|
|
969
|
-
const auto lte =
|
|
970
|
-
const auto gt =
|
|
971
|
-
const auto gte =
|
|
995
|
+
const auto lt = StringProperty(env, options, "lt");
|
|
996
|
+
const auto lte = StringProperty(env, options, "lte");
|
|
997
|
+
const auto gt = StringProperty(env, options, "gt");
|
|
998
|
+
const auto gte = StringProperty(env, options, "gte");
|
|
972
999
|
|
|
973
|
-
auto iterator =
|
|
974
|
-
|
|
975
|
-
napi_value result;
|
|
1000
|
+
auto iterator = std::make_unique<Iterator>(database, reverse, keys, values, limit, lt, lte, gt, gte, fillCache,
|
|
1001
|
+
keyAsBuffer, valueAsBuffer, highWaterMarkBytes);
|
|
976
1002
|
|
|
977
|
-
|
|
1003
|
+
napi_value result;
|
|
1004
|
+
NAPI_STATUS_THROWS(napi_create_external(env, iterator.get(), Finalize<Iterator>, iterator.get(), &result));
|
|
978
1005
|
|
|
979
1006
|
// Prevent GC of JS object before the iterator is closed (explicitly or on
|
|
980
1007
|
// db close) and keep track of non-closed iterators to end them on db close.
|
|
981
|
-
iterator->Attach(env, result);
|
|
1008
|
+
iterator.release()->Attach(env, result);
|
|
982
1009
|
|
|
983
1010
|
return result;
|
|
984
1011
|
}
|
|
@@ -987,39 +1014,22 @@ NAPI_METHOD(iterator_seek) {
|
|
|
987
1014
|
NAPI_ARGV(2);
|
|
988
1015
|
NAPI_ITERATOR_CONTEXT();
|
|
989
1016
|
|
|
990
|
-
const auto target =
|
|
1017
|
+
const auto target = NapiSlice(env, argv[1]);
|
|
1018
|
+
|
|
1019
|
+
NAPI_PENDING_EXCEPTION();
|
|
1020
|
+
|
|
991
1021
|
iterator->first_ = true;
|
|
992
1022
|
iterator->Seek(target);
|
|
993
1023
|
|
|
994
1024
|
return 0;
|
|
995
1025
|
}
|
|
996
1026
|
|
|
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) {}
|
|
1000
|
-
|
|
1001
|
-
rocksdb::Status Execute(Database& database) override {
|
|
1002
|
-
iterator_->Close();
|
|
1003
|
-
return rocksdb::Status::OK();
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
void Destroy(napi_env env) override {
|
|
1007
|
-
iterator_->Detach(env);
|
|
1008
|
-
Worker::Destroy(env);
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
private:
|
|
1012
|
-
Iterator* iterator_;
|
|
1013
|
-
};
|
|
1014
|
-
|
|
1015
1027
|
NAPI_METHOD(iterator_close) {
|
|
1016
|
-
NAPI_ARGV(
|
|
1028
|
+
NAPI_ARGV(1);
|
|
1017
1029
|
NAPI_ITERATOR_CONTEXT();
|
|
1018
1030
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
auto worker = new CloseIteratorWorker(env, iterator, callback);
|
|
1022
|
-
worker->Queue(env);
|
|
1031
|
+
iterator->Detach(env);
|
|
1032
|
+
iterator->Close();
|
|
1023
1033
|
|
|
1024
1034
|
return 0;
|
|
1025
1035
|
}
|
|
@@ -1033,9 +1043,6 @@ struct NextWorker final : public Worker {
|
|
|
1033
1043
|
iterator_->SeekToRange();
|
|
1034
1044
|
}
|
|
1035
1045
|
|
|
1036
|
-
// Limit the size of the cache to prevent starving the event loop
|
|
1037
|
-
// in JS-land while we're recursively calling process.nextTick().
|
|
1038
|
-
|
|
1039
1046
|
cache_.reserve(size_ * 2);
|
|
1040
1047
|
size_t bytesRead = 0;
|
|
1041
1048
|
|
|
@@ -1075,29 +1082,29 @@ struct NextWorker final : public Worker {
|
|
|
1075
1082
|
return iterator_->Status();
|
|
1076
1083
|
}
|
|
1077
1084
|
|
|
1078
|
-
|
|
1085
|
+
napi_status OnOk(napi_env env, napi_value callback) override {
|
|
1079
1086
|
const auto size = cache_.size();
|
|
1080
1087
|
napi_value result;
|
|
1081
|
-
napi_create_array_with_length(env, size, &result);
|
|
1088
|
+
NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &result));
|
|
1082
1089
|
|
|
1083
1090
|
for (size_t idx = 0; idx < cache_.size(); idx += 2) {
|
|
1084
1091
|
napi_value key;
|
|
1085
1092
|
napi_value val;
|
|
1086
1093
|
|
|
1087
|
-
Convert(env, cache_[idx + 0], iterator_->keyAsBuffer_, key);
|
|
1088
|
-
Convert(env, cache_[idx + 1], iterator_->valueAsBuffer_, val);
|
|
1094
|
+
NAPI_STATUS_RETURN(Convert(env, std::move(cache_[idx + 0]), iterator_->keyAsBuffer_, key));
|
|
1095
|
+
NAPI_STATUS_RETURN(Convert(env, std::move(cache_[idx + 1]), iterator_->valueAsBuffer_, val));
|
|
1089
1096
|
|
|
1090
|
-
napi_set_element(env, result, static_cast<int>(idx + 0), key);
|
|
1091
|
-
napi_set_element(env, result, static_cast<int>(idx + 1), val);
|
|
1097
|
+
NAPI_STATUS_RETURN(napi_set_element(env, result, static_cast<int>(idx + 0), key));
|
|
1098
|
+
NAPI_STATUS_RETURN(napi_set_element(env, result, static_cast<int>(idx + 1), val));
|
|
1092
1099
|
}
|
|
1093
1100
|
|
|
1094
1101
|
cache_.clear();
|
|
1095
1102
|
|
|
1096
1103
|
napi_value argv[3];
|
|
1097
|
-
napi_get_null(env, &argv[0]);
|
|
1104
|
+
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
1098
1105
|
argv[1] = result;
|
|
1099
|
-
napi_get_boolean(env, !finished_, &argv[2]);
|
|
1100
|
-
CallFunction(env, callback, 3, argv);
|
|
1106
|
+
NAPI_STATUS_RETURN(napi_get_boolean(env, !finished_, &argv[2]));
|
|
1107
|
+
return CallFunction(env, callback, 3, argv);
|
|
1101
1108
|
}
|
|
1102
1109
|
|
|
1103
1110
|
private:
|
|
@@ -1113,8 +1120,6 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1113
1120
|
|
|
1114
1121
|
uint32_t size;
|
|
1115
1122
|
NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &size));
|
|
1116
|
-
if (size == 0)
|
|
1117
|
-
size = 1;
|
|
1118
1123
|
|
|
1119
1124
|
const auto callback = argv[2];
|
|
1120
1125
|
|
|
@@ -1150,6 +1155,8 @@ NAPI_METHOD(batch_do) {
|
|
|
1150
1155
|
|
|
1151
1156
|
const auto key = NapiSlice(env, GetProperty(env, element, "key"));
|
|
1152
1157
|
|
|
1158
|
+
NAPI_PENDING_EXCEPTION();
|
|
1159
|
+
|
|
1153
1160
|
batch.Delete(key);
|
|
1154
1161
|
} else if (type == "put") {
|
|
1155
1162
|
if (!HasProperty(env, element, "key"))
|
|
@@ -1160,6 +1167,8 @@ NAPI_METHOD(batch_do) {
|
|
|
1160
1167
|
const auto key = NapiSlice(env, GetProperty(env, element, "key"));
|
|
1161
1168
|
const auto value = NapiSlice(env, GetProperty(env, element, "value"));
|
|
1162
1169
|
|
|
1170
|
+
NAPI_PENDING_EXCEPTION();
|
|
1171
|
+
|
|
1163
1172
|
batch.Put(key, value);
|
|
1164
1173
|
}
|
|
1165
1174
|
}
|
|
@@ -1168,12 +1177,6 @@ NAPI_METHOD(batch_do) {
|
|
|
1168
1177
|
return ToError(env, database->db_->Write(options, &batch));
|
|
1169
1178
|
}
|
|
1170
1179
|
|
|
1171
|
-
static void FinalizeBatch(napi_env env, void* data, void* hint) {
|
|
1172
|
-
if (data) {
|
|
1173
|
-
delete reinterpret_cast<rocksdb::WriteBatch*>(data);
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
1180
|
NAPI_METHOD(batch_init) {
|
|
1178
1181
|
NAPI_ARGV(1);
|
|
1179
1182
|
NAPI_DB_CONTEXT();
|
|
@@ -1181,7 +1184,7 @@ NAPI_METHOD(batch_init) {
|
|
|
1181
1184
|
auto batch = new rocksdb::WriteBatch();
|
|
1182
1185
|
|
|
1183
1186
|
napi_value result;
|
|
1184
|
-
NAPI_STATUS_THROWS(napi_create_external(env, batch,
|
|
1187
|
+
NAPI_STATUS_THROWS(napi_create_external(env, batch, Finalize<rocksdb::WriteBatch>, batch, &result));
|
|
1185
1188
|
return result;
|
|
1186
1189
|
}
|
|
1187
1190
|
|
|
@@ -1190,9 +1193,11 @@ NAPI_METHOD(batch_put) {
|
|
|
1190
1193
|
NAPI_BATCH_CONTEXT();
|
|
1191
1194
|
|
|
1192
1195
|
const auto key = NapiSlice(env, argv[1]);
|
|
1193
|
-
const auto
|
|
1196
|
+
const auto val = NapiSlice(env, argv[2]);
|
|
1194
1197
|
|
|
1195
|
-
|
|
1198
|
+
NAPI_PENDING_EXCEPTION();
|
|
1199
|
+
|
|
1200
|
+
batch->Put(key, val);
|
|
1196
1201
|
|
|
1197
1202
|
return 0;
|
|
1198
1203
|
}
|
|
@@ -1203,6 +1208,8 @@ NAPI_METHOD(batch_del) {
|
|
|
1203
1208
|
|
|
1204
1209
|
const auto key = NapiSlice(env, argv[1]);
|
|
1205
1210
|
|
|
1211
|
+
NAPI_PENDING_EXCEPTION();
|
|
1212
|
+
|
|
1206
1213
|
batch->Delete(key);
|
|
1207
1214
|
|
|
1208
1215
|
return 0;
|