@nxtedition/rocksdb 7.0.63 → 7.0.64
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 +431 -905
- package/deps/rocksdb/rocksdb/db/wal_manager.cc +4 -0
- package/index.js +47 -131
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/util.h +338 -0
package/binding.cc
CHANGED
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
#include <rocksdb/filter_policy.h>
|
|
13
13
|
#include <rocksdb/merge_operator.h>
|
|
14
14
|
#include <rocksdb/options.h>
|
|
15
|
+
#include <rocksdb/slice.h>
|
|
15
16
|
#include <rocksdb/slice_transform.h>
|
|
17
|
+
#include <rocksdb/status.h>
|
|
16
18
|
#include <rocksdb/table.h>
|
|
17
19
|
#include <rocksdb/write_batch.h>
|
|
18
20
|
|
|
19
|
-
#include <array>
|
|
20
21
|
#include <memory>
|
|
21
22
|
#include <optional>
|
|
22
23
|
#include <set>
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
#include <vector>
|
|
26
27
|
|
|
27
28
|
#include "max_rev_operator.h"
|
|
29
|
+
#include "util.h"
|
|
28
30
|
|
|
29
31
|
class NullLogger : public rocksdb::Logger {
|
|
30
32
|
public:
|
|
@@ -37,298 +39,6 @@ struct Database;
|
|
|
37
39
|
struct Iterator;
|
|
38
40
|
struct Updates;
|
|
39
41
|
|
|
40
|
-
#define NAPI_STATUS_RETURN(call) \
|
|
41
|
-
{ \
|
|
42
|
-
auto _status = (call); \
|
|
43
|
-
if (_status != napi_ok) { \
|
|
44
|
-
return _status; \
|
|
45
|
-
} \
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
#define ROCKS_STATUS_RETURN(call) \
|
|
49
|
-
{ \
|
|
50
|
-
auto _status = (call); \
|
|
51
|
-
if (!_status.ok()) { \
|
|
52
|
-
return _status; \
|
|
53
|
-
} \
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
#define ROCKS_STATUS_THROWS(call) \
|
|
57
|
-
{ \
|
|
58
|
-
auto _status = (call); \
|
|
59
|
-
if (!_status.ok()) { \
|
|
60
|
-
napi_throw(env, ToError(env, _status)); \
|
|
61
|
-
return NULL; \
|
|
62
|
-
} \
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
static napi_value CreateError(napi_env env, const std::optional<std::string_view>& code, const std::string_view& msg) {
|
|
66
|
-
napi_value codeValue = nullptr;
|
|
67
|
-
if (code) {
|
|
68
|
-
NAPI_STATUS_THROWS(napi_create_string_utf8(env, code->data(), code->size(), &codeValue));
|
|
69
|
-
}
|
|
70
|
-
napi_value msgValue;
|
|
71
|
-
NAPI_STATUS_THROWS(napi_create_string_utf8(env, msg.data(), msg.size(), &msgValue));
|
|
72
|
-
napi_value error;
|
|
73
|
-
NAPI_STATUS_THROWS(napi_create_error(env, codeValue, msgValue, &error));
|
|
74
|
-
return error;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
static bool HasProperty(napi_env env, napi_value obj, const std::string_view& key) {
|
|
78
|
-
bool has = false;
|
|
79
|
-
napi_has_named_property(env, obj, key.data(), &has);
|
|
80
|
-
return has;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
static napi_value GetProperty(napi_env env, napi_value obj, const std::string_view& key) {
|
|
84
|
-
napi_value value = nullptr;
|
|
85
|
-
napi_get_named_property(env, obj, key.data(), &value);
|
|
86
|
-
return value;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
static std::optional<bool> BooleanProperty(napi_env env, napi_value obj, const std::string_view& key) {
|
|
90
|
-
if (HasProperty(env, obj, key.data())) {
|
|
91
|
-
const auto value = GetProperty(env, obj, key.data());
|
|
92
|
-
bool result;
|
|
93
|
-
napi_get_value_bool(env, value, &result);
|
|
94
|
-
return result;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return {};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
static bool EncodingIsBuffer(napi_env env, napi_value obj, const std::string_view& option) {
|
|
101
|
-
napi_value value;
|
|
102
|
-
size_t size;
|
|
103
|
-
|
|
104
|
-
if (napi_get_named_property(env, obj, option.data(), &value) == napi_ok &&
|
|
105
|
-
napi_get_value_string_utf8(env, value, nullptr, 0, &size) == napi_ok) {
|
|
106
|
-
// Value is either "buffer" or "utf8" so we can tell them apart just by size
|
|
107
|
-
return size == 6;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
static std::optional<uint32_t> Uint32Property(napi_env env, napi_value obj, const std::string_view& key) {
|
|
114
|
-
if (HasProperty(env, obj, key.data())) {
|
|
115
|
-
const auto value = GetProperty(env, obj, key.data());
|
|
116
|
-
uint32_t result;
|
|
117
|
-
napi_get_value_uint32(env, value, &result);
|
|
118
|
-
return result;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return {};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
static std::optional<int> Int32Property(napi_env env, napi_value obj, const std::string_view& key) {
|
|
125
|
-
if (HasProperty(env, obj, key.data())) {
|
|
126
|
-
const auto value = GetProperty(env, obj, key.data());
|
|
127
|
-
int result;
|
|
128
|
-
napi_get_value_int32(env, value, &result);
|
|
129
|
-
return result;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return {};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
static napi_status ToString(napi_env env, napi_value from, std::string& to) {
|
|
136
|
-
napi_valuetype type;
|
|
137
|
-
NAPI_STATUS_RETURN(napi_typeof(env, from, &type));
|
|
138
|
-
|
|
139
|
-
if (type == napi_string) {
|
|
140
|
-
size_t length = 0;
|
|
141
|
-
NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, nullptr, 0, &length));
|
|
142
|
-
to.resize(length, '\0');
|
|
143
|
-
NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, &to[0], length + 1, &length));
|
|
144
|
-
} else {
|
|
145
|
-
bool isBuffer;
|
|
146
|
-
NAPI_STATUS_RETURN(napi_is_buffer(env, from, &isBuffer));
|
|
147
|
-
|
|
148
|
-
if (isBuffer) {
|
|
149
|
-
char* buf = nullptr;
|
|
150
|
-
size_t length = 0;
|
|
151
|
-
NAPI_STATUS_RETURN(napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length));
|
|
152
|
-
to.assign(buf, length);
|
|
153
|
-
} else {
|
|
154
|
-
return napi_invalid_arg;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return napi_ok;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
void noop(void* arg1, void* arg2) {}
|
|
162
|
-
|
|
163
|
-
// TODO (fix): Should use rocksdb::Slice since "to" cannot outlive "from".
|
|
164
|
-
static napi_status ToString(napi_env env, napi_value from, rocksdb::PinnableSlice& to) {
|
|
165
|
-
napi_valuetype type;
|
|
166
|
-
NAPI_STATUS_RETURN(napi_typeof(env, from, &type));
|
|
167
|
-
|
|
168
|
-
if (type == napi_string) {
|
|
169
|
-
size_t length = 0;
|
|
170
|
-
NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, nullptr, 0, &length));
|
|
171
|
-
to.GetSelf()->resize(length, '\0');
|
|
172
|
-
NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, &(*to.GetSelf())[0], length + 1, &length));
|
|
173
|
-
to.PinSelf();
|
|
174
|
-
} else {
|
|
175
|
-
bool isBuffer;
|
|
176
|
-
NAPI_STATUS_RETURN(napi_is_buffer(env, from, &isBuffer));
|
|
177
|
-
|
|
178
|
-
if (isBuffer) {
|
|
179
|
-
char* buf = nullptr;
|
|
180
|
-
size_t length = 0;
|
|
181
|
-
NAPI_STATUS_RETURN(napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length));
|
|
182
|
-
|
|
183
|
-
// TODO (fix): Should extend life of "from". Or "to" should be a non-pinnable slice.
|
|
184
|
-
to.PinSlice(rocksdb::Slice(buf, length), noop, nullptr, nullptr);
|
|
185
|
-
} else {
|
|
186
|
-
return napi_invalid_arg;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return napi_ok;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
static std::optional<std::string> StringProperty(napi_env env, napi_value opts, const std::string_view& name) {
|
|
194
|
-
if (HasProperty(env, opts, name)) {
|
|
195
|
-
const auto property = GetProperty(env, opts, name);
|
|
196
|
-
std::string value;
|
|
197
|
-
ToString(env, property, value);
|
|
198
|
-
return value;
|
|
199
|
-
}
|
|
200
|
-
return {};
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
static napi_status CallFunction(napi_env env, napi_value callback, const int argc, napi_value* argv) {
|
|
204
|
-
napi_value global;
|
|
205
|
-
|
|
206
|
-
NAPI_STATUS_RETURN(napi_get_global(env, &global));
|
|
207
|
-
NAPI_STATUS_RETURN(napi_call_function(env, global, callback, argc, argv, nullptr));
|
|
208
|
-
|
|
209
|
-
return napi_ok;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
static napi_value ToError(napi_env env, const rocksdb::Status& status) {
|
|
213
|
-
if (status.ok()) {
|
|
214
|
-
return 0;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const auto msg = status.ToString();
|
|
218
|
-
|
|
219
|
-
if (status.IsNotFound()) {
|
|
220
|
-
return CreateError(env, "LEVEL_NOT_FOUND", msg);
|
|
221
|
-
} else if (status.IsCorruption()) {
|
|
222
|
-
return CreateError(env, "LEVEL_CORRUPTION", msg);
|
|
223
|
-
} else if (status.IsTryAgain()) {
|
|
224
|
-
return CreateError(env, "LEVEL_TRYAGAIN", msg);
|
|
225
|
-
} else if (status.IsIOError()) {
|
|
226
|
-
if (msg.find("IO error: lock ") != std::string::npos) { // env_posix.cc
|
|
227
|
-
return CreateError(env, "LEVEL_LOCKED", msg);
|
|
228
|
-
} else if (msg.find("IO error: LockFile ") != std::string::npos) { // env_win.cc
|
|
229
|
-
return CreateError(env, "LEVEL_LOCKED", msg);
|
|
230
|
-
} else if (msg.find("IO error: While lock file") != std::string::npos) { // env_mac.cc
|
|
231
|
-
return CreateError(env, "LEVEL_LOCKED", msg);
|
|
232
|
-
} else {
|
|
233
|
-
return CreateError(env, "LEVEL_IO_ERROR", msg);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return CreateError(env, {}, msg);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
template <typename T>
|
|
241
|
-
static void Finalize(napi_env env, void* data, void* hint) {
|
|
242
|
-
if (hint) {
|
|
243
|
-
delete reinterpret_cast<T*>(hint);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
template <typename T>
|
|
248
|
-
napi_status Convert(napi_env env, T&& s, bool asBuffer, napi_value& result) {
|
|
249
|
-
if (!s) {
|
|
250
|
-
return napi_get_null(env, &result);
|
|
251
|
-
} else if (asBuffer) {
|
|
252
|
-
using Y = typename std::decay<decltype(*s)>::type;
|
|
253
|
-
auto ptr = new Y(std::move(*s));
|
|
254
|
-
return napi_create_external_buffer(env, ptr->size(), const_cast<char*>(ptr->data()), Finalize<Y>, ptr, &result);
|
|
255
|
-
} else {
|
|
256
|
-
return napi_create_string_utf8(env, s->data(), s->size(), &result);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Base worker class. Handles the async work. Derived classes can override the
|
|
262
|
-
* following virtual methods (listed in the order in which they're called):
|
|
263
|
-
*
|
|
264
|
-
* - Execute (abstract, worker pool thread): main work
|
|
265
|
-
* - OnOk (main thread): call JS callback on success
|
|
266
|
-
* - OnError (main thread): call JS callback on error
|
|
267
|
-
* - Destroy (main thread): do cleanup regardless of success
|
|
268
|
-
*/
|
|
269
|
-
struct Worker {
|
|
270
|
-
Worker(napi_env env, Database* database, napi_value callback, const std::string& resourceName) : database_(database) {
|
|
271
|
-
NAPI_STATUS_THROWS_VOID(napi_create_reference(env, callback, 1, &callbackRef_));
|
|
272
|
-
napi_value asyncResourceName;
|
|
273
|
-
NAPI_STATUS_THROWS_VOID(napi_create_string_utf8(env, resourceName.data(), resourceName.size(), &asyncResourceName));
|
|
274
|
-
NAPI_STATUS_THROWS_VOID(
|
|
275
|
-
napi_create_async_work(env, callback, asyncResourceName, Worker::Execute, Worker::Complete, this, &asyncWork_));
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
virtual ~Worker() {}
|
|
279
|
-
|
|
280
|
-
static void Execute(napi_env env, void* data) {
|
|
281
|
-
auto self = reinterpret_cast<Worker*>(data);
|
|
282
|
-
self->status_ = self->Execute(*self->database_);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
static void Complete(napi_env env, napi_status status, void* data) {
|
|
286
|
-
auto self = reinterpret_cast<Worker*>(data);
|
|
287
|
-
|
|
288
|
-
// TODO (fix): napi status handling...
|
|
289
|
-
|
|
290
|
-
napi_value callback;
|
|
291
|
-
napi_get_reference_value(env, self->callbackRef_, &callback);
|
|
292
|
-
|
|
293
|
-
if (self->status_.ok()) {
|
|
294
|
-
self->OnOk(env, callback);
|
|
295
|
-
} else {
|
|
296
|
-
self->OnError(env, callback, ToError(env, self->status_));
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
self->Destroy(env);
|
|
300
|
-
|
|
301
|
-
napi_delete_reference(env, self->callbackRef_);
|
|
302
|
-
napi_delete_async_work(env, self->asyncWork_);
|
|
303
|
-
|
|
304
|
-
delete self;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
virtual rocksdb::Status Execute(Database& database) = 0;
|
|
308
|
-
|
|
309
|
-
virtual napi_status OnOk(napi_env env, napi_value callback) {
|
|
310
|
-
napi_value argv[1];
|
|
311
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
312
|
-
|
|
313
|
-
return CallFunction(env, callback, 1, &argv[0]);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
virtual napi_status OnError(napi_env env, napi_value callback, napi_value err) {
|
|
317
|
-
return CallFunction(env, callback, 1, &err);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
virtual void Destroy(napi_env env) {}
|
|
321
|
-
|
|
322
|
-
void Queue(napi_env env) { napi_queue_async_work(env, asyncWork_); }
|
|
323
|
-
|
|
324
|
-
Database* database_;
|
|
325
|
-
|
|
326
|
-
private:
|
|
327
|
-
napi_ref callbackRef_;
|
|
328
|
-
napi_async_work asyncWork_;
|
|
329
|
-
rocksdb::Status status_;
|
|
330
|
-
};
|
|
331
|
-
|
|
332
42
|
struct ColumnFamily {
|
|
333
43
|
napi_ref ref;
|
|
334
44
|
napi_value val;
|
|
@@ -336,80 +46,69 @@ struct ColumnFamily {
|
|
|
336
46
|
rocksdb::ColumnFamilyDescriptor descriptor;
|
|
337
47
|
};
|
|
338
48
|
|
|
339
|
-
struct
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
void DetachIterator(napi_env env, Iterator* iterator) {
|
|
346
|
-
iterators_.erase(iterator);
|
|
347
|
-
DecrementPriorityWork(env);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
void AttachUpdates(napi_env env, Updates* update) {
|
|
351
|
-
updates_.insert(update);
|
|
352
|
-
IncrementPriorityWork(env);
|
|
353
|
-
}
|
|
49
|
+
struct Closable {
|
|
50
|
+
virtual ~Closable() {}
|
|
51
|
+
virtual rocksdb::Status Close() = 0;
|
|
52
|
+
};
|
|
354
53
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
DecrementPriorityWork(env);
|
|
358
|
-
}
|
|
54
|
+
struct Database final {
|
|
55
|
+
~Database() { assert(!db); }
|
|
359
56
|
|
|
360
|
-
|
|
57
|
+
rocksdb::Status Close() {
|
|
58
|
+
if (!db) {
|
|
59
|
+
return rocksdb::Status::OK();
|
|
60
|
+
}
|
|
361
61
|
|
|
362
|
-
|
|
363
|
-
|
|
62
|
+
for (auto closable : closables) {
|
|
63
|
+
closable->Close();
|
|
64
|
+
}
|
|
65
|
+
closables.clear();
|
|
364
66
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
pendingCloseWorker_ = nullptr;
|
|
67
|
+
for (auto& [id, column] : columns) {
|
|
68
|
+
db->DestroyColumnFamilyHandle(column.handle);
|
|
368
69
|
}
|
|
369
|
-
|
|
70
|
+
columns.clear();
|
|
370
71
|
|
|
371
|
-
|
|
72
|
+
db->FlushWAL(true);
|
|
372
73
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
std::set<Updates*> updates_;
|
|
377
|
-
std::map<int32_t, ColumnFamily> columns_;
|
|
378
|
-
napi_ref priorityRef_;
|
|
74
|
+
auto db2 = std::move(db);
|
|
75
|
+
return db2->Close();
|
|
76
|
+
}
|
|
379
77
|
|
|
380
|
-
|
|
381
|
-
|
|
78
|
+
std::unique_ptr<rocksdb::DB> db;
|
|
79
|
+
std::set<Closable*> closables;
|
|
80
|
+
std::map<int32_t, ColumnFamily> columns;
|
|
382
81
|
};
|
|
383
82
|
|
|
384
83
|
enum BatchOp { Empty, Put, Delete, Merge, Data };
|
|
385
84
|
|
|
386
85
|
struct BatchEntry {
|
|
387
86
|
BatchOp op = BatchOp::Empty;
|
|
388
|
-
std::optional<std::string> key;
|
|
389
|
-
std::optional<std::string> val;
|
|
390
|
-
std::optional<ColumnFamily> column;
|
|
87
|
+
std::optional<std::string> key = std::nullopt;
|
|
88
|
+
std::optional<std::string> val = std::nullopt;
|
|
89
|
+
std::optional<ColumnFamily> column = std::nullopt;
|
|
391
90
|
};
|
|
392
91
|
|
|
393
92
|
struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
394
93
|
BatchIterator(Database* database,
|
|
395
|
-
bool keys
|
|
396
|
-
bool values
|
|
397
|
-
bool data
|
|
398
|
-
const rocksdb::ColumnFamilyHandle* column
|
|
399
|
-
|
|
400
|
-
|
|
94
|
+
const bool keys,
|
|
95
|
+
const bool values,
|
|
96
|
+
const bool data,
|
|
97
|
+
const rocksdb::ColumnFamilyHandle* column,
|
|
98
|
+
const Encoding keyEncoding,
|
|
99
|
+
const Encoding valueEncoding)
|
|
401
100
|
: database_(database),
|
|
402
101
|
keys_(keys),
|
|
403
102
|
values_(values),
|
|
404
103
|
data_(data),
|
|
405
104
|
column_(column),
|
|
406
|
-
|
|
407
|
-
|
|
105
|
+
keyEncoding_(keyEncoding),
|
|
106
|
+
valueEncoding_(valueEncoding) {}
|
|
408
107
|
|
|
409
108
|
napi_status Iterate(napi_env env, const rocksdb::WriteBatch& batch, napi_value* result) {
|
|
410
109
|
cache_.reserve(batch.Count());
|
|
411
110
|
|
|
412
|
-
batch.Iterate(this);
|
|
111
|
+
ROCKS_STATUS_RETURN_NAPI(batch.Iterate(this));
|
|
413
112
|
|
|
414
113
|
napi_value putStr;
|
|
415
114
|
NAPI_STATUS_RETURN(napi_create_string_utf8(env, "put", NAPI_AUTO_LENGTH, &putStr));
|
|
@@ -444,11 +143,11 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
444
143
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 0, op));
|
|
445
144
|
|
|
446
145
|
napi_value key;
|
|
447
|
-
NAPI_STATUS_RETURN(Convert(env, cache_[n].key,
|
|
146
|
+
NAPI_STATUS_RETURN(Convert(env, cache_[n].key, keyEncoding_, key));
|
|
448
147
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 1, key));
|
|
449
148
|
|
|
450
149
|
napi_value val;
|
|
451
|
-
NAPI_STATUS_RETURN(Convert(env, cache_[n].val,
|
|
150
|
+
NAPI_STATUS_RETURN(Convert(env, cache_[n].val, valueEncoding_, val));
|
|
452
151
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 2, val));
|
|
453
152
|
|
|
454
153
|
// TODO (fix)
|
|
@@ -466,9 +165,7 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
466
165
|
return rocksdb::Status::OK();
|
|
467
166
|
}
|
|
468
167
|
|
|
469
|
-
BatchEntry entry;
|
|
470
|
-
|
|
471
|
-
entry.op = BatchOp::Put;
|
|
168
|
+
BatchEntry entry = {BatchOp::Put};
|
|
472
169
|
|
|
473
170
|
if (keys_) {
|
|
474
171
|
entry.key = key.ToStringView();
|
|
@@ -478,8 +175,8 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
478
175
|
entry.val = value.ToStringView();
|
|
479
176
|
}
|
|
480
177
|
|
|
481
|
-
// if (database_ && database_->
|
|
482
|
-
// entry.column = database_->
|
|
178
|
+
// if (database_ && database_->columns.find(column_family_id) != database_->columns.end()) {
|
|
179
|
+
// entry.column = database_->columns[column_family_id];
|
|
483
180
|
// }
|
|
484
181
|
|
|
485
182
|
cache_.push_back(entry);
|
|
@@ -492,16 +189,14 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
492
189
|
return rocksdb::Status::OK();
|
|
493
190
|
}
|
|
494
191
|
|
|
495
|
-
BatchEntry entry;
|
|
496
|
-
|
|
497
|
-
entry.op = BatchOp::Delete;
|
|
192
|
+
BatchEntry entry = {BatchOp::Delete};
|
|
498
193
|
|
|
499
194
|
if (keys_) {
|
|
500
195
|
entry.key = key.ToStringView();
|
|
501
196
|
}
|
|
502
197
|
|
|
503
|
-
// if (database_ && database_->
|
|
504
|
-
// entry.column = database_->
|
|
198
|
+
// if (database_ && database_->columns.find(column_family_id) != database_->columns.end()) {
|
|
199
|
+
// entry.column = database_->columns[column_family_id];
|
|
505
200
|
// }
|
|
506
201
|
|
|
507
202
|
cache_.push_back(entry);
|
|
@@ -514,9 +209,7 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
514
209
|
return rocksdb::Status::OK();
|
|
515
210
|
}
|
|
516
211
|
|
|
517
|
-
BatchEntry entry;
|
|
518
|
-
|
|
519
|
-
entry.op = BatchOp::Merge;
|
|
212
|
+
BatchEntry entry = {BatchOp::Merge};
|
|
520
213
|
|
|
521
214
|
if (keys_) {
|
|
522
215
|
entry.key = key.ToStringView();
|
|
@@ -526,8 +219,8 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
526
219
|
entry.val = value.ToStringView();
|
|
527
220
|
}
|
|
528
221
|
|
|
529
|
-
// if (database_ && database_->
|
|
530
|
-
// entry.column = database_->
|
|
222
|
+
// if (database_ && database_->columns.find(column_family_id) != database_->columns.end()) {
|
|
223
|
+
// entry.column = database_->columns[column_family_id];
|
|
531
224
|
// }
|
|
532
225
|
|
|
533
226
|
cache_.push_back(entry);
|
|
@@ -540,9 +233,7 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
540
233
|
return;
|
|
541
234
|
}
|
|
542
235
|
|
|
543
|
-
BatchEntry entry;
|
|
544
|
-
|
|
545
|
-
entry.op = BatchOp::Data;
|
|
236
|
+
BatchEntry entry = {BatchOp::Data};
|
|
546
237
|
|
|
547
238
|
entry.val = data.ToStringView();
|
|
548
239
|
|
|
@@ -553,40 +244,47 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
553
244
|
|
|
554
245
|
private:
|
|
555
246
|
Database* database_;
|
|
556
|
-
bool keys_;
|
|
557
|
-
bool values_;
|
|
558
|
-
bool data_;
|
|
247
|
+
const bool keys_;
|
|
248
|
+
const bool values_;
|
|
249
|
+
const bool data_;
|
|
559
250
|
const rocksdb::ColumnFamilyHandle* column_;
|
|
560
|
-
|
|
561
|
-
|
|
251
|
+
const Encoding keyEncoding_;
|
|
252
|
+
const Encoding valueEncoding_;
|
|
562
253
|
std::vector<BatchEntry> cache_;
|
|
563
254
|
};
|
|
564
255
|
|
|
565
|
-
struct Updates : public BatchIterator {
|
|
256
|
+
struct Updates : public BatchIterator, public Closable {
|
|
566
257
|
Updates(Database* database,
|
|
567
|
-
int64_t seqNumber,
|
|
568
|
-
bool keys,
|
|
569
|
-
bool values,
|
|
570
|
-
bool data,
|
|
258
|
+
const int64_t seqNumber,
|
|
259
|
+
const bool keys,
|
|
260
|
+
const bool values,
|
|
261
|
+
const bool data,
|
|
571
262
|
const rocksdb::ColumnFamilyHandle* column,
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
: BatchIterator(database, keys, values, data, column,
|
|
263
|
+
const Encoding keyEncoding,
|
|
264
|
+
const Encoding valueEncoding)
|
|
265
|
+
: BatchIterator(database, keys, values, data, column, keyEncoding, valueEncoding),
|
|
575
266
|
database_(database),
|
|
576
267
|
start_(seqNumber) {}
|
|
577
268
|
|
|
578
|
-
|
|
269
|
+
virtual ~Updates() { assert(!iterator_); }
|
|
270
|
+
|
|
271
|
+
rocksdb::Status Close() override {
|
|
272
|
+
iterator_.reset();
|
|
273
|
+
return rocksdb::Status::OK();
|
|
274
|
+
}
|
|
579
275
|
|
|
580
|
-
|
|
581
|
-
napi_create_reference(env, context, 1, &ref_);
|
|
582
|
-
database_->
|
|
276
|
+
napi_status Attach(napi_env env, napi_value context) {
|
|
277
|
+
NAPI_STATUS_RETURN(napi_create_reference(env, context, 1, &ref_));
|
|
278
|
+
database_->closables.insert(this);
|
|
279
|
+
return napi_ok;
|
|
583
280
|
}
|
|
584
281
|
|
|
585
|
-
|
|
586
|
-
database_->
|
|
282
|
+
napi_status Detach(napi_env env) {
|
|
283
|
+
database_->closables.erase(this);
|
|
587
284
|
if (ref_) {
|
|
588
|
-
napi_delete_reference(env, ref_);
|
|
285
|
+
NAPI_STATUS_RETURN(napi_delete_reference(env, ref_));
|
|
589
286
|
}
|
|
287
|
+
return napi_ok;
|
|
590
288
|
}
|
|
591
289
|
|
|
592
290
|
Database* database_;
|
|
@@ -597,7 +295,7 @@ struct Updates : public BatchIterator {
|
|
|
597
295
|
napi_ref ref_ = nullptr;
|
|
598
296
|
};
|
|
599
297
|
|
|
600
|
-
struct BaseIterator {
|
|
298
|
+
struct BaseIterator : public Closable {
|
|
601
299
|
BaseIterator(Database* database,
|
|
602
300
|
rocksdb::ColumnFamilyHandle* column,
|
|
603
301
|
const bool reverse,
|
|
@@ -670,9 +368,10 @@ struct BaseIterator {
|
|
|
670
368
|
}
|
|
671
369
|
}
|
|
672
370
|
|
|
673
|
-
|
|
371
|
+
rocksdb::Status Close() override {
|
|
674
372
|
snapshot_.reset();
|
|
675
373
|
iterator_.reset();
|
|
374
|
+
return rocksdb::Status::OK();
|
|
676
375
|
}
|
|
677
376
|
|
|
678
377
|
bool Valid() const {
|
|
@@ -727,7 +426,7 @@ struct BaseIterator {
|
|
|
727
426
|
readOptions.async_io = true;
|
|
728
427
|
readOptions.adaptive_readahead = true;
|
|
729
428
|
|
|
730
|
-
iterator_.reset(database_->
|
|
429
|
+
iterator_.reset(database_->db->NewIterator(readOptions, column_));
|
|
731
430
|
}
|
|
732
431
|
|
|
733
432
|
int count_ = 0;
|
|
@@ -751,33 +450,35 @@ struct Iterator final : public BaseIterator {
|
|
|
751
450
|
const std::optional<std::string>& gt,
|
|
752
451
|
const std::optional<std::string>& gte,
|
|
753
452
|
const bool fillCache,
|
|
754
|
-
const
|
|
755
|
-
const
|
|
453
|
+
const Encoding keyEncoding,
|
|
454
|
+
const Encoding valueEncoding,
|
|
756
455
|
const size_t highWaterMarkBytes,
|
|
757
456
|
std::shared_ptr<const rocksdb::Snapshot> snapshot)
|
|
758
457
|
: BaseIterator(database, column, reverse, lt, lte, gt, gte, limit, fillCache, snapshot),
|
|
759
458
|
keys_(keys),
|
|
760
459
|
values_(values),
|
|
761
|
-
|
|
762
|
-
|
|
460
|
+
keyEncoding_(keyEncoding),
|
|
461
|
+
valueEncoding_(valueEncoding),
|
|
763
462
|
highWaterMarkBytes_(highWaterMarkBytes) {}
|
|
764
463
|
|
|
765
|
-
|
|
766
|
-
napi_create_reference(env, context, 1, &ref_);
|
|
767
|
-
database_->
|
|
464
|
+
napi_status Attach(napi_env env, napi_value context) {
|
|
465
|
+
NAPI_STATUS_RETURN(napi_create_reference(env, context, 1, &ref_));
|
|
466
|
+
database_->closables.insert(this);
|
|
467
|
+
return napi_ok;
|
|
768
468
|
}
|
|
769
469
|
|
|
770
|
-
|
|
771
|
-
database_->
|
|
470
|
+
napi_status Detach(napi_env env) {
|
|
471
|
+
database_->closables.erase(this);
|
|
772
472
|
if (ref_) {
|
|
773
|
-
napi_delete_reference(env, ref_);
|
|
473
|
+
NAPI_STATUS_RETURN(napi_delete_reference(env, ref_));
|
|
774
474
|
}
|
|
475
|
+
return napi_ok;
|
|
775
476
|
}
|
|
776
477
|
|
|
777
478
|
const bool keys_;
|
|
778
479
|
const bool values_;
|
|
779
|
-
const
|
|
780
|
-
const
|
|
480
|
+
const Encoding keyEncoding_;
|
|
481
|
+
const Encoding valueEncoding_;
|
|
781
482
|
const size_t highWaterMarkBytes_;
|
|
782
483
|
bool first_ = true;
|
|
783
484
|
|
|
@@ -785,152 +486,20 @@ struct Iterator final : public BaseIterator {
|
|
|
785
486
|
napi_ref ref_ = nullptr;
|
|
786
487
|
};
|
|
787
488
|
|
|
788
|
-
static napi_status GetColumnFamily(Database* database,
|
|
789
|
-
napi_env env,
|
|
790
|
-
napi_value options,
|
|
791
|
-
rocksdb::ColumnFamilyHandle** column) {
|
|
792
|
-
bool hasColumn = false;
|
|
793
|
-
NAPI_STATUS_RETURN(napi_has_named_property(env, options, "column", &hasColumn));
|
|
794
|
-
|
|
795
|
-
if (hasColumn) {
|
|
796
|
-
napi_value value = nullptr;
|
|
797
|
-
NAPI_STATUS_RETURN(napi_get_named_property(env, options, "column", &value));
|
|
798
|
-
|
|
799
|
-
bool nully = false;
|
|
800
|
-
|
|
801
|
-
napi_value nullVal;
|
|
802
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &nullVal));
|
|
803
|
-
NAPI_STATUS_RETURN(napi_strict_equals(env, nullVal, value, &nully));
|
|
804
|
-
if (nully) {
|
|
805
|
-
*column = nullptr;
|
|
806
|
-
return napi_ok;
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
napi_value undefinedVal;
|
|
810
|
-
NAPI_STATUS_RETURN(napi_get_undefined(env, &undefinedVal));
|
|
811
|
-
NAPI_STATUS_RETURN(napi_strict_equals(env, undefinedVal, value, &nully));
|
|
812
|
-
if (nully) {
|
|
813
|
-
*column = nullptr;
|
|
814
|
-
return napi_ok;
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
NAPI_STATUS_RETURN(napi_get_value_external(env, value, reinterpret_cast<void**>(column)));
|
|
818
|
-
} else if (database) {
|
|
819
|
-
*column = database->db_->DefaultColumnFamily();
|
|
820
|
-
} else {
|
|
821
|
-
*column = nullptr;
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
return napi_ok;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
template <typename State,
|
|
828
|
-
typename ExecuteType = std::function<rocksdb::Status(State& state, Database& database)>,
|
|
829
|
-
typename OnOkType = std::function<napi_status(State& state, napi_env env, napi_value callback)>>
|
|
830
|
-
struct GenericWorker final : public Worker {
|
|
831
|
-
template <typename T1, typename T2>
|
|
832
|
-
GenericWorker(const std::string& name,
|
|
833
|
-
napi_env env,
|
|
834
|
-
napi_value callback,
|
|
835
|
-
Database* database,
|
|
836
|
-
bool priority,
|
|
837
|
-
T1&& execute,
|
|
838
|
-
T2&& onOK)
|
|
839
|
-
: Worker(env, database, callback, name),
|
|
840
|
-
priority_(priority),
|
|
841
|
-
execute_(std::forward<T1>(execute)),
|
|
842
|
-
onOk_(std::forward<T2>(onOK)) {
|
|
843
|
-
if (priority_) {
|
|
844
|
-
database_->IncrementPriorityWork(env);
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
rocksdb::Status Execute(Database& database) override { return execute_(state_, database); }
|
|
849
|
-
|
|
850
|
-
napi_status OnOk(napi_env env, napi_value callback) override { return onOk_(state_, env, callback); }
|
|
851
|
-
|
|
852
|
-
void Destroy(napi_env env) override {
|
|
853
|
-
if (priority_) {
|
|
854
|
-
database_->DecrementPriorityWork(env);
|
|
855
|
-
}
|
|
856
|
-
Worker::Destroy(env);
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
private:
|
|
860
|
-
State state_;
|
|
861
|
-
bool priority_ = false;
|
|
862
|
-
ExecuteType execute_;
|
|
863
|
-
OnOkType onOk_;
|
|
864
|
-
};
|
|
865
|
-
|
|
866
|
-
template <typename State, typename T1, typename T2>
|
|
867
|
-
Worker* createWorker(const std::string& name,
|
|
868
|
-
napi_env env,
|
|
869
|
-
napi_value callback,
|
|
870
|
-
Database* database,
|
|
871
|
-
bool priority,
|
|
872
|
-
T1&& execute,
|
|
873
|
-
T2&& onOk) {
|
|
874
|
-
return new GenericWorker<State, typename std::decay<T1>::type, typename std::decay<T2>::type>(
|
|
875
|
-
name, env, callback, database, priority, std::forward<T1>(execute), std::forward<T2>(onOk));
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
template <typename State, typename T1, typename T2>
|
|
879
|
-
void runWorker(const std::string& name,
|
|
880
|
-
napi_env env,
|
|
881
|
-
napi_value callback,
|
|
882
|
-
Database* database,
|
|
883
|
-
bool priority,
|
|
884
|
-
T1&& execute,
|
|
885
|
-
T2&& onOk) {
|
|
886
|
-
auto worker = new GenericWorker<State, typename std::decay<T1>::type, typename std::decay<T2>::type>(
|
|
887
|
-
name, env, callback, database, priority, std::forward<T1>(execute), std::forward<T2>(onOk));
|
|
888
|
-
worker->Queue(env);
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
/**
|
|
892
|
-
* Hook for when the environment exits. This hook will be called after
|
|
893
|
-
* already-scheduled napi_async_work items have finished, which gives us
|
|
894
|
-
* the guarantee that no db operations will be in-flight at this time.
|
|
895
|
-
*/
|
|
896
489
|
static void env_cleanup_hook(void* arg) {
|
|
897
490
|
auto database = reinterpret_cast<Database*>(arg);
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
// GC did not (yet) collect the database because that would be a user mistake
|
|
901
|
-
// (not closing their db) made during the lifetime of the environment. That's
|
|
902
|
-
// different from an environment being torn down (like the main process or a
|
|
903
|
-
// worker thread) where it's our responsibility to clean up. Note also, the
|
|
904
|
-
// following code must be a safe noop if called before db_open() or after
|
|
905
|
-
// db_close().
|
|
906
|
-
if (database && database->db_) {
|
|
907
|
-
for (auto& it : database->iterators_) {
|
|
908
|
-
// TODO: does not do `napi_delete_reference`. Problem?
|
|
909
|
-
it->Close();
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
for (auto& it : database->updates_) {
|
|
913
|
-
// TODO: does not do `napi_delete_reference`. Problem?
|
|
914
|
-
it->Close();
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
for (auto& it : database->columns_) {
|
|
918
|
-
database->db_->DestroyColumnFamilyHandle(it.second.handle);
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
// Having closed the iterators (and released snapshots) we can safely close.
|
|
922
|
-
database->db_->Close();
|
|
491
|
+
if (database) {
|
|
492
|
+
database->Close();
|
|
923
493
|
}
|
|
924
494
|
}
|
|
925
495
|
|
|
926
496
|
static void FinalizeDatabase(napi_env env, void* data, void* hint) {
|
|
927
497
|
if (data) {
|
|
928
498
|
auto database = reinterpret_cast<Database*>(data);
|
|
499
|
+
database->Close();
|
|
929
500
|
napi_remove_env_cleanup_hook(env, env_cleanup_hook, database);
|
|
930
|
-
|
|
931
|
-
napi_delete_reference(env,
|
|
932
|
-
for (auto& it : database->columns_) {
|
|
933
|
-
napi_delete_reference(env, it.second.ref);
|
|
501
|
+
for (auto& [id, column] : database->columns) {
|
|
502
|
+
napi_delete_reference(env, column.ref);
|
|
934
503
|
}
|
|
935
504
|
delete database;
|
|
936
505
|
}
|
|
@@ -943,94 +512,109 @@ NAPI_METHOD(db_init) {
|
|
|
943
512
|
napi_value result;
|
|
944
513
|
NAPI_STATUS_THROWS(napi_create_external(env, database, FinalizeDatabase, nullptr, &result));
|
|
945
514
|
|
|
946
|
-
NAPI_STATUS_THROWS(napi_create_reference(env, result, 0, &database->priorityRef_));
|
|
947
|
-
|
|
948
515
|
return result;
|
|
949
516
|
}
|
|
950
517
|
|
|
951
518
|
template <typename T, typename U>
|
|
952
|
-
|
|
519
|
+
napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
|
|
953
520
|
rocksdb::ConfigOptions configOptions;
|
|
954
521
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
522
|
+
size_t memtable_memory_budget = 256 * 1024 * 1024;
|
|
523
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "memtableMemoryBudget", memtable_memory_budget));
|
|
524
|
+
|
|
525
|
+
std::optional<std::string> compactionOpt;
|
|
526
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "compaction", compactionOpt));
|
|
527
|
+
if (compactionOpt) {
|
|
528
|
+
if (*compactionOpt == "universal") {
|
|
529
|
+
columnOptions.write_buffer_size = memtable_memory_budget / 4;
|
|
530
|
+
// merge two memtables when flushing to L0
|
|
531
|
+
columnOptions.min_write_buffer_number_to_merge = 2;
|
|
532
|
+
// this means we'll use 50% extra memory in the worst case, but will reduce
|
|
533
|
+
// write stalls.
|
|
534
|
+
columnOptions.max_write_buffer_number = 6;
|
|
535
|
+
// universal style compaction
|
|
536
|
+
columnOptions.compaction_style = rocksdb::kCompactionStyleUniversal;
|
|
537
|
+
columnOptions.compaction_options_universal.compression_size_percent = 80;
|
|
538
|
+
} else if (*compactionOpt == "level") {
|
|
539
|
+
// merge two memtables when flushing to L0
|
|
540
|
+
columnOptions.min_write_buffer_number_to_merge = 2;
|
|
541
|
+
// this means we'll use 50% extra memory in the worst case, but will reduce
|
|
542
|
+
// write stalls.
|
|
543
|
+
columnOptions.max_write_buffer_number = 6;
|
|
544
|
+
// start flushing L0->L1 as soon as possible. each file on level0 is
|
|
545
|
+
// (memtable_memory_budget / 2). This will flush level 0 when it's bigger than
|
|
546
|
+
// memtable_memory_budget.
|
|
547
|
+
columnOptions.level0_file_num_compaction_trigger = 2;
|
|
548
|
+
// doesn't really matter much, but we don't want to create too many files
|
|
549
|
+
columnOptions.target_file_size_base = memtable_memory_budget / 8;
|
|
550
|
+
// make Level1 size equal to Level0 size, so that L0->L1 compactions are fast
|
|
551
|
+
columnOptions.max_bytes_for_level_base = memtable_memory_budget;
|
|
552
|
+
|
|
553
|
+
// level style compaction
|
|
554
|
+
columnOptions.compaction_style = rocksdb::kCompactionStyleLevel;
|
|
555
|
+
|
|
556
|
+
// only compress levels >= 2
|
|
557
|
+
columnOptions.compression_per_level.resize(columnOptions.num_levels);
|
|
558
|
+
for (int i = 0; i < columnOptions.compression_per_level.size(); ++i) {
|
|
559
|
+
if (i < 2) {
|
|
560
|
+
columnOptions.compression_per_level[i] = rocksdb::kNoCompression;
|
|
561
|
+
} else {
|
|
562
|
+
columnOptions.compression_per_level[i] = rocksdb::kZSTD;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
} else {
|
|
566
|
+
return napi_invalid_arg;
|
|
567
|
+
}
|
|
988
568
|
}
|
|
989
569
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
570
|
+
bool compression = true;
|
|
571
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "compression", compression));
|
|
572
|
+
|
|
573
|
+
if (compression) {
|
|
574
|
+
columnOptions.compression = rocksdb::kZSTD;
|
|
993
575
|
columnOptions.compression_opts.max_dict_bytes = 16 * 1024;
|
|
994
576
|
columnOptions.compression_opts.zstd_max_train_bytes = 16 * 1024 * 100;
|
|
995
577
|
// TODO (perf): compression_opts.parallel_threads
|
|
996
578
|
}
|
|
997
579
|
|
|
998
|
-
|
|
580
|
+
std::optional<std::string> prefixExtractorOpt;
|
|
581
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "prefixExtractor", prefixExtractorOpt));
|
|
999
582
|
if (prefixExtractorOpt) {
|
|
1000
|
-
|
|
583
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
1001
584
|
rocksdb::SliceTransform::CreateFromString(configOptions, *prefixExtractorOpt, &columnOptions.prefix_extractor));
|
|
1002
585
|
}
|
|
1003
586
|
|
|
1004
|
-
|
|
587
|
+
std::optional<std::string> comparatorOpt;
|
|
588
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "comparator", comparatorOpt));
|
|
1005
589
|
if (comparatorOpt) {
|
|
1006
|
-
|
|
590
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
1007
591
|
rocksdb::Comparator::CreateFromString(configOptions, *comparatorOpt, &columnOptions.comparator));
|
|
1008
592
|
}
|
|
1009
593
|
|
|
1010
|
-
|
|
594
|
+
std::optional<std::string> mergeOperatorOpt;
|
|
595
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "mergeOperator", mergeOperatorOpt));
|
|
1011
596
|
if (mergeOperatorOpt) {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
} else {
|
|
1015
|
-
ROCKS_STATUS_RETURN(
|
|
1016
|
-
rocksdb::MergeOperator::CreateFromString(configOptions, *mergeOperatorOpt, &columnOptions.merge_operator));
|
|
1017
|
-
}
|
|
597
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
598
|
+
rocksdb::MergeOperator::CreateFromString(configOptions, *mergeOperatorOpt, &columnOptions.merge_operator));
|
|
1018
599
|
}
|
|
1019
600
|
|
|
1020
|
-
|
|
601
|
+
uint32_t cacheSize = 8 << 20;
|
|
602
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "cacheSize", cacheSize));
|
|
1021
603
|
|
|
1022
604
|
rocksdb::BlockBasedTableOptions tableOptions;
|
|
1023
605
|
|
|
1024
606
|
if (cacheSize) {
|
|
1025
607
|
tableOptions.block_cache = rocksdb::NewLRUCache(cacheSize);
|
|
1026
|
-
tableOptions.cache_index_and_filter_blocks =
|
|
1027
|
-
|
|
608
|
+
tableOptions.cache_index_and_filter_blocks = true;
|
|
609
|
+
NAPI_STATUS_RETURN(
|
|
610
|
+
GetProperty(env, options, "cacheIndexAndFilterBlocks", tableOptions.cache_index_and_filter_blocks));
|
|
1028
611
|
} else {
|
|
1029
612
|
tableOptions.no_block_cache = true;
|
|
1030
613
|
tableOptions.cache_index_and_filter_blocks = false;
|
|
1031
614
|
}
|
|
1032
615
|
|
|
1033
|
-
|
|
616
|
+
std::string optimize = "";
|
|
617
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "optimize", optimize));
|
|
1034
618
|
|
|
1035
619
|
if (optimize == "point-lookup") {
|
|
1036
620
|
tableOptions.data_block_index_type = rocksdb::BlockBasedTableOptions::kDataBlockBinaryAndHash;
|
|
@@ -1042,25 +626,29 @@ rocksdb::Status InitOptions(napi_env env, T& columnOptions, const U& options) {
|
|
|
1042
626
|
} else if (optimize == "range-lookup") {
|
|
1043
627
|
// TODO?
|
|
1044
628
|
} else {
|
|
1045
|
-
tableOptions.filter_policy.reset(rocksdb::
|
|
629
|
+
tableOptions.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10));
|
|
1046
630
|
}
|
|
1047
631
|
|
|
1048
|
-
|
|
632
|
+
std::optional<std::string> filterPolicyOpt;
|
|
633
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "filterPolicy", filterPolicyOpt));
|
|
1049
634
|
if (filterPolicyOpt) {
|
|
1050
|
-
|
|
1051
|
-
ROCKS_STATUS_RETURN(
|
|
635
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
1052
636
|
rocksdb::FilterPolicy::CreateFromString(configOptions, *filterPolicyOpt, &tableOptions.filter_policy));
|
|
1053
637
|
}
|
|
1054
638
|
|
|
1055
|
-
|
|
1056
|
-
|
|
639
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "blockSize", tableOptions.block_size));
|
|
640
|
+
|
|
641
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "blockRestartInterval", tableOptions.block_restart_interval));
|
|
642
|
+
|
|
1057
643
|
tableOptions.format_version = 5;
|
|
1058
644
|
tableOptions.checksum = rocksdb::kXXH3;
|
|
1059
|
-
|
|
645
|
+
|
|
646
|
+
tableOptions.optimize_filters_for_memory = true;
|
|
647
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "optimizeFiltersForMemory", tableOptions.optimize_filters_for_memory));
|
|
1060
648
|
|
|
1061
649
|
columnOptions.table_factory.reset(rocksdb::NewBlockBasedTableFactory(tableOptions));
|
|
1062
650
|
|
|
1063
|
-
return
|
|
651
|
+
return napi_ok;
|
|
1064
652
|
}
|
|
1065
653
|
|
|
1066
654
|
NAPI_METHOD(db_open) {
|
|
@@ -1070,32 +658,44 @@ NAPI_METHOD(db_open) {
|
|
|
1070
658
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1071
659
|
|
|
1072
660
|
std::string location;
|
|
1073
|
-
NAPI_STATUS_THROWS(
|
|
661
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], location));
|
|
1074
662
|
|
|
1075
663
|
rocksdb::Options dbOptions;
|
|
1076
664
|
|
|
1077
|
-
|
|
1078
|
-
|
|
665
|
+
const auto options = argv[2];
|
|
666
|
+
|
|
667
|
+
int parallelism = std::max<int>(1, std::thread::hardware_concurrency() / 2);
|
|
668
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "parallelism", parallelism));
|
|
669
|
+
dbOptions.IncreaseParallelism(parallelism);
|
|
670
|
+
|
|
671
|
+
uint32_t walTTL = 0;
|
|
672
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "walTTL", walTTL));
|
|
673
|
+
dbOptions.WAL_ttl_seconds = walTTL / 1e3;
|
|
674
|
+
|
|
675
|
+
uint32_t walSizeLimit = 0;
|
|
676
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "walSizeLimit", walSizeLimit));
|
|
677
|
+
dbOptions.WAL_size_limit_MB = walSizeLimit / 1e6;
|
|
678
|
+
|
|
679
|
+
bool walCompression = false;
|
|
680
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "walCompression", walCompression));
|
|
681
|
+
dbOptions.wal_compression =
|
|
682
|
+
walCompression ? rocksdb::CompressionType::kZSTD : rocksdb::CompressionType::kNoCompression;
|
|
1079
683
|
|
|
1080
|
-
dbOptions.create_if_missing = BooleanProperty(env, argv[2], "createIfMissing").value_or(true);
|
|
1081
|
-
dbOptions.error_if_exists = BooleanProperty(env, argv[2], "errorIfExists").value_or(false);
|
|
1082
684
|
dbOptions.avoid_unnecessary_blocking_io = true;
|
|
1083
685
|
dbOptions.write_dbid_to_manifest = true;
|
|
1084
686
|
dbOptions.use_adaptive_mutex = true; // We don't have soo many threads in the libuv thread pool...
|
|
1085
687
|
dbOptions.enable_pipelined_write = false; // We only write in the main thread...
|
|
1086
|
-
dbOptions.WAL_ttl_seconds = Uint32Property(env, argv[2], "walTTL").value_or(0) / 1e3;
|
|
1087
|
-
dbOptions.WAL_size_limit_MB = Uint32Property(env, argv[2], "walSizeLimit").value_or(0) / 1e6;
|
|
1088
|
-
dbOptions.wal_compression = BooleanProperty(env, argv[2], "walCompression").value_or(false)
|
|
1089
|
-
? rocksdb::CompressionType::kZSTD
|
|
1090
|
-
: rocksdb::CompressionType::kNoCompression;
|
|
1091
688
|
dbOptions.create_missing_column_families = true;
|
|
1092
|
-
dbOptions.unordered_write = BooleanProperty(env, argv[2], "unorderedWrite").value_or(false);
|
|
1093
689
|
dbOptions.fail_if_options_file_error = true;
|
|
1094
|
-
|
|
690
|
+
|
|
691
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "createIfMissing", dbOptions.create_if_missing));
|
|
692
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "errorIfExists", dbOptions.error_if_exists));
|
|
693
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "unorderedWrite", dbOptions.unordered_write));
|
|
1095
694
|
|
|
1096
695
|
// TODO (feat): dbOptions.listeners
|
|
1097
696
|
|
|
1098
|
-
|
|
697
|
+
std::string infoLogLevel;
|
|
698
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "infoLogLevel", infoLogLevel));
|
|
1099
699
|
if (infoLogLevel.size() > 0) {
|
|
1100
700
|
rocksdb::InfoLogLevel lvl = {};
|
|
1101
701
|
|
|
@@ -1122,16 +722,16 @@ NAPI_METHOD(db_open) {
|
|
|
1122
722
|
dbOptions.info_log.reset(new NullLogger());
|
|
1123
723
|
}
|
|
1124
724
|
|
|
1125
|
-
|
|
725
|
+
NAPI_STATUS_THROWS(InitOptions(env, dbOptions, options));
|
|
1126
726
|
|
|
1127
727
|
std::vector<rocksdb::ColumnFamilyDescriptor> descriptors;
|
|
1128
728
|
|
|
1129
729
|
bool hasColumns;
|
|
1130
|
-
NAPI_STATUS_THROWS(napi_has_named_property(env,
|
|
730
|
+
NAPI_STATUS_THROWS(napi_has_named_property(env, options, "columns", &hasColumns));
|
|
1131
731
|
|
|
1132
732
|
if (hasColumns) {
|
|
1133
733
|
napi_value columns;
|
|
1134
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env,
|
|
734
|
+
NAPI_STATUS_THROWS(napi_get_named_property(env, options, "columns", &columns));
|
|
1135
735
|
|
|
1136
736
|
napi_value keys;
|
|
1137
737
|
NAPI_STATUS_THROWS(napi_get_property_names(env, columns, &keys));
|
|
@@ -1147,26 +747,25 @@ NAPI_METHOD(db_open) {
|
|
|
1147
747
|
napi_value column;
|
|
1148
748
|
NAPI_STATUS_THROWS(napi_get_property(env, columns, key, &column));
|
|
1149
749
|
|
|
1150
|
-
|
|
750
|
+
NAPI_STATUS_THROWS(InitOptions(env, descriptors[n].options, column));
|
|
1151
751
|
|
|
1152
|
-
NAPI_STATUS_THROWS(
|
|
752
|
+
NAPI_STATUS_THROWS(GetValue(env, key, descriptors[n].name));
|
|
1153
753
|
}
|
|
1154
754
|
}
|
|
1155
755
|
|
|
1156
756
|
auto callback = argv[3];
|
|
1157
757
|
|
|
1158
|
-
|
|
1159
|
-
"leveldown.open", env, callback,
|
|
1160
|
-
[=](auto& handles
|
|
758
|
+
runAsync<std::vector<rocksdb::ColumnFamilyHandle*>>(
|
|
759
|
+
"leveldown.open", env, callback,
|
|
760
|
+
[=](auto& handles) {
|
|
1161
761
|
rocksdb::DB* db = nullptr;
|
|
1162
762
|
const auto status = descriptors.empty() ? rocksdb::DB::Open(dbOptions, location, &db)
|
|
1163
763
|
: rocksdb::DB::Open(dbOptions, location, descriptors, &handles, &db);
|
|
1164
|
-
database.
|
|
764
|
+
database->db.reset(db);
|
|
1165
765
|
return status;
|
|
1166
766
|
},
|
|
1167
|
-
[=](auto& handles,
|
|
1168
|
-
|
|
1169
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
767
|
+
[=](auto& handles, auto env, auto& argv) {
|
|
768
|
+
argv.resize(2);
|
|
1170
769
|
|
|
1171
770
|
const auto size = handles.size();
|
|
1172
771
|
NAPI_STATUS_RETURN(napi_create_object(env, &argv[1]));
|
|
@@ -1177,13 +776,11 @@ NAPI_METHOD(db_open) {
|
|
|
1177
776
|
column.descriptor = descriptors[n];
|
|
1178
777
|
NAPI_STATUS_RETURN(napi_create_external(env, column.handle, nullptr, nullptr, &column.val));
|
|
1179
778
|
NAPI_STATUS_RETURN(napi_create_reference(env, column.val, 1, &column.ref));
|
|
1180
|
-
|
|
1181
779
|
NAPI_STATUS_RETURN(napi_set_named_property(env, argv[1], descriptors[n].name.c_str(), column.val));
|
|
1182
|
-
|
|
1183
|
-
database->columns_[column.handle->GetID()] = column;
|
|
780
|
+
database->columns[column.handle->GetID()] = column;
|
|
1184
781
|
}
|
|
1185
782
|
|
|
1186
|
-
return
|
|
783
|
+
return napi_ok;
|
|
1187
784
|
});
|
|
1188
785
|
|
|
1189
786
|
return 0;
|
|
@@ -1202,28 +799,9 @@ NAPI_METHOD(db_close) {
|
|
|
1202
799
|
auto callback = argv[1];
|
|
1203
800
|
|
|
1204
801
|
struct State {};
|
|
1205
|
-
|
|
1206
|
-
"leveldown.close", env, callback, database
|
|
1207
|
-
[
|
|
1208
|
-
for (auto& it : database.columns_) {
|
|
1209
|
-
database.db_->DestroyColumnFamilyHandle(it.second.handle);
|
|
1210
|
-
}
|
|
1211
|
-
database.columns_.clear();
|
|
1212
|
-
|
|
1213
|
-
return database.db_->Close();
|
|
1214
|
-
},
|
|
1215
|
-
[](auto& state, napi_env env, napi_value callback) -> napi_status {
|
|
1216
|
-
napi_value argv[1];
|
|
1217
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
1218
|
-
|
|
1219
|
-
return CallFunction(env, callback, 1, &argv[0]);
|
|
1220
|
-
});
|
|
1221
|
-
|
|
1222
|
-
if (!database->HasPriorityWork()) {
|
|
1223
|
-
worker->Queue(env);
|
|
1224
|
-
} else {
|
|
1225
|
-
database->pendingCloseWorker_ = worker;
|
|
1226
|
-
}
|
|
802
|
+
runAsync<State>(
|
|
803
|
+
"leveldown.close", env, callback, [=](auto& state) { return database->Close(); },
|
|
804
|
+
[](auto& state, auto env, auto& argv) { return napi_ok; });
|
|
1227
805
|
|
|
1228
806
|
return 0;
|
|
1229
807
|
}
|
|
@@ -1234,40 +812,38 @@ NAPI_METHOD(updates_init) {
|
|
|
1234
812
|
Database* database;
|
|
1235
813
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1236
814
|
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
NAPI_STATUS_THROWS(
|
|
815
|
+
const auto options = argv[1];
|
|
816
|
+
|
|
817
|
+
int64_t since = 0;
|
|
818
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "since", since));
|
|
819
|
+
|
|
820
|
+
bool keys = true;
|
|
821
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keys", keys));
|
|
1241
822
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[1], "keys", &keysProperty));
|
|
1245
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, keysProperty, &keys));
|
|
823
|
+
bool values = true;
|
|
824
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "values", values));
|
|
1246
825
|
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[1], "values", &valuesProperty));
|
|
1250
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, valuesProperty, &values));
|
|
826
|
+
bool data = true;
|
|
827
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "data", data));
|
|
1251
828
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[1], "data", &dataProperty));
|
|
1255
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, dataProperty, &data));
|
|
829
|
+
Encoding keyEncoding = Encoding::String;
|
|
830
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keyEncoding", keyEncoding));
|
|
1256
831
|
|
|
1257
|
-
|
|
1258
|
-
|
|
832
|
+
Encoding valueEncoding = Encoding::String;
|
|
833
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1259
834
|
|
|
1260
835
|
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1261
|
-
NAPI_STATUS_THROWS(
|
|
836
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1262
837
|
|
|
1263
|
-
auto updates =
|
|
838
|
+
auto updates =
|
|
839
|
+
std::unique_ptr<Updates>(new Updates(database, since, keys, values, data, column, keyEncoding, valueEncoding));
|
|
1264
840
|
|
|
1265
841
|
napi_value result;
|
|
1266
842
|
NAPI_STATUS_THROWS(napi_create_external(env, updates.get(), Finalize<Updates>, updates.get(), &result));
|
|
1267
843
|
|
|
1268
844
|
// Prevent GC of JS object before the iterator is closed (explicitly or on
|
|
1269
845
|
// db close) and keep track of non-closed iterators to end them on db close.
|
|
1270
|
-
updates.release()->Attach(env, result);
|
|
846
|
+
NAPI_STATUS_THROWS(updates.release()->Attach(env, result));
|
|
1271
847
|
|
|
1272
848
|
return result;
|
|
1273
849
|
}
|
|
@@ -1280,12 +856,12 @@ NAPI_METHOD(updates_next) {
|
|
|
1280
856
|
|
|
1281
857
|
auto callback = argv[1];
|
|
1282
858
|
|
|
1283
|
-
|
|
1284
|
-
"leveldown.updates.next", env, callback,
|
|
1285
|
-
[=](auto& batchResult
|
|
859
|
+
runAsync<rocksdb::BatchResult>(
|
|
860
|
+
"leveldown.updates.next", env, callback,
|
|
861
|
+
[=](auto& batchResult) {
|
|
1286
862
|
if (!updates->iterator_) {
|
|
1287
863
|
rocksdb::TransactionLogIterator::ReadOptions options;
|
|
1288
|
-
const auto status =
|
|
864
|
+
const auto status = updates->database_->db->GetUpdatesSince(updates->start_, &updates->iterator_, options);
|
|
1289
865
|
if (!status.ok()) {
|
|
1290
866
|
return status;
|
|
1291
867
|
}
|
|
@@ -1301,22 +877,18 @@ NAPI_METHOD(updates_next) {
|
|
|
1301
877
|
|
|
1302
878
|
return rocksdb::Status::OK();
|
|
1303
879
|
},
|
|
1304
|
-
[=](auto& batchResult,
|
|
1305
|
-
napi_value argv[5];
|
|
1306
|
-
|
|
1307
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
1308
|
-
|
|
880
|
+
[=](auto& batchResult, auto env, auto& argv) {
|
|
1309
881
|
if (!batchResult.writeBatchPtr) {
|
|
1310
|
-
return
|
|
882
|
+
return napi_ok;
|
|
1311
883
|
}
|
|
1312
884
|
|
|
885
|
+
argv.resize(5);
|
|
1313
886
|
NAPI_STATUS_RETURN(updates->Iterate(env, *batchResult.writeBatchPtr, &argv[1]));
|
|
1314
|
-
|
|
1315
887
|
NAPI_STATUS_RETURN(napi_create_int64(env, batchResult.sequence, &argv[2]));
|
|
1316
888
|
NAPI_STATUS_RETURN(napi_create_int64(env, batchResult.writeBatchPtr->Count(), &argv[3]));
|
|
1317
889
|
NAPI_STATUS_RETURN(napi_create_int64(env, updates->start_, &argv[4]));
|
|
1318
890
|
|
|
1319
|
-
return
|
|
891
|
+
return napi_ok;
|
|
1320
892
|
});
|
|
1321
893
|
|
|
1322
894
|
return 0;
|
|
@@ -1328,8 +900,8 @@ NAPI_METHOD(updates_close) {
|
|
|
1328
900
|
Updates* updates;
|
|
1329
901
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&updates)));
|
|
1330
902
|
|
|
1331
|
-
updates->
|
|
1332
|
-
updates->
|
|
903
|
+
ROCKS_STATUS_THROWS_NAPI(updates->Close());
|
|
904
|
+
NAPI_STATUS_THROWS(updates->Detach(env));
|
|
1333
905
|
|
|
1334
906
|
return 0;
|
|
1335
907
|
}
|
|
@@ -1349,44 +921,53 @@ NAPI_METHOD(db_get_many) {
|
|
|
1349
921
|
for (uint32_t n = 0; n < length; n++) {
|
|
1350
922
|
napi_value element;
|
|
1351
923
|
NAPI_STATUS_THROWS(napi_get_element(env, argv[1], n, &element));
|
|
1352
|
-
NAPI_STATUS_THROWS(
|
|
924
|
+
NAPI_STATUS_THROWS(GetValue(env, element, keys[n]));
|
|
1353
925
|
}
|
|
1354
926
|
}
|
|
1355
927
|
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
|
|
928
|
+
const auto options = argv[2];
|
|
929
|
+
|
|
930
|
+
Encoding valueEncoding = Encoding::String;
|
|
931
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1359
932
|
|
|
1360
|
-
|
|
1361
|
-
NAPI_STATUS_THROWS(
|
|
933
|
+
bool fillCache = true;
|
|
934
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "fillCache", fillCache));
|
|
935
|
+
|
|
936
|
+
bool ignoreRangeDeletions = false;
|
|
937
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "ignoreRangeDeletions", ignoreRangeDeletions));
|
|
938
|
+
|
|
939
|
+
rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
|
|
940
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1362
941
|
|
|
1363
942
|
auto callback = argv[3];
|
|
1364
943
|
|
|
1365
944
|
auto snapshot = std::shared_ptr<const rocksdb::Snapshot>(
|
|
1366
|
-
database->
|
|
945
|
+
database->db->GetSnapshot(), [database](auto ptr) { database->db->ReleaseSnapshot(ptr); });
|
|
1367
946
|
|
|
1368
|
-
|
|
1369
|
-
"leveldown.get.many", env, callback,
|
|
1370
|
-
[=, keys = std::move(keys)](auto& values
|
|
947
|
+
runAsync<std::vector<rocksdb::PinnableSlice>>(
|
|
948
|
+
"leveldown.get.many", env, callback,
|
|
949
|
+
[=, keys = std::move(keys), snapshot = std::move(snapshot)](auto& values) {
|
|
1371
950
|
rocksdb::ReadOptions readOptions;
|
|
1372
951
|
readOptions.fill_cache = fillCache;
|
|
1373
952
|
readOptions.snapshot = snapshot.get();
|
|
1374
953
|
readOptions.async_io = true;
|
|
1375
954
|
readOptions.ignore_range_deletions = ignoreRangeDeletions;
|
|
1376
955
|
|
|
956
|
+
const auto size = keys.size();
|
|
957
|
+
|
|
1377
958
|
std::vector<rocksdb::Slice> keys2;
|
|
1378
|
-
keys2.reserve(
|
|
959
|
+
keys2.reserve(size);
|
|
1379
960
|
for (const auto& key : keys) {
|
|
1380
961
|
keys2.emplace_back(key);
|
|
1381
962
|
}
|
|
1382
963
|
std::vector<rocksdb::Status> statuses;
|
|
1383
964
|
|
|
1384
|
-
statuses.resize(
|
|
1385
|
-
values.resize(
|
|
965
|
+
statuses.resize(size);
|
|
966
|
+
values.resize(size);
|
|
1386
967
|
|
|
1387
|
-
db
|
|
968
|
+
database->db->MultiGet(readOptions, column, size, keys2.data(), values.data(), statuses.data());
|
|
1388
969
|
|
|
1389
|
-
for (size_t idx = 0; idx <
|
|
970
|
+
for (size_t idx = 0; idx < size; idx++) {
|
|
1390
971
|
if (statuses[idx].IsNotFound()) {
|
|
1391
972
|
values[idx] = rocksdb::PinnableSlice(nullptr);
|
|
1392
973
|
} else if (!statuses[idx].ok()) {
|
|
@@ -1396,23 +977,22 @@ NAPI_METHOD(db_get_many) {
|
|
|
1396
977
|
|
|
1397
978
|
return rocksdb::Status::OK();
|
|
1398
979
|
},
|
|
1399
|
-
[=](auto& values,
|
|
1400
|
-
|
|
1401
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
980
|
+
[=](auto& values, auto env, auto& argv) {
|
|
981
|
+
argv.resize(2);
|
|
1402
982
|
|
|
1403
983
|
NAPI_STATUS_RETURN(napi_create_array_with_length(env, values.size(), &argv[1]));
|
|
1404
984
|
|
|
1405
985
|
for (size_t idx = 0; idx < values.size(); idx++) {
|
|
1406
986
|
napi_value element;
|
|
1407
987
|
if (values[idx].GetSelf()) {
|
|
1408
|
-
NAPI_STATUS_RETURN(Convert(env, &values[idx],
|
|
988
|
+
NAPI_STATUS_RETURN(Convert(env, &values[idx], valueEncoding, element));
|
|
1409
989
|
} else {
|
|
1410
990
|
NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
|
|
1411
991
|
}
|
|
1412
992
|
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<uint32_t>(idx), element));
|
|
1413
993
|
}
|
|
1414
994
|
|
|
1415
|
-
return
|
|
995
|
+
return napi_ok;
|
|
1416
996
|
});
|
|
1417
997
|
|
|
1418
998
|
return 0;
|
|
@@ -1424,16 +1004,28 @@ NAPI_METHOD(db_clear) {
|
|
|
1424
1004
|
Database* database;
|
|
1425
1005
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1426
1006
|
|
|
1427
|
-
const auto
|
|
1428
|
-
|
|
1007
|
+
const auto options = argv[1];
|
|
1008
|
+
|
|
1009
|
+
bool reverse = false;
|
|
1010
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "reverse", reverse));
|
|
1011
|
+
|
|
1012
|
+
int32_t limit = -1;
|
|
1013
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "limit", limit));
|
|
1014
|
+
|
|
1015
|
+
rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
|
|
1016
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1017
|
+
|
|
1018
|
+
std::optional<std::string> lt;
|
|
1019
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "lt", lt));
|
|
1020
|
+
|
|
1021
|
+
std::optional<std::string> lte;
|
|
1022
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "lte", lte));
|
|
1429
1023
|
|
|
1430
|
-
|
|
1431
|
-
NAPI_STATUS_THROWS(
|
|
1024
|
+
std::optional<std::string> gt;
|
|
1025
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gt", gt));
|
|
1432
1026
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
auto gt = StringProperty(env, argv[1], "gt");
|
|
1436
|
-
auto gte = StringProperty(env, argv[1], "gte");
|
|
1027
|
+
std::optional<std::string> gte;
|
|
1028
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gte", gte));
|
|
1437
1029
|
|
|
1438
1030
|
if (limit == -1) {
|
|
1439
1031
|
rocksdb::PinnableSlice begin;
|
|
@@ -1458,7 +1050,7 @@ NAPI_METHOD(db_clear) {
|
|
|
1458
1050
|
|
|
1459
1051
|
if (begin.compare(end) < 0) {
|
|
1460
1052
|
rocksdb::WriteOptions writeOptions;
|
|
1461
|
-
|
|
1053
|
+
ROCKS_STATUS_THROWS_NAPI(database->db->DeleteRange(writeOptions, column, begin, end));
|
|
1462
1054
|
}
|
|
1463
1055
|
|
|
1464
1056
|
return 0;
|
|
@@ -1466,8 +1058,8 @@ NAPI_METHOD(db_clear) {
|
|
|
1466
1058
|
// TODO (fix): Error handling.
|
|
1467
1059
|
// TODO (fix): This should be async...
|
|
1468
1060
|
|
|
1469
|
-
std::shared_ptr<const rocksdb::Snapshot> snapshot(database->
|
|
1470
|
-
[=](const auto ptr) { database->
|
|
1061
|
+
std::shared_ptr<const rocksdb::Snapshot> snapshot(database->db->GetSnapshot(),
|
|
1062
|
+
[=](const auto ptr) { database->db->ReleaseSnapshot(ptr); });
|
|
1471
1063
|
BaseIterator it(database, column, reverse, lt, lte, gt, gte, limit, false, snapshot);
|
|
1472
1064
|
|
|
1473
1065
|
it.SeekToRange();
|
|
@@ -1491,7 +1083,7 @@ NAPI_METHOD(db_clear) {
|
|
|
1491
1083
|
break;
|
|
1492
1084
|
}
|
|
1493
1085
|
|
|
1494
|
-
status = database->
|
|
1086
|
+
status = database->db->Write(writeOptions, &batch);
|
|
1495
1087
|
if (!status.ok()) {
|
|
1496
1088
|
break;
|
|
1497
1089
|
}
|
|
@@ -1502,7 +1094,7 @@ NAPI_METHOD(db_clear) {
|
|
|
1502
1094
|
it.Close();
|
|
1503
1095
|
|
|
1504
1096
|
if (!status.ok()) {
|
|
1505
|
-
|
|
1097
|
+
ROCKS_STATUS_THROWS_NAPI(status);
|
|
1506
1098
|
}
|
|
1507
1099
|
|
|
1508
1100
|
return 0;
|
|
@@ -1516,10 +1108,10 @@ NAPI_METHOD(db_get_property) {
|
|
|
1516
1108
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1517
1109
|
|
|
1518
1110
|
rocksdb::PinnableSlice property;
|
|
1519
|
-
NAPI_STATUS_THROWS(
|
|
1111
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], property));
|
|
1520
1112
|
|
|
1521
1113
|
std::string value;
|
|
1522
|
-
database->
|
|
1114
|
+
database->db->GetProperty(property, &value);
|
|
1523
1115
|
|
|
1524
1116
|
napi_value result;
|
|
1525
1117
|
NAPI_STATUS_THROWS(napi_create_string_utf8(env, value.data(), value.size(), &result));
|
|
@@ -1533,7 +1125,7 @@ NAPI_METHOD(db_get_latest_sequence) {
|
|
|
1533
1125
|
Database* database;
|
|
1534
1126
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1535
1127
|
|
|
1536
|
-
const auto seq = database->
|
|
1128
|
+
const auto seq = database->db->GetLatestSequenceNumber();
|
|
1537
1129
|
|
|
1538
1130
|
napi_value result;
|
|
1539
1131
|
NAPI_STATUS_THROWS(napi_create_int64(env, seq, &result));
|
|
@@ -1548,35 +1140,59 @@ NAPI_METHOD(iterator_init) {
|
|
|
1548
1140
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1549
1141
|
|
|
1550
1142
|
const auto options = argv[1];
|
|
1551
|
-
const auto reverse = BooleanProperty(env, options, "reverse").value_or(false);
|
|
1552
|
-
const auto keys = BooleanProperty(env, options, "keys").value_or(true);
|
|
1553
|
-
const auto values = BooleanProperty(env, options, "values").value_or(true);
|
|
1554
|
-
const auto fillCache = BooleanProperty(env, options, "fillCache").value_or(false);
|
|
1555
|
-
const bool keyAsBuffer = EncodingIsBuffer(env, options, "keyEncoding");
|
|
1556
|
-
const bool valueAsBuffer = EncodingIsBuffer(env, options, "valueEncoding");
|
|
1557
|
-
const auto limit = Int32Property(env, options, "limit").value_or(-1);
|
|
1558
|
-
const auto highWaterMarkBytes = Uint32Property(env, options, "highWaterMarkBytes").value_or(64 * 1024);
|
|
1559
1143
|
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
const auto gt = StringProperty(env, options, "gt");
|
|
1563
|
-
const auto gte = StringProperty(env, options, "gte");
|
|
1144
|
+
bool reverse = false;
|
|
1145
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "reverse", reverse));
|
|
1564
1146
|
|
|
1565
|
-
|
|
1566
|
-
NAPI_STATUS_THROWS(
|
|
1147
|
+
bool keys = true;
|
|
1148
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keys", keys));
|
|
1567
1149
|
|
|
1568
|
-
|
|
1569
|
-
|
|
1150
|
+
bool values = true;
|
|
1151
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "values", values));
|
|
1570
1152
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1153
|
+
bool fillCache = false;
|
|
1154
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "fillCache", fillCache));
|
|
1155
|
+
|
|
1156
|
+
Encoding keyEncoding = Encoding::String;
|
|
1157
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keyEncoding", keyEncoding));
|
|
1158
|
+
|
|
1159
|
+
Encoding valueEncoding = Encoding::String;
|
|
1160
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1161
|
+
|
|
1162
|
+
int32_t limit = -1;
|
|
1163
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "limit", limit));
|
|
1164
|
+
|
|
1165
|
+
int32_t highWaterMarkBytes = 64 * 1024;
|
|
1166
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "highWaterMarkBytes", highWaterMarkBytes));
|
|
1167
|
+
|
|
1168
|
+
std::optional<std::string> lt;
|
|
1169
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "lt", lt));
|
|
1170
|
+
|
|
1171
|
+
std::optional<std::string> lte;
|
|
1172
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "lte", lte));
|
|
1173
|
+
|
|
1174
|
+
std::optional<std::string> gt;
|
|
1175
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gt", gt));
|
|
1176
|
+
|
|
1177
|
+
std::optional<std::string> gte;
|
|
1178
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gte", gte));
|
|
1179
|
+
|
|
1180
|
+
rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
|
|
1181
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1182
|
+
|
|
1183
|
+
std::shared_ptr<const rocksdb::Snapshot> snapshot(database->db->GetSnapshot(),
|
|
1184
|
+
[=](const auto ptr) { database->db->ReleaseSnapshot(ptr); });
|
|
1185
|
+
|
|
1186
|
+
auto iterator =
|
|
1187
|
+
std::unique_ptr<Iterator>(new Iterator(database, column, reverse, keys, values, limit, lt, lte, gt, gte,
|
|
1188
|
+
fillCache, keyEncoding, valueEncoding, highWaterMarkBytes, snapshot));
|
|
1573
1189
|
|
|
1574
1190
|
napi_value result;
|
|
1575
1191
|
NAPI_STATUS_THROWS(napi_create_external(env, iterator.get(), Finalize<Iterator>, iterator.get(), &result));
|
|
1576
1192
|
|
|
1577
1193
|
// Prevent GC of JS object before the iterator is closed (explicitly or on
|
|
1578
1194
|
// db close) and keep track of non-closed iterators to end them on db close.
|
|
1579
|
-
iterator.release()->Attach(env, result);
|
|
1195
|
+
NAPI_STATUS_THROWS(iterator.release()->Attach(env, result));
|
|
1580
1196
|
|
|
1581
1197
|
return result;
|
|
1582
1198
|
}
|
|
@@ -1588,7 +1204,7 @@ NAPI_METHOD(iterator_seek) {
|
|
|
1588
1204
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
|
|
1589
1205
|
|
|
1590
1206
|
rocksdb::PinnableSlice target;
|
|
1591
|
-
NAPI_STATUS_THROWS(
|
|
1207
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], target));
|
|
1592
1208
|
|
|
1593
1209
|
iterator->first_ = true;
|
|
1594
1210
|
iterator->Seek(target); // TODO: Does seek causing blocking IO?
|
|
@@ -1602,8 +1218,8 @@ NAPI_METHOD(iterator_close) {
|
|
|
1602
1218
|
Iterator* iterator;
|
|
1603
1219
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
|
|
1604
1220
|
|
|
1605
|
-
iterator->
|
|
1606
|
-
iterator->
|
|
1221
|
+
ROCKS_STATUS_THROWS_NAPI(iterator->Close());
|
|
1222
|
+
NAPI_STATUS_THROWS(iterator->Detach(env));
|
|
1607
1223
|
|
|
1608
1224
|
return 0;
|
|
1609
1225
|
}
|
|
@@ -1638,9 +1254,9 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1638
1254
|
bool finished = false;
|
|
1639
1255
|
};
|
|
1640
1256
|
|
|
1641
|
-
|
|
1642
|
-
std::string("leveldown.iterator.next"), env, callback,
|
|
1643
|
-
[=](auto& state
|
|
1257
|
+
runAsync<State>(
|
|
1258
|
+
std::string("leveldown.iterator.next"), env, callback,
|
|
1259
|
+
[=](auto& state) {
|
|
1644
1260
|
if (!iterator->DidSeek()) {
|
|
1645
1261
|
iterator->SeekToRange();
|
|
1646
1262
|
}
|
|
@@ -1685,9 +1301,8 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1685
1301
|
|
|
1686
1302
|
return iterator->Status();
|
|
1687
1303
|
},
|
|
1688
|
-
[=](auto& state,
|
|
1689
|
-
|
|
1690
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
1304
|
+
[=](auto& state, auto env, auto& argv) {
|
|
1305
|
+
argv.resize(3);
|
|
1691
1306
|
|
|
1692
1307
|
NAPI_STATUS_RETURN(napi_create_array_with_length(env, state.cache.size(), &argv[1]));
|
|
1693
1308
|
|
|
@@ -1695,8 +1310,8 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1695
1310
|
napi_value key;
|
|
1696
1311
|
napi_value val;
|
|
1697
1312
|
|
|
1698
|
-
NAPI_STATUS_RETURN(Convert(env, state.cache[n + 0], iterator->
|
|
1699
|
-
NAPI_STATUS_RETURN(Convert(env, state.cache[n + 1], iterator->
|
|
1313
|
+
NAPI_STATUS_RETURN(Convert(env, state.cache[n + 0], iterator->keyEncoding_, key));
|
|
1314
|
+
NAPI_STATUS_RETURN(Convert(env, state.cache[n + 1], iterator->valueEncoding_, val));
|
|
1700
1315
|
|
|
1701
1316
|
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 0), key));
|
|
1702
1317
|
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 1), val));
|
|
@@ -1704,7 +1319,7 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1704
1319
|
|
|
1705
1320
|
NAPI_STATUS_RETURN(napi_get_boolean(env, state.finished, &argv[2]));
|
|
1706
1321
|
|
|
1707
|
-
return
|
|
1322
|
+
return napi_ok;
|
|
1708
1323
|
});
|
|
1709
1324
|
|
|
1710
1325
|
return 0;
|
|
@@ -1718,63 +1333,49 @@ NAPI_METHOD(batch_do) {
|
|
|
1718
1333
|
|
|
1719
1334
|
rocksdb::WriteBatch batch;
|
|
1720
1335
|
|
|
1336
|
+
auto elements = argv[1];
|
|
1337
|
+
|
|
1721
1338
|
uint32_t length;
|
|
1722
|
-
NAPI_STATUS_THROWS(napi_get_array_length(env,
|
|
1339
|
+
NAPI_STATUS_THROWS(napi_get_array_length(env, elements, &length));
|
|
1340
|
+
|
|
1341
|
+
rocksdb::PinnableSlice type;
|
|
1342
|
+
rocksdb::PinnableSlice key;
|
|
1343
|
+
rocksdb::PinnableSlice value;
|
|
1723
1344
|
|
|
1724
1345
|
for (uint32_t i = 0; i < length; i++) {
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1346
|
+
type.Reset();
|
|
1347
|
+
key.Reset();
|
|
1348
|
+
value.Reset();
|
|
1728
1349
|
|
|
1729
1350
|
napi_value element;
|
|
1730
|
-
NAPI_STATUS_THROWS(napi_get_element(env,
|
|
1351
|
+
NAPI_STATUS_THROWS(napi_get_element(env, elements, i, &element));
|
|
1731
1352
|
|
|
1732
|
-
|
|
1733
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, element, "type", &typeProperty));
|
|
1734
|
-
NAPI_STATUS_THROWS(ToString(env, typeProperty, type));
|
|
1353
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "type", type, true));
|
|
1735
1354
|
|
|
1736
|
-
rocksdb::ColumnFamilyHandle* column;
|
|
1737
|
-
NAPI_STATUS_THROWS(
|
|
1355
|
+
rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
|
|
1356
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "column", column));
|
|
1738
1357
|
|
|
1739
1358
|
if (type == "del") {
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
NAPI_STATUS_THROWS(ToString(env, keyProperty, key));
|
|
1743
|
-
|
|
1744
|
-
ROCKS_STATUS_THROWS(batch.Delete(column, key));
|
|
1359
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "key", key, true));
|
|
1360
|
+
ROCKS_STATUS_THROWS_NAPI(batch.Delete(column, key));
|
|
1745
1361
|
} else if (type == "put") {
|
|
1746
|
-
|
|
1747
|
-
NAPI_STATUS_THROWS(
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
napi_value valueProperty;
|
|
1751
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, element, "value", &valueProperty));
|
|
1752
|
-
NAPI_STATUS_THROWS(ToString(env, valueProperty, value));
|
|
1753
|
-
|
|
1754
|
-
ROCKS_STATUS_THROWS(batch.Put(column, key, value));
|
|
1362
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "key", key, true));
|
|
1363
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "value", value, true));
|
|
1364
|
+
ROCKS_STATUS_THROWS_NAPI(batch.Put(column, key, value));
|
|
1755
1365
|
} else if (type == "data") {
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
NAPI_STATUS_THROWS(ToString(env, valueProperty, value));
|
|
1759
|
-
|
|
1760
|
-
ROCKS_STATUS_THROWS(batch.PutLogData(value));
|
|
1366
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "value", value, true));
|
|
1367
|
+
ROCKS_STATUS_THROWS_NAPI(batch.PutLogData(value));
|
|
1761
1368
|
} else if (type == "merge") {
|
|
1762
|
-
|
|
1763
|
-
NAPI_STATUS_THROWS(
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
napi_value valueProperty;
|
|
1767
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, element, "value", &valueProperty));
|
|
1768
|
-
NAPI_STATUS_THROWS(ToString(env, valueProperty, value));
|
|
1769
|
-
|
|
1770
|
-
ROCKS_STATUS_THROWS(batch.Merge(column, key, value));
|
|
1369
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "key", key, true));
|
|
1370
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "value", value, true));
|
|
1371
|
+
ROCKS_STATUS_THROWS_NAPI(batch.Merge(column, key, value));
|
|
1771
1372
|
} else {
|
|
1772
|
-
|
|
1373
|
+
NAPI_STATUS_THROWS(napi_invalid_arg);
|
|
1773
1374
|
}
|
|
1774
1375
|
}
|
|
1775
1376
|
|
|
1776
1377
|
rocksdb::WriteOptions writeOptions;
|
|
1777
|
-
|
|
1378
|
+
ROCKS_STATUS_THROWS_NAPI(database->db->Write(writeOptions, &batch));
|
|
1778
1379
|
|
|
1779
1380
|
return 0;
|
|
1780
1381
|
}
|
|
@@ -1792,21 +1393,23 @@ NAPI_METHOD(batch_put) {
|
|
|
1792
1393
|
NAPI_ARGV(4);
|
|
1793
1394
|
|
|
1794
1395
|
rocksdb::WriteBatch* batch;
|
|
1795
|
-
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0],
|
|
1396
|
+
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
|
|
1796
1397
|
|
|
1797
1398
|
rocksdb::PinnableSlice key;
|
|
1798
|
-
NAPI_STATUS_THROWS(
|
|
1399
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], key));
|
|
1799
1400
|
|
|
1800
1401
|
rocksdb::PinnableSlice val;
|
|
1801
|
-
NAPI_STATUS_THROWS(
|
|
1402
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[2], val));
|
|
1802
1403
|
|
|
1803
|
-
|
|
1804
|
-
|
|
1404
|
+
const auto options = argv[3];
|
|
1405
|
+
|
|
1406
|
+
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1407
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1805
1408
|
|
|
1806
1409
|
if (column) {
|
|
1807
|
-
|
|
1410
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Put(column, key, val));
|
|
1808
1411
|
} else {
|
|
1809
|
-
|
|
1412
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Put(key, val));
|
|
1810
1413
|
}
|
|
1811
1414
|
|
|
1812
1415
|
return 0;
|
|
@@ -1819,15 +1422,17 @@ NAPI_METHOD(batch_del) {
|
|
|
1819
1422
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
|
|
1820
1423
|
|
|
1821
1424
|
rocksdb::PinnableSlice key;
|
|
1822
|
-
NAPI_STATUS_THROWS(
|
|
1425
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], key));
|
|
1426
|
+
|
|
1427
|
+
const auto options = argv[2];
|
|
1823
1428
|
|
|
1824
|
-
rocksdb::ColumnFamilyHandle* column;
|
|
1825
|
-
NAPI_STATUS_THROWS(
|
|
1429
|
+
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1430
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1826
1431
|
|
|
1827
1432
|
if (column) {
|
|
1828
|
-
|
|
1433
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Delete(column, key));
|
|
1829
1434
|
} else {
|
|
1830
|
-
|
|
1435
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Delete(key));
|
|
1831
1436
|
}
|
|
1832
1437
|
|
|
1833
1438
|
return 0;
|
|
@@ -1840,18 +1445,20 @@ NAPI_METHOD(batch_merge) {
|
|
|
1840
1445
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)(&batch)));
|
|
1841
1446
|
|
|
1842
1447
|
rocksdb::PinnableSlice key;
|
|
1843
|
-
NAPI_STATUS_THROWS(
|
|
1448
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], key));
|
|
1844
1449
|
|
|
1845
1450
|
rocksdb::PinnableSlice val;
|
|
1846
|
-
NAPI_STATUS_THROWS(
|
|
1451
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[2], val));
|
|
1452
|
+
|
|
1453
|
+
const auto options = argv[3];
|
|
1847
1454
|
|
|
1848
|
-
rocksdb::ColumnFamilyHandle* column;
|
|
1849
|
-
NAPI_STATUS_THROWS(
|
|
1455
|
+
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1456
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1850
1457
|
|
|
1851
1458
|
if (column) {
|
|
1852
|
-
|
|
1459
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Merge(column, key, val));
|
|
1853
1460
|
} else {
|
|
1854
|
-
|
|
1461
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Merge(key, val));
|
|
1855
1462
|
}
|
|
1856
1463
|
|
|
1857
1464
|
return 0;
|
|
@@ -1878,7 +1485,7 @@ NAPI_METHOD(batch_write) {
|
|
|
1878
1485
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
|
|
1879
1486
|
|
|
1880
1487
|
rocksdb::WriteOptions writeOptions;
|
|
1881
|
-
|
|
1488
|
+
ROCKS_STATUS_THROWS_NAPI(database->db->Write(writeOptions, batch));
|
|
1882
1489
|
|
|
1883
1490
|
return 0;
|
|
1884
1491
|
}
|
|
@@ -1890,9 +1497,9 @@ NAPI_METHOD(batch_put_log_data) {
|
|
|
1890
1497
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
|
|
1891
1498
|
|
|
1892
1499
|
rocksdb::PinnableSlice logData;
|
|
1893
|
-
NAPI_STATUS_THROWS(
|
|
1500
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], logData));
|
|
1894
1501
|
|
|
1895
|
-
|
|
1502
|
+
ROCKS_STATUS_THROWS_NAPI(batch->PutLogData(logData));
|
|
1896
1503
|
|
|
1897
1504
|
return 0;
|
|
1898
1505
|
}
|
|
@@ -1918,111 +1525,34 @@ NAPI_METHOD(batch_iterate) {
|
|
|
1918
1525
|
rocksdb::WriteBatch* batch;
|
|
1919
1526
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
|
|
1920
1527
|
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
NAPI_STATUS_THROWS(
|
|
1528
|
+
const auto options = argv[2];
|
|
1529
|
+
|
|
1530
|
+
bool keys = true;
|
|
1531
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keys", keys));
|
|
1532
|
+
|
|
1533
|
+
bool values = true;
|
|
1534
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "values", values));
|
|
1925
1535
|
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "values", &valuesProperty));
|
|
1929
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, valuesProperty, &values));
|
|
1536
|
+
bool data = true;
|
|
1537
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "data", data));
|
|
1930
1538
|
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "data", &dataProperty));
|
|
1934
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, dataProperty, &data));
|
|
1539
|
+
Encoding keyEncoding = Encoding::String;
|
|
1540
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keyEncoding", keyEncoding));
|
|
1935
1541
|
|
|
1936
|
-
|
|
1937
|
-
|
|
1542
|
+
Encoding valueEncoding = Encoding::String;
|
|
1543
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1938
1544
|
|
|
1939
1545
|
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1940
|
-
NAPI_STATUS_THROWS(
|
|
1546
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1941
1547
|
|
|
1942
|
-
|
|
1943
|
-
BatchIterator iterator(nullptr, keys, values, data, column, keyAsBuffer, valueAsBuffer);
|
|
1548
|
+
BatchIterator iterator(nullptr, keys, values, data, column, keyEncoding, valueEncoding);
|
|
1944
1549
|
|
|
1550
|
+
napi_value result;
|
|
1945
1551
|
NAPI_STATUS_THROWS(iterator.Iterate(env, *batch, &result));
|
|
1946
1552
|
|
|
1947
1553
|
return result;
|
|
1948
1554
|
}
|
|
1949
1555
|
|
|
1950
|
-
NAPI_METHOD(db_flush_wal) {
|
|
1951
|
-
NAPI_ARGV(2);
|
|
1952
|
-
|
|
1953
|
-
Database* database;
|
|
1954
|
-
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1955
|
-
|
|
1956
|
-
const auto flush = BooleanProperty(env, argv[1], "flush").value_or(false);
|
|
1957
|
-
|
|
1958
|
-
ROCKS_STATUS_THROWS(database->db_->FlushWAL(flush));
|
|
1959
|
-
|
|
1960
|
-
return 0;
|
|
1961
|
-
}
|
|
1962
|
-
|
|
1963
|
-
template <typename T>
|
|
1964
|
-
napi_status FromLogFile(napi_env env, const T& file, napi_value* obj) {
|
|
1965
|
-
NAPI_STATUS_RETURN(napi_create_object(env, obj));
|
|
1966
|
-
|
|
1967
|
-
napi_value pathName;
|
|
1968
|
-
NAPI_STATUS_RETURN(napi_create_string_utf8(env, file->PathName().c_str(), NAPI_AUTO_LENGTH, &pathName));
|
|
1969
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "pathName", pathName));
|
|
1970
|
-
|
|
1971
|
-
napi_value logNumber;
|
|
1972
|
-
NAPI_STATUS_RETURN(napi_create_int64(env, file->LogNumber(), &logNumber));
|
|
1973
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "logNumber", logNumber));
|
|
1974
|
-
|
|
1975
|
-
napi_value type;
|
|
1976
|
-
NAPI_STATUS_RETURN(napi_create_int64(env, file->Type(), &type));
|
|
1977
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "type", type));
|
|
1978
|
-
|
|
1979
|
-
napi_value startSequence;
|
|
1980
|
-
NAPI_STATUS_RETURN(napi_create_int64(env, file->StartSequence(), &startSequence));
|
|
1981
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "startSequence", startSequence));
|
|
1982
|
-
|
|
1983
|
-
napi_value sizeFileBytes;
|
|
1984
|
-
NAPI_STATUS_RETURN(napi_create_int64(env, file->SizeFileBytes(), &sizeFileBytes));
|
|
1985
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "sizeFileBytes", sizeFileBytes));
|
|
1986
|
-
|
|
1987
|
-
return napi_ok;
|
|
1988
|
-
}
|
|
1989
|
-
|
|
1990
|
-
NAPI_METHOD(db_get_sorted_wal_files) {
|
|
1991
|
-
NAPI_ARGV(1);
|
|
1992
|
-
|
|
1993
|
-
Database* database;
|
|
1994
|
-
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1995
|
-
|
|
1996
|
-
rocksdb::VectorLogPtr files;
|
|
1997
|
-
ROCKS_STATUS_THROWS(database->db_->GetSortedWalFiles(files));
|
|
1998
|
-
|
|
1999
|
-
napi_value ret;
|
|
2000
|
-
NAPI_STATUS_THROWS(napi_create_array_with_length(env, files.size(), &ret));
|
|
2001
|
-
|
|
2002
|
-
for (size_t n = 0; n < files.size(); ++n) {
|
|
2003
|
-
napi_value obj;
|
|
2004
|
-
NAPI_STATUS_THROWS(FromLogFile(env, files[n], &obj));
|
|
2005
|
-
NAPI_STATUS_THROWS(napi_set_element(env, ret, n, obj));
|
|
2006
|
-
}
|
|
2007
|
-
|
|
2008
|
-
return ret;
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
NAPI_METHOD(db_get_current_wal_file) {
|
|
2012
|
-
NAPI_ARGV(1);
|
|
2013
|
-
|
|
2014
|
-
Database* database;
|
|
2015
|
-
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
2016
|
-
|
|
2017
|
-
std::unique_ptr<rocksdb::LogFile> file;
|
|
2018
|
-
ROCKS_STATUS_THROWS(database->db_->GetCurrentWalFile(&file));
|
|
2019
|
-
|
|
2020
|
-
napi_value ret;
|
|
2021
|
-
NAPI_STATUS_THROWS(FromLogFile(env, file, &ret));
|
|
2022
|
-
|
|
2023
|
-
return ret;
|
|
2024
|
-
}
|
|
2025
|
-
|
|
2026
1556
|
NAPI_INIT() {
|
|
2027
1557
|
NAPI_EXPORT_FUNCTION(db_init);
|
|
2028
1558
|
NAPI_EXPORT_FUNCTION(db_open);
|
|
@@ -2042,10 +1572,6 @@ NAPI_INIT() {
|
|
|
2042
1572
|
NAPI_EXPORT_FUNCTION(updates_close);
|
|
2043
1573
|
NAPI_EXPORT_FUNCTION(updates_next);
|
|
2044
1574
|
|
|
2045
|
-
NAPI_EXPORT_FUNCTION(db_flush_wal);
|
|
2046
|
-
NAPI_EXPORT_FUNCTION(db_get_sorted_wal_files);
|
|
2047
|
-
NAPI_EXPORT_FUNCTION(db_get_current_wal_file);
|
|
2048
|
-
|
|
2049
1575
|
NAPI_EXPORT_FUNCTION(batch_do);
|
|
2050
1576
|
NAPI_EXPORT_FUNCTION(batch_init);
|
|
2051
1577
|
NAPI_EXPORT_FUNCTION(batch_put);
|