@nxtedition/rocksdb 7.0.61 → 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 +437 -909
- package/deps/rocksdb/rocksdb/db/wal_manager.cc +4 -0
- package/index.js +69 -141
- 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 +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,79 +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
|
+
|
|
111
|
+
ROCKS_STATUS_RETURN_NAPI(batch.Iterate(this));
|
|
412
112
|
|
|
413
113
|
napi_value putStr;
|
|
414
114
|
NAPI_STATUS_RETURN(napi_create_string_utf8(env, "put", NAPI_AUTO_LENGTH, &putStr));
|
|
@@ -443,11 +143,11 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
443
143
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 0, op));
|
|
444
144
|
|
|
445
145
|
napi_value key;
|
|
446
|
-
NAPI_STATUS_RETURN(Convert(env, cache_[n].key,
|
|
146
|
+
NAPI_STATUS_RETURN(Convert(env, cache_[n].key, keyEncoding_, key));
|
|
447
147
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 1, key));
|
|
448
148
|
|
|
449
149
|
napi_value val;
|
|
450
|
-
NAPI_STATUS_RETURN(Convert(env, cache_[n].val,
|
|
150
|
+
NAPI_STATUS_RETURN(Convert(env, cache_[n].val, valueEncoding_, val));
|
|
451
151
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 2, val));
|
|
452
152
|
|
|
453
153
|
// TODO (fix)
|
|
@@ -455,6 +155,8 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
455
155
|
NAPI_STATUS_RETURN(napi_set_element(env, *result, n * 4 + 3, nullVal));
|
|
456
156
|
}
|
|
457
157
|
|
|
158
|
+
cache_.clear();
|
|
159
|
+
|
|
458
160
|
return napi_ok;
|
|
459
161
|
}
|
|
460
162
|
|
|
@@ -463,9 +165,7 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
463
165
|
return rocksdb::Status::OK();
|
|
464
166
|
}
|
|
465
167
|
|
|
466
|
-
BatchEntry entry;
|
|
467
|
-
|
|
468
|
-
entry.op = BatchOp::Put;
|
|
168
|
+
BatchEntry entry = {BatchOp::Put};
|
|
469
169
|
|
|
470
170
|
if (keys_) {
|
|
471
171
|
entry.key = key.ToStringView();
|
|
@@ -475,8 +175,8 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
475
175
|
entry.val = value.ToStringView();
|
|
476
176
|
}
|
|
477
177
|
|
|
478
|
-
// if (database_ && database_->
|
|
479
|
-
// entry.column = database_->
|
|
178
|
+
// if (database_ && database_->columns.find(column_family_id) != database_->columns.end()) {
|
|
179
|
+
// entry.column = database_->columns[column_family_id];
|
|
480
180
|
// }
|
|
481
181
|
|
|
482
182
|
cache_.push_back(entry);
|
|
@@ -489,16 +189,14 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
489
189
|
return rocksdb::Status::OK();
|
|
490
190
|
}
|
|
491
191
|
|
|
492
|
-
BatchEntry entry;
|
|
493
|
-
|
|
494
|
-
entry.op = BatchOp::Delete;
|
|
192
|
+
BatchEntry entry = {BatchOp::Delete};
|
|
495
193
|
|
|
496
194
|
if (keys_) {
|
|
497
195
|
entry.key = key.ToStringView();
|
|
498
196
|
}
|
|
499
197
|
|
|
500
|
-
// if (database_ && database_->
|
|
501
|
-
// entry.column = database_->
|
|
198
|
+
// if (database_ && database_->columns.find(column_family_id) != database_->columns.end()) {
|
|
199
|
+
// entry.column = database_->columns[column_family_id];
|
|
502
200
|
// }
|
|
503
201
|
|
|
504
202
|
cache_.push_back(entry);
|
|
@@ -511,9 +209,7 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
511
209
|
return rocksdb::Status::OK();
|
|
512
210
|
}
|
|
513
211
|
|
|
514
|
-
BatchEntry entry;
|
|
515
|
-
|
|
516
|
-
entry.op = BatchOp::Merge;
|
|
212
|
+
BatchEntry entry = {BatchOp::Merge};
|
|
517
213
|
|
|
518
214
|
if (keys_) {
|
|
519
215
|
entry.key = key.ToStringView();
|
|
@@ -523,8 +219,8 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
523
219
|
entry.val = value.ToStringView();
|
|
524
220
|
}
|
|
525
221
|
|
|
526
|
-
// if (database_ && database_->
|
|
527
|
-
// entry.column = database_->
|
|
222
|
+
// if (database_ && database_->columns.find(column_family_id) != database_->columns.end()) {
|
|
223
|
+
// entry.column = database_->columns[column_family_id];
|
|
528
224
|
// }
|
|
529
225
|
|
|
530
226
|
cache_.push_back(entry);
|
|
@@ -537,9 +233,7 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
537
233
|
return;
|
|
538
234
|
}
|
|
539
235
|
|
|
540
|
-
BatchEntry entry;
|
|
541
|
-
|
|
542
|
-
entry.op = BatchOp::Data;
|
|
236
|
+
BatchEntry entry = {BatchOp::Data};
|
|
543
237
|
|
|
544
238
|
entry.val = data.ToStringView();
|
|
545
239
|
|
|
@@ -550,40 +244,47 @@ struct BatchIterator : public rocksdb::WriteBatch::Handler {
|
|
|
550
244
|
|
|
551
245
|
private:
|
|
552
246
|
Database* database_;
|
|
553
|
-
bool keys_;
|
|
554
|
-
bool values_;
|
|
555
|
-
bool data_;
|
|
247
|
+
const bool keys_;
|
|
248
|
+
const bool values_;
|
|
249
|
+
const bool data_;
|
|
556
250
|
const rocksdb::ColumnFamilyHandle* column_;
|
|
557
|
-
|
|
558
|
-
|
|
251
|
+
const Encoding keyEncoding_;
|
|
252
|
+
const Encoding valueEncoding_;
|
|
559
253
|
std::vector<BatchEntry> cache_;
|
|
560
254
|
};
|
|
561
255
|
|
|
562
|
-
struct Updates : public BatchIterator {
|
|
256
|
+
struct Updates : public BatchIterator, public Closable {
|
|
563
257
|
Updates(Database* database,
|
|
564
|
-
int64_t seqNumber,
|
|
565
|
-
bool keys,
|
|
566
|
-
bool values,
|
|
567
|
-
bool data,
|
|
258
|
+
const int64_t seqNumber,
|
|
259
|
+
const bool keys,
|
|
260
|
+
const bool values,
|
|
261
|
+
const bool data,
|
|
568
262
|
const rocksdb::ColumnFamilyHandle* column,
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
: BatchIterator(database, keys, values, data, column,
|
|
263
|
+
const Encoding keyEncoding,
|
|
264
|
+
const Encoding valueEncoding)
|
|
265
|
+
: BatchIterator(database, keys, values, data, column, keyEncoding, valueEncoding),
|
|
572
266
|
database_(database),
|
|
573
267
|
start_(seqNumber) {}
|
|
574
268
|
|
|
575
|
-
|
|
269
|
+
virtual ~Updates() { assert(!iterator_); }
|
|
270
|
+
|
|
271
|
+
rocksdb::Status Close() override {
|
|
272
|
+
iterator_.reset();
|
|
273
|
+
return rocksdb::Status::OK();
|
|
274
|
+
}
|
|
576
275
|
|
|
577
|
-
|
|
578
|
-
napi_create_reference(env, context, 1, &ref_);
|
|
579
|
-
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;
|
|
580
280
|
}
|
|
581
281
|
|
|
582
|
-
|
|
583
|
-
database_->
|
|
282
|
+
napi_status Detach(napi_env env) {
|
|
283
|
+
database_->closables.erase(this);
|
|
584
284
|
if (ref_) {
|
|
585
|
-
napi_delete_reference(env, ref_);
|
|
285
|
+
NAPI_STATUS_RETURN(napi_delete_reference(env, ref_));
|
|
586
286
|
}
|
|
287
|
+
return napi_ok;
|
|
587
288
|
}
|
|
588
289
|
|
|
589
290
|
Database* database_;
|
|
@@ -594,7 +295,7 @@ struct Updates : public BatchIterator {
|
|
|
594
295
|
napi_ref ref_ = nullptr;
|
|
595
296
|
};
|
|
596
297
|
|
|
597
|
-
struct BaseIterator {
|
|
298
|
+
struct BaseIterator : public Closable {
|
|
598
299
|
BaseIterator(Database* database,
|
|
599
300
|
rocksdb::ColumnFamilyHandle* column,
|
|
600
301
|
const bool reverse,
|
|
@@ -667,9 +368,10 @@ struct BaseIterator {
|
|
|
667
368
|
}
|
|
668
369
|
}
|
|
669
370
|
|
|
670
|
-
|
|
371
|
+
rocksdb::Status Close() override {
|
|
671
372
|
snapshot_.reset();
|
|
672
373
|
iterator_.reset();
|
|
374
|
+
return rocksdb::Status::OK();
|
|
673
375
|
}
|
|
674
376
|
|
|
675
377
|
bool Valid() const {
|
|
@@ -724,7 +426,7 @@ struct BaseIterator {
|
|
|
724
426
|
readOptions.async_io = true;
|
|
725
427
|
readOptions.adaptive_readahead = true;
|
|
726
428
|
|
|
727
|
-
iterator_.reset(database_->
|
|
429
|
+
iterator_.reset(database_->db->NewIterator(readOptions, column_));
|
|
728
430
|
}
|
|
729
431
|
|
|
730
432
|
int count_ = 0;
|
|
@@ -748,33 +450,35 @@ struct Iterator final : public BaseIterator {
|
|
|
748
450
|
const std::optional<std::string>& gt,
|
|
749
451
|
const std::optional<std::string>& gte,
|
|
750
452
|
const bool fillCache,
|
|
751
|
-
const
|
|
752
|
-
const
|
|
453
|
+
const Encoding keyEncoding,
|
|
454
|
+
const Encoding valueEncoding,
|
|
753
455
|
const size_t highWaterMarkBytes,
|
|
754
456
|
std::shared_ptr<const rocksdb::Snapshot> snapshot)
|
|
755
457
|
: BaseIterator(database, column, reverse, lt, lte, gt, gte, limit, fillCache, snapshot),
|
|
756
458
|
keys_(keys),
|
|
757
459
|
values_(values),
|
|
758
|
-
|
|
759
|
-
|
|
460
|
+
keyEncoding_(keyEncoding),
|
|
461
|
+
valueEncoding_(valueEncoding),
|
|
760
462
|
highWaterMarkBytes_(highWaterMarkBytes) {}
|
|
761
463
|
|
|
762
|
-
|
|
763
|
-
napi_create_reference(env, context, 1, &ref_);
|
|
764
|
-
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;
|
|
765
468
|
}
|
|
766
469
|
|
|
767
|
-
|
|
768
|
-
database_->
|
|
470
|
+
napi_status Detach(napi_env env) {
|
|
471
|
+
database_->closables.erase(this);
|
|
769
472
|
if (ref_) {
|
|
770
|
-
napi_delete_reference(env, ref_);
|
|
473
|
+
NAPI_STATUS_RETURN(napi_delete_reference(env, ref_));
|
|
771
474
|
}
|
|
475
|
+
return napi_ok;
|
|
772
476
|
}
|
|
773
477
|
|
|
774
478
|
const bool keys_;
|
|
775
479
|
const bool values_;
|
|
776
|
-
const
|
|
777
|
-
const
|
|
480
|
+
const Encoding keyEncoding_;
|
|
481
|
+
const Encoding valueEncoding_;
|
|
778
482
|
const size_t highWaterMarkBytes_;
|
|
779
483
|
bool first_ = true;
|
|
780
484
|
|
|
@@ -782,152 +486,20 @@ struct Iterator final : public BaseIterator {
|
|
|
782
486
|
napi_ref ref_ = nullptr;
|
|
783
487
|
};
|
|
784
488
|
|
|
785
|
-
static napi_status GetColumnFamily(Database* database,
|
|
786
|
-
napi_env env,
|
|
787
|
-
napi_value options,
|
|
788
|
-
rocksdb::ColumnFamilyHandle** column) {
|
|
789
|
-
bool hasColumn = false;
|
|
790
|
-
NAPI_STATUS_RETURN(napi_has_named_property(env, options, "column", &hasColumn));
|
|
791
|
-
|
|
792
|
-
if (hasColumn) {
|
|
793
|
-
napi_value value = nullptr;
|
|
794
|
-
NAPI_STATUS_RETURN(napi_get_named_property(env, options, "column", &value));
|
|
795
|
-
|
|
796
|
-
bool nully = false;
|
|
797
|
-
|
|
798
|
-
napi_value nullVal;
|
|
799
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &nullVal));
|
|
800
|
-
NAPI_STATUS_RETURN(napi_strict_equals(env, nullVal, value, &nully));
|
|
801
|
-
if (nully) {
|
|
802
|
-
*column = nullptr;
|
|
803
|
-
return napi_ok;
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
napi_value undefinedVal;
|
|
807
|
-
NAPI_STATUS_RETURN(napi_get_undefined(env, &undefinedVal));
|
|
808
|
-
NAPI_STATUS_RETURN(napi_strict_equals(env, undefinedVal, value, &nully));
|
|
809
|
-
if (nully) {
|
|
810
|
-
*column = nullptr;
|
|
811
|
-
return napi_ok;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
NAPI_STATUS_RETURN(napi_get_value_external(env, value, reinterpret_cast<void**>(column)));
|
|
815
|
-
} else if (database) {
|
|
816
|
-
*column = database->db_->DefaultColumnFamily();
|
|
817
|
-
} else {
|
|
818
|
-
*column = nullptr;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
return napi_ok;
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
template <typename State,
|
|
825
|
-
typename ExecuteType = std::function<rocksdb::Status(State& state, Database& database)>,
|
|
826
|
-
typename OnOkType = std::function<napi_status(State& state, napi_env env, napi_value callback)>>
|
|
827
|
-
struct GenericWorker final : public Worker {
|
|
828
|
-
template <typename T1, typename T2>
|
|
829
|
-
GenericWorker(const std::string& name,
|
|
830
|
-
napi_env env,
|
|
831
|
-
napi_value callback,
|
|
832
|
-
Database* database,
|
|
833
|
-
bool priority,
|
|
834
|
-
T1&& execute,
|
|
835
|
-
T2&& onOK)
|
|
836
|
-
: Worker(env, database, callback, name),
|
|
837
|
-
priority_(priority),
|
|
838
|
-
execute_(std::forward<T1>(execute)),
|
|
839
|
-
onOk_(std::forward<T2>(onOK)) {
|
|
840
|
-
if (priority_) {
|
|
841
|
-
database_->IncrementPriorityWork(env);
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
rocksdb::Status Execute(Database& database) override { return execute_(state_, database); }
|
|
846
|
-
|
|
847
|
-
napi_status OnOk(napi_env env, napi_value callback) override { return onOk_(state_, env, callback); }
|
|
848
|
-
|
|
849
|
-
void Destroy(napi_env env) override {
|
|
850
|
-
if (priority_) {
|
|
851
|
-
database_->DecrementPriorityWork(env);
|
|
852
|
-
}
|
|
853
|
-
Worker::Destroy(env);
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
private:
|
|
857
|
-
State state_;
|
|
858
|
-
bool priority_ = false;
|
|
859
|
-
ExecuteType execute_;
|
|
860
|
-
OnOkType onOk_;
|
|
861
|
-
};
|
|
862
|
-
|
|
863
|
-
template <typename State, typename T1, typename T2>
|
|
864
|
-
Worker* createWorker(const std::string& name,
|
|
865
|
-
napi_env env,
|
|
866
|
-
napi_value callback,
|
|
867
|
-
Database* database,
|
|
868
|
-
bool priority,
|
|
869
|
-
T1&& execute,
|
|
870
|
-
T2&& onOk) {
|
|
871
|
-
return new GenericWorker<State, typename std::decay<T1>::type, typename std::decay<T2>::type>(
|
|
872
|
-
name, env, callback, database, priority, std::forward<T1>(execute), std::forward<T2>(onOk));
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
template <typename State, typename T1, typename T2>
|
|
876
|
-
void runWorker(const std::string& name,
|
|
877
|
-
napi_env env,
|
|
878
|
-
napi_value callback,
|
|
879
|
-
Database* database,
|
|
880
|
-
bool priority,
|
|
881
|
-
T1&& execute,
|
|
882
|
-
T2&& onOk) {
|
|
883
|
-
auto worker = new GenericWorker<State, typename std::decay<T1>::type, typename std::decay<T2>::type>(
|
|
884
|
-
name, env, callback, database, priority, std::forward<T1>(execute), std::forward<T2>(onOk));
|
|
885
|
-
worker->Queue(env);
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
/**
|
|
889
|
-
* Hook for when the environment exits. This hook will be called after
|
|
890
|
-
* already-scheduled napi_async_work items have finished, which gives us
|
|
891
|
-
* the guarantee that no db operations will be in-flight at this time.
|
|
892
|
-
*/
|
|
893
489
|
static void env_cleanup_hook(void* arg) {
|
|
894
490
|
auto database = reinterpret_cast<Database*>(arg);
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
// GC did not (yet) collect the database because that would be a user mistake
|
|
898
|
-
// (not closing their db) made during the lifetime of the environment. That's
|
|
899
|
-
// different from an environment being torn down (like the main process or a
|
|
900
|
-
// worker thread) where it's our responsibility to clean up. Note also, the
|
|
901
|
-
// following code must be a safe noop if called before db_open() or after
|
|
902
|
-
// db_close().
|
|
903
|
-
if (database && database->db_) {
|
|
904
|
-
for (auto& it : database->iterators_) {
|
|
905
|
-
// TODO: does not do `napi_delete_reference`. Problem?
|
|
906
|
-
it->Close();
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
for (auto& it : database->updates_) {
|
|
910
|
-
// TODO: does not do `napi_delete_reference`. Problem?
|
|
911
|
-
it->Close();
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
for (auto& it : database->columns_) {
|
|
915
|
-
database->db_->DestroyColumnFamilyHandle(it.second.handle);
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
// Having closed the iterators (and released snapshots) we can safely close.
|
|
919
|
-
database->db_->Close();
|
|
491
|
+
if (database) {
|
|
492
|
+
database->Close();
|
|
920
493
|
}
|
|
921
494
|
}
|
|
922
495
|
|
|
923
496
|
static void FinalizeDatabase(napi_env env, void* data, void* hint) {
|
|
924
497
|
if (data) {
|
|
925
498
|
auto database = reinterpret_cast<Database*>(data);
|
|
499
|
+
database->Close();
|
|
926
500
|
napi_remove_env_cleanup_hook(env, env_cleanup_hook, database);
|
|
927
|
-
|
|
928
|
-
napi_delete_reference(env,
|
|
929
|
-
for (auto& it : database->columns_) {
|
|
930
|
-
napi_delete_reference(env, it.second.ref);
|
|
501
|
+
for (auto& [id, column] : database->columns) {
|
|
502
|
+
napi_delete_reference(env, column.ref);
|
|
931
503
|
}
|
|
932
504
|
delete database;
|
|
933
505
|
}
|
|
@@ -940,94 +512,109 @@ NAPI_METHOD(db_init) {
|
|
|
940
512
|
napi_value result;
|
|
941
513
|
NAPI_STATUS_THROWS(napi_create_external(env, database, FinalizeDatabase, nullptr, &result));
|
|
942
514
|
|
|
943
|
-
NAPI_STATUS_THROWS(napi_create_reference(env, result, 0, &database->priorityRef_));
|
|
944
|
-
|
|
945
515
|
return result;
|
|
946
516
|
}
|
|
947
517
|
|
|
948
518
|
template <typename T, typename U>
|
|
949
|
-
|
|
519
|
+
napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
|
|
950
520
|
rocksdb::ConfigOptions configOptions;
|
|
951
521
|
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
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
|
-
|
|
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
|
+
}
|
|
985
568
|
}
|
|
986
569
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
570
|
+
bool compression = true;
|
|
571
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "compression", compression));
|
|
572
|
+
|
|
573
|
+
if (compression) {
|
|
574
|
+
columnOptions.compression = rocksdb::kZSTD;
|
|
990
575
|
columnOptions.compression_opts.max_dict_bytes = 16 * 1024;
|
|
991
576
|
columnOptions.compression_opts.zstd_max_train_bytes = 16 * 1024 * 100;
|
|
992
577
|
// TODO (perf): compression_opts.parallel_threads
|
|
993
578
|
}
|
|
994
579
|
|
|
995
|
-
|
|
580
|
+
std::optional<std::string> prefixExtractorOpt;
|
|
581
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "prefixExtractor", prefixExtractorOpt));
|
|
996
582
|
if (prefixExtractorOpt) {
|
|
997
|
-
|
|
583
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
998
584
|
rocksdb::SliceTransform::CreateFromString(configOptions, *prefixExtractorOpt, &columnOptions.prefix_extractor));
|
|
999
585
|
}
|
|
1000
586
|
|
|
1001
|
-
|
|
587
|
+
std::optional<std::string> comparatorOpt;
|
|
588
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "comparator", comparatorOpt));
|
|
1002
589
|
if (comparatorOpt) {
|
|
1003
|
-
|
|
590
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
1004
591
|
rocksdb::Comparator::CreateFromString(configOptions, *comparatorOpt, &columnOptions.comparator));
|
|
1005
592
|
}
|
|
1006
593
|
|
|
1007
|
-
|
|
594
|
+
std::optional<std::string> mergeOperatorOpt;
|
|
595
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "mergeOperator", mergeOperatorOpt));
|
|
1008
596
|
if (mergeOperatorOpt) {
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
} else {
|
|
1012
|
-
ROCKS_STATUS_RETURN(
|
|
1013
|
-
rocksdb::MergeOperator::CreateFromString(configOptions, *mergeOperatorOpt, &columnOptions.merge_operator));
|
|
1014
|
-
}
|
|
597
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
598
|
+
rocksdb::MergeOperator::CreateFromString(configOptions, *mergeOperatorOpt, &columnOptions.merge_operator));
|
|
1015
599
|
}
|
|
1016
600
|
|
|
1017
|
-
|
|
601
|
+
uint32_t cacheSize = 8 << 20;
|
|
602
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "cacheSize", cacheSize));
|
|
1018
603
|
|
|
1019
604
|
rocksdb::BlockBasedTableOptions tableOptions;
|
|
1020
605
|
|
|
1021
606
|
if (cacheSize) {
|
|
1022
607
|
tableOptions.block_cache = rocksdb::NewLRUCache(cacheSize);
|
|
1023
|
-
tableOptions.cache_index_and_filter_blocks =
|
|
1024
|
-
|
|
608
|
+
tableOptions.cache_index_and_filter_blocks = true;
|
|
609
|
+
NAPI_STATUS_RETURN(
|
|
610
|
+
GetProperty(env, options, "cacheIndexAndFilterBlocks", tableOptions.cache_index_and_filter_blocks));
|
|
1025
611
|
} else {
|
|
1026
612
|
tableOptions.no_block_cache = true;
|
|
1027
613
|
tableOptions.cache_index_and_filter_blocks = false;
|
|
1028
614
|
}
|
|
1029
615
|
|
|
1030
|
-
|
|
616
|
+
std::string optimize = "";
|
|
617
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "optimize", optimize));
|
|
1031
618
|
|
|
1032
619
|
if (optimize == "point-lookup") {
|
|
1033
620
|
tableOptions.data_block_index_type = rocksdb::BlockBasedTableOptions::kDataBlockBinaryAndHash;
|
|
@@ -1039,25 +626,29 @@ rocksdb::Status InitOptions(napi_env env, T& columnOptions, const U& options) {
|
|
|
1039
626
|
} else if (optimize == "range-lookup") {
|
|
1040
627
|
// TODO?
|
|
1041
628
|
} else {
|
|
1042
|
-
tableOptions.filter_policy.reset(rocksdb::
|
|
629
|
+
tableOptions.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10));
|
|
1043
630
|
}
|
|
1044
631
|
|
|
1045
|
-
|
|
632
|
+
std::optional<std::string> filterPolicyOpt;
|
|
633
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "filterPolicy", filterPolicyOpt));
|
|
1046
634
|
if (filterPolicyOpt) {
|
|
1047
|
-
|
|
1048
|
-
ROCKS_STATUS_RETURN(
|
|
635
|
+
ROCKS_STATUS_RETURN_NAPI(
|
|
1049
636
|
rocksdb::FilterPolicy::CreateFromString(configOptions, *filterPolicyOpt, &tableOptions.filter_policy));
|
|
1050
637
|
}
|
|
1051
638
|
|
|
1052
|
-
|
|
1053
|
-
|
|
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
|
+
|
|
1054
643
|
tableOptions.format_version = 5;
|
|
1055
644
|
tableOptions.checksum = rocksdb::kXXH3;
|
|
1056
|
-
|
|
645
|
+
|
|
646
|
+
tableOptions.optimize_filters_for_memory = true;
|
|
647
|
+
NAPI_STATUS_RETURN(GetProperty(env, options, "optimizeFiltersForMemory", tableOptions.optimize_filters_for_memory));
|
|
1057
648
|
|
|
1058
649
|
columnOptions.table_factory.reset(rocksdb::NewBlockBasedTableFactory(tableOptions));
|
|
1059
650
|
|
|
1060
|
-
return
|
|
651
|
+
return napi_ok;
|
|
1061
652
|
}
|
|
1062
653
|
|
|
1063
654
|
NAPI_METHOD(db_open) {
|
|
@@ -1067,32 +658,44 @@ NAPI_METHOD(db_open) {
|
|
|
1067
658
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1068
659
|
|
|
1069
660
|
std::string location;
|
|
1070
|
-
NAPI_STATUS_THROWS(
|
|
661
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], location));
|
|
1071
662
|
|
|
1072
663
|
rocksdb::Options dbOptions;
|
|
1073
664
|
|
|
1074
|
-
|
|
1075
|
-
|
|
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;
|
|
1076
683
|
|
|
1077
|
-
dbOptions.create_if_missing = BooleanProperty(env, argv[2], "createIfMissing").value_or(true);
|
|
1078
|
-
dbOptions.error_if_exists = BooleanProperty(env, argv[2], "errorIfExists").value_or(false);
|
|
1079
684
|
dbOptions.avoid_unnecessary_blocking_io = true;
|
|
1080
685
|
dbOptions.write_dbid_to_manifest = true;
|
|
1081
686
|
dbOptions.use_adaptive_mutex = true; // We don't have soo many threads in the libuv thread pool...
|
|
1082
687
|
dbOptions.enable_pipelined_write = false; // We only write in the main thread...
|
|
1083
|
-
dbOptions.WAL_ttl_seconds = Uint32Property(env, argv[2], "walTTL").value_or(0) / 1e3;
|
|
1084
|
-
dbOptions.WAL_size_limit_MB = Uint32Property(env, argv[2], "walSizeLimit").value_or(0) / 1e6;
|
|
1085
|
-
dbOptions.wal_compression = BooleanProperty(env, argv[2], "walCompression").value_or(false)
|
|
1086
|
-
? rocksdb::CompressionType::kZSTD
|
|
1087
|
-
: rocksdb::CompressionType::kNoCompression;
|
|
1088
688
|
dbOptions.create_missing_column_families = true;
|
|
1089
|
-
dbOptions.unordered_write = BooleanProperty(env, argv[2], "unorderedWrite").value_or(false);
|
|
1090
689
|
dbOptions.fail_if_options_file_error = true;
|
|
1091
|
-
|
|
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));
|
|
1092
694
|
|
|
1093
695
|
// TODO (feat): dbOptions.listeners
|
|
1094
696
|
|
|
1095
|
-
|
|
697
|
+
std::string infoLogLevel;
|
|
698
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "infoLogLevel", infoLogLevel));
|
|
1096
699
|
if (infoLogLevel.size() > 0) {
|
|
1097
700
|
rocksdb::InfoLogLevel lvl = {};
|
|
1098
701
|
|
|
@@ -1119,16 +722,16 @@ NAPI_METHOD(db_open) {
|
|
|
1119
722
|
dbOptions.info_log.reset(new NullLogger());
|
|
1120
723
|
}
|
|
1121
724
|
|
|
1122
|
-
|
|
725
|
+
NAPI_STATUS_THROWS(InitOptions(env, dbOptions, options));
|
|
1123
726
|
|
|
1124
727
|
std::vector<rocksdb::ColumnFamilyDescriptor> descriptors;
|
|
1125
728
|
|
|
1126
729
|
bool hasColumns;
|
|
1127
|
-
NAPI_STATUS_THROWS(napi_has_named_property(env,
|
|
730
|
+
NAPI_STATUS_THROWS(napi_has_named_property(env, options, "columns", &hasColumns));
|
|
1128
731
|
|
|
1129
732
|
if (hasColumns) {
|
|
1130
733
|
napi_value columns;
|
|
1131
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env,
|
|
734
|
+
NAPI_STATUS_THROWS(napi_get_named_property(env, options, "columns", &columns));
|
|
1132
735
|
|
|
1133
736
|
napi_value keys;
|
|
1134
737
|
NAPI_STATUS_THROWS(napi_get_property_names(env, columns, &keys));
|
|
@@ -1144,27 +747,25 @@ NAPI_METHOD(db_open) {
|
|
|
1144
747
|
napi_value column;
|
|
1145
748
|
NAPI_STATUS_THROWS(napi_get_property(env, columns, key, &column));
|
|
1146
749
|
|
|
1147
|
-
|
|
750
|
+
NAPI_STATUS_THROWS(InitOptions(env, descriptors[n].options, column));
|
|
1148
751
|
|
|
1149
|
-
NAPI_STATUS_THROWS(
|
|
752
|
+
NAPI_STATUS_THROWS(GetValue(env, key, descriptors[n].name));
|
|
1150
753
|
}
|
|
1151
754
|
}
|
|
1152
755
|
|
|
1153
756
|
auto callback = argv[3];
|
|
1154
757
|
|
|
1155
|
-
|
|
1156
|
-
"leveldown.open", env, callback,
|
|
1157
|
-
[=](auto& handles
|
|
758
|
+
runAsync<std::vector<rocksdb::ColumnFamilyHandle*>>(
|
|
759
|
+
"leveldown.open", env, callback,
|
|
760
|
+
[=](auto& handles) {
|
|
1158
761
|
rocksdb::DB* db = nullptr;
|
|
1159
|
-
const auto status = descriptors.empty()
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
database.db_.reset(db);
|
|
762
|
+
const auto status = descriptors.empty() ? rocksdb::DB::Open(dbOptions, location, &db)
|
|
763
|
+
: rocksdb::DB::Open(dbOptions, location, descriptors, &handles, &db);
|
|
764
|
+
database->db.reset(db);
|
|
1163
765
|
return status;
|
|
1164
766
|
},
|
|
1165
|
-
[=](auto& handles,
|
|
1166
|
-
|
|
1167
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
767
|
+
[=](auto& handles, auto env, auto& argv) {
|
|
768
|
+
argv.resize(2);
|
|
1168
769
|
|
|
1169
770
|
const auto size = handles.size();
|
|
1170
771
|
NAPI_STATUS_RETURN(napi_create_object(env, &argv[1]));
|
|
@@ -1175,13 +776,11 @@ NAPI_METHOD(db_open) {
|
|
|
1175
776
|
column.descriptor = descriptors[n];
|
|
1176
777
|
NAPI_STATUS_RETURN(napi_create_external(env, column.handle, nullptr, nullptr, &column.val));
|
|
1177
778
|
NAPI_STATUS_RETURN(napi_create_reference(env, column.val, 1, &column.ref));
|
|
1178
|
-
|
|
1179
779
|
NAPI_STATUS_RETURN(napi_set_named_property(env, argv[1], descriptors[n].name.c_str(), column.val));
|
|
1180
|
-
|
|
1181
|
-
database->columns_[column.handle->GetID()] = column;
|
|
780
|
+
database->columns[column.handle->GetID()] = column;
|
|
1182
781
|
}
|
|
1183
782
|
|
|
1184
|
-
return
|
|
783
|
+
return napi_ok;
|
|
1185
784
|
});
|
|
1186
785
|
|
|
1187
786
|
return 0;
|
|
@@ -1200,28 +799,9 @@ NAPI_METHOD(db_close) {
|
|
|
1200
799
|
auto callback = argv[1];
|
|
1201
800
|
|
|
1202
801
|
struct State {};
|
|
1203
|
-
|
|
1204
|
-
"leveldown.close", env, callback, database
|
|
1205
|
-
[
|
|
1206
|
-
for (auto& it : database.columns_) {
|
|
1207
|
-
database.db_->DestroyColumnFamilyHandle(it.second.handle);
|
|
1208
|
-
}
|
|
1209
|
-
database.columns_.clear();
|
|
1210
|
-
|
|
1211
|
-
return database.db_->Close();
|
|
1212
|
-
},
|
|
1213
|
-
[](auto& state, napi_env env, napi_value callback) -> napi_status {
|
|
1214
|
-
napi_value argv[1];
|
|
1215
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
1216
|
-
|
|
1217
|
-
return CallFunction(env, callback, 1, &argv[0]);
|
|
1218
|
-
});
|
|
1219
|
-
|
|
1220
|
-
if (!database->HasPriorityWork()) {
|
|
1221
|
-
worker->Queue(env);
|
|
1222
|
-
} else {
|
|
1223
|
-
database->pendingCloseWorker_ = worker;
|
|
1224
|
-
}
|
|
802
|
+
runAsync<State>(
|
|
803
|
+
"leveldown.close", env, callback, [=](auto& state) { return database->Close(); },
|
|
804
|
+
[](auto& state, auto env, auto& argv) { return napi_ok; });
|
|
1225
805
|
|
|
1226
806
|
return 0;
|
|
1227
807
|
}
|
|
@@ -1232,40 +812,38 @@ NAPI_METHOD(updates_init) {
|
|
|
1232
812
|
Database* database;
|
|
1233
813
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1234
814
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
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));
|
|
1239
822
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[1], "keys", &keysProperty));
|
|
1243
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, keysProperty, &keys));
|
|
823
|
+
bool values = true;
|
|
824
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "values", values));
|
|
1244
825
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[1], "values", &valuesProperty));
|
|
1248
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, valuesProperty, &values));
|
|
826
|
+
bool data = true;
|
|
827
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "data", data));
|
|
1249
828
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[1], "data", &dataProperty));
|
|
1253
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, dataProperty, &data));
|
|
829
|
+
Encoding keyEncoding = Encoding::String;
|
|
830
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keyEncoding", keyEncoding));
|
|
1254
831
|
|
|
1255
|
-
|
|
1256
|
-
|
|
832
|
+
Encoding valueEncoding = Encoding::String;
|
|
833
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1257
834
|
|
|
1258
835
|
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1259
|
-
NAPI_STATUS_THROWS(
|
|
836
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1260
837
|
|
|
1261
|
-
auto updates =
|
|
838
|
+
auto updates =
|
|
839
|
+
std::unique_ptr<Updates>(new Updates(database, since, keys, values, data, column, keyEncoding, valueEncoding));
|
|
1262
840
|
|
|
1263
841
|
napi_value result;
|
|
1264
842
|
NAPI_STATUS_THROWS(napi_create_external(env, updates.get(), Finalize<Updates>, updates.get(), &result));
|
|
1265
843
|
|
|
1266
844
|
// Prevent GC of JS object before the iterator is closed (explicitly or on
|
|
1267
845
|
// db close) and keep track of non-closed iterators to end them on db close.
|
|
1268
|
-
updates.release()->Attach(env, result);
|
|
846
|
+
NAPI_STATUS_THROWS(updates.release()->Attach(env, result));
|
|
1269
847
|
|
|
1270
848
|
return result;
|
|
1271
849
|
}
|
|
@@ -1278,12 +856,12 @@ NAPI_METHOD(updates_next) {
|
|
|
1278
856
|
|
|
1279
857
|
auto callback = argv[1];
|
|
1280
858
|
|
|
1281
|
-
|
|
1282
|
-
"leveldown.updates.next", env, callback,
|
|
1283
|
-
[=](auto& batchResult
|
|
859
|
+
runAsync<rocksdb::BatchResult>(
|
|
860
|
+
"leveldown.updates.next", env, callback,
|
|
861
|
+
[=](auto& batchResult) {
|
|
1284
862
|
if (!updates->iterator_) {
|
|
1285
863
|
rocksdb::TransactionLogIterator::ReadOptions options;
|
|
1286
|
-
const auto status =
|
|
864
|
+
const auto status = updates->database_->db->GetUpdatesSince(updates->start_, &updates->iterator_, options);
|
|
1287
865
|
if (!status.ok()) {
|
|
1288
866
|
return status;
|
|
1289
867
|
}
|
|
@@ -1299,22 +877,18 @@ NAPI_METHOD(updates_next) {
|
|
|
1299
877
|
|
|
1300
878
|
return rocksdb::Status::OK();
|
|
1301
879
|
},
|
|
1302
|
-
[=](auto& batchResult,
|
|
1303
|
-
napi_value argv[5];
|
|
1304
|
-
|
|
1305
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
1306
|
-
|
|
880
|
+
[=](auto& batchResult, auto env, auto& argv) {
|
|
1307
881
|
if (!batchResult.writeBatchPtr) {
|
|
1308
|
-
return
|
|
882
|
+
return napi_ok;
|
|
1309
883
|
}
|
|
1310
884
|
|
|
885
|
+
argv.resize(5);
|
|
1311
886
|
NAPI_STATUS_RETURN(updates->Iterate(env, *batchResult.writeBatchPtr, &argv[1]));
|
|
1312
|
-
|
|
1313
887
|
NAPI_STATUS_RETURN(napi_create_int64(env, batchResult.sequence, &argv[2]));
|
|
1314
888
|
NAPI_STATUS_RETURN(napi_create_int64(env, batchResult.writeBatchPtr->Count(), &argv[3]));
|
|
1315
889
|
NAPI_STATUS_RETURN(napi_create_int64(env, updates->start_, &argv[4]));
|
|
1316
890
|
|
|
1317
|
-
return
|
|
891
|
+
return napi_ok;
|
|
1318
892
|
});
|
|
1319
893
|
|
|
1320
894
|
return 0;
|
|
@@ -1326,8 +900,8 @@ NAPI_METHOD(updates_close) {
|
|
|
1326
900
|
Updates* updates;
|
|
1327
901
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&updates)));
|
|
1328
902
|
|
|
1329
|
-
updates->
|
|
1330
|
-
updates->
|
|
903
|
+
ROCKS_STATUS_THROWS_NAPI(updates->Close());
|
|
904
|
+
NAPI_STATUS_THROWS(updates->Detach(env));
|
|
1331
905
|
|
|
1332
906
|
return 0;
|
|
1333
907
|
}
|
|
@@ -1347,44 +921,53 @@ NAPI_METHOD(db_get_many) {
|
|
|
1347
921
|
for (uint32_t n = 0; n < length; n++) {
|
|
1348
922
|
napi_value element;
|
|
1349
923
|
NAPI_STATUS_THROWS(napi_get_element(env, argv[1], n, &element));
|
|
1350
|
-
NAPI_STATUS_THROWS(
|
|
924
|
+
NAPI_STATUS_THROWS(GetValue(env, element, keys[n]));
|
|
1351
925
|
}
|
|
1352
926
|
}
|
|
1353
927
|
|
|
1354
|
-
const
|
|
1355
|
-
|
|
1356
|
-
|
|
928
|
+
const auto options = argv[2];
|
|
929
|
+
|
|
930
|
+
Encoding valueEncoding = Encoding::String;
|
|
931
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1357
932
|
|
|
1358
|
-
|
|
1359
|
-
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));
|
|
1360
941
|
|
|
1361
942
|
auto callback = argv[3];
|
|
1362
943
|
|
|
1363
944
|
auto snapshot = std::shared_ptr<const rocksdb::Snapshot>(
|
|
1364
|
-
database->
|
|
945
|
+
database->db->GetSnapshot(), [database](auto ptr) { database->db->ReleaseSnapshot(ptr); });
|
|
1365
946
|
|
|
1366
|
-
|
|
1367
|
-
"leveldown.get.many", env, callback,
|
|
1368
|
-
[=, 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) {
|
|
1369
950
|
rocksdb::ReadOptions readOptions;
|
|
1370
951
|
readOptions.fill_cache = fillCache;
|
|
1371
952
|
readOptions.snapshot = snapshot.get();
|
|
1372
953
|
readOptions.async_io = true;
|
|
1373
954
|
readOptions.ignore_range_deletions = ignoreRangeDeletions;
|
|
1374
955
|
|
|
956
|
+
const auto size = keys.size();
|
|
957
|
+
|
|
1375
958
|
std::vector<rocksdb::Slice> keys2;
|
|
1376
|
-
keys2.reserve(
|
|
959
|
+
keys2.reserve(size);
|
|
1377
960
|
for (const auto& key : keys) {
|
|
1378
961
|
keys2.emplace_back(key);
|
|
1379
962
|
}
|
|
1380
963
|
std::vector<rocksdb::Status> statuses;
|
|
1381
|
-
|
|
1382
|
-
statuses.resize(keys2.size());
|
|
1383
|
-
values.resize(keys2.size());
|
|
1384
964
|
|
|
1385
|
-
|
|
965
|
+
statuses.resize(size);
|
|
966
|
+
values.resize(size);
|
|
1386
967
|
|
|
1387
|
-
|
|
968
|
+
database->db->MultiGet(readOptions, column, size, keys2.data(), values.data(), statuses.data());
|
|
969
|
+
|
|
970
|
+
for (size_t idx = 0; idx < size; idx++) {
|
|
1388
971
|
if (statuses[idx].IsNotFound()) {
|
|
1389
972
|
values[idx] = rocksdb::PinnableSlice(nullptr);
|
|
1390
973
|
} else if (!statuses[idx].ok()) {
|
|
@@ -1394,23 +977,22 @@ NAPI_METHOD(db_get_many) {
|
|
|
1394
977
|
|
|
1395
978
|
return rocksdb::Status::OK();
|
|
1396
979
|
},
|
|
1397
|
-
[=](auto& values,
|
|
1398
|
-
|
|
1399
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
980
|
+
[=](auto& values, auto env, auto& argv) {
|
|
981
|
+
argv.resize(2);
|
|
1400
982
|
|
|
1401
983
|
NAPI_STATUS_RETURN(napi_create_array_with_length(env, values.size(), &argv[1]));
|
|
1402
984
|
|
|
1403
985
|
for (size_t idx = 0; idx < values.size(); idx++) {
|
|
1404
986
|
napi_value element;
|
|
1405
987
|
if (values[idx].GetSelf()) {
|
|
1406
|
-
NAPI_STATUS_RETURN(Convert(env, &values[idx],
|
|
988
|
+
NAPI_STATUS_RETURN(Convert(env, &values[idx], valueEncoding, element));
|
|
1407
989
|
} else {
|
|
1408
990
|
NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
|
|
1409
991
|
}
|
|
1410
992
|
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<uint32_t>(idx), element));
|
|
1411
993
|
}
|
|
1412
994
|
|
|
1413
|
-
return
|
|
995
|
+
return napi_ok;
|
|
1414
996
|
});
|
|
1415
997
|
|
|
1416
998
|
return 0;
|
|
@@ -1422,16 +1004,28 @@ NAPI_METHOD(db_clear) {
|
|
|
1422
1004
|
Database* database;
|
|
1423
1005
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1424
1006
|
|
|
1425
|
-
const auto
|
|
1426
|
-
|
|
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));
|
|
1427
1020
|
|
|
1428
|
-
|
|
1429
|
-
NAPI_STATUS_THROWS(
|
|
1021
|
+
std::optional<std::string> lte;
|
|
1022
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "lte", lte));
|
|
1430
1023
|
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1024
|
+
std::optional<std::string> gt;
|
|
1025
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gt", gt));
|
|
1026
|
+
|
|
1027
|
+
std::optional<std::string> gte;
|
|
1028
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gte", gte));
|
|
1435
1029
|
|
|
1436
1030
|
if (limit == -1) {
|
|
1437
1031
|
rocksdb::PinnableSlice begin;
|
|
@@ -1456,7 +1050,7 @@ NAPI_METHOD(db_clear) {
|
|
|
1456
1050
|
|
|
1457
1051
|
if (begin.compare(end) < 0) {
|
|
1458
1052
|
rocksdb::WriteOptions writeOptions;
|
|
1459
|
-
|
|
1053
|
+
ROCKS_STATUS_THROWS_NAPI(database->db->DeleteRange(writeOptions, column, begin, end));
|
|
1460
1054
|
}
|
|
1461
1055
|
|
|
1462
1056
|
return 0;
|
|
@@ -1464,8 +1058,8 @@ NAPI_METHOD(db_clear) {
|
|
|
1464
1058
|
// TODO (fix): Error handling.
|
|
1465
1059
|
// TODO (fix): This should be async...
|
|
1466
1060
|
|
|
1467
|
-
std::shared_ptr<const rocksdb::Snapshot> snapshot(database->
|
|
1468
|
-
[=](const auto ptr) { database->
|
|
1061
|
+
std::shared_ptr<const rocksdb::Snapshot> snapshot(database->db->GetSnapshot(),
|
|
1062
|
+
[=](const auto ptr) { database->db->ReleaseSnapshot(ptr); });
|
|
1469
1063
|
BaseIterator it(database, column, reverse, lt, lte, gt, gte, limit, false, snapshot);
|
|
1470
1064
|
|
|
1471
1065
|
it.SeekToRange();
|
|
@@ -1489,7 +1083,7 @@ NAPI_METHOD(db_clear) {
|
|
|
1489
1083
|
break;
|
|
1490
1084
|
}
|
|
1491
1085
|
|
|
1492
|
-
status = database->
|
|
1086
|
+
status = database->db->Write(writeOptions, &batch);
|
|
1493
1087
|
if (!status.ok()) {
|
|
1494
1088
|
break;
|
|
1495
1089
|
}
|
|
@@ -1500,7 +1094,7 @@ NAPI_METHOD(db_clear) {
|
|
|
1500
1094
|
it.Close();
|
|
1501
1095
|
|
|
1502
1096
|
if (!status.ok()) {
|
|
1503
|
-
|
|
1097
|
+
ROCKS_STATUS_THROWS_NAPI(status);
|
|
1504
1098
|
}
|
|
1505
1099
|
|
|
1506
1100
|
return 0;
|
|
@@ -1514,10 +1108,10 @@ NAPI_METHOD(db_get_property) {
|
|
|
1514
1108
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1515
1109
|
|
|
1516
1110
|
rocksdb::PinnableSlice property;
|
|
1517
|
-
NAPI_STATUS_THROWS(
|
|
1111
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], property));
|
|
1518
1112
|
|
|
1519
1113
|
std::string value;
|
|
1520
|
-
database->
|
|
1114
|
+
database->db->GetProperty(property, &value);
|
|
1521
1115
|
|
|
1522
1116
|
napi_value result;
|
|
1523
1117
|
NAPI_STATUS_THROWS(napi_create_string_utf8(env, value.data(), value.size(), &result));
|
|
@@ -1531,7 +1125,7 @@ NAPI_METHOD(db_get_latest_sequence) {
|
|
|
1531
1125
|
Database* database;
|
|
1532
1126
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1533
1127
|
|
|
1534
|
-
const auto seq = database->
|
|
1128
|
+
const auto seq = database->db->GetLatestSequenceNumber();
|
|
1535
1129
|
|
|
1536
1130
|
napi_value result;
|
|
1537
1131
|
NAPI_STATUS_THROWS(napi_create_int64(env, seq, &result));
|
|
@@ -1546,35 +1140,59 @@ NAPI_METHOD(iterator_init) {
|
|
|
1546
1140
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1547
1141
|
|
|
1548
1142
|
const auto options = argv[1];
|
|
1549
|
-
const auto reverse = BooleanProperty(env, options, "reverse").value_or(false);
|
|
1550
|
-
const auto keys = BooleanProperty(env, options, "keys").value_or(true);
|
|
1551
|
-
const auto values = BooleanProperty(env, options, "values").value_or(true);
|
|
1552
|
-
const auto fillCache = BooleanProperty(env, options, "fillCache").value_or(false);
|
|
1553
|
-
const bool keyAsBuffer = EncodingIsBuffer(env, options, "keyEncoding");
|
|
1554
|
-
const bool valueAsBuffer = EncodingIsBuffer(env, options, "valueEncoding");
|
|
1555
|
-
const auto limit = Int32Property(env, options, "limit").value_or(-1);
|
|
1556
|
-
const auto highWaterMarkBytes = Uint32Property(env, options, "highWaterMarkBytes").value_or(64 * 1024);
|
|
1557
1143
|
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1144
|
+
bool reverse = false;
|
|
1145
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "reverse", reverse));
|
|
1146
|
+
|
|
1147
|
+
bool keys = true;
|
|
1148
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keys", keys));
|
|
1149
|
+
|
|
1150
|
+
bool values = true;
|
|
1151
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "values", values));
|
|
1152
|
+
|
|
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));
|
|
1562
1173
|
|
|
1563
|
-
|
|
1564
|
-
NAPI_STATUS_THROWS(
|
|
1174
|
+
std::optional<std::string> gt;
|
|
1175
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gt", gt));
|
|
1565
1176
|
|
|
1566
|
-
std::
|
|
1567
|
-
|
|
1177
|
+
std::optional<std::string> gte;
|
|
1178
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "gte", gte));
|
|
1568
1179
|
|
|
1569
|
-
|
|
1570
|
-
|
|
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));
|
|
1571
1189
|
|
|
1572
1190
|
napi_value result;
|
|
1573
1191
|
NAPI_STATUS_THROWS(napi_create_external(env, iterator.get(), Finalize<Iterator>, iterator.get(), &result));
|
|
1574
1192
|
|
|
1575
1193
|
// Prevent GC of JS object before the iterator is closed (explicitly or on
|
|
1576
1194
|
// db close) and keep track of non-closed iterators to end them on db close.
|
|
1577
|
-
iterator.release()->Attach(env, result);
|
|
1195
|
+
NAPI_STATUS_THROWS(iterator.release()->Attach(env, result));
|
|
1578
1196
|
|
|
1579
1197
|
return result;
|
|
1580
1198
|
}
|
|
@@ -1586,7 +1204,7 @@ NAPI_METHOD(iterator_seek) {
|
|
|
1586
1204
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
|
|
1587
1205
|
|
|
1588
1206
|
rocksdb::PinnableSlice target;
|
|
1589
|
-
NAPI_STATUS_THROWS(
|
|
1207
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], target));
|
|
1590
1208
|
|
|
1591
1209
|
iterator->first_ = true;
|
|
1592
1210
|
iterator->Seek(target); // TODO: Does seek causing blocking IO?
|
|
@@ -1600,8 +1218,8 @@ NAPI_METHOD(iterator_close) {
|
|
|
1600
1218
|
Iterator* iterator;
|
|
1601
1219
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
|
|
1602
1220
|
|
|
1603
|
-
iterator->
|
|
1604
|
-
iterator->
|
|
1221
|
+
ROCKS_STATUS_THROWS_NAPI(iterator->Close());
|
|
1222
|
+
NAPI_STATUS_THROWS(iterator->Detach(env));
|
|
1605
1223
|
|
|
1606
1224
|
return 0;
|
|
1607
1225
|
}
|
|
@@ -1636,9 +1254,9 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1636
1254
|
bool finished = false;
|
|
1637
1255
|
};
|
|
1638
1256
|
|
|
1639
|
-
|
|
1640
|
-
std::string("leveldown.iterator.next"), env, callback,
|
|
1641
|
-
[=](auto& state
|
|
1257
|
+
runAsync<State>(
|
|
1258
|
+
std::string("leveldown.iterator.next"), env, callback,
|
|
1259
|
+
[=](auto& state) {
|
|
1642
1260
|
if (!iterator->DidSeek()) {
|
|
1643
1261
|
iterator->SeekToRange();
|
|
1644
1262
|
}
|
|
@@ -1683,9 +1301,8 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1683
1301
|
|
|
1684
1302
|
return iterator->Status();
|
|
1685
1303
|
},
|
|
1686
|
-
[=](auto& state,
|
|
1687
|
-
|
|
1688
|
-
NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
|
|
1304
|
+
[=](auto& state, auto env, auto& argv) {
|
|
1305
|
+
argv.resize(3);
|
|
1689
1306
|
|
|
1690
1307
|
NAPI_STATUS_RETURN(napi_create_array_with_length(env, state.cache.size(), &argv[1]));
|
|
1691
1308
|
|
|
@@ -1693,8 +1310,8 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1693
1310
|
napi_value key;
|
|
1694
1311
|
napi_value val;
|
|
1695
1312
|
|
|
1696
|
-
NAPI_STATUS_RETURN(Convert(env, state.cache[n + 0], iterator->
|
|
1697
|
-
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));
|
|
1698
1315
|
|
|
1699
1316
|
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 0), key));
|
|
1700
1317
|
NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 1), val));
|
|
@@ -1702,7 +1319,7 @@ NAPI_METHOD(iterator_nextv) {
|
|
|
1702
1319
|
|
|
1703
1320
|
NAPI_STATUS_RETURN(napi_get_boolean(env, state.finished, &argv[2]));
|
|
1704
1321
|
|
|
1705
|
-
return
|
|
1322
|
+
return napi_ok;
|
|
1706
1323
|
});
|
|
1707
1324
|
|
|
1708
1325
|
return 0;
|
|
@@ -1716,63 +1333,49 @@ NAPI_METHOD(batch_do) {
|
|
|
1716
1333
|
|
|
1717
1334
|
rocksdb::WriteBatch batch;
|
|
1718
1335
|
|
|
1336
|
+
auto elements = argv[1];
|
|
1337
|
+
|
|
1719
1338
|
uint32_t length;
|
|
1720
|
-
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;
|
|
1721
1344
|
|
|
1722
1345
|
for (uint32_t i = 0; i < length; i++) {
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1346
|
+
type.Reset();
|
|
1347
|
+
key.Reset();
|
|
1348
|
+
value.Reset();
|
|
1726
1349
|
|
|
1727
1350
|
napi_value element;
|
|
1728
|
-
NAPI_STATUS_THROWS(napi_get_element(env,
|
|
1351
|
+
NAPI_STATUS_THROWS(napi_get_element(env, elements, i, &element));
|
|
1729
1352
|
|
|
1730
|
-
|
|
1731
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, element, "type", &typeProperty));
|
|
1732
|
-
NAPI_STATUS_THROWS(ToString(env, typeProperty, type));
|
|
1353
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "type", type, true));
|
|
1733
1354
|
|
|
1734
|
-
rocksdb::ColumnFamilyHandle* column;
|
|
1735
|
-
NAPI_STATUS_THROWS(
|
|
1355
|
+
rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
|
|
1356
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "column", column));
|
|
1736
1357
|
|
|
1737
1358
|
if (type == "del") {
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
NAPI_STATUS_THROWS(ToString(env, keyProperty, key));
|
|
1741
|
-
|
|
1742
|
-
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));
|
|
1743
1361
|
} else if (type == "put") {
|
|
1744
|
-
|
|
1745
|
-
NAPI_STATUS_THROWS(
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
napi_value valueProperty;
|
|
1749
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, element, "value", &valueProperty));
|
|
1750
|
-
NAPI_STATUS_THROWS(ToString(env, valueProperty, value));
|
|
1751
|
-
|
|
1752
|
-
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));
|
|
1753
1365
|
} else if (type == "data") {
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
NAPI_STATUS_THROWS(ToString(env, valueProperty, value));
|
|
1757
|
-
|
|
1758
|
-
ROCKS_STATUS_THROWS(batch.PutLogData(value));
|
|
1366
|
+
NAPI_STATUS_THROWS(GetProperty(env, element, "value", value, true));
|
|
1367
|
+
ROCKS_STATUS_THROWS_NAPI(batch.PutLogData(value));
|
|
1759
1368
|
} else if (type == "merge") {
|
|
1760
|
-
|
|
1761
|
-
NAPI_STATUS_THROWS(
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
napi_value valueProperty;
|
|
1765
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, element, "value", &valueProperty));
|
|
1766
|
-
NAPI_STATUS_THROWS(ToString(env, valueProperty, value));
|
|
1767
|
-
|
|
1768
|
-
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));
|
|
1769
1372
|
} else {
|
|
1770
|
-
|
|
1373
|
+
NAPI_STATUS_THROWS(napi_invalid_arg);
|
|
1771
1374
|
}
|
|
1772
1375
|
}
|
|
1773
1376
|
|
|
1774
1377
|
rocksdb::WriteOptions writeOptions;
|
|
1775
|
-
|
|
1378
|
+
ROCKS_STATUS_THROWS_NAPI(database->db->Write(writeOptions, &batch));
|
|
1776
1379
|
|
|
1777
1380
|
return 0;
|
|
1778
1381
|
}
|
|
@@ -1790,21 +1393,23 @@ NAPI_METHOD(batch_put) {
|
|
|
1790
1393
|
NAPI_ARGV(4);
|
|
1791
1394
|
|
|
1792
1395
|
rocksdb::WriteBatch* batch;
|
|
1793
|
-
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)));
|
|
1794
1397
|
|
|
1795
1398
|
rocksdb::PinnableSlice key;
|
|
1796
|
-
NAPI_STATUS_THROWS(
|
|
1399
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], key));
|
|
1797
1400
|
|
|
1798
1401
|
rocksdb::PinnableSlice val;
|
|
1799
|
-
NAPI_STATUS_THROWS(
|
|
1402
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[2], val));
|
|
1800
1403
|
|
|
1801
|
-
|
|
1802
|
-
|
|
1404
|
+
const auto options = argv[3];
|
|
1405
|
+
|
|
1406
|
+
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1407
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1803
1408
|
|
|
1804
1409
|
if (column) {
|
|
1805
|
-
|
|
1410
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Put(column, key, val));
|
|
1806
1411
|
} else {
|
|
1807
|
-
|
|
1412
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Put(key, val));
|
|
1808
1413
|
}
|
|
1809
1414
|
|
|
1810
1415
|
return 0;
|
|
@@ -1817,15 +1422,17 @@ NAPI_METHOD(batch_del) {
|
|
|
1817
1422
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
|
|
1818
1423
|
|
|
1819
1424
|
rocksdb::PinnableSlice key;
|
|
1820
|
-
NAPI_STATUS_THROWS(
|
|
1425
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], key));
|
|
1426
|
+
|
|
1427
|
+
const auto options = argv[2];
|
|
1821
1428
|
|
|
1822
|
-
rocksdb::ColumnFamilyHandle* column;
|
|
1823
|
-
NAPI_STATUS_THROWS(
|
|
1429
|
+
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1430
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1824
1431
|
|
|
1825
1432
|
if (column) {
|
|
1826
|
-
|
|
1433
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Delete(column, key));
|
|
1827
1434
|
} else {
|
|
1828
|
-
|
|
1435
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Delete(key));
|
|
1829
1436
|
}
|
|
1830
1437
|
|
|
1831
1438
|
return 0;
|
|
@@ -1838,18 +1445,20 @@ NAPI_METHOD(batch_merge) {
|
|
|
1838
1445
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)(&batch)));
|
|
1839
1446
|
|
|
1840
1447
|
rocksdb::PinnableSlice key;
|
|
1841
|
-
NAPI_STATUS_THROWS(
|
|
1448
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], key));
|
|
1842
1449
|
|
|
1843
1450
|
rocksdb::PinnableSlice val;
|
|
1844
|
-
NAPI_STATUS_THROWS(
|
|
1451
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[2], val));
|
|
1452
|
+
|
|
1453
|
+
const auto options = argv[3];
|
|
1845
1454
|
|
|
1846
|
-
rocksdb::ColumnFamilyHandle* column;
|
|
1847
|
-
NAPI_STATUS_THROWS(
|
|
1455
|
+
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1456
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1848
1457
|
|
|
1849
1458
|
if (column) {
|
|
1850
|
-
|
|
1459
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Merge(column, key, val));
|
|
1851
1460
|
} else {
|
|
1852
|
-
|
|
1461
|
+
ROCKS_STATUS_THROWS_NAPI(batch->Merge(key, val));
|
|
1853
1462
|
}
|
|
1854
1463
|
|
|
1855
1464
|
return 0;
|
|
@@ -1876,7 +1485,7 @@ NAPI_METHOD(batch_write) {
|
|
|
1876
1485
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
|
|
1877
1486
|
|
|
1878
1487
|
rocksdb::WriteOptions writeOptions;
|
|
1879
|
-
|
|
1488
|
+
ROCKS_STATUS_THROWS_NAPI(database->db->Write(writeOptions, batch));
|
|
1880
1489
|
|
|
1881
1490
|
return 0;
|
|
1882
1491
|
}
|
|
@@ -1888,9 +1497,9 @@ NAPI_METHOD(batch_put_log_data) {
|
|
|
1888
1497
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&batch)));
|
|
1889
1498
|
|
|
1890
1499
|
rocksdb::PinnableSlice logData;
|
|
1891
|
-
NAPI_STATUS_THROWS(
|
|
1500
|
+
NAPI_STATUS_THROWS(GetValue(env, argv[1], logData));
|
|
1892
1501
|
|
|
1893
|
-
|
|
1502
|
+
ROCKS_STATUS_THROWS_NAPI(batch->PutLogData(logData));
|
|
1894
1503
|
|
|
1895
1504
|
return 0;
|
|
1896
1505
|
}
|
|
@@ -1916,111 +1525,34 @@ NAPI_METHOD(batch_iterate) {
|
|
|
1916
1525
|
rocksdb::WriteBatch* batch;
|
|
1917
1526
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
|
|
1918
1527
|
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
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));
|
|
1923
1535
|
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "values", &valuesProperty));
|
|
1927
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, valuesProperty, &values));
|
|
1536
|
+
bool data = true;
|
|
1537
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "data", data));
|
|
1928
1538
|
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "data", &dataProperty));
|
|
1932
|
-
NAPI_STATUS_THROWS(napi_get_value_bool(env, dataProperty, &data));
|
|
1539
|
+
Encoding keyEncoding = Encoding::String;
|
|
1540
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "keyEncoding", keyEncoding));
|
|
1933
1541
|
|
|
1934
|
-
|
|
1935
|
-
|
|
1542
|
+
Encoding valueEncoding = Encoding::String;
|
|
1543
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "valueEncoding", valueEncoding));
|
|
1936
1544
|
|
|
1937
1545
|
rocksdb::ColumnFamilyHandle* column = nullptr;
|
|
1938
|
-
NAPI_STATUS_THROWS(
|
|
1546
|
+
NAPI_STATUS_THROWS(GetProperty(env, options, "column", column));
|
|
1939
1547
|
|
|
1940
|
-
|
|
1941
|
-
BatchIterator iterator(nullptr, keys, values, data, column, keyAsBuffer, valueAsBuffer);
|
|
1548
|
+
BatchIterator iterator(nullptr, keys, values, data, column, keyEncoding, valueEncoding);
|
|
1942
1549
|
|
|
1550
|
+
napi_value result;
|
|
1943
1551
|
NAPI_STATUS_THROWS(iterator.Iterate(env, *batch, &result));
|
|
1944
1552
|
|
|
1945
1553
|
return result;
|
|
1946
1554
|
}
|
|
1947
1555
|
|
|
1948
|
-
NAPI_METHOD(db_flush_wal) {
|
|
1949
|
-
NAPI_ARGV(2);
|
|
1950
|
-
|
|
1951
|
-
Database* database;
|
|
1952
|
-
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1953
|
-
|
|
1954
|
-
const auto flush = BooleanProperty(env, argv[1], "flush").value_or(false);
|
|
1955
|
-
|
|
1956
|
-
ROCKS_STATUS_THROWS(database->db_->FlushWAL(flush));
|
|
1957
|
-
|
|
1958
|
-
return 0;
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
template <typename T>
|
|
1962
|
-
napi_status FromLogFile(napi_env env, const T& file, napi_value* obj) {
|
|
1963
|
-
NAPI_STATUS_RETURN(napi_create_object(env, obj));
|
|
1964
|
-
|
|
1965
|
-
napi_value pathName;
|
|
1966
|
-
NAPI_STATUS_RETURN(napi_create_string_utf8(env, file->PathName().c_str(), NAPI_AUTO_LENGTH, &pathName));
|
|
1967
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "pathName", pathName));
|
|
1968
|
-
|
|
1969
|
-
napi_value logNumber;
|
|
1970
|
-
NAPI_STATUS_RETURN(napi_create_int64(env, file->LogNumber(), &logNumber));
|
|
1971
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "logNumber", logNumber));
|
|
1972
|
-
|
|
1973
|
-
napi_value type;
|
|
1974
|
-
NAPI_STATUS_RETURN(napi_create_int64(env, file->Type(), &type));
|
|
1975
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "type", type));
|
|
1976
|
-
|
|
1977
|
-
napi_value startSequence;
|
|
1978
|
-
NAPI_STATUS_RETURN(napi_create_int64(env, file->StartSequence(), &startSequence));
|
|
1979
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "startSequence", startSequence));
|
|
1980
|
-
|
|
1981
|
-
napi_value sizeFileBytes;
|
|
1982
|
-
NAPI_STATUS_RETURN(napi_create_int64(env, file->SizeFileBytes(), &sizeFileBytes));
|
|
1983
|
-
NAPI_STATUS_RETURN(napi_set_named_property(env, *obj, "sizeFileBytes", sizeFileBytes));
|
|
1984
|
-
|
|
1985
|
-
return napi_ok;
|
|
1986
|
-
}
|
|
1987
|
-
|
|
1988
|
-
NAPI_METHOD(db_get_sorted_wal_files) {
|
|
1989
|
-
NAPI_ARGV(1);
|
|
1990
|
-
|
|
1991
|
-
Database* database;
|
|
1992
|
-
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
1993
|
-
|
|
1994
|
-
rocksdb::VectorLogPtr files;
|
|
1995
|
-
ROCKS_STATUS_THROWS(database->db_->GetSortedWalFiles(files));
|
|
1996
|
-
|
|
1997
|
-
napi_value ret;
|
|
1998
|
-
NAPI_STATUS_THROWS(napi_create_array_with_length(env, files.size(), &ret));
|
|
1999
|
-
|
|
2000
|
-
for (size_t n = 0; n < files.size(); ++n) {
|
|
2001
|
-
napi_value obj;
|
|
2002
|
-
NAPI_STATUS_THROWS(FromLogFile(env, files[n], &obj));
|
|
2003
|
-
NAPI_STATUS_THROWS(napi_set_element(env, ret, n, obj));
|
|
2004
|
-
}
|
|
2005
|
-
|
|
2006
|
-
return ret;
|
|
2007
|
-
}
|
|
2008
|
-
|
|
2009
|
-
NAPI_METHOD(db_get_current_wal_file) {
|
|
2010
|
-
NAPI_ARGV(1);
|
|
2011
|
-
|
|
2012
|
-
Database* database;
|
|
2013
|
-
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
|
|
2014
|
-
|
|
2015
|
-
std::unique_ptr<rocksdb::LogFile> file;
|
|
2016
|
-
ROCKS_STATUS_THROWS(database->db_->GetCurrentWalFile(&file));
|
|
2017
|
-
|
|
2018
|
-
napi_value ret;
|
|
2019
|
-
NAPI_STATUS_THROWS(FromLogFile(env, file, &ret));
|
|
2020
|
-
|
|
2021
|
-
return ret;
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
1556
|
NAPI_INIT() {
|
|
2025
1557
|
NAPI_EXPORT_FUNCTION(db_init);
|
|
2026
1558
|
NAPI_EXPORT_FUNCTION(db_open);
|
|
@@ -2040,10 +1572,6 @@ NAPI_INIT() {
|
|
|
2040
1572
|
NAPI_EXPORT_FUNCTION(updates_close);
|
|
2041
1573
|
NAPI_EXPORT_FUNCTION(updates_next);
|
|
2042
1574
|
|
|
2043
|
-
NAPI_EXPORT_FUNCTION(db_flush_wal);
|
|
2044
|
-
NAPI_EXPORT_FUNCTION(db_get_sorted_wal_files);
|
|
2045
|
-
NAPI_EXPORT_FUNCTION(db_get_current_wal_file);
|
|
2046
|
-
|
|
2047
1575
|
NAPI_EXPORT_FUNCTION(batch_do);
|
|
2048
1576
|
NAPI_EXPORT_FUNCTION(batch_init);
|
|
2049
1577
|
NAPI_EXPORT_FUNCTION(batch_put);
|