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