@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.
Files changed (124) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +72 -28
  3. package/SECURITY.md +12 -12
  4. package/bin/download-prebuilds.js +15 -0
  5. package/binding.gyp +115 -111
  6. package/build/Release/lmdb.node +0 -0
  7. package/caching.js +212 -156
  8. package/dependencies/lmdb/libraries/liblmdb/COPYRIGHT +20 -20
  9. package/dependencies/lmdb/libraries/liblmdb/Doxyfile +1631 -1631
  10. package/dependencies/lmdb/libraries/liblmdb/LICENSE +47 -47
  11. package/dependencies/lmdb/libraries/liblmdb/Makefile +136 -136
  12. package/dependencies/lmdb/libraries/liblmdb/chacha8.c +183 -183
  13. package/dependencies/lmdb/libraries/liblmdb/chacha8.h +14 -14
  14. package/dependencies/lmdb/libraries/liblmdb/crypto.c +121 -121
  15. package/dependencies/lmdb/libraries/liblmdb/intro.doc +192 -192
  16. package/dependencies/lmdb/libraries/liblmdb/lmdb.h +28 -3
  17. package/dependencies/lmdb/libraries/liblmdb/mdb.c +157 -31
  18. package/dependencies/lmdb/libraries/liblmdb/mdb_copy.1 +74 -74
  19. package/dependencies/lmdb/libraries/liblmdb/mdb_copy.c +106 -106
  20. package/dependencies/lmdb/libraries/liblmdb/mdb_drop.1 +53 -53
  21. package/dependencies/lmdb/libraries/liblmdb/mdb_drop.c +154 -154
  22. package/dependencies/lmdb/libraries/liblmdb/mdb_dump.1 +94 -94
  23. package/dependencies/lmdb/libraries/liblmdb/mdb_dump.c +333 -333
  24. package/dependencies/lmdb/libraries/liblmdb/mdb_load.1 +97 -97
  25. package/dependencies/lmdb/libraries/liblmdb/mdb_load.c +530 -530
  26. package/dependencies/lmdb/libraries/liblmdb/mdb_stat.1 +83 -83
  27. package/dependencies/lmdb/libraries/liblmdb/mdb_stat.c +276 -276
  28. package/dependencies/lmdb/libraries/liblmdb/midl-sparse.c +452 -0
  29. package/dependencies/lmdb/libraries/liblmdb/midl.c +452 -452
  30. package/dependencies/lmdb/libraries/liblmdb/midl.h +208 -208
  31. package/dependencies/lmdb/libraries/liblmdb/module.c +101 -101
  32. package/dependencies/lmdb/libraries/liblmdb/module.h +16 -16
  33. package/dependencies/lmdb/libraries/liblmdb/mtest.c +178 -178
  34. package/dependencies/lmdb/libraries/liblmdb/mtest2.c +124 -124
  35. package/dependencies/lmdb/libraries/liblmdb/mtest3.c +133 -133
  36. package/dependencies/lmdb/libraries/liblmdb/mtest4.c +168 -168
  37. package/dependencies/lmdb/libraries/liblmdb/mtest5.c +135 -135
  38. package/dependencies/lmdb/libraries/liblmdb/mtest6.c +141 -141
  39. package/dependencies/lmdb/libraries/liblmdb/mtest_enc.c +190 -190
  40. package/dependencies/lmdb/libraries/liblmdb/mtest_enc2.c +189 -189
  41. package/dependencies/lmdb/libraries/liblmdb/mtest_remap.c +177 -177
  42. package/dependencies/lmdb/libraries/liblmdb/sample-bdb.txt +73 -73
  43. package/dependencies/lmdb/libraries/liblmdb/sample-mdb.txt +62 -62
  44. package/dependencies/lmdb/libraries/liblmdb/tooltag +27 -27
  45. package/dependencies/lmdb-data-v1/libraries/liblmdb/CHANGES +266 -0
  46. package/dependencies/lmdb-data-v1/libraries/liblmdb/COPYRIGHT +20 -20
  47. package/dependencies/lmdb-data-v1/libraries/liblmdb/Doxyfile +1631 -1631
  48. package/dependencies/lmdb-data-v1/libraries/liblmdb/LICENSE +47 -47
  49. package/dependencies/lmdb-data-v1/libraries/liblmdb/intro.doc +192 -192
  50. package/dependencies/lmdb-data-v1/libraries/liblmdb/lmdb.h +1608 -1653
  51. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb.c +10320 -11359
  52. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.1 +55 -61
  53. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.c +82 -84
  54. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.1 +75 -81
  55. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.c +319 -319
  56. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.1 +84 -84
  57. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.c +496 -492
  58. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.1 +64 -70
  59. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.c +263 -264
  60. package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.c +359 -421
  61. package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.h +186 -200
  62. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest.c +177 -177
  63. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest2.c +124 -124
  64. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest3.c +133 -133
  65. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest4.c +168 -168
  66. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest5.c +135 -135
  67. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest6.c +141 -141
  68. package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-bdb.txt +73 -73
  69. package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-mdb.txt +62 -62
  70. package/dependencies/lmdb-data-v1/libraries/liblmdb/tooltag +22 -27
  71. package/dependencies/lz4/LICENSE +11 -11
  72. package/dependencies/lz4/lib/LICENSE +24 -24
  73. package/dependencies/lz4/lib/Makefile +225 -0
  74. package/dependencies/lz4/lib/README.md +169 -137
  75. package/dependencies/lz4/lib/dll/example/Makefile +63 -0
  76. package/dependencies/lz4/lib/dll/example/README.md +69 -69
  77. package/dependencies/lz4/lib/dll/liblz4.def +62 -62
  78. package/dependencies/lz4/lib/liblz4-dll.rc.in +35 -35
  79. package/dependencies/lz4/lib/liblz4.pc.in +14 -14
  80. package/dependencies/lz4/lib/lz4.c +2722 -2495
  81. package/dependencies/lz4/lib/lz4.h +842 -774
  82. package/dependencies/lz4/lib/lz4file.c +311 -0
  83. package/dependencies/lz4/lib/lz4file.h +93 -0
  84. package/dependencies/lz4/lib/lz4frame.c +2078 -1899
  85. package/dependencies/lz4/lib/lz4frame.h +692 -623
  86. package/dependencies/lz4/lib/lz4frame_static.h +47 -47
  87. package/dependencies/lz4/lib/lz4hc.c +1631 -1615
  88. package/dependencies/lz4/lib/lz4hc.h +413 -413
  89. package/dependencies/lz4/lib/xxhash.c +1030 -1030
  90. package/dependencies/lz4/lib/xxhash.h +328 -328
  91. package/dependencies/v8/v8-fast-api-calls-v16.h +790 -790
  92. package/dependencies/v8/v8-fast-api-calls.h +784 -888
  93. package/dist/index.cjs +1050 -584
  94. package/dist/index.cjs.map +1 -1
  95. package/index.d.cts +420 -0
  96. package/index.d.ts +450 -385
  97. package/index.js +38 -37
  98. package/keys.js +116 -102
  99. package/level.js +26 -26
  100. package/native.js +8 -5
  101. package/node-index.js +21 -17
  102. package/open.js +51 -17
  103. package/package.json +63 -21
  104. package/read.js +338 -95
  105. package/src/compression.cpp +12 -9
  106. package/src/cursor.cpp +82 -31
  107. package/src/dbi.cpp +78 -40
  108. package/src/env.cpp +336 -68
  109. package/src/lmdb-js.cpp +64 -64
  110. package/src/lmdb-js.h +83 -49
  111. package/src/misc.cpp +297 -28
  112. package/src/ordered-binary.cpp +46 -46
  113. package/src/txn.cpp +210 -257
  114. package/src/v8-functions.cpp +170 -166
  115. package/src/windows.c +34 -34
  116. package/src/writer.cpp +169 -84
  117. package/util/RangeIterable.js +112 -17
  118. package/util/set-optional-deps.cjs +14 -10
  119. package/util/when.js +8 -8
  120. package/write.js +145 -121
  121. package/dependencies/lmdb-data-v1/libraries/liblmdb/Makefile +0 -118
  122. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.1 +0 -40
  123. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.c +0 -135
  124. 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 = 100000;
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[0] = 0;
45
+ uint32[2] = 0;
43
46
  dynamicBytes.float64 = new Float64Array(buffer, 0, WRITE_BUFFER_SIZE >> 3);
