@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/index.js CHANGED
@@ -1,37 +1,38 @@
1
- import { EventEmitter } from 'events';
2
- import { setExternals, setNativeFunctions, Dbi } from './native.js';
3
- import { arch, tmpdir, platform } from 'os';
4
- import fs from 'fs';
5
- import { Encoder as MsgpackrEncoder } from 'msgpackr';
6
- import { WeakLRUCache } from 'weak-lru-cache';
7
- import * as orderedBinary from 'ordered-binary';
8
-
9
-
10
- orderedBinary.enableNullTermination();
11
- setExternals({
12
- arch, fs, tmpdir, MsgpackrEncoder, WeakLRUCache, orderedBinary,
13
- EventEmitter, os: platform(), onExit(callback) {
14
- if (process.getMaxListeners() < process.listenerCount('exit') + 8)
15
- process.setMaxListeners(process.listenerCount('exit') + 8);
16
- process.on('exit', callback);
17
- },
18
- });
19
- export { toBufferKey as keyValueToBuffer, compareKeys, compareKeys as compareKey, fromBufferKey as bufferToKeyValue } from 'ordered-binary';
20
- export { ABORT, IF_EXISTS, asBinary } from './write.js';
21
- import { ABORT, IF_EXISTS, asBinary } from './write.js';
22
- export { levelup } from './level.js';
23
- import { levelup } from './level.js';
24
- export { clearKeptObjects } from './native.js';
25
- import { nativeAddon } from './native.js';
26
- export let { noop } = nativeAddon;
27
- export { open, openAsClass, getLastVersion, allDbs } from './open.js';
28
- import { toBufferKey as keyValueToBuffer, compareKeys as compareKey, fromBufferKey as bufferToKeyValue } from 'ordered-binary';
29
- import { open, openAsClass, getLastVersion } from './open.js';
30
- export const TransactionFlags = {
31
- ABORTABLE: 1,
32
- SYNCHRONOUS_COMMIT: 2,
33
- NO_SYNC_FLUSH: 0x10000,
34
- };
35
- export default {
36
- open, openAsClass, getLastVersion, compareKey, keyValueToBuffer, bufferToKeyValue, ABORT, IF_EXISTS, asBinary, levelup, TransactionFlags
37
- };
1
+ import { EventEmitter } from 'events';
2
+ import { setExternals, setNativeFunctions, Dbi } from './native.js';
3
+ import { arch, tmpdir, platform } from 'os';
4
+ import fs from 'fs';
5
+ import { Encoder as MsgpackrEncoder } from 'msgpackr';
6
+ import { WeakLRUCache } from 'weak-lru-cache';
7
+ import * as orderedBinary from 'ordered-binary';
8
+
9
+
10
+ orderedBinary.enableNullTermination();
11
+ setExternals({
12
+ arch, fs, tmpdir, MsgpackrEncoder, WeakLRUCache, orderedBinary,
13
+ EventEmitter, os: platform(), onExit(callback) {
14
+ if (process.getMaxListeners() < process.listenerCount('exit') + 8)
15
+ process.setMaxListeners(process.listenerCount('exit') + 8);
16
+ process.on('exit', callback);
17
+ },
18
+ });
19
+ export { toBufferKey as keyValueToBuffer, compareKeys, compareKeys as compareKey, fromBufferKey as bufferToKeyValue } from 'ordered-binary';
20
+ export { ABORT, IF_EXISTS, asBinary } from './write.js';
21
+ import { ABORT, IF_EXISTS, asBinary } from './write.js';
22
+ export { levelup } from './level.js';
23
+ export { SKIP } from './util/RangeIterable.js';
24
+ import { levelup } from './level.js';
25
+ export { clearKeptObjects } from './native.js';
26
+ import { nativeAddon } from './native.js';
27
+ export let { noop } = nativeAddon;
28
+ export { open, openAsClass, getLastVersion, allDbs, getLastTxnId } from './open.js';
29
+ import { toBufferKey as keyValueToBuffer, compareKeys as compareKey, fromBufferKey as bufferToKeyValue } from 'ordered-binary';
30
+ import { open, openAsClass, getLastVersion } from './open.js';
31
+ export const TransactionFlags = {
32
+ ABORTABLE: 1,
33
+ SYNCHRONOUS_COMMIT: 2,
34
+ NO_SYNC_FLUSH: 0x10000,
35
+ };
36
+ export default {
37
+ open, openAsClass, getLastVersion, compareKey, keyValueToBuffer, bufferToKeyValue, ABORT, IF_EXISTS, asBinary, levelup, TransactionFlags
38
+ };
package/keys.js CHANGED
@@ -1,102 +1,116 @@
1
- import { getAddress, orderedBinary } from './native.js';
2
-
3
- const writeUint32Key = (key, target, start) => {
4
- (target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length))).setUint32(start, key, true);
5
- return start + 4;
6
- };
7
- const readUint32Key = (target, start) => {
8
- return (target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length))).getUint32(start, true);
9
- };
10
- const writeBufferKey = (key, target, start) => {
11
- target.set(key, start);
12
- return key.length + start;
13
- };
14
- const Uint8ArraySlice = Uint8Array.prototype.slice;
15
- const readBufferKey = (target, start, end) => {
16
- return Uint8ArraySlice.call(target, start, end);
17
- };
18
-
19
- export function applyKeyHandling(store) {
20
- if (store.encoding == 'ordered-binary') {
21
- store.encoder = store.decoder = {
22
- writeKey: orderedBinary.writeKey,
23
- readKey: orderedBinary.readKey,
24
- };
25
- }
26
- if (store.encoder && store.encoder.writeKey && !store.encoder.encode) {
27
- store.encoder.encode = function(value) {
28
- return saveKey(value, this.writeKey, false, store.maxKeySize);
29
- };
30
- }
31
- if (store.decoder && store.decoder.readKey && !store.decoder.decode) {
32
- store.decoder.decode = function(buffer) { return this.readKey(buffer, 0, buffer.length); };
33
- store.decoderCopies = true;
34
- }
35
- if (store.keyIsUint32 || store.keyEncoding == 'uint32') {
36
- store.writeKey = writeUint32Key;
37
- store.readKey = readUint32Key;
38
- } else if (store.keyIsBuffer || store.keyEncoding == 'binary') {
39
- store.writeKey = writeBufferKey;
40
- store.readKey = readBufferKey;
41
- } else if (store.keyEncoder) {
42
- store.writeKey = store.keyEncoder.writeKey;
43
- store.readKey = store.keyEncoder.readKey;
44
- } else {
45
- store.writeKey = orderedBinary.writeKey;
46
- store.readKey = orderedBinary.readKey;
47
- }
48
- }
49
-
50
- let saveBuffer, saveDataView = { setFloat64() {}, setUint32() {} }, saveDataAddress;
51
- let savePosition = 8000;
52
- let DYNAMIC_KEY_BUFFER_SIZE = 8192;
53
- function allocateSaveBuffer() {
54
- saveBuffer = typeof Buffer != 'undefined' ? Buffer.alloc(DYNAMIC_KEY_BUFFER_SIZE) : new Uint8Array(DYNAMIC_KEY_BUFFER_SIZE);
55
- saveBuffer.buffer.address = getAddress(saveBuffer);
56
- saveDataAddress = saveBuffer.buffer.address;
57
- // TODO: Conditionally only do this for key sequences?
58
- saveDataView.setUint32(savePosition, 0xffffffff);
59
- saveDataView.setFloat64(savePosition + 4, saveDataAddress, true); // save a pointer from the old buffer to the new address for the sake of the prefetch sequences
60
- saveBuffer.dataView = saveDataView = new DataView(saveBuffer.buffer, saveBuffer.byteOffset, saveBuffer.byteLength);
61
- savePosition = 0;
62
- }
63
- export function saveKey(key, writeKey, saveTo, maxKeySize) {
64
- if (savePosition > 7800) {
65
- allocateSaveBuffer();
66
- }
67
- let start = savePosition;
68
- try {
69
- savePosition = key === undefined ? start + 4 :
70
- writeKey(key, saveBuffer, start + 4);
71
- } catch (error) {
72
- saveBuffer.fill(0, start + 4); // restore zeros
73
- if (error.name == 'RangeError') {
74
- if (8180 - start < maxKeySize) {
75
- allocateSaveBuffer(); // try again:
76
- return saveKey(key, writeKey, saveTo, maxKeySize);
77
- }
78
- throw new Error('Key was too large, max key size is ' + maxKeySize);
79
- } else
80
- throw error;
81
- }
82
- let length = savePosition - start - 4;
83
- if (length > maxKeySize) {
84
- throw new Error('Key of size ' + length + ' was too large, max key size is ' + maxKeySize);
85
- }
86
- if (savePosition >= 8160) { // need to reserve enough room at the end for pointers
87
- savePosition = start // reset position
88
- allocateSaveBuffer(); // try again:
89
- return saveKey(key, writeKey, saveTo, maxKeySize);
90
- }
91
- if (saveTo) {
92
- saveDataView.setUint32(start, length, true); // save the length
93
- saveTo.saveBuffer = saveBuffer;
94
- savePosition = (savePosition + 12) & 0xfffffc;
95
- return start + saveDataAddress;
96
- } else {
97
- saveBuffer.start = start + 4;
98
- saveBuffer.end = savePosition;
99
- savePosition = (savePosition + 7) & 0xfffff8; // full 64-bit word alignment since these are usually copied
100
- return saveBuffer;
101
- }
102
- }
1
+ import { getAddress, orderedBinary } from './native.js';
2
+
3
+ const REUSE_BUFFER_MODE = 512;
4
+ const writeUint32Key = (key, target, start) => {
5
+ (target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length))).setUint32(start, key, true);
6
+ return start + 4;
7
+ };
8
+ const readUint32Key = (target, start) => {
9
+ return (target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length))).getUint32(start, true);
10
+ };
11
+ const writeBufferKey = (key, target, start) => {
12
+ target.set(key, start);
13
+ return key.length + start;
14
+ };
15
+ const Uint8ArraySlice = Uint8Array.prototype.slice;
16
+ const readBufferKey = (target, start, end) => {
17
+ return Uint8ArraySlice.call(target, start, end);
18
+ };
19
+
20
+ let lastEncodedValue, bytes;
21
+ export function applyKeyHandling(store) {
22
+ if (store.encoding == 'ordered-binary') {
23
+ store.encoder = store.decoder = {
24
+ writeKey: orderedBinary.writeKey,
25
+ readKey: orderedBinary.readKey,
26
+ };
27
+ }
28
+ if (store.encoder && store.encoder.writeKey && !store.encoder.encode) {
29
+ store.encoder.encode = function(value, mode) {
30
+ if (typeof value !== 'object' && value && value === lastEncodedValue) {
31
+ // reuse the last serialized bytes
32
+ // NOTE that it is very important that nothing else calls saveKey with saveTo: false
33
+ } else {
34
+ lastEncodedValue = value;
35
+ bytes = saveKey(value, this.writeKey, false, store.maxKeySize);
36
+ }
37
+ if (bytes.end > 0 && !(REUSE_BUFFER_MODE & mode)) {
38
+ return bytes.subarray(bytes.start, bytes.end);
39
+ }
40
+ return bytes;
41
+ };
42
+ store.encoder.copyBuffers = true; // just an indicator for the buffer reuse in write.js
43
+ }
44
+ if (store.decoder && store.decoder.readKey && !store.decoder.decode) {
45
+ store.decoder.decode = function(buffer) { return this.readKey(buffer, 0, buffer.length); };
46
+ store.decoderCopies = true;
47
+ }
48
+ if (store.keyIsUint32 || store.keyEncoding == 'uint32') {
49
+ store.writeKey = writeUint32Key;
50
+ store.readKey = readUint32Key;
51
+ } else if (store.keyIsBuffer || store.keyEncoding == 'binary') {
52
+ store.writeKey = writeBufferKey;
53
+ store.readKey = readBufferKey;
54
+ } else if (store.keyEncoder) {
55
+ store.writeKey = store.keyEncoder.writeKey;
56
+ store.readKey = store.keyEncoder.readKey;
57
+ } else {
58
+ store.writeKey = orderedBinary.writeKey;
59
+ store.readKey = orderedBinary.readKey;
60
+ }
61
+ }
62
+
63
+ let saveBuffer, uint32, saveDataView = { setFloat64() {}, setUint32() {} }, saveDataAddress;
64
+ let savePosition = 8000;
65
+ let DYNAMIC_KEY_BUFFER_SIZE = 8192;
66
+ function allocateSaveBuffer() {
67
+ saveBuffer = typeof Buffer != 'undefined' ? Buffer.alloc(DYNAMIC_KEY_BUFFER_SIZE) : new Uint8Array(DYNAMIC_KEY_BUFFER_SIZE);
68
+ uint32 = null;
69
+ saveBuffer.buffer.address = getAddress(saveBuffer.buffer);
70
+ saveDataAddress = saveBuffer.buffer.address;
71
+ // TODO: Conditionally only do this for key sequences?
72
+ saveDataView.setUint32(savePosition, 0xffffffff);
73
+ saveDataView.setFloat64(savePosition + 4, saveDataAddress, true); // save a pointer from the old buffer to the new address for the sake of the prefetch sequences
74
+ saveDataView = saveBuffer.dataView || (saveBuffer.dataView = new DataView(saveBuffer.buffer, saveBuffer.byteOffset, saveBuffer.byteLength));
75
+ savePosition = 0;
76
+ }
77
+ export function saveKey(key, writeKey, saveTo, maxKeySize, flags) {
78
+ if (savePosition > 7800) {
79
+ allocateSaveBuffer();
80
+ }
81
+ let start = savePosition;
82
+ try {
83
+ savePosition = key === undefined ? start + 4 :
84
+ writeKey(key, saveBuffer, start + 4);
85
+ } catch (error) {
86
+ saveBuffer.fill(0, start + 4); // restore zeros
87
+ if (error.name == 'RangeError') {
88
+ if (8180 - start < maxKeySize) {
89
+ allocateSaveBuffer(); // try again:
90
+ return saveKey(key, writeKey, saveTo, maxKeySize);
91
+ }
92
+ throw new Error('Key was too large, max key size is ' + maxKeySize);
93
+ } else
94
+ throw error;
95
+ }
96
+ let length = savePosition - start - 4;
97
+ if (length > maxKeySize) {
98
+ throw new Error('Key of size ' + length + ' was too large, max key size is ' + maxKeySize);
99
+ }
100
+ if (savePosition >= 8160) { // need to reserve enough room at the end for pointers
101
+ savePosition = start // reset position
102
+ allocateSaveBuffer(); // try again:
103
+ return saveKey(key, writeKey, saveTo, maxKeySize);
104
+ }
105
+ if (saveTo) {
106
+ saveDataView.setUint32(start, flags ? length | flags : length, true); // save the length
107
+ saveTo.saveBuffer = saveBuffer;
108
+ savePosition = (savePosition + 12) & 0xfffffc;
109
+ return start + saveDataAddress;
110
+ } else {
111
+ saveBuffer.start = start + 4;
112
+ saveBuffer.end = savePosition;
113
+ savePosition = (savePosition + 7) & 0xfffff8; // full 64-bit word alignment since these are usually copied
114
+ return saveBuffer;
115
+ }
116
+ }
package/level.js CHANGED
@@ -1,27 +1,27 @@
1
- export function levelup(store) {
2
- return Object.assign(Object.create(store), {
3
- get(key, options, callback) {
4
- let result = store.get(key);
5
- if (typeof options == 'function')
6
- callback = options;
7
- if (callback) {
8
- if (result === undefined)
9
- callback(new NotFoundError());
10
- else
11
- callback(null, result);
12
- } else {
13
- if (result === undefined)
14
- return Promise.reject(new NotFoundError());
15
- else
16
- return Promise.resolve(result);
17
- }
18
- },
19
- });
20
- }
21
- class NotFoundError extends Error {
22
- constructor(message) {
23
- super(message);
24
- this.name = 'NotFoundError';
25
- this.notFound = true;
26
- }
1
+ export function levelup(store) {
2
+ return Object.assign(Object.create(store), {
3
+ get(key, options, callback) {
4
+ let result = store.get(key);
5
+ if (typeof options == 'function')
6
+ callback = options;
7
+ if (callback) {
8
+ if (result === undefined)
9
+ callback(new NotFoundError());
10
+ else
11
+ callback(null, result);
12
+ } else {
13
+ if (result === undefined)
14
+ return Promise.reject(new NotFoundError());
15
+ else
16
+ return Promise.resolve(result);
17
+ }
18
+ },
19
+ });
20
+ }
21
+ class NotFoundError extends Error {
22
+ constructor(message) {
23
+ super(message);
24
+ this.name = 'NotFoundError';
25
+ this.notFound = true;
26
+ }
27
27
  }
package/native.js CHANGED
@@ -1,14 +1,12 @@
1
1
  import { dirname, join, default as pathModule } from 'path';
2
2
  import { fileURLToPath } from 'url';
3
3
  import loadNAPI from 'node-gyp-build-optional-packages';
4
- export let Env, Txn, Dbi, Compression, Cursor, getAddress, createBufferForAddress, clearKeptObjects, setGlobalBuffer, arch, fs, os, onExit, tmpdir, lmdbError, path, EventEmitter, orderedBinary, MsgpackrEncoder, WeakLRUCache, setEnvMap, getEnvMap, getByBinary, detachBuffer, write, position, iterate, prefetch, resetTxn, getCurrentValue, getCurrentShared, getStringByBinary, getSharedByBinary, compress;
5
-
4
+ export let Env, Txn, Dbi, Compression, Cursor, getAddress, getBufferAddress, createBufferForAddress, clearKeptObjects, globalBuffer, setGlobalBuffer, arch, fs, os, onExit, tmpdir, lmdbError, path, EventEmitter, orderedBinary, MsgpackrEncoder, WeakLRUCache, setEnvMap, getEnvMap, getByBinary, detachBuffer, startRead, setReadCallback, write, position, iterate, prefetch, resetTxn, getCurrentValue, getCurrentShared, getStringByBinary, getSharedByBinary, getSharedBuffer, compress;
6
5
  path = pathModule;
7
- let dirName = (typeof __dirname == 'string' ? __dirname : // for bun, which doesn't have fileURLToPath
8
- dirname(fileURLToPath(import.meta.url))).replace(/dist$/, ''); // for node, which doesn't have __dirname in ESM
6
+ let dirName = dirname(fileURLToPath(import.meta.url)).replace(/dist$/, '');
9
7
  export let nativeAddon = loadNAPI(dirName);
10
8
 
11
- if (process.isBun) {
9
+ if (process.isBun && false) {
12
10
  const { linkSymbols, FFIType } = require('bun:ffi');
13
11
  let lmdbLib = linkSymbols({
14
12
  getByBinary: {
@@ -49,11 +47,16 @@ export function setNativeFunctions(externals) {
49
47
  Dbi = externals.Dbi;
50
48
  Compression = externals.Compression;
51
49
  getAddress = externals.getAddress;
50
+ getBufferAddress = externals.getBufferAddress;
52
51
  createBufferForAddress = externals.createBufferForAddress;
53
52
  clearKeptObjects = externals.clearKeptObjects || function() {};
54
53
  getByBinary = externals.getByBinary;
55
54
  detachBuffer = externals.detachBuffer;
55
+ startRead = externals.startRead;
56
+ setReadCallback = externals.setReadCallback;
56
57
  setGlobalBuffer = externals.setGlobalBuffer;
58
+ globalBuffer = externals.globalBuffer;
59
+ getSharedBuffer = externals.getSharedBuffer;
57
60
  prefetch = externals.prefetch;
58
61
  iterate = externals.iterate;
59
62
  position = externals.position;
package/node-index.js CHANGED
@@ -1,26 +1,30 @@
1
1
  import { createRequire } from 'module';
2
2
  import { setRequire } from './open.js';
3
3
  import { nativeAddon, setNativeFunctions } from './native.js';
4
- import { setFlagsFromString } from 'v8';
5
- setRequire(createRequire(import.meta.url));
4
+ export { nativeAddon } from './native.js'
5
+ let require = createRequire(import.meta.url);
6
+ setRequire(require);
6
7
  export let v8AccelerationEnabled = false
7
8
 
8
9
  let versions = process.versions;
9
- let [ majorVersion, minorVersion ] = versions.node.split('.')
10
-
11
- if (versions.v8 && +majorVersion == nativeAddon.version.nodeCompiledVersion) {
12
- let v8Funcs = {};
13
- let fastApiCalls = (majorVersion == 17 || majorVersion == 18 || majorVersion == 16 && minorVersion > 6) && !process.env.DISABLE_TURBO_CALLS;
14
- if (fastApiCalls)
15
- setFlagsFromString('--turbo-fast-api-calls')
16
- nativeAddon.enableDirectV8(v8Funcs, fastApiCalls);
17
- Object.assign(nativeAddon, v8Funcs);
18
- v8AccelerationEnabled = true;
19
- } else if (majorVersion == 14) {
20
- // node v14 only has ABI compatibility with node v16 for zero-arg clearKeptObjects
21
- let v8Funcs = {};
22
- nativeAddon.enableDirectV8(v8Funcs, false);
23
- nativeAddon.clearKeptObjects = v8Funcs.clearKeptObjects;
10
+ if (!versions.deno && !process.isBun) {
11
+ let [ majorVersion, minorVersion ] = versions.node.split('.');
12
+ if (versions.v8 && +majorVersion == nativeAddon.version.nodeCompiledVersion) {
13
+ let v8Funcs = {};
14
+ let fastApiCalls = (majorVersion == 17 || majorVersion == 18 || majorVersion == 16 && minorVersion > 8) && !process.env.DISABLE_TURBO_CALLS;
15
+ if (fastApiCalls) {
16
+ require('v8').setFlagsFromString('--turbo-fast-api-calls');
17
+ }
18
+ nativeAddon.enableDirectV8(v8Funcs, fastApiCalls);
19
+ Object.assign(nativeAddon, v8Funcs);
20
+ v8AccelerationEnabled = true;
21
+ } else if (majorVersion == 14) {
22
+ // node v14 only has ABI compatibility with node v16 for zero-arg clearKeptObjects
23
+ let v8Funcs = {};
24
+ nativeAddon.enableDirectV8(v8Funcs, false);
25
+ nativeAddon.clearKeptObjects = v8Funcs.clearKeptObjects;
26
+ }
27
+ nativeAddon.enableThreadSafeCalls();
24
28
  }
25
29
  setNativeFunctions(nativeAddon);
26
30
 
package/open.js CHANGED
@@ -1,4 +1,5 @@
1
- import { Compression, getAddress, arch, fs, path as pathModule, lmdbError, EventEmitter, MsgpackrEncoder, Env, Dbi, tmpdir, os, nativeAddon } from './native.js';
1
+ import { Compression, getAddress, arch, fs, path as pathModule, lmdbError, EventEmitter, MsgpackrEncoder, Env,
2
+ Dbi, tmpdir, os, nativeAddon } from './native.js';
2
3
  import { CachingStore, setGetLastVersion } from './caching.js';
3
4
  import { addReadMethods, makeReusableBuffer } from './read.js';
4
5
  import { addWriteMethods } from './write.js';
@@ -8,7 +9,7 @@ export function setRequire(require) {
8
9
  moduleRequire = require;
9
10
  }
10
11
 
11
- setGetLastVersion(getLastVersion);
12
+ setGetLastVersion(getLastVersion, getLastTxnId);
12
13
  let keyBytes, keyBytesView;
13
14
  const buffers = [];
14
15
  const { onExit, getEnvsPointer, setEnvsPointer, getEnvFlags, setJSFlags } = nativeAddon;
@@ -20,6 +21,9 @@ else
20
21
  // this is hard coded as an upper limit because it is important assumption of the fixed buffers in writing instructions
21
22
  // this corresponds to the max key size for 8KB pages
22
23
  const MAX_KEY_SIZE = 4026;
24
+ // this is used as the key size by default because default page size is OS page size, which is usually
25
+ // 4KB (but is 16KB on M-series MacOS), and this keeps a consistent max key size when no page size specified.
26
+ const DEFAULT_MAX_KEY_SIZE = 1978;
23
27
  const DEFAULT_COMMIT_DELAY = 0;
24
28
 
25
29
  export const allDbs = new Map();
@@ -27,6 +31,20 @@ let defaultCompression;
27
31
  let lastSize;
28
32
  let hasRegisteredOnExit;
29
33
  export function open(path, options) {
34
+ if (nativeAddon.open) {
35
+ if (nativeAddon.open !== open) {
36
+ // this is the case when lmdb-js has been opened in both ESM and CJS mode, which means that there are two
37
+ // separate JS modules, but they are both using the same native module.
38
+ getLastVersion = nativeAddon.getLastVersion;
39
+ getLastTxnId = nativeAddon.getLastTxnId;
40
+ setGetLastVersion(getLastVersion, getLastTxnId);
41
+ return nativeAddon.open(path, options);
42
+ }
43
+ } else {
44
+ nativeAddon.open = open;
45
+ nativeAddon.getLastVersion = getLastVersion;
46
+ nativeAddon.getLastTxnId = getLastTxnId;
47
+ }
30
48
  if (!keyBytes) // TODO: Consolidate get buffer and key buffer (don't think we need both)
31
49
  allocateFixedBuffer();
32
50
  if (typeof path == 'object' && !options) {
@@ -34,8 +52,9 @@ export function open(path, options) {
34
52
  path = options.path;
35
53
  }
36
54
  options = options || {};
55
+ let noFSAccess = options.noFSAccess; // this can only be configured on open, can't let users change it
37
56
  let userOptions = options;
38
- if (!path) {
57
+ if (path == null) {
39
58
  options = Object.assign({
40
59
  deleteOnClose: true,
41
60
  noSync: true,
@@ -46,17 +65,16 @@ export function open(path, options) {
46
65
  let extension = pathModule.extname(path);
47
66
  let name = pathModule.basename(path, extension);
48
67
  let is32Bit = arch().endsWith('32');
49
- let remapChunks = options.remapChunks || (options.mapSize ?
68
+ let remapChunks = options.remapChunks || options.encryptionKey || (options.mapSize ?
50
69
  (is32Bit && options.mapSize > 0x100000000) : // larger than fits in address space, must use dynamic maps
51
70
  is32Bit); // without a known map size, we default to being able to handle large data correctly/well*/
71
+ let userMapSize = options.mapSize;
52
72
  options = Object.assign({
53
- path,
54
73
  noSubdir: Boolean(extension),
55
74
  isRoot: true,
56
75
  maxDbs: 12,
57
76
  remapChunks,
58
77
  keyBytes,
59
- pageSize: 4096,
60
78
  overlappingSync: (options.noSync || options.readOnly) ? false : (os != 'win32'),
61
79
  // default map size limit of 4 exabytes when using remapChunks, since it is not preallocated and we can
62
80
  // make it super huge.
@@ -64,9 +82,18 @@ export function open(path, options) {
64
82
  0x20000, // Otherwise we start small with 128KB
65
83
  safeRestore: process.env.LMDB_RESTORE == 'safe',
66
84
  }, options);
85
+ options.path = path;
67
86
  if (options.asyncTransactionOrder == 'strict') {
68
87
  options.strictAsyncOrder = true;
69
88
  }
89
+ if (nativeAddon.version.major + nativeAddon.version.minor / 100 + nativeAddon.version.patch / 10000 < 0.0980) {
90
+ options.overlappingSync = false; // not support on older versions
91
+ options.trackMetrics = false;
92
+ options.usePreviousSnapshot = false;
93
+ options.safeRestore = false;
94
+ options.remapChunks = false;
95
+ if (!userMapSize) options.mapSize = 0x40000000; // 1 GB
96
+ }
70
97
 
71
98
  if (!exists(options.noSubdir ? pathModule.dirname(path) : path))
72
99
  fs.mkdirSync(options.noSubdir ? pathModule.dirname(path) : path, { recursive: true }
@@ -102,17 +129,20 @@ export function open(path, options) {
102
129
  (options.noMemInit ? 0x1000000 : 0) |
103
130
  (options.usePreviousSnapshot ? 0x2000000 : 0) |
104
131
  (options.remapChunks ? 0x4000000 : 0) |
105
- (options.safeRestore ? 0x8000000 : 0);
132
+ (options.safeRestore ? 0x800 : 0) |
133
+ (options.trackMetrics ? 0x400 : 0);
106
134
 
107
135
  let env = new Env();
108
136
  let jsFlags = (options.overlappingSync ? 0x1000 : 0) |
109
137
  (options.separateFlushed ? 1 : 0) |
110
- (options.deleteOnClose ? 2 : 0)
138
+ (options.deleteOnClose ? 2 : 0);
111
139
  let rc = env.open(options, flags, jsFlags);
140
+ env.path = path;
112
141
  if (rc)
113
142
  lmdbError(rc);
143
+ delete options.keyBytes // no longer needed, don't copy to stores
114
144
  let maxKeySize = env.getMaxKeySize();
115
- maxKeySize = Math.min(maxKeySize, MAX_KEY_SIZE);
145
+ maxKeySize = Math.min(maxKeySize, options.pageSize ? MAX_KEY_SIZE : DEFAULT_MAX_KEY_SIZE);
116
146
  flags = getEnvFlags(env.address); // re-retrieve them, they are not necessarily the same if we are connecting to an existing env
117
147
  if (flags & 0x1000) {
118
148
  if (userOptions.noSync) {
@@ -130,7 +160,6 @@ export function open(path, options) {
130
160
  }
131
161
 
132
162
  env.readerCheck(); // clear out any stale entries
133
- let stores = [];
134
163
  if ((options.overlappingSync || options.deleteOnClose) && !hasRegisteredOnExit && process.on) {
135
164
  hasRegisteredOnExit = true;
136
165
  process.on('exit', onExit);
@@ -167,14 +196,14 @@ export function open(path, options) {
167
196
  (dbOptions.integerDup ? 0x20 : 0) |
168
197
  (dbOptions.reverseDup ? 0x40 : 0) |
169
198
  (!options.readOnly && dbOptions.create !== false ? 0x40000 : 0) |
170
- (dbOptions.useVersions ? 0x1000 : 0);
199
+ (dbOptions.useVersions ? 0x100 : 0);
171
200
  let keyType = (dbOptions.keyIsUint32 || dbOptions.keyEncoding == 'uint32') ? 2 : keyIsBuffer ? 3 : 0;
172
201
  if (keyType == 2)
173
202
  flags |= 0x08; // integer key
174
203
 
175
204
  if (options.readOnly) {
176
205
  // in read-only mode we use a read-only txn to open the database
177
- // TODO: LMDB is actually not entire thread-safe when it comes to opening databases with
206
+ // TODO: LMDB is actually not entirely thread-safe when it comes to opening databases with
178
207
  // read-only transactions since there is a race condition on setting the update dbis that
179
208
  // occurs outside the lock
180
209
  // make sure we are using a fresh read txn, so we don't want to share with a cursor txn
@@ -219,7 +248,7 @@ export function open(path, options) {
219
248
  }
220
249
  if (Encoder) {
221
250
  this.encoder = new Encoder(Object.assign(
222
- assignConstrainedProperties(['copyBuffers', 'getStructures', 'saveStructures', 'useFloat32', 'useRecords', 'structuredClone', 'variableMapSize', 'useTimestamp32', 'largeBigIntToFloat', 'encodeUndefinedAsNil', 'int64AsNumber', 'onInvalidDate', 'mapsAsObjects', 'useTag259ForMaps', 'pack', 'maxSharedStructures', 'shouldShareStructure'],
251
+ assignConstrainedProperties(['copyBuffers', 'getStructures', 'saveStructures', 'useFloat32', 'useRecords', 'structuredClone', 'variableMapSize', 'useTimestamp32', 'largeBigIntToFloat', 'encodeUndefinedAsNil', 'int64AsNumber', 'onInvalidDate', 'mapsAsObjects', 'useTag259ForMaps', 'pack', 'maxSharedStructures', 'shouldShareStructure', 'randomAccessStructure', 'freezeData'],
223
252
  this.sharedStructuresKey ? this.setupSharedStructures() : {
224
253
  copyBuffers: true, // need to copy any embedded buffers that are found since we use unsafe buffers
225
254
  }, options, dbOptions), this.encoder));
@@ -235,7 +264,6 @@ export function open(path, options) {
235
264
  this.maxKeySize = maxKeySize;
236
265
  applyKeyHandling(this);
237
266
  allDbs.set(dbName ? name + '-' + dbName : name, this);
238
- stores.push(this);
239
267
  }
240
268
  openDB(dbName, dbOptions) {
241
269
  if (this.dupSort && this.name == null)
@@ -264,7 +292,10 @@ export function open(path, options) {
264
292
  callback(null, db);
265
293
  return db;
266
294
  }
267
- backup(path) {
295
+ backup(path, compact) {
296
+ if (noFSAccess)
297
+ return;
298
+ fs.mkdirSync(pathModule.dirname(path), { recursive: true });
268
299
  return new Promise((resolve, reject) => env.copy(path, false, (error) => {
269
300
  if (error) {
270
301
  reject(error);
@@ -377,11 +408,14 @@ export function openAsClass(path, options) {
377
408
  export function getLastVersion() {
378
409
  return keyBytesView.getFloat64(16, true);
379
410
  }
380
-
381
411
  export function setLastVersion(version) {
382
412
  return keyBytesView.setFloat64(16, version, true);
383
413
  }
384
414
 
415
+ export function getLastTxnId() {
416
+ return keyBytesView.getUint32(32, true);
417
+ }
418
+
385
419
  const KEY_BUFFER_SIZE = 4096;
386
420
  function allocateFixedBuffer() {
387
421
  keyBytes = typeof Buffer != 'undefined' ? Buffer.allocUnsafeSlow(KEY_BUFFER_SIZE) : new Uint8Array(KEY_BUFFER_SIZE);
@@ -389,7 +423,7 @@ function allocateFixedBuffer() {
389
423
  keyBytesView = keyBytes.dataView || (keyBytes.dataView = new DataView(keyBytes.buffer, 0, KEY_BUFFER_SIZE)); // max key size is actually 4026
390
424
  keyBytes.uint32 = new Uint32Array(keyBuffer, 0, KEY_BUFFER_SIZE >> 2);
391
425
  keyBytes.float64 = new Float64Array(keyBuffer, 0, KEY_BUFFER_SIZE >> 3);
392
- keyBytes.uint32.address = keyBytes.address = keyBuffer.address = getAddress(keyBytes);
426
+ keyBytes.uint32.address = keyBytes.address = keyBuffer.address = getAddress(keyBuffer);
393
427
  }
394
428
 
395
429
  function exists(path) {