@nxtedition/rocksdb 7.0.63 → 7.0.67
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 +435 -908
- package/binding.gyp +50 -79
- package/deps/rocksdb/rocksdb/db/wal_manager.cc +4 -0
- package/index.js +47 -131
- package/max_rev_operator.h +3 -0
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.node +0 -0
- package/util.h +339 -0
package/binding.cc
CHANGED
|
@@ -12,11 +12,13 @@
|
|
|
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 <
|
|
21
|
+
#include <iostream>
|
|
20
22
|
#include <memory>
|
|
21
23
|
#include <optional>
|
|
22
24
|
#include <set>
|
|
@@ -25,6 +27,7 @@
|
|
|
25
27
|
#include <vector>
|
|
26
28
|
|
|
27
29
|
#include "max_rev_operator.h"
|
|
30
|
+
#include "util.h"
|
|
28
31
|
|
|
29
32
|
class NullLogger : public rocksdb::Logger {
|
|
30
33
|
public:
|
|
@@ -37,298 +40,6 @@ struct Database;
|
|
|
37
40
|
struct Iterator;
|
|
38
41
|
struct Updates;
|
|
39
42
|
|
|
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
43
|
struct ColumnFamily {
|
|
333
44
|
napi_ref ref;
|
|
334
45
|
napi_value val;
|
|
@@ -336,80 +47,69 @@ struct ColumnFamily {
|
|
|
336
47
|
rocksdb::ColumnFamilyDescriptor descriptor;
|
|
337
48
|
};
|
|
338
49
|
|
|
339
|
-
struct
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
void DetachIterator(napi_env env, Iterator* iterator) {
|
|
346
|
-
iterators_.erase(iterator);
|
|
347
|
-
DecrementPriorityWork(env);
|
|
348
|
-
}
|
|
50
|
+
struct Closable {
|
|
51
|
+
virtual ~Closable() {}
|
|
52
|
+
virtual rocksdb::Status Close() = 0;
|
|
53
|
+
};
|
|
349
54
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
IncrementPriorityWork(env);
|
|
353
|
-
}
|
|
55
|
+
struct Database final {
|
|
56
|
+
~Database() { assert(!db); }
|
|
354
57
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
void IncrementPriorityWork(napi_env env) { napi_reference_ref(env, priorityRef_, &priorityWork_); }
|
|
58
|
+
rocksdb::Status Close() {
|
|
59
|
+
if (!db) {
|
|
60
|
+
return rocksdb::Status::OK();
|
|
61
|
+
}
|
|
361
62
|
|
|
362
|
-
|
|
363
|
-
|
|
63
|
+
for (auto closable : closables) {
|
|
64
|
+
closable->Close();
|
|
65
|
+
}
|
|
66
|
+
closables.clear();
|
|
364
67
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
pendingCloseWorker_ = nullptr;
|
|
68
|
+
for (auto& [id, column] : columns) {
|
|
69
|
+
db->DestroyColumnFamilyHandle(column.handle);
|
|
368
70
|
}
|
|
369
|
-
|
|
71
|
+
columns.clear();
|
|
370
72
|
|
|
371
|
-
|
|
73
|
+
db->FlushWAL(true);
|
|
372
74
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
std::set<Updates*> updates_;
|
|
377
|
-
std::map<int32_t, ColumnFamily> columns_;
|
|
378
|
-
napi_ref priorityRef_;
|
|
75
|
+
auto db2 = std::move(db);
|
|
76
|
+
return db2->Close();
|
|
77
|
+
}
|
|
379
78
|
|
|
380
|
-
|
|
381
|
-
|
|
79
|
+
std::unique_ptr<rocksdb::DB> db;
|
|
80
|
+
std::set<Closable*> closables;
|
|
81
|
+
std::map<int32_t, ColumnFamily> columns;
|
|
382
82
|
};
|
|
383
83
|
|
|
384
84
|
enum BatchOp { Empty, Put, Delete, Merge, Data };
|
|
385
85
|
|
|
386
86
|
struct BatchEntry {
|
|
387
87
|
BatchOp op = BatchOp::Empty;
|
|
388
|
-
std::optional<std::string> key;
|
|
389
|
-
std::optional<std::string> val;
|
|
390
|
-
std::optional<ColumnFamily> column;
|
|
88
|
+
std::optional<std::string> key = std::nullopt;
|
|
89
|
+
std::optional<std::string> val = std::nullopt;
|
|
90
|
+
std::optional<ColumnFamily> column = std::nullopt;
|
|
391
91
|
};
|
|
392
92
|
|
|
393
93
|
struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
394
94
|
BatchIterator(Database* database,
|
|
395
|
-
bool keys
|
|
396
|
-
bool values
|
|
397
|
-
bool data
|
|
398
|
-
const rocksdb::ColumnFamilyHandle* column
|
|
399
|
-
|
|
400
|
-
|
|
95
|
+
const bool keys,
|
|
96
|
+
const bool values,
|
|
97
|
+
const bool data,
|
|
98
|
+
const rocksdb::ColumnFamilyHandle* column,
|
|
99
|
+
const Encoding keyEncoding,
|
|
100
|
+
const Encoding valueEncoding)
|
|
401
101
|
: database_(database),
|
|
402
102
|
keys_(keys),
|
|
403
103
|
values_(values),
|
|
404
104
|
data_(data),
|
|
405
105
|
column_(column),
|
|
406
|
-
|
|
407
|
-
|
|
106
|
+
keyEncoding_(keyEncoding),
|
|
107
|
+
valueEncoding_(valueEncoding) {}
|
|
408
108
|
|
|
409
109
|
napi_status Iterate(napi_env env, const rocksdb::WriteBatch& batch, napi_value* result) {
|
|
410
110
|
cache_.reserve(batch.Count());
|
|
411
111
|
|
|
412
|
-
batch.Iterate(this);
|
|
112
|
+
ROCKS_STATUS_RETURN_NAPI(batch.Iterate(this));
|
|
413
113
|
|
|
414
114
|
napi_value putStr;
|
|
415
115
|
NAPI_STATUS_RETURN(napi_create_string_utf8(env, "put", NAPI_AUTO_LENGTH, &putStr));
|
|
@@ -444,11 +144,11 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
444
144
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 0, op));
|
|
445
145
|
|
|
446
146
|
napi_value key;
|
|
447
|
-
NAPI_STATUS_RETURN(Convert(env, cache_[n].key,
|
|
147
|
+
NAPI_STATUS_RETURN(Convert(env, cache_[n].key, keyEncoding_, key));
|
|
448
148
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 1, key));
|
|
449
149
|
|
|
450
150
|
napi_value val;
|
|
451
|
-
NAPI_STATUS_RETURN(Convert(env, cache_[n].val,
|
|
151
|
+
NAPI_STATUS_RETURN(Convert(env, cache_[n].val, valueEncoding_, val));
|
|
452
152
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 2, val));
|
|
453
153
|
|
|
454
154
|
// TODO (fix)
|
|
@@ -466,9 +166,7 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
466
166
|
return rocksdb::Status::OK();
|
|
467
167
|
}
|
|
468
168
|
|
|
469
|
-
BatchEntry entry;
|
|
470
|
-
|
|
471
|
-
entry.op = BatchOp::Put;
|
|
169
|
+
BatchEntry entry = {BatchOp::Put};
|
|
472
170
|
|
|
473
171
|
if (keys_) {
|
|
474
172
|
entry.key = key.ToStringView();
|
|
@@ -478,8 +176,8 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
478
176
|
entry.val = value.ToStringView();
|
|
479
177
|
}
|
|
480
178
|
|
|
481
|
-
// if (database_ && database_->
|
|
482
|
-
// entry.column = database_->
|
|
179
|
+
// if (database_ && database_->columns.find(column_family_id) != database_->columns.end()) {
|
|
180
|
+
// entry.column = database_->columns[column_family_id];
|
|
483
181
|
// }
|
|
484
182
|
|
|
485
183
|
cache_.push_back(entry);
|
|
@@ -492,16 +190,14 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
492
190
|
return rocksdb::Status::OK();
|
|
493
191
|
}
|
|
494
192
|
|
|
495
|
-
BatchEntry entry;
|
|
496
|
-
|
|
497
|
-
entry.op = BatchOp::Delete;
|
|
193
|
+
BatchEntry entry = {BatchOp::Delete};
|
|
498
194
|
|
|
499
195
|
if (keys_) {
|
|
500
196
|
entry.key = key.ToStringView();
|
|
501
197
|
}
|
|
502
198
|
|
|
503
|
-
// if (database_ && database_->
|
|
504
|
-
// entry.column = database_->
|
|
199
|
+
// if (database_ && database_->columns.find(column_family_id) != database_->columns.end()) {
|
|
200
|
+
// entry.column = database_->columns[column_family_id];
|
|
505
201
|
// }
|
|
506
202
|
|
|
507
203
|
cache_.push_back(entry);
|
|
@@ -514,9 +210,7 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
514
210
|
return rocksdb::Status::OK();
|
|
515
211
|
}
|
|
516
212
|
|
|
517
|
-
BatchEntry entry;
|
|
518
|
-
|
|
519
|
-
entry.op = BatchOp::Merge;
|
|
213
|
+
BatchEntry entry = {BatchOp::Merge};
|
|
520
214
|
|
|
521
215
|
if (keys_) {
|
|
522
216
|
entry.key = key.ToStringView();
|
|
@@ -526,8 +220,8 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
526
220
|
entry.val = value.ToStringView();
|
|
527
221
|
}
|
|
528
222
|
|
|
529
|
-
// if (database_ && database_->
|
|
530
|
-
// entry.column = database_->
|
|
223
|
+
// if (database_ && database_->columns.find(column_family_id) != database_->columns.end()) {
|
|
224
|
+
// entry.column = database_->columns[column_family_id];
|
|
531
225
|
// }
|
|
532
226
|
|
|
533
227
|
cache_.push_back(entry);
|
|
@@ -540,9 +234,7 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
540
234
|
return;
|
|
541
235
|
}
|
|
542
236
|
|
|
543
|
-
BatchEntry entry;
|
|
544
|
-
|
|
545
|
-
entry.op = BatchOp::Data;
|
|
237
|
+
BatchEntry entry = {BatchOp::Data};
|
|
546
238
|
|
|
547
239
|
entry.val = data.ToStringView();
|
|
548
240
|
|
|
@@ -553,40 +245,47 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
553
245
|
|
|
554
246
|
private:
|
|
555
247
|
Database* database_;
|
|
556
|
-
bool keys_;
|
|
557
|
-
bool values_;
|
|
558
|
-
bool data_;
|
|
248
|
+
const bool keys_;
|
|
249
|
+
const bool values_;
|
|
250
|
+
const bool data_;
|
|
559
251
|
const rocksdb::ColumnFamilyHandle* column_;
|
|
560
|
-
|
|
561
|
-
|
|
252
|
+
const Encoding keyEncoding_;
|
|
253
|
+
const Encoding valueEncoding_;
|
|
562
254
|
std::vector<BatchEntry> cache_;
|
|
563
255
|
};
|
|
564
256
|
|
|
565
|
-
struct Updates : public BatchIterator {
|
|
257
|
+
struct Updates : public BatchIterator, public Closable {
|
|
566
258
|
Updates(Database* database,
|
|
567
|
-
int64_t seqNumber,
|
|
568
|
-
bool keys,
|
|
569
|
-
bool values,
|
|
570
|
-
bool data,
|
|
259
|
+
const int64_t seqNumber,
|
|
260
|
+
const bool keys,
|
|
261
|
+
const bool values,
|
|
262
|
+
const bool data,
|
|
571
263
|
const rocksdb::ColumnFamilyHandle* column,
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
: BatchIterator(database, keys, values, data, column,
|
|
264
|
+
const Encoding keyEncoding,
|
|
265
|
+
const Encoding valueEncoding)
|
|
266
|
+
: BatchIterator(database, keys, values, data, column, keyEncoding, valueEncoding),
|
|
575
267
|
database_(database),
|
|
576
268
|
start_(seqNumber) {}
|
|
577
269
|
|
|
578
|
-
|
|
270
|
+
virtual ~Updates() { assert(!iterator_); }
|
|
579
271
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
272
|
+
rocksdb::Status Close() override {
|
|
273
|
+
iterator_.reset();
|
|
274
|
+
return rocksdb::Status::OK();
|
|
583
275
|
}
|
|
584
276
|
|
|
585
|
-
|
|
586
|
-
|
|
277
|
+
napi_status Attach(napi_env env, napi_value context) {
|
|
278
|
+
NAPI_STATUS_RETURN(napi_create_reference(env, context, 1, &ref_));
|
|
279
|
+
database_->closables.insert(this);
|
|
280
|
+
return napi_ok;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
napi_status Detach(napi_env env) {
|
|
284
|
+
database_->closables.erase(this);
|
|
587
285
|
if (ref_) {
|
|
588
|
-
napi_delete_reference(env, ref_);
|
|
286
|
+
NAPI_STATUS_RETURN(napi_delete_reference(env, ref_));
|
|
589
287
|
}
|
|
288
|
+
return napi_ok;
|
|
590
289
|
}
|
|
591
290
|
|
|
592
291
|
Database* database_;
|
|
@@ -597,7 +296,7 @@ struct Updates : public BatchIterator {
|
|
|
597
296
|
napi_ref ref_ = nullptr;
|
|
598
297
|
};
|
|
599
298
|
|
|
600
|
-
struct BaseIterator {
|
|
299
|
+
struct BaseIterator : public Closable {
|
|
601
300
|
BaseIterator(Database* database,
|
|
602
301
|
rocksdb::ColumnFamilyHandle* column,
|
|
603
302
|
const bool reverse,
|
|
@@ -670,9 +369,10 @@ struct BaseIterator {
|
|
|
670
369
|
}
|
|
671
370
|
}
|
|
672
371
|
|
|
673
|
-
|
|
372
|
+
rocksdb::Status Close() override {
|
|
674
373
|
snapshot_.reset();
|
|
675
374
|
iterator_.reset();
|
|
375
|
+
return rocksdb::Status::OK();
|
|
676
376
|
}
|
|
677
377
|
|
|
678
378
|
bool Valid() const {
|
|
@@ -727,7 +427,7 @@ struct BaseIterator {
|
|
|
727
427
|
readOptions.async_io = true;
|
|
728
428
|
readOptions.adaptive_readahead = true;
|
|
729
429
|
|
|
730
|
-
iterator_.reset(database_->
|
|
430
|
+
iterator_.reset(database_->db->NewIterator(readOptions, column_));
|
|
731
431
|
}
|
|
732
432
|
|
|
733
433
|
int count_ = 0;
|
|
@@ -751,33 +451,35 @@ struct Iterator final : public BaseIterator {
|
|
|
751
451
|
const std::optional<std::string>& gt,
|
|
752
452
|
const std::optional<std::string>& gte,
|
|
753
453
|
const bool fillCache,
|
|
754
|
-
const
|
|
755
|
-
const
|
|
454
|
+
const Encoding keyEncoding,
|
|
455
|
+
const Encoding valueEncoding,
|
|
756
456
|
const size_t highWaterMarkBytes,
|
|
757
457
|
std::shared_ptr<const rocksdb::Snapshot> snapshot)
|
|
758
458
|
: BaseIterator(database, column, reverse, lt, lte, gt, gte, limit, fillCache, snapshot),
|
|
759
459
|
keys_(keys),
|
|
760
460
|
values_(values),
|
|
761
|
-
|
|
762
|
-
|
|
461
|
+
keyEncoding_(keyEncoding),
|
|
462
|
+
valueEncoding_(valueEncoding),
|
|
763
463
|
highWaterMarkBytes_(highWaterMarkBytes) {}
|
|
764
464
|
|
|
765
|
-
|
|
766
|
-
napi_create_reference(env, context, 1, &ref_);
|
|
767
|
-
database_->
|
|
465
|
+
napi_status Attach(napi_env env, napi_value context) {
|
|
466
|
+
NAPI_STATUS_RETURN(napi_create_reference(env, context, 1, &ref_));
|
|
467
|
+
database_->closables.insert(this);
|
|
468
|
+
return napi_ok;
|
|
768
469
|
}
|
|
769
470
|
|
|
770
|
-
|
|
771
|
-
database_->
|
|
471
|
+
napi_status Detach(napi_env env) {
|
|
472
|
+
database_->closables.erase(this);
|
|
772
473
|
if (ref_) {
|
|
773
|
-
napi_delete_reference(env, ref_);
|
|
474
|
+
NAPI_STATUS_RETURN(napi_delete_reference(env, ref_));
|
|
774
475
|
}
|
|
476
|
+
return napi_ok;
|
|
775
477
|
}
|
|
776
478
|
|
|
777
479
|
const bool keys_;
|
|
778
480
|
const bool values_;
|
|
779
|
-
const
|
|
780
|
-
const
|
|
481
|
+
const Encoding keyEncoding_;
|
|
482
|
+
const Encoding valueEncoding_;
|
|
781
483
|
const size_t highWaterMarkBytes_;
|
|
782
484
|
bool first_ = true;
|
|
783
485
|
|
|
@@ -785,152 +487,20 @@ struct Iterator final : public BaseIterator {
|
|
|
785
487
|
napi_ref ref_ = nullptr;
|
|
786
488
|
};
|
|
787
489
|
|
|
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
490
|
static void env_cleanup_hook(void* arg) {
|
|
897
491
|
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();
|
|
492
|
+
if (database) {
|
|
493
|
+
database->Close();
|
|
923
494
|
}
|
|
924
495
|
}
|
|
925
496
|
|
|
926
497
|
static void FinalizeDatabase(napi_env env, void* data, void* hint) {
|
|
927
498
|
if (data) {
|
|
928
499
|
auto database = reinterpret_cast<Database*>(data);
|
|
500
|
+
database->Close();
|
|
929
501
|
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);
|
|
502
|
+
for (auto& [id, column] : database->columns) {
|
|
503
|
+
napi_delete_reference(env, column.ref);
|
|
934
504
|
}
|
|
935
505
|
delete database;
|
|
936
506
|
}
|
|
@@ -943,94 +513,113 @@ NAPI_METHOD(db_init) {
|
|
|
943
513
|
napi_value result;
|
|
944
514
|
NAPI_STATUS_THROWS(napi_create_external(env, database, FinalizeDatabase, nullptr, &result));
|
|
945
515
|
|
|
946
|
-
NAPI_STATUS_THROWS(napi_create_reference(env, result, 0, &database->priorityRef_));
|
|
947
|
-
|
|
948
516
|
return result;
|
|
949
517
|
}
|
|
950
518
|
|
|
951
519
|
template <typename T, typename U>
|
|
952
|
-
|
|
520
|
+
napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
|
|
953
521
|
rocksdb::ConfigOptions configOptions;
|
|
954
522
|
|
|
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
|
-
|
|
523
|
+
uint64_t memtable_memory_budget = 256 * 1024 * 1024;
|
|
524
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "memtableMemoryBudget", memtable_memory_budget));
|
|
525
|
+
|
|
526
|
+
std::optional<std::string> compactionOpt;
|
|
527
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "compaction", compactionOpt));
|
|
528
|
+
if (compactionOpt) {
|
|
529
|
+
if (*compactionOpt == "universal") {
|
|
530
|
+
columnOptions.write_buffer_size = memtable_memory_budget / 4;
|
|
531
|
+
// merge two memtables when flushing to L0
|
|
532
|
+
columnOptions.min_write_buffer_number_to_merge = 2;
|
|
533
|
+
// this means we'll use 50% extra memory in the worst case, but will reduce
|
|
534
|
+
// write stalls.
|
|
535
|
+
columnOptions.max_write_buffer_number = 6;
|
|
536
|
+
// universal style compaction
|
|
537
|
+
columnOptions.compaction_style = rocksdb::kCompactionStyleUniversal;
|
|
538
|
+
columnOptions.compaction_options_universal.compression_size_percent = 80;
|
|
539
|
+
} else if (*compactionOpt == "level") {
|
|
540
|
+
// merge two memtables when flushing to L0
|
|
541
|
+
columnOptions.min_write_buffer_number_to_merge = 2;
|
|
542
|
+
// this means we'll use 50% extra memory in the worst case, but will reduce
|
|
543
|
+
// write stalls.
|
|
544
|
+
columnOptions.max_write_buffer_number = 6;
|
|
545
|
+
// start flushing L0->L1 as soon as possible. each file on level0 is
|
|
546
|
+
// (memtable_memory_budget / 2). This will flush level 0 when it's bigger than
|
|
547
|
+
// memtable_memory_budget.
|
|
548
|
+
columnOptions.level0_file_num_compaction_trigger = 2;
|
|
549
|
+
// doesn't really matter much, but we don't want to create too many files
|
|
550
|
+
columnOptions.target_file_size_base = memtable_memory_budget / 8;
|
|
551
|
+
// make Level1 size equal to Level0 size, so that L0->L1 compactions are fast
|
|
552
|
+
columnOptions.max_bytes_for_level_base = memtable_memory_budget;
|
|
553
|
+
|
|
554
|
+
// level style compaction
|
|
555
|
+
columnOptions.compaction_style = rocksdb::kCompactionStyleLevel;
|
|
556
|
+
|
|
557
|
+
// only compress levels >= 2
|
|
558
|
+
columnOptions.compression_per_level.resize(columnOptions.num_levels);
|
|
559
|
+
for (int i = 0; i < columnOptions.num_levels; ++i) {
|
|
560
|
+
if (i < 2) {
|
|
561
|
+
columnOptions.compression_per_level[i] = rocksdb::kNoCompression;
|
|
562
|
+
} else {
|
|
563
|
+
columnOptions.compression_per_level[i] = rocksdb::kZSTD;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
} else {
|
|
567
|
+
return napi_invalid_arg;
|
|
568
|
+
}
|
|
988
569
|
}
|
|
989
570
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
571
|
+
bool compression = true;
|
|
572
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "compression", compression));
|
|
573
|
+
|
|
574
|
+
if (compression) {
|
|
575
|
+
columnOptions.compression = rocksdb::kZSTD;
|
|
993
576
|
columnOptions.compression_opts.max_dict_bytes = 16 * 1024;
|
|
994
577
|
columnOptions.compression_opts.zstd_max_train_bytes = 16 * 1024 * 100;
|
|
995
578
|
// TODO (perf): compression_opts.parallel_threads
|
|
996
579
|
}
|
|
997
580
|
|
|
998
|
-
|
|
581
|
+
std::optional<std::string> prefixExtractorOpt;
|
|
582
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "prefixExtractor", prefixExtractorOpt));
|
|
999
583
|
if (prefixExtractorOpt) {
|
|
1000
|
-
|
|
584
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
1001
585
|
rocksdb::SliceTransform::CreateFromString(configOptions, *prefixExtractorOpt, &columnOptions.prefix_extractor));
|
|
1002
586
|
}
|
|
1003
587
|
|
|
1004
|
-
|
|
588
|
+
std::optional<std::string> comparatorOpt;
|
|
589
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "comparator", comparatorOpt));
|
|
1005
590
|
if (comparatorOpt) {
|
|
1006
|
-
|
|
591
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
1007
592
|
rocksdb::Comparator::CreateFromString(configOptions, *comparatorOpt, &columnOptions.comparator));
|
|
1008
593
|
}
|
|
1009
594
|
|
|
1010
|
-
|
|
595
|
+
std::optional<std::string> mergeOperatorOpt;
|
|
596
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "mergeOperator", mergeOperatorOpt));
|
|
1011
597
|
if (mergeOperatorOpt) {
|
|
1012
598
|
if (*mergeOperatorOpt == "maxRev") {
|
|
1013
599
|
columnOptions.merge_operator = std::make_shared<MaxRevOperator>();
|
|
1014
600
|
} else {
|
|
1015
|
-
|
|
601
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
1016
602
|
rocksdb::MergeOperator::CreateFromString(configOptions, *mergeOperatorOpt, &columnOptions.merge_operator));
|
|
1017
603
|
}
|
|
1018
604
|
}
|
|
1019
605
|
|
|
1020
|
-
|
|
606
|
+
uint32_t cacheSize = 8 << 20;
|
|
607
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "cacheSize", cacheSize));
|
|
1021
608
|
|
|
1022
609
|
rocksdb::BlockBasedTableOptions tableOptions;
|
|
1023
610
|
|
|
1024
611
|
if (cacheSize) {
|
|
1025
612
|
tableOptions.block_cache = rocksdb::NewLRUCache(cacheSize);
|
|
1026
|
-
tableOptions.cache_index_and_filter_blocks =
|
|
1027
|
-
|
|
613
|
+
tableOptions.cache_index_and_filter_blocks = true;
|
|
614
|
+
NAPI_STATUS_RETURN(
|
|
615
|
+
GetProperty(env, options, "cacheIndexAndFilterBlocks", tableOptions.cache_index_and_filter_blocks));
|
|
1028
616
|
} else {
|
|
1029
617
|
tableOptions.no_block_cache = true;
|
|
1030
618
|
tableOptions.cache_index_and_filter_blocks = false;
|
|
1031
619
|
}
|
|
1032
620
|
|
|
1033
|
-
|
|
621
|
+
std::string optimize = "";
|
|
622
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "optimize", optimize));
|
|
1034
623
|
|
|
1035
624
|
if (optimize == "point-lookup") {
|
|
1036
625
|
tableOptions.data_block_index_type = rocksdb::BlockBasedTableOptions::kDataBlockBinaryAndHash;
|
|
@@ -1042,25 +631,29 @@ rocksdb::Status InitOptions(napi_env env, T& columnOptions, const U& options) {
|
|
|
1042
631
|
} else if (optimize == "range-lookup") {
|
|
1043
632
|
// TODO?
|
|
1044
633
|
} else {
|
|
1045
|
-
tableOptions.filter_policy.reset(rocksdb::
|
|
634
|
+
tableOptions.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10));
|
|
1046
635
|
}
|
|
1047
636
|
|
|
1048
|
-
|
|
637
|
+
std::optional<std::string> filterPolicyOpt;
|
|
638
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "filterPolicy", filterPolicyOpt));
|
|
1049
639
|
if (filterPolicyOpt) {
|
|
1050
|
-
|
|
1051
|
-
ROCKS_STATUS_RETURN(
|
|
640
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
1052
641
|
rocksdb::FilterPolicy::CreateFromString(configOptions, *filterPolicyOpt, &tableOptions.filter_policy));
|
|
1053
642
|
}
|
|
1054
643
|
|
|
1055
|
-
|
|
1056
|
-
|
|
644
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "blockSize", tableOptions.block_size));
|
|
645
|
+
|
|
646
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "blockRestartInterval", tableOptions.block_restart_interval));
|
|
647
|
+
|
|
1057
648
|
tableOptions.format_version = 5;
|
|
1058
649
|
tableOptions.checksum = rocksdb::kXXH3;
|
|
1059
|
-
|
|
650
|
+
|
|
651
|
+
tableOptions.optimize_filters_for_memory = true;
|
|
652
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "optimizeFiltersForMemory", tableOptions.optimize_filters_for_memory));
|
|
1060
653
|
|
|
1061
654
|
columnOptions.table_factory.reset(rocksdb::NewBlockBasedTableFactory(tableOptions));
|
|
1062
655
|
|
|
1063
|
-
return
|
|
656
|
+
return napi_ok;
|
|
1064
657
|
}
|
|
1065
658
|
|
|
1066
659
|
NAPI_METHOD(db_open) {
|
|
@@ -1070,32 +663,44 @@ NAPI_METHOD(db_open) {
|
|
|
1070
663
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1071
664
|
|
|
1072
665
|
std::string location;
|
|
1073
|
-
NAPI_STATUS_THROWS(
|
|
666
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], location));
|
|
1074
667
|
|
|
1075
668
|
rocksdb::Options dbOptions;
|
|
1076
669
|
|
|
1077
|
-
|
|
1078
|
-
|
|
670
|
+
const auto options = argv[2];
|
|
671
|
+
|
|
672
|
+
int parallelism = std::max<int>(1, std::thread::hardware_concurrency() / 2);
|
|
673
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "parallelism", parallelism));
|
|
674
|
+
dbOptions.IncreaseParallelism(parallelism);
|
|
675
|
+
|
|
676
|
+
uint32_t walTTL = 0;
|
|
677
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "walTTL", walTTL));
|
|
678
|
+
dbOptions.WAL_ttl_seconds = walTTL / 1e3;
|
|
679
|
+
|
|
680
|
+
uint32_t walSizeLimit = 0;
|
|
681
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "walSizeLimit", walSizeLimit));
|
|
682
|
+
dbOptions.WAL_size_limit_MB = walSizeLimit / 1e6;
|
|
683
|
+
|
|
684
|
+
bool walCompression = false;
|
|
685
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "walCompression", walCompression));
|
|
686
|
+
dbOptions.wal_compression =
|
|
687
|
+
walCompression ? rocksdb::CompressionType::kZSTD : rocksdb::CompressionType::kNoCompression;
|
|
1079
688
|
|
|
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
689
|
dbOptions.avoid_unnecessary_blocking_io = true;
|
|
1083
690
|
dbOptions.write_dbid_to_manifest = true;
|
|
1084
691
|
dbOptions.use_adaptive_mutex = true; // We don't have soo many threads in the libuv thread pool...
|
|
1085
692
|
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
693
|
dbOptions.create_missing_column_families = true;
|
|
1092
|
-
dbOptions.unordered_write = BooleanProperty(env, argv[2], "unorderedWrite").value_or(false);
|
|
1093
694
|
dbOptions.fail_if_options_file_error = true;
|
|
1094
|
-
|
|
695
|
+
|
|
696
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "createIfMissing", dbOptions.create_if_missing));
|
|
697
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "errorIfExists", dbOptions.error_if_exists));
|
|
698
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "unorderedWrite", dbOptions.unordered_write));
|
|
1095
699
|
|
|
1096
700
|
// TODO (feat): dbOptions.listeners
|
|
1097
701
|
|
|
1098
|
-
|
|
702
|
+
std::string infoLogLevel;
|
|
703
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "infoLogLevel", infoLogLevel));
|
|
1099
704
|
if (infoLogLevel.size() > 0) {
|
|
1100
705
|
rocksdb::InfoLogLevel lvl = {};
|
|
1101
706
|
|
|
@@ -1122,16 +727,16 @@ NAPI_METHOD(db_open) {
|
|
|
1122
727
|
dbOptions.info_log.reset(new NullLogger());
|
|
1123
728
|
}
|
|
1124
729
|
|
|
1125
|
-
|
|
730
|
+
NAPI_STATUS_THROWS(InitOptions(env, dbOptions, options));
|
|
1126
731
|
|
|
1127
732
|
std::vector<rocksdb::ColumnFamilyDescriptor> descriptors;
|
|
1128
733
|
|
|
1129
734
|
bool hasColumns;
|
|
1130
|
-
NAPI_STATUS_THROWS(napi_has_named_property(env,
|
|
735
|
+
NAPI_STATUS_THROWS(napi_has_named_property(env, options, "columns", &hasColumns));
|
|
1131
736
|
|
|
1132
737
|
if (hasColumns) {
|
|
1133
738
|
napi_value columns;
|
|
1134
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env,
|
|
739
|
+
NAPI_STATUS_THROWS(napi_get_named_property(env, options, "columns", &columns));
|
|
1135
740
|
|
|
1136
741
|
napi_value keys;
|
|
1137
742
|
NAPI_STATUS_THROWS(napi_get_property_names(env, columns, &keys));
|
|
@@ -1147,26 +752,25 @@ NAPI_METHOD(db_open) {
|
|
|
1147
752
|
napi_value column;
|
|
1148
753
|
NAPI_STATUS_THROWS(napi_get_property(env, columns, key, &column));
|
|
1149
754
|
|
|
1150
|
-
|
|
755
|
+
NAPI_STATUS_THROWS(InitOptions(env, descriptors[n].options, column));
|
|
1151
756
|
|
|
1152
|
-
NAPI_STATUS_THROWS(
|
|
757
|
+
NAPI_STATUS_THROWS(GetValue(env, key, descriptors[n].name));
|
|
1153
758
|
}
|
|
1154
759
|
}
|
|
1155
760
|
|
|
1156
761
|
auto callback = argv[3];
|
|
1157
762
|
|
|
1158
|
-
|
|
1159
|
-
"leveldown.open", env, callback,
|
|
1160
|
-
[=](auto& handles
|
|
763
|
+
runAsync<std::vector<rocksdb::ColumnFamilyHandle*>>(
|
|
764
|
+
"leveldown.open", env, callback,
|
|
765
|
+
[=](auto& handles) {
|
|
1161
766
|
rocksdb::DB* db = nullptr;
|
|
1162
767
|
const auto status = descriptors.empty() ? rocksdb::DB::Open(dbOptions, location, &db)
|
|
1163
768
|
: rocksdb::DB::Open(dbOptions, location, descriptors, &handles, &db);
|
|
1164
|
-
database.
|
|
769
|
+
database->db.reset(db);
|
|
1165
770
|
return status;
|
|
1166
771
|
},
|
|
1167
|
-
[=](auto& handles,
|
|
1168
|
-
|
|
1169
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
772
|
+
[=](auto& handles, auto env, auto& argv) {
|
|
773
|
+
argv.resize(2);
|
|
1170
774
|
|
|
1171
775
|
const auto size = handles.size();
|
|
1172
776
|
NAPI_STATUS_RETURN(napi_create_object(env, &argv[1]));
|
|
@@ -1177,13 +781,11 @@ NAPI_METHOD(db_open) {
|
|
|
1177
781
|
column.descriptor = descriptors[n];
|
|
1178
782
|
NAPI_STATUS_RETURN(napi_create_external(env, column.handle, nullptr, nullptr, &column.val));
|
|
1179
783
|
NAPI_STATUS_RETURN(napi_create_reference(env, column.val, 1, &column.ref));
|
|
1180
|
-
|
|
1181
784
|
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;
|
|
785
|
+
database->columns[column.handle->GetID()] = column;
|
|
1184
786
|
}
|
|
1185
787
|
|
|
1186
|
-
return
|
|
788
|
+
return napi_ok;
|
|
1187
789
|
});
|
|
1188
790
|
|
|
1189
791
|
return 0;
|
|
@@ -1202,28 +804,9 @@ NAPI_METHOD(db_close) {
|
|
|
1202
804
|
auto callback = argv[1];
|
|
1203
805
|
|
|
1204
806
|
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
|
-
}
|
|
807
|
+
runAsync<State>(
|
|
808
|
+
"leveldown.close", env, callback, [=](auto& state) { return database->Close(); },
|
|
809
|
+
[](auto& state, auto env, auto& argv) { return napi_ok; });
|
|
1227
810
|
|
|
1228
811
|
return 0;
|
|
1229
812
|
}
|
|
@@ -1234,40 +817,38 @@ NAPI_METHOD(updates_init) {
|
|
|
1234
817
|
Database* database;
|
|
1235
818
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1236
819
|
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
NAPI_STATUS_THROWS(
|
|
820
|
+
const auto options = argv[1];
|
|
821
|
+
|
|
822
|
+
int64_t since = 0;
|
|
823
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "since", since));
|
|
824
|
+
|
|
825
|
+
bool keys = true;
|
|
826
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keys", keys));
|
|
1241
827
|
|
|
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));
|
|
828
|
+
bool values = true;
|
|
829
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "values", values));
|
|
1246
830
|
|
|
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));
|
|
831
|
+
bool data = true;
|
|
832
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "data", data));
|
|
1251
833
|
|
|
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));
|
|
834
|
+
Encoding keyEncoding = Encoding::String;
|
|
835
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keyEncoding", keyEncoding));
|
|
1256
836
|
|
|
1257
|
-
|
|
1258
|
-
|
|
837
|
+
Encoding valueEncoding = Encoding::String;
|
|
838
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1259
839
|
|
|
1260
840
|
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1261
|
-
NAPI_STATUS_THROWS(
|
|
841
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1262
842
|
|
|
1263
|
-
auto updates =
|
|
843
|
+
auto updates =
|
|
844
|
+
std::unique_ptr<Updates>(new Updates(database, since, keys, values, data, column, keyEncoding, valueEncoding));
|
|
1264
845
|
|
|
1265
846
|
napi_value result;
|
|
1266
847
|
NAPI_STATUS_THROWS(napi_create_external(env, updates.get(), Finalize<Updates>, updates.get(), &result));
|
|
1267
848
|
|
|
1268
849
|
// Prevent GC of JS object before the iterator is closed (explicitly or on
|
|
1269
850
|
// db close) and keep track of non-closed iterators to end them on db close.
|
|
1270
|
-
updates.release()->Attach(env, result);
|
|
851
|
+
NAPI_STATUS_THROWS(updates.release()->Attach(env, result));
|
|
1271
852
|
|
|
1272
853
|
return result;
|
|
1273
854
|
}
|
|
@@ -1280,12 +861,12 @@ NAPI_METHOD(updates_next) {
|
|
|
1280
861
|
|
|
1281
862
|
auto callback = argv[1];
|
|
1282
863
|
|
|
1283
|
-
|
|
1284
|
-
"leveldown.updates.next", env, callback,
|
|
1285
|
-
[=](auto& batchResult
|
|
864
|
+
runAsync<rocksdb::BatchResult>(
|
|
865
|
+
"leveldown.updates.next", env, callback,
|
|
866
|
+
[=](auto& batchResult) {
|
|
1286
867
|
if (!updates->iterator_) {
|
|
1287
868
|
rocksdb::TransactionLogIterator::ReadOptions options;
|
|
1288
|
-
const auto status =
|
|
869
|
+
const auto status = updates->database_->db->GetUpdatesSince(updates->start_, &updates->iterator_, options);
|
|
1289
870
|
if (!status.ok()) {
|
|
1290
871
|
return status;
|
|
1291
872
|
}
|
|
@@ -1301,22 +882,18 @@ NAPI_METHOD(updates_next) {
|
|
|
1301
882
|
|
|
1302
883
|
return rocksdb::Status::OK();
|
|
1303
884
|
},
|
|
1304
|
-
[=](auto& batchResult,
|
|
1305
|
-
napi_value argv[5];
|
|
1306
|
-
|
|
1307
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
1308
|
-
|
|
885
|
+
[=](auto& batchResult, auto env, auto& argv) {
|
|
1309
886
|
if (!batchResult.writeBatchPtr) {
|
|
1310
|
-
return
|
|
887
|
+
return napi_ok;
|
|
1311
888
|
}
|
|
1312
889
|
|
|
890
|
+
argv.resize(5);
|
|
1313
891
|
NAPI_STATUS_RETURN(updates->Iterate(env, *batchResult.writeBatchPtr, &argv[1]));
|
|
1314
|
-
|
|
1315
892
|
NAPI_STATUS_RETURN(napi_create_int64(env, batchResult.sequence, &argv[2]));
|
|
1316
893
|
NAPI_STATUS_RETURN(napi_create_int64(env, batchResult.writeBatchPtr->Count(), &argv[3]));
|
|
1317
894
|
NAPI_STATUS_RETURN(napi_create_int64(env, updates->start_, &argv[4]));
|
|
1318
895
|
|
|
1319
|
-
return
|
|
896
|
+
return napi_ok;
|
|
1320
897
|
});
|
|
1321
898
|
|
|
1322
899
|
return 0;
|
|
@@ -1328,8 +905,8 @@ NAPI_METHOD(updates_close) {
|
|
|
1328
905
|
Updates* updates;
|
|
1329
906
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&updates)));
|
|
1330
907
|
|
|
1331
|
-
updates->
|
|
1332
|
-
updates->
|
|
908
|
+
ROCKS_STATUS_THROWS_NAPI(updates->Close());
|
|
909
|
+
NAPI_STATUS_THROWS(updates->Detach(env));
|
|
1333
910
|
|
|
1334
911
|
return 0;
|
|
1335
912
|
}
|
|
@@ -1349,44 +926,53 @@ NAPI_METHOD(db_get_many) {
|
|
|
1349
926
|
for (uint32_t n = 0; n < length; n++) {
|
|
1350
927
|
napi_value element;
|
|
1351
928
|
NAPI_STATUS_THROWS(napi_get_element(env, argv[1], n, &element));
|
|
1352
|
-
NAPI_STATUS_THROWS(
|
|
929
|
+
NAPI_STATUS_THROWS(GetValue(env, element, keys[n]));
|
|
1353
930
|
}
|
|
1354
931
|
}
|
|
1355
932
|
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
|
|
933
|
+
const auto options = argv[2];
|
|
934
|
+
|
|
935
|
+
Encoding valueEncoding = Encoding::String;
|
|
936
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1359
937
|
|
|
1360
|
-
|
|
1361
|
-
NAPI_STATUS_THROWS(
|
|
938
|
+
bool fillCache = true;
|
|
939
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "fillCache", fillCache));
|
|
940
|
+
|
|
941
|
+
bool ignoreRangeDeletions = false;
|
|
942
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "ignoreRangeDeletions", ignoreRangeDeletions));
|
|
943
|
+
|
|
944
|
+
rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
|
|
945
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1362
946
|
|
|
1363
947
|
auto callback = argv[3];
|
|
1364
948
|
|
|
1365
949
|
auto snapshot = std::shared_ptr<const rocksdb::Snapshot>(
|
|
1366
|
-
database->
|
|
950
|
+
database->db->GetSnapshot(), [database](auto ptr) { database->db->ReleaseSnapshot(ptr); });
|
|
1367
951
|
|
|
1368
|
-
|
|
1369
|
-
"leveldown.get.many", env, callback,
|
|
1370
|
-
[=, keys = std::move(keys)](auto& values
|
|
952
|
+
runAsync<std::vector<rocksdb::PinnableSlice>>(
|
|
953
|
+
"leveldown.get.many", env, callback,
|
|
954
|
+
[=, keys = std::move(keys), snapshot = std::move(snapshot)](auto& values) {
|
|
1371
955
|
rocksdb::ReadOptions readOptions;
|
|
1372
956
|
readOptions.fill_cache = fillCache;
|
|
1373
957
|
readOptions.snapshot = snapshot.get();
|
|
1374
958
|
readOptions.async_io = true;
|
|
1375
959
|
readOptions.ignore_range_deletions = ignoreRangeDeletions;
|
|
1376
960
|
|
|
961
|
+
const auto size = keys.size();
|
|
962
|
+
|
|
1377
963
|
std::vector<rocksdb::Slice> keys2;
|
|
1378
|
-
keys2.reserve(
|
|
964
|
+
keys2.reserve(size);
|
|
1379
965
|
for (const auto& key : keys) {
|
|
1380
966
|
keys2.emplace_back(key);
|
|
1381
967
|
}
|
|
1382
968
|
std::vector<rocksdb::Status> statuses;
|
|
1383
969
|
|
|
1384
|
-
statuses.resize(
|
|
1385
|
-
values.resize(
|
|
970
|
+
statuses.resize(size);
|
|
971
|
+
values.resize(size);
|
|
1386
972
|
|
|
1387
|
-
db
|
|
973
|
+
database->db->MultiGet(readOptions, column, size, keys2.data(), values.data(), statuses.data());
|
|
1388
974
|
|
|
1389
|
-
for (size_t idx = 0; idx <
|
|
975
|
+
for (size_t idx = 0; idx < size; idx++) {
|
|
1390
976
|
if (statuses[idx].IsNotFound()) {
|
|
1391
977
|
values[idx] = rocksdb::PinnableSlice(nullptr);
|
|
1392
978
|
} else if (!statuses[idx].ok()) {
|
|
@@ -1396,23 +982,22 @@ NAPI_METHOD(db_get_many) {
|
|
|
1396
982
|
|
|
1397
983
|
return rocksdb::Status::OK();
|
|
1398
984
|
},
|
|
1399
|
-
[=](auto& values,
|
|
1400
|
-
|
|
1401
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
985
|
+
[=](auto& values, auto env, auto& argv) {
|
|
986
|
+
argv.resize(2);
|
|
1402
987
|
|
|
1403
988
|
NAPI_STATUS_RETURN(napi_create_array_with_length(env, values.size(), &argv[1]));
|
|
1404
989
|
|
|
1405
990
|
for (size_t idx = 0; idx < values.size(); idx++) {
|
|
1406
991
|
napi_value element;
|
|
1407
992
|
if (values[idx].GetSelf()) {
|
|
1408
|
-
NAPI_STATUS_RETURN(Convert(env, &values[idx],
|
|
993
|
+
NAPI_STATUS_RETURN(Convert(env, &values[idx], valueEncoding, element));
|
|
1409
994
|
} else {
|
|
1410
995
|
NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
|
|
1411
996
|
}
|
|
1412
997
|
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<uint32_t>(idx), element));
|
|
1413
998
|
}
|
|
1414
999
|
|
|
1415
|
-
return
|
|
1000
|
+
return napi_ok;
|
|
1416
1001
|
});
|
|
1417
1002
|
|
|
1418
1003
|
return 0;
|
|
@@ -1424,16 +1009,28 @@ NAPI_METHOD(db_clear) {
|
|
|
1424
1009
|
Database* database;
|
|
1425
1010
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1426
1011
|
|
|
1427
|
-
const auto
|
|
1428
|
-
|
|
1012
|
+
const auto options = argv[1];
|
|
1013
|
+
|
|
1014
|
+
bool reverse = false;
|
|
1015
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "reverse", reverse));
|
|
1016
|
+
|
|
1017
|
+
int32_t limit = -1;
|
|
1018
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "limit", limit));
|
|
1019
|
+
|
|
1020
|
+
rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
|
|
1021
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1022
|
+
|
|
1023
|
+
std::optional<std::string> lt;
|
|
1024
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "lt", lt));
|
|
1429
1025
|
|
|
1430
|
-
|
|
1431
|
-
NAPI_STATUS_THROWS(
|
|
1026
|
+
std::optional<std::string> lte;
|
|
1027
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "lte", lte));
|
|
1432
1028
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1029
|
+
std::optional<std::string> gt;
|
|
1030
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gt", gt));
|
|
1031
|
+
|
|
1032
|
+
std::optional<std::string> gte;
|
|
1033
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gte", gte));
|
|
1437
1034
|
|
|
1438
1035
|
if (limit == -1) {
|
|
1439
1036
|
rocksdb::PinnableSlice begin;
|
|
@@ -1458,7 +1055,7 @@ NAPI_METHOD(db_clear) {
|
|
|
1458
1055
|
|
|
1459
1056
|
if (begin.compare(end) < 0) {
|
|
1460
1057
|
rocksdb::WriteOptions writeOptions;
|
|
1461
|
-
|
|
1058
|
+
ROCKS_STATUS_THROWS_NAPI(database->db->DeleteRange(writeOptions, column, begin, end));
|
|
1462
1059
|
}
|
|
1463
1060
|
|
|
1464
1061
|
return 0;
|
|
@@ -1466,8 +1063,8 @@ NAPI_METHOD(db_clear) {
|
|
|
1466
1063
|
// TODO (fix): Error handling.
|
|
1467
1064
|
// TODO (fix): This should be async...
|
|
1468
1065
|
|
|
1469
|
-
std::shared_ptr<const rocksdb::Snapshot> snapshot(database->
|
|
1470
|
-
[=](const auto ptr) { database->
|
|
1066
|
+
std::shared_ptr<const rocksdb::Snapshot> snapshot(database->db->GetSnapshot(),
|
|
1067
|
+
[=](const auto ptr) { database->db->ReleaseSnapshot(ptr); });
|
|
1471
1068
|
BaseIterator it(database, column, reverse, lt, lte, gt, gte, limit, false, snapshot);
|
|
1472
1069
|
|
|
1473
1070
|
it.SeekToRange();
|
|
@@ -1491,7 +1088,7 @@ NAPI_METHOD(db_clear) {
|
|
|
1491
1088
|
break;
|
|
1492
1089
|
}
|
|
1493
1090
|
|
|
1494
|
-
status = database->
|
|
1091
|
+
status = database->db->Write(writeOptions, &batch);
|
|
1495
1092
|
if (!status.ok()) {
|
|
1496
1093
|
break;
|
|
1497
1094
|
}
|
|
@@ -1502,7 +1099,7 @@ NAPI_METHOD(db_clear) {
|
|
|
1502
1099
|
it.Close();
|
|
1503
1100
|
|
|
1504
1101
|
if (!status.ok()) {
|
|
1505
|
-
|
|
1102
|
+
ROCKS_STATUS_THROWS_NAPI(status);
|
|
1506
1103
|
}
|
|
1507
1104
|
|
|
1508
1105
|
return 0;
|
|
@@ -1515,11 +1112,11 @@ NAPI_METHOD(db_get_property) {
|
|
|
1515
1112
|
Database* database;
|
|
1516
1113
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1517
1114
|
|
|
1518
|
-
|
|
1519
|
-
NAPI_STATUS_THROWS(
|
|
1115
|
+
NapiSlice property;
|
|
1116
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], property));
|
|
1520
1117
|
|
|
1521
1118
|
std::string value;
|
|
1522
|
-
database->
|
|
1119
|
+
database->db->GetProperty(property, &value);
|
|
1523
1120
|
|
|
1524
1121
|
napi_value result;
|
|
1525
1122
|
NAPI_STATUS_THROWS(napi_create_string_utf8(env, value.data(), value.size(), &result));
|
|
@@ -1533,7 +1130,7 @@ NAPI_METHOD(db_get_latest_sequence) {
|
|
|
1533
1130
|
Database* database;
|
|
1534
1131
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1535
1132
|
|
|
1536
|
-
const auto seq = database->
|
|
1133
|
+
const auto seq = database->db->GetLatestSequenceNumber();
|
|
1537
1134
|
|
|
1538
1135
|
napi_value result;
|
|
1539
1136
|
NAPI_STATUS_THROWS(napi_create_int64(env, seq, &result));
|
|
@@ -1548,35 +1145,59 @@ NAPI_METHOD(iterator_init) {
|
|
|
1548
1145
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1549
1146
|
|
|
1550
1147
|
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
1148
|
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1149
|
+
bool reverse = false;
|
|
1150
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "reverse", reverse));
|
|
1151
|
+
|
|
1152
|
+
bool keys = true;
|
|
1153
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keys", keys));
|
|
1154
|
+
|
|
1155
|
+
bool values = true;
|
|
1156
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "values", values));
|
|
1157
|
+
|
|
1158
|
+
bool fillCache = false;
|
|
1159
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "fillCache", fillCache));
|
|
1160
|
+
|
|
1161
|
+
Encoding keyEncoding = Encoding::String;
|
|
1162
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keyEncoding", keyEncoding));
|
|
1163
|
+
|
|
1164
|
+
Encoding valueEncoding = Encoding::String;
|
|
1165
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1166
|
+
|
|
1167
|
+
int32_t limit = -1;
|
|
1168
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "limit", limit));
|
|
1169
|
+
|
|
1170
|
+
int32_t highWaterMarkBytes = 64 * 1024;
|
|
1171
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "highWaterMarkBytes", highWaterMarkBytes));
|
|
1172
|
+
|
|
1173
|
+
std::optional<std::string> lt;
|
|
1174
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "lt", lt));
|
|
1564
1175
|
|
|
1565
|
-
|
|
1566
|
-
NAPI_STATUS_THROWS(
|
|
1176
|
+
std::optional<std::string> lte;
|
|
1177
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "lte", lte));
|
|
1567
1178
|
|
|
1568
|
-
std::
|
|
1569
|
-
|
|
1179
|
+
std::optional<std::string> gt;
|
|
1180
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gt", gt));
|
|
1570
1181
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1182
|
+
std::optional<std::string> gte;
|
|
1183
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gte", gte));
|
|
1184
|
+
|
|
1185
|
+
rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
|
|
1186
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1187
|
+
|
|
1188
|
+
std::shared_ptr<const rocksdb::Snapshot> snapshot(database->db->GetSnapshot(),
|
|
1189
|
+
[=](const auto ptr) { database->db->ReleaseSnapshot(ptr); });
|
|
1190
|
+
|
|
1191
|
+
auto iterator =
|
|
1192
|
+
std::unique_ptr<Iterator>(new Iterator(database, column, reverse, keys, values, limit, lt, lte, gt, gte,
|
|
1193
|
+
fillCache, keyEncoding, valueEncoding, highWaterMarkBytes, snapshot));
|
|
1573
1194
|
|
|
1574
1195
|
napi_value result;
|
|
1575
1196
|
NAPI_STATUS_THROWS(napi_create_external(env, iterator.get(), Finalize<Iterator>, iterator.get(), &result));
|
|
1576
1197
|
|
|
1577
1198
|
// Prevent GC of JS object before the iterator is closed (explicitly or on
|
|
1578
1199
|
// db close) and keep track of non-closed iterators to end them on db close.
|
|
1579
|
-
iterator.release()->Attach(env, result);
|
|
1200
|
+
NAPI_STATUS_THROWS(iterator.release()->Attach(env, result));
|
|
1580
1201
|
|
|
1581
1202
|
return result;
|
|
1582
1203
|
}
|
|
@@ -1587,8 +1208,8 @@ NAPI_METHOD(iterator_seek) {
|
|
|
1587
1208
|
Iterator* iterator;
|
|
1588
1209
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
|
|
1589
1210
|
|
|
1590
|
-
|
|
1591
|
-
NAPI_STATUS_THROWS(
|
|
1211
|
+
NapiSlice target;
|
|
1212
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], target));
|
|
1592
1213
|
|
|
1593
1214
|
iterator->first_ = true;
|
|
1594
1215
|
iterator->Seek(target); // TODO: Does seek causing blocking IO?
|
|
@@ -1602,8 +1223,8 @@ NAPI_METHOD(iterator_close) {
|
|
|
1602
1223
|
Iterator* iterator;
|
|
1603
1224
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
|
|
1604
1225
|
|
|
1605
|
-
iterator->
|
|
1606
|
-
iterator->
|
|
1226
|
+
ROCKS_STATUS_THROWS_NAPI(iterator->Close());
|
|
1227
|
+
NAPI_STATUS_THROWS(iterator->Detach(env));
|
|
1607
1228
|
|
|
1608
1229
|
return 0;
|
|
1609
1230
|
}
|
|
@@ -1638,9 +1259,9 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1638
1259
|
bool finished = false;
|
|
1639
1260
|
};
|
|
1640
1261
|
|
|
1641
|
-
|
|
1642
|
-
std::string("leveldown.iterator.next"), env, callback,
|
|
1643
|
-
[=](auto& state
|
|
1262
|
+
runAsync<State>(
|
|
1263
|
+
std::string("leveldown.iterator.next"), env, callback,
|
|
1264
|
+
[=](auto& state) {
|
|
1644
1265
|
if (!iterator->DidSeek()) {
|
|
1645
1266
|
iterator->SeekToRange();
|
|
1646
1267
|
}
|
|
@@ -1685,9 +1306,8 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1685
1306
|
|
|
1686
1307
|
return iterator->Status();
|
|
1687
1308
|
},
|
|
1688
|
-
[=](auto& state,
|
|
1689
|
-
|
|
1690
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
1309
|
+
[=](auto& state, auto env, auto& argv) {
|
|
1310
|
+
argv.resize(3);
|
|
1691
1311
|
|
|
1692
1312
|
NAPI_STATUS_RETURN(napi_create_array_with_length(env, state.cache.size(), &argv[1]));
|
|
1693
1313
|
|
|
@@ -1695,8 +1315,8 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1695
1315
|
napi_value key;
|
|
1696
1316
|
napi_value val;
|
|
1697
1317
|
|
|
1698
|
-
NAPI_STATUS_RETURN(Convert(env, state.cache[n + 0], iterator->
|
|
1699
|
-
NAPI_STATUS_RETURN(Convert(env, state.cache[n + 1], iterator->
|
|
1318
|
+
NAPI_STATUS_RETURN(Convert(env, state.cache[n + 0], iterator->keyEncoding_, key));
|
|
1319
|
+
NAPI_STATUS_RETURN(Convert(env, state.cache[n + 1], iterator->valueEncoding_, val));
|
|
1700
1320
|
|
|
1701
1321
|
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 0), key));
|
|
1702
1322
|
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 1), val));
|
|
@@ -1704,7 +1324,7 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1704
1324
|
|
|
1705
1325
|
NAPI_STATUS_RETURN(napi_get_boolean(env, state.finished, &argv[2]));
|
|
1706
1326
|
|
|
1707
|
-
return
|
|
1327
|
+
return napi_ok;
|
|
1708
1328
|
});
|
|
1709
1329
|
|
|
1710
1330
|
return 0;
|
|
@@ -1718,63 +1338,45 @@ NAPI_METHOD(batch_do) {
|
|
|
1718
1338
|
|
|
1719
1339
|
rocksdb::WriteBatch batch;
|
|
1720
1340
|
|
|
1341
|
+
auto elements = argv[1];
|
|
1342
|
+
|
|
1721
1343
|
uint32_t length;
|
|
1722
|
-
NAPI_STATUS_THROWS(napi_get_array_length(env,
|
|
1344
|
+
NAPI_STATUS_THROWS(napi_get_array_length(env, elements, &length));
|
|
1723
1345
|
|
|
1724
1346
|
for (uint32_t i = 0; i < length; i++) {
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1347
|
+
NapiSlice type;
|
|
1348
|
+
NapiSlice key;
|
|
1349
|
+
NapiSlice value;
|
|
1728
1350
|
|
|
1729
1351
|
napi_value element;
|
|
1730
|
-
NAPI_STATUS_THROWS(napi_get_element(env,
|
|
1352
|
+
NAPI_STATUS_THROWS(napi_get_element(env, elements, i, &element));
|
|
1731
1353
|
|
|
1732
|
-
|
|
1733
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, element, "type", &typeProperty));
|
|
1734
|
-
NAPI_STATUS_THROWS(ToString(env, typeProperty, type));
|
|
1354
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "type", type, true));
|
|
1735
1355
|
|
|
1736
|
-
rocksdb::ColumnFamilyHandle* column;
|
|
1737
|
-
NAPI_STATUS_THROWS(
|
|
1356
|
+
rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
|
|
1357
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "column", column));
|
|
1738
1358
|
|
|
1739
1359
|
if (type == "del") {
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
NAPI_STATUS_THROWS(ToString(env, keyProperty, key));
|
|
1743
|
-
|
|
1744
|
-
ROCKS_STATUS_THROWS(batch.Delete(column, key));
|
|
1360
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "key", key, true));
|
|
1361
|
+
ROCKS_STATUS_THROWS_NAPI(batch.Delete(column, key));
|
|
1745
1362
|
} 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));
|
|
1363
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "key", key, true));
|
|
1364
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "value", value, true));
|
|
1365
|
+
ROCKS_STATUS_THROWS_NAPI(batch.Put(column, key, value));
|
|
1755
1366
|
} else if (type == "data") {
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
NAPI_STATUS_THROWS(ToString(env, valueProperty, value));
|
|
1759
|
-
|
|
1760
|
-
ROCKS_STATUS_THROWS(batch.PutLogData(value));
|
|
1367
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "value", value, true));
|
|
1368
|
+
ROCKS_STATUS_THROWS_NAPI(batch.PutLogData(value));
|
|
1761
1369
|
} 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));
|
|
1370
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "key", key, true));
|
|
1371
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "value", value, true));
|
|
1372
|
+
ROCKS_STATUS_THROWS_NAPI(batch.Merge(column, key, value));
|
|
1771
1373
|
} else {
|
|
1772
|
-
|
|
1374
|
+
NAPI_STATUS_THROWS(napi_invalid_arg);
|
|
1773
1375
|
}
|
|
1774
1376
|
}
|
|
1775
1377
|
|
|
1776
1378
|
rocksdb::WriteOptions writeOptions;
|
|
1777
|
-
|
|
1379
|
+
ROCKS_STATUS_THROWS_NAPI(database->db->Write(writeOptions, &batch));
|
|
1778
1380
|
|
|
1779
1381
|
return 0;
|
|
1780
1382
|
}
|
|
@@ -1792,21 +1394,23 @@ NAPI_METHOD(batch_put) {
|
|
|
1792
1394
|
NAPI_ARGV(4);
|
|
1793
1395
|
|
|
1794
1396
|
rocksdb::WriteBatch* batch;
|
|
1795
|
-
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0],
|
|
1397
|
+
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
|
|
1796
1398
|
|
|
1797
|
-
|
|
1798
|
-
NAPI_STATUS_THROWS(
|
|
1399
|
+
NapiSlice key;
|
|
1400
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], key));
|
|
1799
1401
|
|
|
1800
|
-
|
|
1801
|
-
NAPI_STATUS_THROWS(
|
|
1402
|
+
NapiSlice val;
|
|
1403
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[2], val));
|
|
1802
1404
|
|
|
1803
|
-
|
|
1804
|
-
|
|
1405
|
+
const auto options = argv[3];
|
|
1406
|
+
|
|
1407
|
+
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1408
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1805
1409
|
|
|
1806
1410
|
if (column) {
|
|
1807
|
-
|
|
1411
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Put(column, key, val));
|
|
1808
1412
|
} else {
|
|
1809
|
-
|
|
1413
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Put(key, val));
|
|
1810
1414
|
}
|
|
1811
1415
|
|
|
1812
1416
|
return 0;
|
|
@@ -1818,16 +1422,18 @@ NAPI_METHOD(batch_del) {
|
|
|
1818
1422
|
rocksdb::WriteBatch* batch;
|
|
1819
1423
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
|
|
1820
1424
|
|
|
1821
|
-
|
|
1822
|
-
NAPI_STATUS_THROWS(
|
|
1425
|
+
NapiSlice key;
|
|
1426
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], key));
|
|
1823
1427
|
|
|
1824
|
-
|
|
1825
|
-
|
|
1428
|
+
const auto options = argv[2];
|
|
1429
|
+
|
|
1430
|
+
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1431
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1826
1432
|
|
|
1827
1433
|
if (column) {
|
|
1828
|
-
|
|
1434
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Delete(column, key));
|
|
1829
1435
|
} else {
|
|
1830
|
-
|
|
1436
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Delete(key));
|
|
1831
1437
|
}
|
|
1832
1438
|
|
|
1833
1439
|
return 0;
|
|
@@ -1839,19 +1445,21 @@ NAPI_METHOD(batch_merge) {
|
|
|
1839
1445
|
rocksdb::WriteBatch* batch;
|
|
1840
1446
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)(&batch)));
|
|
1841
1447
|
|
|
1842
|
-
|
|
1843
|
-
NAPI_STATUS_THROWS(
|
|
1448
|
+
NapiSlice key;
|
|
1449
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], key));
|
|
1844
1450
|
|
|
1845
|
-
|
|
1846
|
-
NAPI_STATUS_THROWS(
|
|
1451
|
+
NapiSlice val;
|
|
1452
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[2], val));
|
|
1847
1453
|
|
|
1848
|
-
|
|
1849
|
-
|
|
1454
|
+
const auto options = argv[3];
|
|
1455
|
+
|
|
1456
|
+
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1457
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1850
1458
|
|
|
1851
1459
|
if (column) {
|
|
1852
|
-
|
|
1460
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Merge(column, key, val));
|
|
1853
1461
|
} else {
|
|
1854
|
-
|
|
1462
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Merge(key, val));
|
|
1855
1463
|
}
|
|
1856
1464
|
|
|
1857
1465
|
return 0;
|
|
@@ -1878,7 +1486,7 @@ NAPI_METHOD(batch_write) {
|
|
|
1878
1486
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
|
|
1879
1487
|
|
|
1880
1488
|
rocksdb::WriteOptions writeOptions;
|
|
1881
|
-
|
|
1489
|
+
ROCKS_STATUS_THROWS_NAPI(database->db->Write(writeOptions, batch));
|
|
1882
1490
|
|
|
1883
1491
|
return 0;
|
|
1884
1492
|
}
|
|
@@ -1889,10 +1497,10 @@ NAPI_METHOD(batch_put_log_data) {
|
|
|
1889
1497
|
rocksdb::WriteBatch* batch;
|
|
1890
1498
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
|
|
1891
1499
|
|
|
1892
|
-
|
|
1893
|
-
NAPI_STATUS_THROWS(
|
|
1500
|
+
NapiSlice logData;
|
|
1501
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], logData));
|
|
1894
1502
|
|
|
1895
|
-
|
|
1503
|
+
ROCKS_STATUS_THROWS_NAPI(batch->PutLogData(logData));
|
|
1896
1504
|
|
|
1897
1505
|
return 0;
|
|
1898
1506
|
}
|
|
@@ -1918,111 +1526,34 @@ NAPI_METHOD(batch_iterate) {
|
|
|
1918
1526
|
rocksdb::WriteBatch* batch;
|
|
1919
1527
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
|
|
1920
1528
|
|
|
1921
|
-
|
|
1922
|
-
bool keys;
|
|
1923
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "keys", &keysProperty));
|
|
1924
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, keysProperty, &keys));
|
|
1529
|
+
const auto options = argv[2];
|
|
1925
1530
|
|
|
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));
|
|
1531
|
+
bool keys = true;
|
|
1532
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keys", keys));
|
|
1930
1533
|
|
|
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));
|
|
1534
|
+
bool values = true;
|
|
1535
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "values", values));
|
|
1935
1536
|
|
|
1936
|
-
|
|
1937
|
-
|
|
1537
|
+
bool data = true;
|
|
1538
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "data", data));
|
|
1539
|
+
|
|
1540
|
+
Encoding keyEncoding = Encoding::String;
|
|
1541
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keyEncoding", keyEncoding));
|
|
1542
|
+
|
|
1543
|
+
Encoding valueEncoding = Encoding::String;
|
|
1544
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1938
1545
|
|
|
1939
1546
|
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1940
|
-
NAPI_STATUS_THROWS(
|
|
1547
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1941
1548
|
|
|
1942
|
-
|
|
1943
|
-
BatchIterator iterator(nullptr, keys, values, data, column, keyAsBuffer, valueAsBuffer);
|
|
1549
|
+
BatchIterator iterator(nullptr, keys, values, data, column, keyEncoding, valueEncoding);
|
|
1944
1550
|
|
|
1551
|
+
napi_value result;
|
|
1945
1552
|
NAPI_STATUS_THROWS(iterator.Iterate(env, *batch, &result));
|
|
1946
1553
|
|
|
1947
1554
|
return result;
|
|
1948
1555
|
}
|
|
1949
1556
|
|
|
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
1557
|
NAPI_INIT() {
|
|
2027
1558
|
NAPI_EXPORT_FUNCTION(db_init);
|
|
2028
1559
|
NAPI_EXPORT_FUNCTION(db_open);
|
|
@@ -2042,10 +1573,6 @@ NAPI_INIT() {
|
|
|
2042
1573
|
NAPI_EXPORT_FUNCTION(updates_close);
|
|
2043
1574
|
NAPI_EXPORT_FUNCTION(updates_next);
|
|
2044
1575
|
|
|
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
1576
|
NAPI_EXPORT_FUNCTION(batch_do);
|
|
2050
1577
|
NAPI_EXPORT_FUNCTION(batch_init);
|
|
2051
1578
|
NAPI_EXPORT_FUNCTION(batch_put);
|