44
- buffer.address = getAddress(dynamicBytes);
47
+ buffer.address = getBufferAddress(dynamicBytes);
45
48
  uint32.address = buffer.address + uint32.byteOffset;
46
- dynamicBytes.position = 0;
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[0] = TXN_DELIMITER | TXN_COMMITTED | TXN_FLUSHED;
72
- var txnResolution, lastQueuedResolution, nextResolution = {
73
- uint32: dynamicBytes.uint32, flagPosition: 0, flag: 0, valueBuffer: null, next: null, meta: null };
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: 0, flag: 0, valueBuffer: null, next: nextResolution, meta: null };
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 valueBuffer, valueSize, valueBufferStart;
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
- beforeCommitCallbacks[i]();
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
- (valueArrayBuffer.address = (getAddress(valueBuffer) - valueBuffer.byteOffset))))
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 (!flushPromise && overlappingSync)
275
- flushPromise = new Promise(resolve => flushResolvers.push(resolve));
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
- if (resolvers.length > 0) {
364
- let delay = Date.now() - start
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
- break;
391
+ break;
369
392
  case 2:
393
+ hasUnresolvedTxns = false;
370
394
  executeTxnCallbacks();
371
- break;
395
+ return hasUnresolvedTxns;
396
+ break;
372
397
  default:
373
- console.error(status);
374
- if (commitRejectPromise) {
375
- commitRejectPromise.reject(status);
376
- commitRejectPromise = null;
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.store) {
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
- return Atomics.or(uint32, flagPosition, newStatus);
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
- afterCommitCallbacks[i]({ next: uncommittedResolution, last: unwrittenResolution});
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
- //this.emit('begin-transaction');
511
- let promises;
512
- let txnCallbacks;
513
- for (let i = 0, l = nextTxnCallbacks.length; i < l; i++) {
514
- txnCallbacks = nextTxnCallbacks[i];
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[i] = result;
542
+ txnCallbacks[j] = result;
538
543
  } catch(error) {
539
544
  clearWriteTxn(parentTxn);
540
545
  env.abortTxn();
541
- txnError(error, i);
546
+ txnError(error, txnCallbacks, j);
542
547
  }
543
548
  } else {
544
549
  try {
545
550
  let result = userTxnCallback();
546
- txnCallbacks[i] = result;
551
+ txnCallbacks[j] = result;
547
552
  if (result && result.then) {
548
- if (!promises)
549
- promises = [];
550
- promises.push(result.catch(() => {}));
553
+ hasUnresolvedTxns = true;
554
+ await result;
551
555
  }
552
556
  } catch(error) {
553
- txnError(error, i);
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
- function txnError(error, i) {
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.cursorCount > 0)
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 = versionsOrOptions.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 finishStartWrite = writeInstructions(key === undefined || version === undefined ? 1 : 4, this, key, undefined, undefined, version);
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, undefined, undefined, undefined, undefined)(callback);
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, undefined, undefined, undefined, undefined)(callback);
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) == SYNC_PROMISE_SUCCESS, overlappingSync? 0x10002 : 2); // non-abortable, async flush
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) == SYNC_PROMISE_SUCCESS, overlappingSync? 0x10002 : 2); // non-abortable, async flush
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 (!nextResolution.callbacks) {
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
- nextResolution.callbacks = txnCallbacks;
754
- txnCallbacks.results = writeInstructions(8 | (this.strictAsyncOrder ? 0x100000 : 0), this)();
771
+ txnCallbacks.results = commitPromise;
772
+ nextTxnCallbacks.push(txnCallbacks);
755
773
  txnIndex = 0;
756
774
  } else {
757
- txnCallbacks = lastQueuedResolution.callbacks;
758
- txnIndex = txnCallbacks.push(asChild ? { callback, asChild } : callback) - 1;
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 && !this.isCaching) // can't use child transactions in write maps or caching stores
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) {