@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/write.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { getAddress, write, compress } from './native.js';
|
|
1
|
+
import { getAddress, getBufferAddress, write, compress, lmdbError } from './native.js';
|
|
2
2
|
import { when } from './util/when.js';
|
|
3
3
|
var backpressureArray;
|
|
4
4
|
|
|
5
5
|
const WAITING_OPERATION = 0x2000000;
|
|
6
|
-
const BACKPRESSURE_THRESHOLD =
|
|
6
|
+
const BACKPRESSURE_THRESHOLD = 300000;
|
|
7
7
|
const TXN_DELIMITER = 0x8000000;
|
|
8
8
|
const TXN_COMMITTED = 0x10000000;
|
|
9
9
|
const TXN_FLUSHED = 0x20000000;
|
|
@@ -13,13 +13,15 @@ const REUSE_BUFFER_MODE = 512;
|
|
|
13
13
|
const RESET_BUFFER_MODE = 1024;
|
|
14
14
|
const NO_RESOLVE = 16;
|
|
15
15
|
const HAS_TXN = 8;
|
|
16
|
+
const CONDITIONAL_VERSION_LESS_THAN = 0x800;
|
|
17
|
+
const CONDITIONAL_ALLOW_NOTFOUND = 0x800;
|
|
16
18
|
|
|
17
19
|
const SYNC_PROMISE_SUCCESS = Promise.resolve(true);
|
|
18
20
|
const SYNC_PROMISE_FAIL = Promise.resolve(false);
|
|
19
21
|
SYNC_PROMISE_SUCCESS.isSync = true;
|
|
20
22
|
SYNC_PROMISE_FAIL.isSync = true;
|
|
21
23
|
const PROMISE_SUCCESS = Promise.resolve(true);
|
|
22
|
-
export const ABORT =
|
|
24
|
+
export const ABORT = 4.452694326329068e-106; // random/unguessable numbers, which work across module/versions and native
|
|
23
25
|
export const IF_EXISTS = 3.542694326329068e-103;
|
|
24
26
|
const CALLBACK_THREW = {};
|
|
25
27
|
const LocalSharedArrayBuffer = typeof Deno != 'undefined' ? ArrayBuffer : SharedArrayBuffer; // Deno can't handle SharedArrayBuffer as an FFI argument due to https://github.com/denoland/deno/issues/12678
|
|
@@ -32,18 +34,23 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
32
34
|
eventTurnBatching, txnStartThreshold, batchStartThreshold, overlappingSync, commitDelay, separateFlushed, maxFlushDelay }) {
|
|
33
35
|
// stands for write instructions
|
|
34
36
|
var dynamicBytes;
|
|
35
|
-
function allocateInstructionBuffer() {
|
|
37
|
+
function allocateInstructionBuffer(lastPosition) {
|
|
36
38
|
// Must use a shared buffer on older node in order to use Atomics, and it is also more correct since we are
|
|
37
39
|
// indeed accessing and modifying it from another thread (in C). However, Deno can't handle it for
|
|
38
40
|
// FFI so aliased above
|
|
39
41
|
let buffer = new LocalSharedArrayBuffer(WRITE_BUFFER_SIZE);
|
|
42
|
+
let lastBytes = dynamicBytes;
|
|
40
43
|
dynamicBytes = new ByteArray(buffer);
|
|
41
44
|
let uint32 = dynamicBytes.uint32 = new Uint32Array(buffer, 0, WRITE_BUFFER_SIZE >> 2);
|
|
42
|
-
uint32[
|
|
45
|
+
uint32[2] = 0;
|
|
43
46
|
dynamicBytes.float64 = new Float64Array(buffer, 0, WRITE_BUFFER_SIZE >> 3);
|
|
44
|
-
buffer.address =
|
|
47
|
+
buffer.address = getBufferAddress(dynamicBytes);
|
|
45
48
|
uint32.address = buffer.address + uint32.byteOffset;
|
|
46
|
-
dynamicBytes.position =
|
|
49
|
+
dynamicBytes.position = 1; // we start at position 1 to save space for writing the txn id before the txn delimiter
|
|
50
|
+
if (lastPosition) {
|
|
51
|
+
lastBytes.float64[lastPosition + 1] = dynamicBytes.uint32.address + (dynamicBytes.position << 3);
|
|
52
|
+
lastBytes.uint32[lastPosition << 1] = 3; // pointer instruction
|
|
53
|
+
}
|
|
47
54
|
return dynamicBytes;
|
|
48
55
|
}
|
|
49
56
|
var newBufferThreshold = (WRITE_BUFFER_SIZE - maxKeySize - 64) >> 3; // need to reserve more room if we do inline values
|
|
@@ -53,7 +60,7 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
53
60
|
var committed;
|
|
54
61
|
var abortedNonChildTransactionWarn;
|
|
55
62
|
var nextTxnCallbacks = [];
|
|
56
|
-
var commitPromise, flushPromise, flushResolvers = [];
|
|
63
|
+
var commitPromise, flushPromise, flushResolvers = [], batchFlushResolvers = [];
|
|
57
64
|
commitDelay = commitDelay || 0;
|
|
58
65
|
eventTurnBatching = eventTurnBatching === false ? false : true;
|
|
59
66
|
var enqueuedCommit;
|
|
@@ -63,22 +70,24 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
63
70
|
var batchDepth = 0;
|
|
64
71
|
var lastWritePromise;
|
|
65
72
|
var writeBatchStart, outstandingBatchCount, lastSyncTxnFlush, lastFlushTimeout, lastFlushCallback;
|
|
73
|
+
var hasUnresolvedTxns;
|
|
66
74
|
txnStartThreshold = txnStartThreshold || 5;
|
|
67
75
|
batchStartThreshold = batchStartThreshold || 1000;
|
|
68
76
|
maxFlushDelay = maxFlushDelay || 500;
|
|
69
77
|
|
|
70
78
|
allocateInstructionBuffer();
|
|
71
|
-
dynamicBytes.uint32[
|
|
72
|
-
var txnResolution,
|
|
73
|
-
uint32: dynamicBytes.uint32, flagPosition:
|
|
79
|
+
dynamicBytes.uint32[2] = TXN_DELIMITER | TXN_COMMITTED | TXN_FLUSHED;
|
|
80
|
+
var txnResolution, nextResolution = {
|
|
81
|
+
uint32: dynamicBytes.uint32, flagPosition: 2, flag: 0, valueBuffer: null, next: null, meta: null };
|
|
74
82
|
var uncommittedResolution = {
|
|
75
|
-
uint32: null, flagPosition:
|
|
83
|
+
uint32: null, flagPosition: 2, flag: 0, valueBuffer: null, next: nextResolution, meta: null };
|
|
76
84
|
var unwrittenResolution = nextResolution;
|
|
77
85
|
var lastPromisedResolution = uncommittedResolution;
|
|
86
|
+
var lastQueuedResolution = uncommittedResolution;
|
|
78
87
|
function writeInstructions(flags, store, key, value, version, ifVersion) {
|
|
79
88
|
let writeStatus;
|
|
80
89
|
let targetBytes, position, encoder;
|
|
81
|
-
let
|
|
90
|
+
let valueSize, valueBuffer, valueBufferStart;
|
|
82
91
|
if (flags & 2) {
|
|
83
92
|
// encode first in case we have to write a shared structure
|
|
84
93
|
encoder = store.encoder;
|
|
@@ -115,7 +124,11 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
115
124
|
enqueuedEventTurnBatch = queueTask(() => {
|
|
116
125
|
try {
|
|
117
126
|
for (let i = 0, l = beforeCommitCallbacks.length; i < l; i++) {
|
|
118
|
-
|
|
127
|
+
try {
|
|
128
|
+
beforeCommitCallbacks[i]();
|
|
129
|
+
} catch(error) {
|
|
130
|
+
console.error('In beforecommit callback', error);
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
} catch(error) {
|
|
121
134
|
console.error(error);
|
|
@@ -149,7 +162,7 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
149
162
|
try {
|
|
150
163
|
endPosition = store.writeKey(key, targetBytes, keyStartPosition);
|
|
151
164
|
if (!(keyStartPosition < endPosition) && (flags & 0xf) != 12)
|
|
152
|
-
throw new Error('Invalid key or zero length key is not allowed in LMDB')
|
|
165
|
+
throw new Error('Invalid key or zero length key is not allowed in LMDB ' + key)
|
|
153
166
|
} catch(error) {
|
|
154
167
|
targetBytes.fill(0, keyStartPosition);
|
|
155
168
|
if (error.name == 'RangeError')
|
|
@@ -168,14 +181,14 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
168
181
|
if (valueBufferStart > -1) { // if we have buffers with start/end position
|
|
169
182
|
// record pointer to value buffer
|
|
170
183
|
float64[position] = (valueBuffer.address ||
|
|
171
|
-
(valueBuffer.address = getAddress(valueBuffer))) + valueBufferStart;
|
|
184
|
+
(valueBuffer.address = getAddress(valueBuffer.buffer))) + valueBufferStart;
|
|
172
185
|
mustCompress = valueBuffer[valueBufferStart] >= 250; // this is the compression indicator, so we must compress
|
|
173
186
|
} else {
|
|
174
187
|
let valueArrayBuffer = valueBuffer.buffer;
|
|
175
188
|
// record pointer to value buffer
|
|
176
189
|
let address = (valueArrayBuffer.address ||
|
|
177
190
|
(valueBuffer.length === 0 ? 0 : // externally allocated buffers of zero-length with the same non-null-pointer can crash node, #161
|
|
178
|
-
|
|
191
|
+
valueArrayBuffer.address = getAddress(valueArrayBuffer)))
|
|
179
192
|
+ valueBuffer.byteOffset;
|
|
180
193
|
if (address <= 0 && valueBuffer.length > 0)
|
|
181
194
|
console.error('Supplied buffer had an invalid address', address);
|
|
@@ -222,10 +235,8 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
222
235
|
if (position > newBufferThreshold) {
|
|
223
236
|
// make new buffer and make pointer to it
|
|
224
237
|
let lastPosition = position;
|
|
225
|
-
targetBytes = allocateInstructionBuffer();
|
|
238
|
+
targetBytes = allocateInstructionBuffer(position);
|
|
226
239
|
position = targetBytes.position;
|
|
227
|
-
float64[lastPosition + 1] = targetBytes.uint32.address + position;
|
|
228
|
-
uint32[lastPosition << 1] = 3; // pointer instruction
|
|
229
240
|
nextUint32 = targetBytes.uint32;
|
|
230
241
|
} else
|
|
231
242
|
nextUint32 = uint32;
|
|
@@ -239,6 +250,8 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
239
250
|
next: null,
|
|
240
251
|
meta: null,
|
|
241
252
|
};
|
|
253
|
+
lastQueuedResolution = resolution;
|
|
254
|
+
|
|
242
255
|
let writtenBatchDepth = batchDepth;
|
|
243
256
|
|
|
244
257
|
return (callback) => {
|
|
@@ -266,13 +279,25 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
266
279
|
if (writeStatus & TXN_DELIMITER) {
|
|
267
280
|
commitPromise = null; // TODO: Don't reset these if this comes from the batch start operation on an event turn batch
|
|
268
281
|
flushPromise = null;
|
|
282
|
+
flushResolvers = [];
|
|
269
283
|
queueCommitResolution(resolution);
|
|
270
284
|
if (!startAddress) {
|
|
271
285
|
startAddress = uint32.address + (flagPosition << 2);
|
|
272
286
|
}
|
|
273
287
|
}
|
|
274
|
-
if (!
|
|
275
|
-
|
|
288
|
+
if (!writtenBatchDepth && batchFlushResolvers.length > 0) {
|
|
289
|
+
flushResolvers.push(...batchFlushResolvers);
|
|
290
|
+
batchFlushResolvers = [];
|
|
291
|
+
}
|
|
292
|
+
if (!flushPromise && overlappingSync) {
|
|
293
|
+
flushPromise = new Promise(resolve => {
|
|
294
|
+
if (writtenBatchDepth) {
|
|
295
|
+
batchFlushResolvers.push(resolve);
|
|
296
|
+
} else {
|
|
297
|
+
flushResolvers.push(resolve);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
276
301
|
if (writeStatus & WAITING_OPERATION) { // write thread is waiting
|
|
277
302
|
write(env.address, 0);
|
|
278
303
|
}
|
|
@@ -301,7 +326,6 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
301
326
|
};
|
|
302
327
|
}
|
|
303
328
|
resolution.valueBuffer = valueBuffer;
|
|
304
|
-
lastQueuedResolution = resolution;
|
|
305
329
|
|
|
306
330
|
if (callback) {
|
|
307
331
|
if (callback === IF_EXISTS)
|
|
@@ -351,7 +375,6 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
351
375
|
enqueuedCommit = null;
|
|
352
376
|
}
|
|
353
377
|
let resolvers = flushResolvers;
|
|
354
|
-
flushResolvers = [];
|
|
355
378
|
let start = Date.now();
|
|
356
379
|
env.startWriting(startAddress, (status) => {
|
|
357
380
|
if (dynamicBytes.uint32[dynamicBytes.position << 1] & TXN_DELIMITER)
|
|
@@ -360,52 +383,31 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
360
383
|
resolveWrites(true);
|
|
361
384
|
switch (status) {
|
|
362
385
|
case 0:
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
scheduleFlush(resolvers, Math.min((flushPromise && flushPromise.hasCallbacks ? delay >> 1 : delay) + 1, maxFlushDelay))
|
|
386
|
+
for (let resolver of resolvers) {
|
|
387
|
+
resolver();
|
|
366
388
|
}
|
|
389
|
+
break;
|
|
367
390
|
case 1:
|
|
368
|
-
|
|
391
|
+
break;
|
|
369
392
|
case 2:
|
|
393
|
+
hasUnresolvedTxns = false;
|
|
370
394
|
executeTxnCallbacks();
|
|
371
|
-
|
|
395
|
+
return hasUnresolvedTxns;
|
|
396
|
+
break;
|
|
372
397
|
default:
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
398
|
+
try {
|
|
399
|
+
lmdbError(status);
|
|
400
|
+
} catch(error) {
|
|
401
|
+
console.error(error);
|
|
402
|
+
if (commitRejectPromise) {
|
|
403
|
+
commitRejectPromise.reject(error);
|
|
404
|
+
commitRejectPromise = null;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
378
407
|
}
|
|
379
408
|
});
|
|
380
409
|
startAddress = 0;
|
|
381
410
|
}
|
|
382
|
-
function scheduleFlush(resolvers, delay) {
|
|
383
|
-
if (committedFlushResolvers)
|
|
384
|
-
committedFlushResolvers.push(...resolvers)
|
|
385
|
-
else {
|
|
386
|
-
committedFlushResolvers = resolvers
|
|
387
|
-
lastFlushTimeout = setTimeout(lastFlushCallback = () => {
|
|
388
|
-
lastFlushTimeout = null;
|
|
389
|
-
lastSync.then(() => {
|
|
390
|
-
let resolvers = committedFlushResolvers || [];
|
|
391
|
-
committedFlushResolvers = null;
|
|
392
|
-
lastSync = new Promise((resolve) => {
|
|
393
|
-
env.sync(() => {
|
|
394
|
-
for (let i = 0; i < resolvers.length; i++)
|
|
395
|
-
resolvers[i]();
|
|
396
|
-
resolve();
|
|
397
|
-
});
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
}, delay || 0);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
function expediteFlush() {
|
|
404
|
-
if (lastFlushTimeout) {
|
|
405
|
-
clearTimeout(lastFlushTimeout);
|
|
406
|
-
lastFlushCallback();
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
411
|
|
|
410
412
|
function queueCommitResolution(resolution) {
|
|
411
413
|
if (!(resolution.flag & HAS_TXN)) {
|
|
@@ -430,7 +432,7 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
430
432
|
}
|
|
431
433
|
outstandingWriteCount--;
|
|
432
434
|
if (unwrittenResolution.flag !== HAS_TXN) {
|
|
433
|
-
if (unwrittenResolution.flag === NO_RESOLVE && !unwrittenResolution.
|
|
435
|
+
if (unwrittenResolution.flag === NO_RESOLVE && !unwrittenResolution.meta) {
|
|
434
436
|
// in this case we can completely remove from the linked list, clearing more memory
|
|
435
437
|
lastPromisedResolution.next = unwrittenResolution = unwrittenResolution.next;
|
|
436
438
|
continue;
|
|
@@ -452,7 +454,7 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
452
454
|
}
|
|
453
455
|
|
|
454
456
|
function resolveCommit(async) {
|
|
455
|
-
afterCommit();
|
|
457
|
+
afterCommit(txnResolution.uint32[txnResolution.flagPosition - 1]);
|
|
456
458
|
if (async)
|
|
457
459
|
resetReadTxn();
|
|
458
460
|
else
|
|
@@ -498,35 +500,38 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
498
500
|
} else // otherwise the transaction could end at any time and we need to know the
|
|
499
501
|
// deterministically if it is ending, so we can reset the commit promise
|
|
500
502
|
// so we use the slower atomic operation
|
|
501
|
-
|
|
503
|
+
try {
|
|
504
|
+
return Atomics.or(uint32, flagPosition, newStatus);
|
|
505
|
+
} catch(error) {
|
|
506
|
+
console.error(error);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
502
509
|
}
|
|
503
|
-
function afterCommit() {
|
|
510
|
+
function afterCommit(txnId) {
|
|
504
511
|
for (let i = 0, l = afterCommitCallbacks.length; i < l; i++) {
|
|
505
|
-
|
|
512
|
+
try {
|
|
513
|
+
afterCommitCallbacks[i]({next: uncommittedResolution, last: txnResolution, txnId});
|
|
514
|
+
} catch(error) {
|
|
515
|
+
console.error('In aftercommit callback', error);
|
|
516
|
+
}
|
|
506
517
|
}
|
|
507
518
|
}
|
|
508
519
|
async function executeTxnCallbacks() {
|
|
509
520
|
env.writeTxn = writeTxn = { write: true };
|
|
510
|
-
|
|
511
|
-
let
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
for (let i = 0, l = txnCallbacks.length; i < l; i++) {
|
|
516
|
-
let userTxnCallback = txnCallbacks[i];
|
|
521
|
+
nextTxnCallbacks.isExecuting = true;
|
|
522
|
+
for (let i = 0; i < nextTxnCallbacks.length; i++) {
|
|
523
|
+
let txnCallbacks = nextTxnCallbacks[i];
|
|
524
|
+
for (let j = 0, l = txnCallbacks.length; j < l; j++) {
|
|
525
|
+
let userTxnCallback = txnCallbacks[j];
|
|
517
526
|
let asChild = userTxnCallback.asChild;
|
|
518
527
|
if (asChild) {
|
|
519
|
-
if (promises) {
|
|
520
|
-
// must complete any outstanding transactions before proceeding
|
|
521
|
-
await Promise.all(promises);
|
|
522
|
-
promises = null;
|
|
523
|
-
}
|
|
524
528
|
env.beginTxn(1); // abortable
|
|
525
529
|
let parentTxn = writeTxn;
|
|
526
530
|
env.writeTxn = writeTxn = { write: true };
|
|
527
531
|
try {
|
|
528
532
|
let result = userTxnCallback.callback();
|
|
529
533
|
if (result && result.then) {
|
|
534
|
+
hasUnresolvedTxns = true;
|
|
530
535
|
await result;
|
|
531
536
|
}
|
|
532
537
|
if (result === ABORT)
|
|
@@ -534,33 +539,32 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
534
539
|
else
|
|
535
540
|
env.commitTxn();
|
|
536
541
|
clearWriteTxn(parentTxn);
|
|
537
|
-
txnCallbacks[
|
|
542
|
+
txnCallbacks[j] = result;
|
|
538
543
|
} catch(error) {
|
|
539
544
|
clearWriteTxn(parentTxn);
|
|
540
545
|
env.abortTxn();
|
|
541
|
-
txnError(error,
|
|
546
|
+
txnError(error, txnCallbacks, j);
|
|
542
547
|
}
|
|
543
548
|
} else {
|
|
544
549
|
try {
|
|
545
550
|
let result = userTxnCallback();
|
|
546
|
-
txnCallbacks[
|
|
551
|
+
txnCallbacks[j] = result;
|
|
547
552
|
if (result && result.then) {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
promises.push(result.catch(() => {}));
|
|
553
|
+
hasUnresolvedTxns = true;
|
|
554
|
+
await result;
|
|
551
555
|
}
|
|
552
556
|
} catch(error) {
|
|
553
|
-
txnError(error,
|
|
557
|
+
txnError(error, txnCallbacks, j);
|
|
554
558
|
}
|
|
555
559
|
}
|
|
556
560
|
}
|
|
557
561
|
}
|
|
558
562
|
nextTxnCallbacks = [];
|
|
559
|
-
if (promises) { // finish any outstanding commit functions
|
|
560
|
-
await Promise.all(promises);
|
|
561
|
-
}
|
|
562
563
|
clearWriteTxn(null);
|
|
563
|
-
|
|
564
|
+
if (hasUnresolvedTxns) {
|
|
565
|
+
env.resumeWriting();
|
|
566
|
+
}
|
|
567
|
+
function txnError(error, txnCallbacks, i) {
|
|
564
568
|
(txnCallbacks.errors || (txnCallbacks.errors = []))[i] = error;
|
|
565
569
|
txnCallbacks[i] = CALLBACK_THREW;
|
|
566
570
|
}
|
|
@@ -572,18 +576,23 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
572
576
|
if (writeStatus & WAITING_OPERATION) {
|
|
573
577
|
write(env.address, 0);
|
|
574
578
|
}
|
|
579
|
+
if (dynamicBytes.position > newBufferThreshold) {
|
|
580
|
+
allocateInstructionBuffer(dynamicBytes.position);
|
|
581
|
+
nextResolution.flagPosition = dynamicBytes.position << 1;
|
|
582
|
+
nextResolution.uint32 = dynamicBytes.uint32;
|
|
583
|
+
}
|
|
575
584
|
}
|
|
576
585
|
function clearWriteTxn(parentTxn) {
|
|
577
586
|
// TODO: We might actually want to track cursors in a write txn and manually
|
|
578
587
|
// close them.
|
|
579
|
-
if (writeTxn.
|
|
588
|
+
if (writeTxn && writeTxn.refCount > 0)
|
|
580
589
|
writeTxn.isDone = true;
|
|
581
590
|
env.writeTxn = writeTxn = parentTxn || null;
|
|
582
591
|
}
|
|
583
592
|
Object.assign(LMDBStore.prototype, {
|
|
584
593
|
put(key, value, versionOrOptions, ifVersion) {
|
|
585
594
|
let callback, flags = 15, type = typeof versionOrOptions;
|
|
586
|
-
if (type == 'object') {
|
|
595
|
+
if (type == 'object' && versionOrOptions) {
|
|
587
596
|
if (versionOrOptions.noOverwrite)
|
|
588
597
|
flags |= 0x10;
|
|
589
598
|
if (versionOrOptions.noDupData)
|
|
@@ -591,7 +600,7 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
591
600
|
if (versionOrOptions.append)
|
|
592
601
|
flags |= 0x20000;
|
|
593
602
|
if (versionOrOptions.ifVersion != undefined)
|
|
594
|
-
ifVersion =
|
|
603
|
+
ifVersion = versionOrOptions.ifVersion;
|
|
595
604
|
versionOrOptions = versionOrOptions.version;
|
|
596
605
|
if (typeof ifVersion == 'function')
|
|
597
606
|
callback = ifVersion;
|
|
@@ -624,11 +633,10 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
624
633
|
ifNoExists(key, callback) {
|
|
625
634
|
return this.ifVersion(key, null, callback);
|
|
626
635
|
},
|
|
627
|
-
|
|
628
|
-
ifVersion(key, version, callback) {
|
|
636
|
+
ifVersion(key, version, callback, options) {
|
|
629
637
|
if (!callback) {
|
|
630
638
|
return new Batch((operations, callback) => {
|
|
631
|
-
let promise = this.ifVersion(key, version, operations);
|
|
639
|
+
let promise = this.ifVersion(key, version, operations, options);
|
|
632
640
|
if (callback)
|
|
633
641
|
promise.then(callback);
|
|
634
642
|
return promise;
|
|
@@ -641,7 +649,12 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
641
649
|
}
|
|
642
650
|
return SYNC_PROMISE_FAIL;
|
|
643
651
|
}
|
|
644
|
-
let
|
|
652
|
+
let flags = key === undefined || version === undefined ? 1 : 4;
|
|
653
|
+
if (options?.ifLessThan)
|
|
654
|
+
flags |= CONDITIONAL_VERSION_LESS_THAN;
|
|
655
|
+
if (options?.allowNotFound)
|
|
656
|
+
flags |= CONDITIONAL_ALLOW_NOTFOUND;
|
|
657
|
+
let finishStartWrite = writeInstructions(flags, this, key, undefined, undefined, version);
|
|
645
658
|
let promise;
|
|
646
659
|
batchDepth += 2;
|
|
647
660
|
if (batchDepth > 2)
|
|
@@ -678,7 +691,7 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
678
691
|
return this.ifVersion(undefined, undefined, callbackOrOperations);
|
|
679
692
|
},
|
|
680
693
|
drop(callback) {
|
|
681
|
-
return writeInstructions(1024 + 12, this,
|
|
694
|
+
return writeInstructions(1024 + 12, this, Buffer.from([]), undefined, undefined, undefined)(callback);
|
|
682
695
|
},
|
|
683
696
|
clearAsync(callback) {
|
|
684
697
|
if (this.encoder) {
|
|
@@ -687,7 +700,7 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
687
700
|
else if (this.encoder.structures)
|
|
688
701
|
this.encoder.structures = []
|
|
689
702
|
}
|
|
690
|
-
return writeInstructions(12, this,
|
|
703
|
+
return writeInstructions(12, this, Buffer.from([]), undefined, undefined, undefined)(callback);
|
|
691
704
|
},
|
|
692
705
|
_triggerError() {
|
|
693
706
|
finishBatch();
|
|
@@ -695,20 +708,20 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
695
708
|
|
|
696
709
|
putSync(key, value, versionOrOptions, ifVersion) {
|
|
697
710
|
if (writeTxn)
|
|
698
|
-
return this.put(key, value, versionOrOptions, ifVersion);
|
|
711
|
+
return this.put(key, value, versionOrOptions, ifVersion) === SYNC_PROMISE_SUCCESS;
|
|
699
712
|
else
|
|
700
713
|
return this.transactionSync(() =>
|
|
701
|
-
this.put(key, value, versionOrOptions, ifVersion)
|
|
714
|
+
this.put(key, value, versionOrOptions, ifVersion) === SYNC_PROMISE_SUCCESS, overlappingSync? 0x10002 : 2); // non-abortable, async flush
|
|
702
715
|
},
|
|
703
716
|
removeSync(key, ifVersionOrValue) {
|
|
704
717
|
if (writeTxn)
|
|
705
|
-
return this.remove(key, ifVersionOrValue);
|
|
718
|
+
return this.remove(key, ifVersionOrValue) === SYNC_PROMISE_SUCCESS;
|
|
706
719
|
else
|
|
707
720
|
return this.transactionSync(() =>
|
|
708
|
-
this.remove(key, ifVersionOrValue)
|
|
721
|
+
this.remove(key, ifVersionOrValue) === SYNC_PROMISE_SUCCESS, overlappingSync? 0x10002 : 2); // non-abortable, async flush
|
|
709
722
|
},
|
|
710
723
|
transaction(callback) {
|
|
711
|
-
if (writeTxn) {
|
|
724
|
+
if (writeTxn && !nextTxnCallbacks.isExecuting) {
|
|
712
725
|
// already nested in a transaction, just execute and return
|
|
713
726
|
return callback();
|
|
714
727
|
}
|
|
@@ -719,11 +732,13 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
719
732
|
throw new Error('Child transactions are not supported in writemap mode');
|
|
720
733
|
if (writeTxn) {
|
|
721
734
|
let parentTxn = writeTxn;
|
|
722
|
-
env.writeTxn = writeTxn = { write: true };
|
|
735
|
+
let thisTxn = env.writeTxn = writeTxn = { write: true };
|
|
723
736
|
env.beginTxn(1); // abortable
|
|
724
|
-
let callbackDone;
|
|
737
|
+
let callbackDone, finishTxn;
|
|
725
738
|
try {
|
|
726
|
-
return when(callback(), (result) => {
|
|
739
|
+
return writeTxn.childResults = when(callback(), finishTxn = (result) => {
|
|
740
|
+
if (writeTxn !== thisTxn) // need to wait for child txn to finish asynchronously
|
|
741
|
+
return writeTxn.childResults.then(() => finishTxn(result));
|
|
727
742
|
callbackDone = true;
|
|
728
743
|
if (result === ABORT)
|
|
729
744
|
env.abortTxn();
|
|
@@ -748,14 +763,23 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
748
763
|
transactionAsync(callback, asChild) {
|
|
749
764
|
let txnIndex;
|
|
750
765
|
let txnCallbacks;
|
|
751
|
-
if (
|
|
766
|
+
if (lastQueuedResolution.callbacks) {
|
|
767
|
+
txnCallbacks = lastQueuedResolution.callbacks;
|
|
768
|
+
txnIndex = txnCallbacks.push(asChild ? { callback, asChild } : callback) - 1;
|
|
769
|
+
} else if (nextTxnCallbacks.isExecuting) {
|
|
752
770
|
txnCallbacks = [asChild ? { callback, asChild } : callback];
|
|
753
|
-
|
|
754
|
-
|
|
771
|
+
txnCallbacks.results = commitPromise;
|
|
772
|
+
nextTxnCallbacks.push(txnCallbacks);
|
|
755
773
|
txnIndex = 0;
|
|
756
774
|
} else {
|
|
757
|
-
|
|
758
|
-
|
|
775
|
+
if (writeTxn)
|
|
776
|
+
throw new Error('Can not enqueue transaction during write txn');
|
|
777
|
+
let finishWrite = writeInstructions(8 | (this.strictAsyncOrder ? 0x100000 : 0), this);
|
|
778
|
+
txnCallbacks = [asChild ? { callback, asChild } : callback];
|
|
779
|
+
lastQueuedResolution.callbacks = txnCallbacks;
|
|
780
|
+
lastQueuedResolution.id = Math.random();
|
|
781
|
+
txnCallbacks.results = finishWrite();
|
|
782
|
+
txnIndex = 0;
|
|
759
783
|
}
|
|
760
784
|
return txnCallbacks.results.then((results) => {
|
|
761
785
|
let result = txnCallbacks[txnIndex];
|
|
@@ -766,7 +790,7 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
766
790
|
},
|
|
767
791
|
transactionSync(callback, flags) {
|
|
768
792
|
if (writeTxn) {
|
|
769
|
-
if (!useWritemap &&
|
|
793
|
+
if (!useWritemap && (flags == undefined || (flags & 1))) // can't use child transactions in write maps
|
|
770
794
|
// already nested in a transaction, execute as child transaction (if possible) and return
|
|
771
795
|
return this.childTransaction(callback);
|
|
772
796
|
let result = callback(); // else just run in current transaction
|
|
@@ -776,13 +800,17 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
776
800
|
}
|
|
777
801
|
return result;
|
|
778
802
|
}
|
|
779
|
-
let callbackDone;
|
|
803
|
+
let callbackDone, finishTxn;
|
|
804
|
+
this.transactions++;
|
|
805
|
+
if (!env.address)
|
|
806
|
+
throw new Error('The database has been closed and you can not transact on it');
|
|
807
|
+
env.beginTxn(flags == undefined ? 3 : flags);
|
|
808
|
+
let thisTxn = writeTxn = env.writeTxn = { write: true };
|
|
780
809
|
try {
|
|
781
|
-
this.transactions++;
|
|
782
|
-
env.beginTxn(flags == undefined ? 3 : flags);
|
|
783
|
-
writeTxn = env.writeTxn = { write: true };
|
|
784
810
|
this.emit('begin-transaction');
|
|
785
|
-
return when(callback(), (result) => {
|
|
811
|
+
return writeTxn.childResults = when(callback(), finishTxn = (result) => {
|
|
812
|
+
if (writeTxn !== thisTxn) // need to wait for child txn to finish asynchronously
|
|
813
|
+
return writeTxn.childResults.then(() => finishTxn(result));
|
|
786
814
|
try {
|
|
787
815
|
callbackDone = true;
|
|
788
816
|
if (result === ABORT)
|
|
@@ -790,8 +818,6 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
790
818
|
else {
|
|
791
819
|
env.commitTxn();
|
|
792
820
|
resetReadTxn();
|
|
793
|
-
if ((flags & 0x10000) && overlappingSync) // if it is no-sync in overlapping-sync mode, need to schedule flush for it to be marked as persisted
|
|
794
|
-
lastSyncTxnFlush = new Promise(resolve => scheduleFlush([resolve]))
|
|
795
821
|
}
|
|
796
822
|
return result;
|
|
797
823
|
} finally {
|
|
@@ -836,8 +862,6 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use
|
|
|
836
862
|
let finalPromise = flushPromise || commitPromise || lastWritePromise;
|
|
837
863
|
if (flushPromise)
|
|
838
864
|
flushPromise.hasCallbacks = true
|
|
839
|
-
if (lastFlushTimeout)
|
|
840
|
-
expediteFlush();
|
|
841
865
|
let finalSyncPromise = lastSyncTxnFlush;
|
|
842
866
|
if (finalPromise && resolvedPromise != finalPromise ||
|
|
843
867
|
finalSyncPromise && resolvedSyncPromise != finalSyncPromise) {
|