@ohos-ports/lmdb 2.5.3 → 2.8.5-beta.0
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/LICENSE +20 -20
- package/README.md +72 -28
- package/SECURITY.md +12 -12
- package/bin/download-prebuilds.js +15 -0
- package/binding.gyp +115 -111
- package/build/Release/lmdb.node +0 -0
- package/caching.js +212 -156
- package/dependencies/lmdb/libraries/liblmdb/COPYRIGHT +20 -20
- package/dependencies/lmdb/libraries/liblmdb/Doxyfile +1631 -1631
- package/dependencies/lmdb/libraries/liblmdb/LICENSE +47 -47
- package/dependencies/lmdb/libraries/liblmdb/Makefile +136 -136
- package/dependencies/lmdb/libraries/liblmdb/chacha8.c +183 -183
- package/dependencies/lmdb/libraries/liblmdb/chacha8.h +14 -14
- package/dependencies/lmdb/libraries/liblmdb/crypto.c +121 -121
- package/dependencies/lmdb/libraries/liblmdb/intro.doc +192 -192
- package/dependencies/lmdb/libraries/liblmdb/lmdb.h +28 -3
- package/dependencies/lmdb/libraries/liblmdb/mdb.c +157 -31
- package/dependencies/lmdb/libraries/liblmdb/mdb_copy.1 +74 -74
- package/dependencies/lmdb/libraries/liblmdb/mdb_copy.c +106 -106
- package/dependencies/lmdb/libraries/liblmdb/mdb_drop.1 +53 -53
- package/dependencies/lmdb/libraries/liblmdb/mdb_drop.c +154 -154
- package/dependencies/lmdb/libraries/liblmdb/mdb_dump.1 +94 -94
- package/dependencies/lmdb/libraries/liblmdb/mdb_dump.c +333 -333
- package/dependencies/lmdb/libraries/liblmdb/mdb_load.1 +97 -97
- package/dependencies/lmdb/libraries/liblmdb/mdb_load.c +530 -530
- package/dependencies/lmdb/libraries/liblmdb/mdb_stat.1 +83 -83
- package/dependencies/lmdb/libraries/liblmdb/mdb_stat.c +276 -276
- package/dependencies/lmdb/libraries/liblmdb/midl-sparse.c +452 -0
- package/dependencies/lmdb/libraries/liblmdb/midl.c +452 -452
- package/dependencies/lmdb/libraries/liblmdb/midl.h +208 -208
- package/dependencies/lmdb/libraries/liblmdb/module.c +101 -101
- package/dependencies/lmdb/libraries/liblmdb/module.h +16 -16
- package/dependencies/lmdb/libraries/liblmdb/mtest.c +178 -178
- package/dependencies/lmdb/libraries/liblmdb/mtest2.c +124 -124
- package/dependencies/lmdb/libraries/liblmdb/mtest3.c +133 -133
- package/dependencies/lmdb/libraries/liblmdb/mtest4.c +168 -168
- package/dependencies/lmdb/libraries/liblmdb/mtest5.c +135 -135
- package/dependencies/lmdb/libraries/liblmdb/mtest6.c +141 -141
- package/dependencies/lmdb/libraries/liblmdb/mtest_enc.c +190 -190
- package/dependencies/lmdb/libraries/liblmdb/mtest_enc2.c +189 -189
- package/dependencies/lmdb/libraries/liblmdb/mtest_remap.c +177 -177
- package/dependencies/lmdb/libraries/liblmdb/sample-bdb.txt +73 -73
- package/dependencies/lmdb/libraries/liblmdb/sample-mdb.txt +62 -62
- package/dependencies/lmdb/libraries/liblmdb/tooltag +27 -27
- package/dependencies/lmdb-data-v1/libraries/liblmdb/CHANGES +266 -0
- package/dependencies/lmdb-data-v1/libraries/liblmdb/COPYRIGHT +20 -20
- package/dependencies/lmdb-data-v1/libraries/liblmdb/Doxyfile +1631 -1631
- package/dependencies/lmdb-data-v1/libraries/liblmdb/LICENSE +47 -47
- package/dependencies/lmdb-data-v1/libraries/liblmdb/intro.doc +192 -192
- package/dependencies/lmdb-data-v1/libraries/liblmdb/lmdb.h +1608 -1653
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb.c +10320 -11359
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.1 +55 -61
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.c +82 -84
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.1 +75 -81
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.c +319 -319
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.1 +84 -84
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.c +496 -492
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.1 +64 -70
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.c +263 -264
- package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.c +359 -421
- package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.h +186 -200
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest.c +177 -177
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest2.c +124 -124
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest3.c +133 -133
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest4.c +168 -168
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest5.c +135 -135
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest6.c +141 -141
- package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-bdb.txt +73 -73
- package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-mdb.txt +62 -62
- package/dependencies/lmdb-data-v1/libraries/liblmdb/tooltag +22 -27
- package/dependencies/lz4/LICENSE +11 -11
- package/dependencies/lz4/lib/LICENSE +24 -24
- package/dependencies/lz4/lib/Makefile +225 -0
- package/dependencies/lz4/lib/README.md +169 -137
- package/dependencies/lz4/lib/dll/example/Makefile +63 -0
- package/dependencies/lz4/lib/dll/example/README.md +69 -69
- package/dependencies/lz4/lib/dll/liblz4.def +62 -62
- package/dependencies/lz4/lib/liblz4-dll.rc.in +35 -35
- package/dependencies/lz4/lib/liblz4.pc.in +14 -14
- package/dependencies/lz4/lib/lz4.c +2722 -2495
- package/dependencies/lz4/lib/lz4.h +842 -774
- package/dependencies/lz4/lib/lz4file.c +311 -0
- package/dependencies/lz4/lib/lz4file.h +93 -0
- package/dependencies/lz4/lib/lz4frame.c +2078 -1899
- package/dependencies/lz4/lib/lz4frame.h +692 -623
- package/dependencies/lz4/lib/lz4frame_static.h +47 -47
- package/dependencies/lz4/lib/lz4hc.c +1631 -1615
- package/dependencies/lz4/lib/lz4hc.h +413 -413
- package/dependencies/lz4/lib/xxhash.c +1030 -1030
- package/dependencies/lz4/lib/xxhash.h +328 -328
- package/dependencies/v8/v8-fast-api-calls-v16.h +790 -790
- package/dependencies/v8/v8-fast-api-calls.h +784 -888
- package/dist/index.cjs +1050 -584
- package/dist/index.cjs.map +1 -1
- package/index.d.cts +420 -0
- package/index.d.ts +450 -385
- package/index.js +38 -37
- package/keys.js +116 -102
- package/level.js +26 -26
- package/native.js +8 -5
- package/node-index.js +21 -17
- package/open.js +51 -17
- package/package.json +63 -21
- package/read.js +338 -95
- package/src/compression.cpp +12 -9
- package/src/cursor.cpp +82 -31
- package/src/dbi.cpp +78 -40
- package/src/env.cpp +336 -68
- package/src/lmdb-js.cpp +64 -64
- package/src/lmdb-js.h +83 -49
- package/src/misc.cpp +297 -28
- package/src/ordered-binary.cpp +46 -46
- package/src/txn.cpp +210 -257
- package/src/v8-functions.cpp +170 -166
- package/src/windows.c +34 -34
- package/src/writer.cpp +169 -84
- package/util/RangeIterable.js +112 -17
- package/util/set-optional-deps.cjs +14 -10
- package/util/when.js +8 -8
- package/write.js +145 -121
- package/dependencies/lmdb-data-v1/libraries/liblmdb/Makefile +0 -118
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.1 +0 -40
- package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.c +0 -135
- package/rollup.config.js +0 -12
package/src/writer.cpp
CHANGED
|
@@ -13,6 +13,7 @@ inline value?
|
|
|
13
13
|
*/
|
|
14
14
|
#include "lmdb-js.h"
|
|
15
15
|
#include <atomic>
|
|
16
|
+
#include <ctime>
|
|
16
17
|
#ifndef _WIN32
|
|
17
18
|
#include <unistd.h>
|
|
18
19
|
#endif
|
|
@@ -34,6 +35,8 @@ const int HAS_KEY = 4;
|
|
|
34
35
|
const int HAS_VALUE = 2;
|
|
35
36
|
const int CONDITIONAL = 8;
|
|
36
37
|
const int CONDITIONAL_VERSION = 0x100;
|
|
38
|
+
const int CONDITIONAL_VERSION_LESS_THAN = 0x800;
|
|
39
|
+
const int CONDITIONAL_ALLOW_NOTFOUND = 0x1000;
|
|
37
40
|
const int SET_VERSION = 0x200;
|
|
38
41
|
//const int HAS_INLINE_VALUE = 0x400;
|
|
39
42
|
const int COMPRESSIBLE = 0x100000;
|
|
@@ -62,25 +65,13 @@ WriteWorker::WriteWorker(MDB_env* env, EnvWrap* envForTxn, uint32_t* instruction
|
|
|
62
65
|
env(env) {
|
|
63
66
|
//fprintf(stdout, "nextCompressibleArg %p\n", nextCompressibleArg);
|
|
64
67
|
interruptionStatus = 0;
|
|
68
|
+
resultCode = 0;
|
|
65
69
|
txn = nullptr;
|
|
66
70
|
}
|
|
67
71
|
|
|
68
|
-
AsyncWriteWorker::AsyncWriteWorker(MDB_env* env, EnvWrap* envForTxn, uint32_t* instructions, const Function& callback)
|
|
69
|
-
: WriteWorker(env, envForTxn, instructions), AsyncProgressWorker(callback, "lmdb:write") {
|
|
70
|
-
//fprintf(stdout, "nextCompressibleArg %p\n", nextCompressibleArg);
|
|
71
|
-
interruptionStatus = 0;
|
|
72
|
-
txn = nullptr;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
void AsyncWriteWorker::Execute(const AsyncProgressWorker::ExecutionProgress& execution) {
|
|
76
|
-
executionProgress = (AsyncProgressWorker::ExecutionProgress*) &execution;
|
|
77
|
-
Write();
|
|
78
|
-
}
|
|
79
72
|
void WriteWorker::SendUpdate() {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
void AsyncWriteWorker::SendUpdate() {
|
|
83
|
-
executionProgress->Send(nullptr, 0);
|
|
73
|
+
if (WriteWorker::threadSafeCallsEnabled)
|
|
74
|
+
napi_call_threadsafe_function(progress, nullptr, napi_tsfn_blocking);
|
|
84
75
|
}
|
|
85
76
|
MDB_txn* WriteWorker::AcquireTxn(int* flags) {
|
|
86
77
|
bool commitSynchronously = *flags & TXN_SYNCHRONOUS_COMMIT;
|
|
@@ -89,16 +80,17 @@ MDB_txn* WriteWorker::AcquireTxn(int* flags) {
|
|
|
89
80
|
pthread_mutex_lock(envForTxn->writingLock);
|
|
90
81
|
retry:
|
|
91
82
|
if (commitSynchronously && interruptionStatus == WORKER_WAITING) {
|
|
92
|
-
//fprintf(stderr, "acquire interupting lock %p %u\n", this, commitSynchronously);
|
|
93
83
|
interruptionStatus = INTERRUPT_BATCH;
|
|
94
84
|
pthread_cond_signal(envForTxn->writingCond);
|
|
95
85
|
pthread_cond_wait(envForTxn->writingCond, envForTxn->writingLock);
|
|
96
86
|
if (interruptionStatus == RESTART_WORKER_TXN) {
|
|
97
87
|
*flags |= TXN_FROM_WORKER;
|
|
98
88
|
return nullptr;
|
|
89
|
+
} else if (interruptionStatus == WORKER_WAITING || interruptionStatus == INTERRUPT_BATCH) {
|
|
90
|
+
interruptionStatus = WORKER_WAITING;
|
|
91
|
+
goto retry;
|
|
99
92
|
} else {
|
|
100
|
-
|
|
101
|
-
goto retry;
|
|
93
|
+
return nullptr;
|
|
102
94
|
}
|
|
103
95
|
} else {
|
|
104
96
|
//if (interruptionStatus == RESTART_WORKER_TXN)
|
|
@@ -112,48 +104,48 @@ MDB_txn* WriteWorker::AcquireTxn(int* flags) {
|
|
|
112
104
|
}
|
|
113
105
|
|
|
114
106
|
void WriteWorker::UnlockTxn() {
|
|
115
|
-
//fprintf(stderr, "release txn %u\n", interruptionStatus);
|
|
116
107
|
interruptionStatus = 0;
|
|
117
108
|
pthread_cond_signal(envForTxn->writingCond);
|
|
118
109
|
pthread_mutex_unlock(envForTxn->writingLock);
|
|
119
110
|
}
|
|
120
|
-
void WriteWorker::ReportError(const char* error) {
|
|
121
|
-
hasError = true;
|
|
122
|
-
fprintf(stderr, "Error %s\n", error);
|
|
123
|
-
}
|
|
124
|
-
void AsyncWriteWorker::ReportError(const char* error) {
|
|
125
|
-
hasError = true;
|
|
126
|
-
SetError(error);
|
|
127
|
-
}
|
|
128
111
|
int WriteWorker::WaitForCallbacks(MDB_txn** txn, bool allowCommit, uint32_t* target) {
|
|
129
112
|
int rc;
|
|
130
|
-
//fprintf(stderr, "wait for callback %p\n", target);
|
|
131
113
|
if (!finishedProgress)
|
|
132
114
|
SendUpdate();
|
|
133
115
|
pthread_cond_signal(envForTxn->writingCond);
|
|
134
116
|
interruptionStatus = WORKER_WAITING;
|
|
117
|
+
uint64_t start;
|
|
118
|
+
if (envForTxn->trackMetrics)
|
|
119
|
+
start = get_time64();
|
|
135
120
|
if (target) {
|
|
136
121
|
uint64_t delay = 1;
|
|
137
122
|
do {
|
|
138
123
|
cond_timedwait(envForTxn->writingCond, envForTxn->writingLock, delay);
|
|
139
124
|
delay = delay << 1ll;
|
|
140
|
-
//if (delay > 500)
|
|
141
|
-
//fprintf(stderr, "waited, %llu %p\n", delay, *target);
|
|
142
125
|
if ((*target & 0xf) || (allowCommit && finishedProgress)) {
|
|
143
126
|
// we are in position to continue writing or commit, so forward progress can be made without interrupting yet
|
|
127
|
+
if (envForTxn->trackMetrics) {
|
|
128
|
+
envForTxn->timeTxnWaiting += get_time64() - start;
|
|
129
|
+
}
|
|
144
130
|
interruptionStatus = 0;
|
|
145
131
|
return 0;
|
|
146
132
|
}
|
|
147
133
|
} while(interruptionStatus != INTERRUPT_BATCH);
|
|
148
|
-
} else
|
|
134
|
+
} else {
|
|
149
135
|
pthread_cond_wait(envForTxn->writingCond, envForTxn->writingLock);
|
|
136
|
+
}
|
|
137
|
+
if (envForTxn->trackMetrics) {
|
|
138
|
+
envForTxn->timeTxnWaiting += get_time64() - start;
|
|
139
|
+
}
|
|
150
140
|
if (interruptionStatus == INTERRUPT_BATCH) { // interrupted by JS code that wants to run a synchronous transaction
|
|
151
|
-
// fprintf(stderr, "Performing batch interruption %u\n", allowCommit);
|
|
152
141
|
interruptionStatus = RESTART_WORKER_TXN;
|
|
153
142
|
rc = mdb_txn_commit(*txn);
|
|
143
|
+
#ifdef MDB_EMPTY_TXN
|
|
144
|
+
if (rc == MDB_EMPTY_TXN)
|
|
145
|
+
rc = 0;
|
|
146
|
+
#endif
|
|
154
147
|
if (rc == 0) {
|
|
155
148
|
// wait again until the sync transaction is completed
|
|
156
|
-
//fprintf(stderr, "Waiting after interruption\n");
|
|
157
149
|
this->txn = *txn = nullptr;
|
|
158
150
|
pthread_cond_signal(envForTxn->writingCond);
|
|
159
151
|
pthread_cond_wait(envForTxn->writingCond, envForTxn->writingLock);
|
|
@@ -179,15 +171,16 @@ int WriteWorker::DoWrites(MDB_txn* txn, EnvWrap* envForTxn, uint32_t* instructio
|
|
|
179
171
|
double conditionalVersion, setVersion = 0;
|
|
180
172
|
bool overlappedWord = !!worker;
|
|
181
173
|
uint32_t* start;
|
|
182
|
-
|
|
174
|
+
do {
|
|
183
175
|
next_inst: start = instruction++;
|
|
184
176
|
uint32_t flags = *start;
|
|
185
177
|
MDB_dbi dbi = 0;
|
|
178
|
+
//fprintf(stderr, "do %u %u\n", flags, get_time64());
|
|
186
179
|
bool validated = conditionDepth == validatedDepth;
|
|
187
180
|
if (flags & 0xf0c0) {
|
|
188
181
|
fprintf(stderr, "Unknown flag bits %u %p\n", flags, start);
|
|
189
182
|
fprintf(stderr, "flags after message %u\n", *start);
|
|
190
|
-
worker->
|
|
183
|
+
worker->resultCode = 22;
|
|
191
184
|
return 0;
|
|
192
185
|
}
|
|
193
186
|
if (flags & HAS_KEY) {
|
|
@@ -228,12 +221,17 @@ next_inst: start = instruction++;
|
|
|
228
221
|
instruction += 2;
|
|
229
222
|
MDB_val conditionalValue;
|
|
230
223
|
rc = mdb_get(txn, dbi, &key, &conditionalValue);
|
|
231
|
-
if (rc)
|
|
232
|
-
|
|
233
|
-
|
|
224
|
+
if (rc) {
|
|
225
|
+
// not found counts as version 0, so this is acceptable for conditional less than,
|
|
226
|
+
// otherwise does not validate
|
|
227
|
+
if (rc == MDB_NOTFOUND)
|
|
228
|
+
validated = flags & CONDITIONAL_ALLOW_NOTFOUND;
|
|
229
|
+
else
|
|
230
|
+
worker->resultCode = rc;
|
|
231
|
+
} else if (conditionalVersion != ANY_VERSION) {
|
|
234
232
|
double version;
|
|
235
233
|
memcpy(&version, conditionalValue.mv_data, 8);
|
|
236
|
-
validated = validated && conditionalVersion ==
|
|
234
|
+
validated = validated && ((flags & CONDITIONAL_VERSION_LESS_THAN) ? version <= conditionalVersion : (version == conditionalVersion));
|
|
237
235
|
}
|
|
238
236
|
}
|
|
239
237
|
if (flags & SET_VERSION) {
|
|
@@ -242,7 +240,12 @@ next_inst: start = instruction++;
|
|
|
242
240
|
}
|
|
243
241
|
if ((flags & IF_NO_EXISTS) && (flags & START_CONDITION_BLOCK)) {
|
|
244
242
|
rc = mdb_get(txn, dbi, &key, &value);
|
|
245
|
-
|
|
243
|
+
if (!rc)
|
|
244
|
+
validated = false;
|
|
245
|
+
else if (rc == MDB_NOTFOUND)
|
|
246
|
+
validated = true;
|
|
247
|
+
else
|
|
248
|
+
worker->resultCode = rc;
|
|
246
249
|
}
|
|
247
250
|
} else
|
|
248
251
|
instruction++;
|
|
@@ -283,7 +286,7 @@ next_inst: start = instruction++;
|
|
|
283
286
|
else
|
|
284
287
|
rc = mdb_put(txn, dbi, &key, &value, flags & (MDB_NOOVERWRITE | MDB_NODUPDATA | MDB_APPEND | MDB_APPENDDUP));
|
|
285
288
|
if (flags & COMPRESSIBLE)
|
|
286
|
-
|
|
289
|
+
delete value.mv_data;
|
|
287
290
|
//fprintf(stdout, "put %u \n", key.mv_size);
|
|
288
291
|
break;
|
|
289
292
|
case DEL:
|
|
@@ -292,7 +295,7 @@ next_inst: start = instruction++;
|
|
|
292
295
|
case DEL_VALUE:
|
|
293
296
|
rc = mdb_del(txn, dbi, &key, &value);
|
|
294
297
|
if (flags & COMPRESSIBLE)
|
|
295
|
-
|
|
298
|
+
delete value.mv_data;
|
|
296
299
|
break;
|
|
297
300
|
case START_BLOCK: case START_CONDITION_BLOCK:
|
|
298
301
|
rc = validated ? 0 : MDB_NOTFOUND;
|
|
@@ -320,13 +323,13 @@ next_inst: start = instruction++;
|
|
|
320
323
|
default:
|
|
321
324
|
fprintf(stderr, "Unknown flags %u %p\n", flags, start);
|
|
322
325
|
fprintf(stderr, "flags after message %u\n", *start);
|
|
323
|
-
worker->
|
|
326
|
+
worker->resultCode = 22;
|
|
324
327
|
return 22;
|
|
325
328
|
}
|
|
326
329
|
if (rc) {
|
|
327
330
|
if (!(rc == MDB_KEYEXIST || rc == MDB_NOTFOUND)) {
|
|
328
331
|
if (worker) {
|
|
329
|
-
worker->
|
|
332
|
+
worker->resultCode = rc;
|
|
330
333
|
} else {
|
|
331
334
|
return rc;
|
|
332
335
|
}
|
|
@@ -347,83 +350,164 @@ next_inst: start = instruction++;
|
|
|
347
350
|
return rc;
|
|
348
351
|
}
|
|
349
352
|
|
|
353
|
+
bool WriteWorker::threadSafeCallsEnabled = false;
|
|
354
|
+
void txn_visible(const void* data) {
|
|
355
|
+
auto worker = (WriteWorker*) data;
|
|
356
|
+
worker->SendUpdate();
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
void do_write(napi_env env, void* data) {
|
|
361
|
+
auto worker = (WriteWorker*) data;
|
|
362
|
+
worker->Write();
|
|
363
|
+
napi_release_threadsafe_function(worker->progress, napi_tsfn_abort);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const int READER_CHECK_INTERVAL = 600; // ten minutes
|
|
350
367
|
void WriteWorker::Write() {
|
|
351
368
|
int rc;
|
|
352
369
|
finishedProgress = true;
|
|
353
370
|
unsigned int envFlags;
|
|
354
371
|
mdb_env_get_flags(env, &envFlags);
|
|
372
|
+
time_t now = time(0);
|
|
373
|
+
if (now - envForTxn->lastReaderCheck > READER_CHECK_INTERVAL) {
|
|
374
|
+
int dead;
|
|
375
|
+
mdb_reader_check(env, &dead);
|
|
376
|
+
envForTxn->lastReaderCheck = now;
|
|
377
|
+
}
|
|
355
378
|
pthread_mutex_lock(envForTxn->writingLock);
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
379
|
+
#ifndef _WIN32
|
|
380
|
+
int retries = 0;
|
|
381
|
+
retry:
|
|
382
|
+
#endif
|
|
383
|
+
rc = mdb_txn_begin(env, nullptr,
|
|
384
|
+
#ifdef MDB_OVERLAPPINGSYNC
|
|
385
|
+
(envForTxn->jsFlags & MDB_OVERLAPPINGSYNC) ? MDB_NOSYNC :
|
|
386
|
+
#endif
|
|
387
|
+
0, &txn);
|
|
388
|
+
#if !defined(_WIN32) && defined(MDB_RPAGE_CACHE)
|
|
389
|
+
if (rc == MDB_LOCK_FAILURE) {
|
|
390
|
+
if (retries++ < 4) {
|
|
391
|
+
sleep(1);
|
|
392
|
+
goto retry;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
#endif
|
|
370
396
|
if (rc != 0) {
|
|
371
|
-
|
|
397
|
+
resultCode = rc;
|
|
398
|
+
return;
|
|
372
399
|
}
|
|
373
|
-
hasError = false;
|
|
374
400
|
rc = DoWrites(txn, envForTxn, instructions, this);
|
|
375
|
-
|
|
376
|
-
|
|
401
|
+
uint32_t txnId = (uint32_t) mdb_txn_id(txn);
|
|
402
|
+
progressStatus = 1;
|
|
403
|
+
#ifdef MDB_OVERLAPPINGSYNC
|
|
404
|
+
if (envForTxn->jsFlags & MDB_OVERLAPPINGSYNC) {
|
|
405
|
+
mdb_txn_set_callback(txn, txn_visible, this);
|
|
406
|
+
}
|
|
407
|
+
#endif
|
|
408
|
+
if (rc || resultCode)
|
|
377
409
|
mdb_txn_abort(txn);
|
|
378
410
|
else
|
|
379
411
|
rc = mdb_txn_commit(txn);
|
|
412
|
+
#ifdef MDB_OVERLAPPINGSYNC
|
|
413
|
+
#endif
|
|
414
|
+
#ifdef MDB_EMPTY_TXN
|
|
415
|
+
if (rc == MDB_EMPTY_TXN)
|
|
416
|
+
rc = 0;
|
|
417
|
+
#endif
|
|
380
418
|
txn = nullptr;
|
|
419
|
+
interruptionStatus = 0;
|
|
420
|
+
pthread_cond_signal(envForTxn->writingCond); // in case there a sync txn waiting for us
|
|
381
421
|
pthread_mutex_unlock(envForTxn->writingLock);
|
|
382
|
-
if (rc ||
|
|
422
|
+
if (rc || resultCode) {
|
|
383
423
|
std::atomic_fetch_or((std::atomic<uint32_t>*) instructions, (uint32_t) TXN_HAD_ERROR);
|
|
384
424
|
if (rc)
|
|
385
|
-
|
|
425
|
+
resultCode = rc ? rc : resultCode;
|
|
386
426
|
return;
|
|
387
427
|
}
|
|
428
|
+
*(instructions - 1) = txnId;
|
|
388
429
|
std::atomic_fetch_or((std::atomic<uint32_t>*) instructions, (uint32_t) TXN_COMMITTED);
|
|
389
430
|
}
|
|
390
431
|
|
|
391
|
-
void
|
|
392
|
-
|
|
393
|
-
|
|
432
|
+
void write_progress(napi_env env,
|
|
433
|
+
napi_value js_callback,
|
|
434
|
+
void* context,
|
|
435
|
+
void* data) {
|
|
436
|
+
if (!js_callback)
|
|
437
|
+
return;
|
|
438
|
+
auto worker = (WriteWorker*) context;
|
|
439
|
+
napi_value result;
|
|
440
|
+
napi_value undefined;
|
|
441
|
+
napi_value arg;
|
|
442
|
+
napi_create_int32(env, worker->progressStatus, &arg);
|
|
443
|
+
napi_get_undefined(env, &undefined);
|
|
444
|
+
if (worker->progressStatus == 1) {
|
|
445
|
+
napi_call_function(env, undefined, js_callback, 1, &arg, &result);
|
|
394
446
|
return;
|
|
395
447
|
}
|
|
396
|
-
if (finishedProgress)
|
|
448
|
+
if (worker->finishedProgress)
|
|
397
449
|
return;
|
|
450
|
+
auto envForTxn = worker->envForTxn;
|
|
398
451
|
pthread_mutex_lock(envForTxn->writingLock);
|
|
399
|
-
while(!txn) // possible to jump in after an interrupted txn here
|
|
452
|
+
while(!worker->txn) // possible to jump in after an interrupted txn here
|
|
400
453
|
pthread_cond_wait(envForTxn->writingCond, envForTxn->writingLock);
|
|
401
|
-
envForTxn->writeTxn = new TxnTracked(txn, 0);
|
|
402
|
-
finishedProgress = true;
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
454
|
+
envForTxn->writeTxn = new TxnTracked(worker->txn, 0);
|
|
455
|
+
worker->finishedProgress = true;
|
|
456
|
+
napi_create_int32(env, worker->progressStatus, &arg);
|
|
457
|
+
napi_call_function(env, undefined, js_callback, 1, &arg, &result);
|
|
458
|
+
bool is_async = false;
|
|
459
|
+
napi_get_value_bool(env, result, &is_async);
|
|
460
|
+
if (!is_async) {
|
|
461
|
+
delete envForTxn->writeTxn;
|
|
462
|
+
envForTxn->writeTxn = nullptr;
|
|
463
|
+
pthread_cond_signal(envForTxn->writingCond);
|
|
464
|
+
pthread_mutex_unlock(envForTxn->writingLock);
|
|
465
|
+
}
|
|
410
466
|
}
|
|
411
467
|
|
|
412
|
-
void
|
|
413
|
-
|
|
468
|
+
void writes_complete(napi_env env,
|
|
469
|
+
napi_status status,
|
|
470
|
+
void* data) {
|
|
471
|
+
auto worker = (WriteWorker*) data;
|
|
472
|
+
worker->finishedProgress = true;
|
|
414
473
|
napi_value result, arg; // we use direct napi call here because node-addon-api interface with throw a fatal error if a worker thread is terminating, and bun doesn't support escapable scopes yet
|
|
415
|
-
napi_create_int32(
|
|
416
|
-
|
|
474
|
+
napi_create_int32(env, worker->resultCode, &arg);
|
|
475
|
+
napi_value callback;
|
|
476
|
+
napi_get_reference_value(env, worker->callback, &callback);
|
|
477
|
+
napi_call_function(env, callback, callback, 1, &arg, &result);
|
|
478
|
+
napi_delete_reference(env, worker->callback);
|
|
479
|
+
napi_delete_async_work(env, worker->work);
|
|
480
|
+
delete worker;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
Value EnvWrap::resumeWriting(const Napi::CallbackInfo& info) {
|
|
484
|
+
// if we had async txns, now we resume
|
|
485
|
+
delete writeTxn;
|
|
486
|
+
writeTxn = nullptr;
|
|
487
|
+
pthread_cond_signal(writingCond);
|
|
488
|
+
pthread_mutex_unlock(writingLock);
|
|
489
|
+
return info.Env().Undefined();
|
|
417
490
|
}
|
|
418
491
|
|
|
419
492
|
Value EnvWrap::startWriting(const Napi::CallbackInfo& info) {
|
|
493
|
+
napi_env n_env = info.Env();
|
|
420
494
|
if (!this->env) {
|
|
421
495
|
return throwError(info.Env(), "The environment is already closed.");
|
|
422
496
|
}
|
|
497
|
+
hasWrites = true;
|
|
423
498
|
size_t instructionAddress = info[0].As<Number>().Int64Value();
|
|
424
|
-
|
|
499
|
+
napi_value resource;
|
|
500
|
+
napi_status status;
|
|
501
|
+
status = napi_create_object(n_env, &resource);
|
|
502
|
+
napi_value resource_name;
|
|
503
|
+
status = napi_create_string_latin1(n_env, "write", NAPI_AUTO_LENGTH, &resource_name);
|
|
504
|
+
auto worker = new WriteWorker(this->env, this, (uint32_t*) instructionAddress);
|
|
425
505
|
this->writeWorker = worker;
|
|
426
|
-
worker->
|
|
506
|
+
napi_create_reference(n_env, info[1].As<Function>(), 1, &worker->callback);
|
|
507
|
+
status = napi_create_async_work(n_env, resource, resource_name, do_write, writes_complete, worker, &worker->work);
|
|
508
|
+
napi_create_threadsafe_function(n_env, info[1].As<Function>(), resource, resource_name, 0, 1, nullptr, nullptr, worker, write_progress, &worker->progress);
|
|
509
|
+
status = napi_queue_async_work(n_env, worker->work);
|
|
510
|
+
|
|
427
511
|
return info.Env().Undefined();
|
|
428
512
|
}
|
|
429
513
|
|
|
@@ -435,6 +519,7 @@ NAPI_FUNCTION(EnvWrap::write) {
|
|
|
435
519
|
napi_throw_error(env, nullptr, "The environment is already closed.");
|
|
436
520
|
RETURN_UNDEFINED;
|
|
437
521
|
}
|
|
522
|
+
ew->hasWrites = true;
|
|
438
523
|
|
|
439
524
|
napi_get_value_int64(env, args[1], &i64);
|
|
440
525
|
uint32_t* instructionAddress = (uint32_t*) i64;
|
package/util/RangeIterable.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
const SKIP = {};
|
|
1
|
+
export const SKIP = {};
|
|
2
|
+
const DONE = {
|
|
3
|
+
value: null,
|
|
4
|
+
done: true,
|
|
5
|
+
}
|
|
2
6
|
if (!Symbol.asyncIterator) {
|
|
3
7
|
Symbol.asyncIterator = Symbol.for('Symbol.asyncIterator');
|
|
4
8
|
}
|
|
@@ -11,9 +15,10 @@ export class RangeIterable {
|
|
|
11
15
|
}
|
|
12
16
|
map(func) {
|
|
13
17
|
let source = this;
|
|
14
|
-
let
|
|
15
|
-
|
|
18
|
+
let iterable = new RangeIterable();
|
|
19
|
+
iterable.iterate = (async) => {
|
|
16
20
|
let iterator = source[Symbol.iterator](async);
|
|
21
|
+
let i = 0;
|
|
17
22
|
return {
|
|
18
23
|
next(resolvedResult) {
|
|
19
24
|
let result;
|
|
@@ -30,31 +35,38 @@ export class RangeIterable {
|
|
|
30
35
|
}
|
|
31
36
|
if (iteratorResult.done === true) {
|
|
32
37
|
this.done = true;
|
|
38
|
+
if (iterable.onDone) iterable.onDone();
|
|
33
39
|
return iteratorResult;
|
|
34
40
|
}
|
|
35
|
-
result = func(iteratorResult.value);
|
|
41
|
+
result = func(iteratorResult.value, i++);
|
|
36
42
|
if (result && result.then) {
|
|
37
43
|
return result.then(result =>
|
|
38
|
-
result
|
|
44
|
+
result === SKIP ?
|
|
39
45
|
this.next() :
|
|
40
46
|
{
|
|
41
47
|
value: result
|
|
42
48
|
});
|
|
43
49
|
}
|
|
44
|
-
} while(result
|
|
50
|
+
} while(result === SKIP);
|
|
51
|
+
if (result === DONE) {
|
|
52
|
+
if (iterable.onDone) iterable.onDone();
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
45
55
|
return {
|
|
46
56
|
value: result
|
|
47
57
|
};
|
|
48
58
|
},
|
|
49
59
|
return() {
|
|
60
|
+
if (iterable.onDone) iterable.onDone();
|
|
50
61
|
return iterator.return();
|
|
51
62
|
},
|
|
52
63
|
throw() {
|
|
64
|
+
if (iterable.onDone) iterable.onDone();
|
|
53
65
|
return iterator.throw();
|
|
54
66
|
}
|
|
55
67
|
};
|
|
56
68
|
};
|
|
57
|
-
return
|
|
69
|
+
return iterable;
|
|
58
70
|
}
|
|
59
71
|
[Symbol.asyncIterator]() {
|
|
60
72
|
return this.iterator = this.iterate();
|
|
@@ -63,7 +75,12 @@ export class RangeIterable {
|
|
|
63
75
|
return this.iterator = this.iterate();
|
|
64
76
|
}
|
|
65
77
|
filter(func) {
|
|
66
|
-
return this.map(element =>
|
|
78
|
+
return this.map(element => {
|
|
79
|
+
let result = func(element);
|
|
80
|
+
// handle promise
|
|
81
|
+
if (result?.then) return result.then((result) => result ? element : SKIP);
|
|
82
|
+
else return result ? element : SKIP;
|
|
83
|
+
});
|
|
67
84
|
}
|
|
68
85
|
|
|
69
86
|
forEach(callback) {
|
|
@@ -78,27 +95,104 @@ export class RangeIterable {
|
|
|
78
95
|
concatIterable.iterate = (async) => {
|
|
79
96
|
let iterator = this.iterator = this.iterate();
|
|
80
97
|
let isFirst = true;
|
|
81
|
-
|
|
98
|
+
function iteratorDone(result) {
|
|
99
|
+
if (isFirst) {
|
|
100
|
+
isFirst = false;
|
|
101
|
+
iterator = secondIterable[Symbol.iterator](async);
|
|
102
|
+
result = iterator.next();
|
|
103
|
+
if (concatIterable.onDone) {
|
|
104
|
+
if (result.then)
|
|
105
|
+
result.then((result) => {
|
|
106
|
+
if (result.done()) concatIterable.onDone();
|
|
107
|
+
});
|
|
108
|
+
else if (result.done) concatIterable.onDone();
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
if (concatIterable.onDone) concatIterable.onDone();
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
82
116
|
next() {
|
|
83
117
|
let result = iterator.next();
|
|
84
|
-
if (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
118
|
+
if (result.then)
|
|
119
|
+
return result.then((result) => {
|
|
120
|
+
if (result.done) return iteratorDone(result);
|
|
121
|
+
return result;
|
|
122
|
+
});
|
|
123
|
+
if (result.done) return iteratorDone(result);
|
|
89
124
|
return result;
|
|
90
125
|
},
|
|
91
126
|
return() {
|
|
127
|
+
if (concatIterable.onDone) concatIterable.onDone();
|
|
92
128
|
return iterator.return();
|
|
93
129
|
},
|
|
94
130
|
throw() {
|
|
131
|
+
if (concatIterable.onDone) concatIterable.onDone();
|
|
95
132
|
return iterator.throw();
|
|
96
133
|
}
|
|
97
134
|
};
|
|
98
|
-
return concatIterator;
|
|
99
135
|
};
|
|
100
136
|
return concatIterable;
|
|
101
137
|
}
|
|
138
|
+
|
|
139
|
+
flatMap(callback) {
|
|
140
|
+
let mappedIterable = new RangeIterable();
|
|
141
|
+
mappedIterable.iterate = (async) => {
|
|
142
|
+
let iterator = this.iterator = this.iterate(async);
|
|
143
|
+
let isFirst = true;
|
|
144
|
+
let currentSubIterator;
|
|
145
|
+
return {
|
|
146
|
+
next() {
|
|
147
|
+
do {
|
|
148
|
+
if (currentSubIterator) {
|
|
149
|
+
let result = currentSubIterator.next();
|
|
150
|
+
if (!result.done) {
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
let result = iterator.next();
|
|
155
|
+
if (result.done) {
|
|
156
|
+
if (mappedIterable.onDone) mappedIterable.onDone();
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
let value = callback(result.value);
|
|
160
|
+
if (Array.isArray(value) || value instanceof RangeIterable)
|
|
161
|
+
currentSubIterator = value[Symbol.iterator]();
|
|
162
|
+
else {
|
|
163
|
+
currentSubIterator = null;
|
|
164
|
+
return { value };
|
|
165
|
+
}
|
|
166
|
+
} while(true);
|
|
167
|
+
},
|
|
168
|
+
return() {
|
|
169
|
+
if (mappedIterable.onDone) mappedIterable.onDone();
|
|
170
|
+
if (currentSubIterator)
|
|
171
|
+
currentSubIterator.return();
|
|
172
|
+
return iterator.return();
|
|
173
|
+
},
|
|
174
|
+
throw() {
|
|
175
|
+
if (mappedIterable.onDone) mappedIterable.onDone();
|
|
176
|
+
if (currentSubIterator)
|
|
177
|
+
currentSubIterator.throw();
|
|
178
|
+
return iterator.throw();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
return mappedIterable;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
slice(start, end) {
|
|
186
|
+
return this.map((element, i) => {
|
|
187
|
+
if (i < start)
|
|
188
|
+
return SKIP;
|
|
189
|
+
if (i >= end) {
|
|
190
|
+
DONE.value = element;
|
|
191
|
+
return DONE;
|
|
192
|
+
}
|
|
193
|
+
return element;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
102
196
|
next() {
|
|
103
197
|
if (!this.iterator)
|
|
104
198
|
this.iterator = this.iterate();
|
|
@@ -108,7 +202,7 @@ export class RangeIterable {
|
|
|
108
202
|
if (this.asArray && this.asArray.forEach) {
|
|
109
203
|
return this.asArray;
|
|
110
204
|
}
|
|
111
|
-
throw new Error('Can not serialize async
|
|
205
|
+
throw new Error('Can not serialize async iterables without first calling resolveJSON');
|
|
112
206
|
//return Array.from(this)
|
|
113
207
|
}
|
|
114
208
|
get asArray() {
|
|
@@ -118,6 +212,7 @@ export class RangeIterable {
|
|
|
118
212
|
let iterator = this.iterate();
|
|
119
213
|
let array = [];
|
|
120
214
|
let iterable = this;
|
|
215
|
+
Object.defineProperty(array, 'iterable', { value: iterable });
|
|
121
216
|
function next(result) {
|
|
122
217
|
while (result.done !== true) {
|
|
123
218
|
if (result.then) {
|
|
@@ -127,7 +222,6 @@ export class RangeIterable {
|
|
|
127
222
|
}
|
|
128
223
|
result = iterator.next();
|
|
129
224
|
}
|
|
130
|
-
array.iterable = iterable;
|
|
131
225
|
resolve(iterable._asArray = array);
|
|
132
226
|
}
|
|
133
227
|
next(iterator.next());
|
|
@@ -139,3 +233,4 @@ export class RangeIterable {
|
|
|
139
233
|
return this.asArray;
|
|
140
234
|
}
|
|
141
235
|
}
|
|
236
|
+
RangeIterable.prototype.DONE = DONE;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
let fs = require('fs');
|
|
2
|
-
packageData = JSON.parse(fs.readFileSync('package.json'));
|
|
3
|
-
let prebuilds = fs.readdirSync('prebuilds');
|
|
4
|
-
let platformDeps = packageData.optionalDependencies = {};
|
|
5
|
-
let packageName = packageData.name;
|
|
6
|
-
let version = packageData.version;
|
|
7
|
-
for (let prebuild of prebuilds) {
|
|
8
|
-
platformDeps['@' + packageName + '/' + packageName + '-' + prebuild] = version;
|
|
9
|
-
}
|
|
10
|
-
|
|
1
|
+
let fs = require('fs');
|
|
2
|
+
packageData = JSON.parse(fs.readFileSync('package.json'));
|
|
3
|
+
let prebuilds = fs.readdirSync('prebuilds');
|
|
4
|
+
let platformDeps = packageData.optionalDependencies = {};
|
|
5
|
+
let packageName = packageData.name;
|
|
6
|
+
let version = packageData.version;
|
|
7
|
+
for (let prebuild of prebuilds) {
|
|
8
|
+
platformDeps['@' + packageName + '/' + packageName + '-' + prebuild] = version;
|
|
9
|
+
}
|
|
10
|
+
/*if (version.endsWith('-v1')) {
|
|
11
|
+
packageData.version = version.slice(0, -3);
|
|
12
|
+
packageData.name = packageName + '-v1';
|
|
13
|
+
}*/
|
|
14
|
+
fs.writeFileSync('package.json', JSON.stringify(packageData, null, 2));
|
package/util/when.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export function when(promise, callback, errback) {
|
|
2
|
-
if (promise && promise.then) {
|
|
3
|
-
return errback ?
|
|
4
|
-
promise.then(callback, errback) :
|
|
5
|
-
promise.then(callback);
|
|
6
|
-
}
|
|
7
|
-
return callback(promise);
|
|
8
|
-
}
|
|
1
|
+
export function when(promise, callback, errback) {
|
|
2
|
+
if (promise && promise.then) {
|
|
3
|
+
return errback ?
|
|
4
|
+
promise.then(callback, errback) :
|
|
5
|
+
promise.then(callback);
|
|
6
|
+
}
|
|
7
|
+
return callback(promise);
|
|
8
|
+
}
|