@nxtedition/rocksdb 7.0.63 → 7.0.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.cc +435 -908
- package/binding.gyp +50 -79
- package/deps/rocksdb/rocksdb/db/wal_manager.cc +4 -0
- package/index.js +47 -131
- package/max_rev_operator.h +3 -0
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.node +0 -0
- package/util.h +339 -0
package/util.h
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <assert.h>
|
|
4
|
+
#include <napi-macros.h>
|
|
5
|
+
#include <node_api.h>
|
|
6
|
+
|
|
7
|
+
#include <rocksdb/db.h>
|
|
8
|
+
#include <rocksdb/slice.h>
|
|
9
|
+
#include <rocksdb/status.h>
|
|
10
|
+
|
|
11
|
+
#include <array>
|
|
12
|
+
#include <optional>
|
|
13
|
+
#include <string>
|
|
14
|
+
|
|
15
|
+
#define NAPI_STATUS_RETURN(call) \
|
|
16
|
+
{ \
|
|
17
|
+
auto _status = (call); \
|
|
18
|
+
if (_status != napi_ok) { \
|
|
19
|
+
return _status; \
|
|
20
|
+
} \
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#define ROCKS_STATUS_THROWS_NAPI(call) \
|
|
24
|
+
{ \
|
|
25
|
+
auto _status = (call); \
|
|
26
|
+
if (!_status.ok()) { \
|
|
27
|
+
napi_throw(env, ToError(env, _status)); \
|
|
28
|
+
return NULL; \
|
|
29
|
+
} \
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#define ROCKS_STATUS_RETURN_NAPI(call) \
|
|
33
|
+
{ \
|
|
34
|
+
auto _status = (call); \
|
|
35
|
+
if (!_status.ok()) { \
|
|
36
|
+
napi_throw(env, ToError(env, _status)); \
|
|
37
|
+
return napi_pending_exception; \
|
|
38
|
+
} \
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
template <typename T>
|
|
42
|
+
static void Finalize(napi_env env, void* data, void* hint) {
|
|
43
|
+
if (hint) {
|
|
44
|
+
delete reinterpret_cast<T*>(hint);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static napi_value CreateError(napi_env env, const std::optional<std::string_view>& code, const std::string_view& msg) {
|
|
49
|
+
napi_value codeValue = nullptr;
|
|
50
|
+
if (code) {
|
|
51
|
+
NAPI_STATUS_THROWS(napi_create_string_utf8(env, code->data(), code->size(), &codeValue));
|
|
52
|
+
}
|
|
53
|
+
napi_value msgValue;
|
|
54
|
+
NAPI_STATUS_THROWS(napi_create_string_utf8(env, msg.data(), msg.size(), &msgValue));
|
|
55
|
+
napi_value error;
|
|
56
|
+
NAPI_STATUS_THROWS(napi_create_error(env, codeValue, msgValue, &error));
|
|
57
|
+
return error;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static napi_value ToError(napi_env env, const rocksdb::Status& status) {
|
|
61
|
+
if (status.ok()) {
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const auto msg = status.ToString();
|
|
66
|
+
|
|
67
|
+
if (status.IsNotFound()) {
|
|
68
|
+
return CreateError(env, "LEVEL_NOT_FOUND", msg);
|
|
69
|
+
} else if (status.IsCorruption()) {
|
|
70
|
+
return CreateError(env, "LEVEL_CORRUPTION", msg);
|
|
71
|
+
} else if (status.IsTryAgain()) {
|
|
72
|
+
return CreateError(env, "LEVEL_TRYAGAIN", msg);
|
|
73
|
+
} else if (status.IsIOError()) {
|
|
74
|
+
if (msg.find("IO error: lock ") != std::string::npos) { // env_posix.cc
|
|
75
|
+
return CreateError(env, "LEVEL_LOCKED", msg);
|
|
76
|
+
} else if (msg.find("IO error: LockFile ") != std::string::npos) { // env_win.cc
|
|
77
|
+
return CreateError(env, "LEVEL_LOCKED", msg);
|
|
78
|
+
} else if (msg.find("IO error: While lock file") != std::string::npos) { // env_mac.cc
|
|
79
|
+
return CreateError(env, "LEVEL_LOCKED", msg);
|
|
80
|
+
} else {
|
|
81
|
+
return CreateError(env, "LEVEL_IO_ERROR", msg);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return CreateError(env, {}, msg);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static napi_status GetString(napi_env env, napi_value from, std::string& to) {
|
|
89
|
+
napi_valuetype type;
|
|
90
|
+
NAPI_STATUS_RETURN(napi_typeof(env, from, &type));
|
|
91
|
+
|
|
92
|
+
if (type == napi_string) {
|
|
93
|
+
size_t length = 0;
|
|
94
|
+
NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, nullptr, 0, &length));
|
|
95
|
+
to.resize(length, '\0');
|
|
96
|
+
NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, &to[0], length + 1, &length));
|
|
97
|
+
} else {
|
|
98
|
+
bool isBuffer;
|
|
99
|
+
NAPI_STATUS_RETURN(napi_is_buffer(env, from, &isBuffer));
|
|
100
|
+
|
|
101
|
+
if (isBuffer) {
|
|
102
|
+
char* buf = nullptr;
|
|
103
|
+
size_t length = 0;
|
|
104
|
+
NAPI_STATUS_RETURN(napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length));
|
|
105
|
+
to.assign(buf, length);
|
|
106
|
+
} else {
|
|
107
|
+
return napi_invalid_arg;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return napi_ok;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
class NapiSlice : public rocksdb::Slice {
|
|
115
|
+
public:
|
|
116
|
+
NapiSlice() {}
|
|
117
|
+
|
|
118
|
+
NapiSlice(NapiSlice&& other) = delete;
|
|
119
|
+
NapiSlice& operator=(NapiSlice&& other) = delete;
|
|
120
|
+
|
|
121
|
+
NapiSlice(NapiSlice&) = delete;
|
|
122
|
+
NapiSlice& operator=(NapiSlice&) = delete;
|
|
123
|
+
|
|
124
|
+
std::string self_space_;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
static napi_status GetString(napi_env env, napi_value from, NapiSlice& to) {
|
|
128
|
+
napi_valuetype type;
|
|
129
|
+
NAPI_STATUS_RETURN(napi_typeof(env, from, &type));
|
|
130
|
+
|
|
131
|
+
if (type == napi_string) {
|
|
132
|
+
size_t length = 0;
|
|
133
|
+
NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, nullptr, 0, &length));
|
|
134
|
+
to.self_space_.resize(length, '\0');
|
|
135
|
+
NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, &to.self_space_[0], length + 1, &length));
|
|
136
|
+
|
|
137
|
+
to.data_ = to.self_space_.data();
|
|
138
|
+
to.size_ = length;
|
|
139
|
+
} else {
|
|
140
|
+
bool isBuffer;
|
|
141
|
+
NAPI_STATUS_RETURN(napi_is_buffer(env, from, &isBuffer));
|
|
142
|
+
|
|
143
|
+
if (isBuffer) {
|
|
144
|
+
char* buf = nullptr;
|
|
145
|
+
size_t length = 0;
|
|
146
|
+
NAPI_STATUS_RETURN(napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length));
|
|
147
|
+
|
|
148
|
+
to.data_ = buf;
|
|
149
|
+
to.size_ = length;
|
|
150
|
+
} else {
|
|
151
|
+
return napi_invalid_arg;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return napi_ok;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
enum class Encoding { Invalid, Buffer, String };
|
|
159
|
+
|
|
160
|
+
static napi_status GetValue(napi_env env, napi_value value, bool& result) {
|
|
161
|
+
return napi_get_value_bool(env, value, &result);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
static napi_status GetValue(napi_env env, napi_value value, uint32_t& result) {
|
|
165
|
+
return napi_get_value_uint32(env, value, &result);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static napi_status GetValue(napi_env env, napi_value value, int32_t& result) {
|
|
169
|
+
return napi_get_value_int32(env, value, &result);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
static napi_status GetValue(napi_env env, napi_value value, int64_t& result) {
|
|
173
|
+
return napi_get_value_int64(env, value, &result);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static napi_status GetValue(napi_env env, napi_value value, uint64_t& result) {
|
|
177
|
+
int64_t result2;
|
|
178
|
+
NAPI_STATUS_RETURN(napi_get_value_int64(env, value, &result2));
|
|
179
|
+
result = static_cast<uint64_t>(result2);
|
|
180
|
+
return napi_ok;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static napi_status GetValue(napi_env env, napi_value value, std::string& result) {
|
|
184
|
+
return GetString(env, value, result);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
static napi_status GetValue(napi_env env, napi_value value, NapiSlice& result) {
|
|
188
|
+
return GetString(env, value, result);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static napi_status GetValue(napi_env env, napi_value value, rocksdb::ColumnFamilyHandle*& result) {
|
|
192
|
+
return napi_get_value_external(env, value, reinterpret_cast<void**>(&result));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
static napi_status GetValue(napi_env env, napi_value value, Encoding& result) {
|
|
196
|
+
size_t size;
|
|
197
|
+
NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, value, nullptr, 0, &size));
|
|
198
|
+
|
|
199
|
+
if (size == 6) {
|
|
200
|
+
result = Encoding::Buffer;
|
|
201
|
+
} else {
|
|
202
|
+
result = Encoding::String;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return napi_ok;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
template <typename T>
|
|
209
|
+
static napi_status GetValue(napi_env env, napi_value value, std::optional<T>& result) {
|
|
210
|
+
result = T{};
|
|
211
|
+
return GetValue(env, value, *result);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
template <typename T>
|
|
215
|
+
static napi_status GetProperty(napi_env env,
|
|
216
|
+
napi_value obj,
|
|
217
|
+
const std::string_view& key,
|
|
218
|
+
T& result,
|
|
219
|
+
bool required = false) {
|
|
220
|
+
bool has = false;
|
|
221
|
+
NAPI_STATUS_RETURN(napi_has_named_property(env, obj, key.data(), &has));
|
|
222
|
+
|
|
223
|
+
if (!has) {
|
|
224
|
+
return required ? napi_invalid_arg : napi_ok;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
napi_value value;
|
|
228
|
+
NAPI_STATUS_RETURN(napi_get_named_property(env, obj, key.data(), &value));
|
|
229
|
+
|
|
230
|
+
bool nully = false;
|
|
231
|
+
|
|
232
|
+
napi_value nullVal;
|
|
233
|
+
NAPI_STATUS_RETURN(napi_get_null(env, &nullVal));
|
|
234
|
+
NAPI_STATUS_RETURN(napi_strict_equals(env, nullVal, value, &nully));
|
|
235
|
+
if (nully) {
|
|
236
|
+
return required ? napi_invalid_arg : napi_ok;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
napi_value undefinedVal;
|
|
240
|
+
NAPI_STATUS_RETURN(napi_get_undefined(env, &undefinedVal));
|
|
241
|
+
NAPI_STATUS_RETURN(napi_strict_equals(env, undefinedVal, value, &nully));
|
|
242
|
+
if (nully) {
|
|
243
|
+
return required ? napi_invalid_arg : napi_ok;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return GetValue(env, value, result);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
template <typename T>
|
|
250
|
+
napi_status Convert(napi_env env, T&& s, Encoding encoding, napi_value& result) {
|
|
251
|
+
if (!s) {
|
|
252
|
+
return napi_get_null(env, &result);
|
|
253
|
+
} else if (encoding == Encoding::Buffer) {
|
|
254
|
+
// napi_create_external_buffer would be nice but is unsafe since node
|
|
255
|
+
// buffers are not read-only.
|
|
256
|
+
return napi_create_buffer_copy(env, s->size(), s->data(), nullptr, &result);
|
|
257
|
+
} else if (encoding == Encoding::String) {
|
|
258
|
+
return napi_create_string_utf8(env, s->data(), s->size(), &result);
|
|
259
|
+
} else {
|
|
260
|
+
return napi_invalid_arg;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
template <typename State, typename T1, typename T2>
|
|
265
|
+
napi_status runAsync(const std::string& name, napi_env env, napi_value callback, T1&& execute, T2&& then) {
|
|
266
|
+
struct Worker final {
|
|
267
|
+
static void Execute(napi_env env, void* data) {
|
|
268
|
+
auto worker = reinterpret_cast<Worker*>(data);
|
|
269
|
+
worker->status = worker->execute(worker->state);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
static void Complete(napi_env env, napi_status status, void* data) {
|
|
273
|
+
auto worker = std::unique_ptr<Worker>(reinterpret_cast<Worker*>(data));
|
|
274
|
+
|
|
275
|
+
napi_value callback;
|
|
276
|
+
NAPI_STATUS_THROWS_VOID(napi_get_reference_value(env, worker->callbackRef, &callback));
|
|
277
|
+
|
|
278
|
+
napi_value global;
|
|
279
|
+
NAPI_STATUS_THROWS_VOID(napi_get_global(env, &global));
|
|
280
|
+
|
|
281
|
+
if (worker->status.ok()) {
|
|
282
|
+
std::vector<napi_value> argv;
|
|
283
|
+
|
|
284
|
+
argv.resize(1);
|
|
285
|
+
NAPI_STATUS_THROWS_VOID(napi_get_null(env, &argv[0]));
|
|
286
|
+
|
|
287
|
+
const auto ret = worker->then(worker->state, env, argv);
|
|
288
|
+
|
|
289
|
+
if (ret == napi_ok) {
|
|
290
|
+
NAPI_STATUS_THROWS_VOID(napi_call_function(env, global, callback, argv.size(), argv.data(), nullptr));
|
|
291
|
+
} else {
|
|
292
|
+
const napi_extended_error_info* errInfo = nullptr;
|
|
293
|
+
NAPI_STATUS_THROWS_VOID(napi_get_last_error_info(env, &errInfo));
|
|
294
|
+
auto err = CreateError(env, std::nullopt,
|
|
295
|
+
!errInfo || !errInfo->error_message ? "empty error message" : errInfo->error_message);
|
|
296
|
+
NAPI_STATUS_THROWS_VOID(napi_call_function(env, global, callback, 1, &err, nullptr));
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
auto err = ToError(env, worker->status);
|
|
300
|
+
NAPI_STATUS_THROWS_VOID(napi_call_function(env, global, callback, 1, &err, nullptr));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
~Worker() {
|
|
305
|
+
if (callbackRef) {
|
|
306
|
+
napi_delete_reference(env, callbackRef);
|
|
307
|
+
callbackRef = nullptr;
|
|
308
|
+
}
|
|
309
|
+
if (asyncWork) {
|
|
310
|
+
napi_delete_async_work(env, asyncWork);
|
|
311
|
+
asyncWork = nullptr;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
napi_env env = nullptr;
|
|
316
|
+
|
|
317
|
+
typename std::decay<T1>::type execute;
|
|
318
|
+
typename std::decay<T2>::type then;
|
|
319
|
+
|
|
320
|
+
napi_ref callbackRef = nullptr;
|
|
321
|
+
napi_async_work asyncWork = nullptr;
|
|
322
|
+
rocksdb::Status status = rocksdb::Status::OK();
|
|
323
|
+
State state = State();
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
auto worker = std::unique_ptr<Worker>(new Worker{env, std::forward<T1>(execute), std::forward<T2>(then)});
|
|
327
|
+
|
|
328
|
+
NAPI_STATUS_RETURN(napi_create_reference(env, callback, 1, &worker->callbackRef));
|
|
329
|
+
napi_value asyncResourceName;
|
|
330
|
+
NAPI_STATUS_RETURN(napi_create_string_utf8(env, name.data(), name.size(), &asyncResourceName));
|
|
331
|
+
NAPI_STATUS_RETURN(napi_create_async_work(env, callback, asyncResourceName, Worker::Execute, Worker::Complete,
|
|
332
|
+
worker.get(), &worker->asyncWork));
|
|
333
|
+
|
|
334
|
+
NAPI_STATUS_RETURN(napi_queue_async_work(env, worker->asyncWork));
|
|
335
|
+
|
|
336
|
+
worker.release();
|
|
337
|
+
|
|
338
|
+
return napi_ok;
|
|
339
|
+
}
|