@ohos-ports/lmdb 2.5.3 → 2.8.5-beta.1
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 +55 -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/read.js
CHANGED
|
@@ -1,44 +1,60 @@
|
|
|
1
1
|
import { RangeIterable } from './util/RangeIterable.js';
|
|
2
|
-
import { getAddress, Cursor, Txn, orderedBinary, lmdbError, getByBinary,
|
|
2
|
+
import { getAddress, Cursor, Txn, orderedBinary, lmdbError, getByBinary, setGlobalBuffer, prefetch, iterate, position as doPosition, resetTxn, getCurrentValue, getCurrentShared, getStringByBinary, globalBuffer, getSharedBuffer, startRead, setReadCallback } from './native.js';
|
|
3
3
|
import { saveKey } from './keys.js';
|
|
4
|
+
const IF_EXISTS = 3.542694326329068e-103;
|
|
4
5
|
const ITERATOR_DONE = { done: true, value: undefined };
|
|
5
6
|
const Uint8ArraySlice = Uint8Array.prototype.slice;
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
let getValueBytes = globalBuffer;
|
|
8
|
+
if (!getValueBytes.maxLength) {
|
|
9
|
+
getValueBytes.maxLength = getValueBytes.length;
|
|
10
|
+
getValueBytes.isGlobal = true;
|
|
11
|
+
Object.defineProperty(getValueBytes, 'length', { value: getValueBytes.length, writable: true, configurable: true });
|
|
12
|
+
}
|
|
8
13
|
const START_ADDRESS_POSITION = 4064;
|
|
9
14
|
const NEW_BUFFER_THRESHOLD = 0x8000;
|
|
15
|
+
const SOURCE_SYMBOL = Symbol.for('source');
|
|
16
|
+
export const UNMODIFIED = {};
|
|
17
|
+
let mmaps = [];
|
|
10
18
|
|
|
11
19
|
export function addReadMethods(LMDBStore, {
|
|
12
|
-
maxKeySize, env, keyBytes, keyBytesView, getLastVersion
|
|
20
|
+
maxKeySize, env, keyBytes, keyBytesView, getLastVersion, getLastTxnId
|
|
13
21
|
}) {
|
|
14
22
|
let readTxn, readTxnRenewed, asSafeBuffer = false;
|
|
15
23
|
let renewId = 1;
|
|
24
|
+
let outstandingReads = 0;
|
|
16
25
|
Object.assign(LMDBStore.prototype, {
|
|
17
|
-
getString(id) {
|
|
18
|
-
|
|
19
|
-
let string = getStringByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0));
|
|
26
|
+
getString(id, options) {
|
|
27
|
+
let txn = env.writeTxn || (options && options.transaction) || (readTxnRenewed ? readTxn : renewReadTxn(this));
|
|
28
|
+
let string = getStringByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0), txn.address || 0);
|
|
20
29
|
if (typeof string === 'number') { // indicates the buffer wasn't large enough
|
|
21
30
|
this._allocateGetBuffer(string);
|
|
22
31
|
// and then try again
|
|
23
|
-
string = getStringByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0));
|
|
32
|
+
string = getStringByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0), txn.address || 0);
|
|
24
33
|
}
|
|
25
34
|
if (string)
|
|
26
35
|
this.lastSize = string.length;
|
|
27
36
|
return string;
|
|
28
37
|
},
|
|
29
|
-
getBinaryFast(id) {
|
|
30
|
-
|
|
31
|
-
let
|
|
38
|
+
getBinaryFast(id, options) {
|
|
39
|
+
let rc;
|
|
40
|
+
let txn = env.writeTxn || (options && options.transaction) || (readTxnRenewed ? readTxn : renewReadTxn(this));
|
|
41
|
+
rc = this.lastSize = getByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0), (options && options.ifNotTxnId) || 0, txn.address || 0);
|
|
32
42
|
if (rc < 0) {
|
|
33
43
|
if (rc == -30798) // MDB_NOTFOUND
|
|
34
44
|
return; // undefined
|
|
45
|
+
if (rc == -30004) // txn id matched
|
|
46
|
+
return UNMODIFIED;
|
|
35
47
|
if (rc == -30781 /*MDB_BAD_VALSIZE*/ && this.writeKey(id, keyBytes, 0) == 0)
|
|
36
48
|
throw new Error(id === undefined ?
|
|
37
49
|
'A key is required for get, but is undefined' :
|
|
38
50
|
'Zero length key is not allowed in LMDB');
|
|
39
51
|
if (rc == -30000) // int32 overflow, read uint32
|
|
40
52
|
rc = this.lastSize = keyBytesView.getUint32(0, true);
|
|
41
|
-
else
|
|
53
|
+
else if (rc == -30001) {// shared buffer
|
|
54
|
+
this.lastSize = keyBytesView.getUint32(0, true);
|
|
55
|
+
let bufferId = keyBytesView.getUint32(4, true);
|
|
56
|
+
return getMMapBuffer(bufferId, this.lastSize);
|
|
57
|
+
} else
|
|
42
58
|
throw lmdbError(rc);
|
|
43
59
|
}
|
|
44
60
|
let compression = this.compression;
|
|
@@ -46,13 +62,89 @@ export function addReadMethods(LMDBStore, {
|
|
|
46
62
|
if (rc > bytes.maxLength) {
|
|
47
63
|
// this means the target buffer wasn't big enough, so the get failed to copy all the data from the database, need to either grow or use special buffer
|
|
48
64
|
return this._returnLargeBuffer(
|
|
49
|
-
() => getByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0))
|
|
50
|
-
() => getSharedByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0)));
|
|
65
|
+
() => getByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0), 0, txn.address || 0));
|
|
51
66
|
}
|
|
52
67
|
bytes.length = this.lastSize;
|
|
53
68
|
return bytes;
|
|
54
69
|
},
|
|
55
|
-
|
|
70
|
+
getBFAsync(id, options, callback) {
|
|
71
|
+
let txn = env.writeTxn || (options && options.transaction) || (readTxnRenewed ? readTxn : renewReadTxn(this));
|
|
72
|
+
txn.refCount = (txn.refCount || 0) + 1;
|
|
73
|
+
outstandingReads++;
|
|
74
|
+
let address = recordReadInstruction(txn.address, this.db.dbi, id, this.writeKey, maxKeySize, ( rc, bufferId, offset, size ) => {
|
|
75
|
+
if (rc && rc !== 1)
|
|
76
|
+
callback(lmdbError(rc));
|
|
77
|
+
outstandingReads--;
|
|
78
|
+
let buffer = mmaps[bufferId];
|
|
79
|
+
if (!buffer) {
|
|
80
|
+
buffer = mmaps[bufferId] = getSharedBuffer(bufferId, env.address);
|
|
81
|
+
}
|
|
82
|
+
//console.log({bufferId, offset, size})
|
|
83
|
+
if (buffer.isSharedMap) {
|
|
84
|
+
// using LMDB shared memory
|
|
85
|
+
// TODO: We may want explicit support for clearing aborting the transaction on the next event turn,
|
|
86
|
+
// but for now we are relying on the GC to cleanup transaction for larger blocks of memory
|
|
87
|
+
let bytes = new Uint8Array(buffer, offset, size);
|
|
88
|
+
bytes.txn = txn;
|
|
89
|
+
callback(bytes, 0, size);
|
|
90
|
+
} else {
|
|
91
|
+
// using copied memory
|
|
92
|
+
txn.done(); // decrement and possibly abort
|
|
93
|
+
callback(buffer, offset, size);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
if (address) {
|
|
97
|
+
startRead(address, () => {
|
|
98
|
+
resolveReads();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
getAsync(id, options, callback) {
|
|
103
|
+
let promise;
|
|
104
|
+
if (!callback)
|
|
105
|
+
promise = new Promise(resolve => callback = resolve);
|
|
106
|
+
this.getBFAsync(id, options, (buffer, offset, size) => {
|
|
107
|
+
if (this.useVersions) {
|
|
108
|
+
// TODO: And get the version
|
|
109
|
+
offset += 8;
|
|
110
|
+
size -= 8;
|
|
111
|
+
}
|
|
112
|
+
let bytes = new Uint8Array(buffer, offset, size);
|
|
113
|
+
let value;
|
|
114
|
+
if (this.decoder) {
|
|
115
|
+
// the decoder potentially uses the data from the buffer in the future and needs a stable buffer
|
|
116
|
+
value = bytes && this.decoder.decode(bytes);
|
|
117
|
+
} else if (this.encoding == 'binary') {
|
|
118
|
+
value = bytes;
|
|
119
|
+
} else {
|
|
120
|
+
value = Buffer.prototype.utf8Slice.call(bytes, 0, size);
|
|
121
|
+
if (this.encoding == 'json' && value)
|
|
122
|
+
value = JSON.parse(value);
|
|
123
|
+
}
|
|
124
|
+
callback(value);
|
|
125
|
+
});
|
|
126
|
+
return promise;
|
|
127
|
+
},
|
|
128
|
+
retain(data, options) {
|
|
129
|
+
if (!data)
|
|
130
|
+
return
|
|
131
|
+
let source = data[SOURCE_SYMBOL];
|
|
132
|
+
let buffer = source ? source.bytes : data;
|
|
133
|
+
if (!buffer.isGlobal && !env.writeTxn) {
|
|
134
|
+
let txn = options?.transaction || (readTxnRenewed ? readTxn : renewReadTxn(this));
|
|
135
|
+
buffer.txn = txn;
|
|
136
|
+
txn.refCount = (txn.refCount || 0) + 1;
|
|
137
|
+
return data;
|
|
138
|
+
} else {
|
|
139
|
+
buffer = Uint8ArraySlice.call(buffer, 0, this.lastSize);
|
|
140
|
+
if (source) {
|
|
141
|
+
source.bytes = buffer;
|
|
142
|
+
return data;
|
|
143
|
+
} else
|
|
144
|
+
return buffer;
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
_returnLargeBuffer(getFast) {
|
|
56
148
|
let bytes;
|
|
57
149
|
let compression = this.compression;
|
|
58
150
|
if (asSafeBuffer && this.lastSize > NEW_BUFFER_THRESHOLD) {
|
|
@@ -64,7 +156,7 @@ export function addReadMethods(LMDBStore, {
|
|
|
64
156
|
let dictionary = compression.dictionary || [];
|
|
65
157
|
let dictLength = (dictionary.length >> 3) << 3;// make sure it is word-aligned
|
|
66
158
|
bytes = makeReusableBuffer(this.lastSize);
|
|
67
|
-
compression.setBuffer(bytes, this.lastSize, dictionary, dictLength);
|
|
159
|
+
compression.setBuffer(bytes.buffer, bytes.byteOffset, this.lastSize, dictionary, dictLength);
|
|
68
160
|
compression.getValueBytes = bytes;
|
|
69
161
|
} else {
|
|
70
162
|
bytesToRestore = getValueBytes;
|
|
@@ -74,7 +166,7 @@ export function addReadMethods(LMDBStore, {
|
|
|
74
166
|
} finally {
|
|
75
167
|
if (compression) {
|
|
76
168
|
let dictLength = (compression.dictionary.length >> 3) << 3;
|
|
77
|
-
compression.setBuffer(bytesToRestore, bytesToRestore.maxLength, compression.dictionary, dictLength);
|
|
169
|
+
compression.setBuffer(bytesToRestore.buffer, bytesToRestore.byteOffset, bytesToRestore.maxLength, compression.dictionary, dictLength);
|
|
78
170
|
compression.getValueBytes = bytesToRestore;
|
|
79
171
|
} else {
|
|
80
172
|
setGlobalBuffer(bytesToRestore);
|
|
@@ -83,12 +175,6 @@ export function addReadMethods(LMDBStore, {
|
|
|
83
175
|
}
|
|
84
176
|
return bytes;
|
|
85
177
|
}
|
|
86
|
-
if (this.lastSize > NEW_BUFFER_THRESHOLD && !compression) {
|
|
87
|
-
// for large binary objects, cheaper to make a buffer that directly points at the shared LMDB memory to avoid copying a large amount of memory, but only for large data since there is significant overhead to instantiating the buffer
|
|
88
|
-
if (globalThis.__lmdb_last_shared__ && detachBuffer) // we have to detach the last one, or else could crash due to two buffers pointing at same location
|
|
89
|
-
detachBuffer(globalThis.__lmdb_last_shared__.buffer);
|
|
90
|
-
return globalThis.__lmdb_last_shared__ = getShared();
|
|
91
|
-
}
|
|
92
178
|
// grow our shared/static buffer to accomodate the size of the data
|
|
93
179
|
bytes = this._allocateGetBuffer(this.lastSize);
|
|
94
180
|
// and try again
|
|
@@ -100,13 +186,13 @@ export function addReadMethods(LMDBStore, {
|
|
|
100
186
|
let newLength = Math.min(Math.max(lastSize * 2, 0x1000), 0xfffffff8);
|
|
101
187
|
let bytes;
|
|
102
188
|
if (this.compression) {
|
|
103
|
-
let dictionary = this.compression.dictionary ||
|
|
189
|
+
let dictionary = this.compression.dictionary || Buffer.allocUnsafeSlow(0);
|
|
104
190
|
let dictLength = (dictionary.length >> 3) << 3;// make sure it is word-aligned
|
|
105
|
-
bytes =
|
|
191
|
+
bytes = Buffer.allocUnsafeSlow(newLength + dictLength);
|
|
106
192
|
bytes.set(dictionary) // copy dictionary into start
|
|
107
193
|
// the section after the dictionary is the target area for get values
|
|
108
194
|
bytes = bytes.subarray(dictLength);
|
|
109
|
-
this.compression.setBuffer(bytes, newLength, dictionary, dictLength);
|
|
195
|
+
this.compression.setBuffer(bytes.buffer, bytes.byteOffset, newLength, dictionary, dictLength);
|
|
110
196
|
bytes.maxLength = newLength;
|
|
111
197
|
Object.defineProperty(bytes, 'length', { value: newLength, writable: true, configurable: true });
|
|
112
198
|
this.compression.getValueBytes = bytes;
|
|
@@ -114,41 +200,51 @@ export function addReadMethods(LMDBStore, {
|
|
|
114
200
|
bytes = makeReusableBuffer(newLength);
|
|
115
201
|
setGlobalBuffer(getValueBytes = bytes);
|
|
116
202
|
}
|
|
117
|
-
bytes.
|
|
203
|
+
bytes.isGlobal = true;
|
|
118
204
|
return bytes;
|
|
119
205
|
},
|
|
120
|
-
getBinary(id) {
|
|
206
|
+
getBinary(id, options) {
|
|
121
207
|
try {
|
|
122
208
|
asSafeBuffer = true;
|
|
123
|
-
let fastBuffer = this.getBinaryFast(id);
|
|
124
|
-
return fastBuffer && (fastBuffer.
|
|
209
|
+
let fastBuffer = this.getBinaryFast(id, options);
|
|
210
|
+
return fastBuffer && (fastBuffer.isGlobal ? Uint8ArraySlice.call(fastBuffer, 0, this.lastSize) : fastBuffer);
|
|
125
211
|
} finally {
|
|
126
212
|
asSafeBuffer = false;
|
|
127
213
|
}
|
|
128
214
|
},
|
|
129
|
-
|
|
215
|
+
getSharedBinary(id, options) {
|
|
216
|
+
let fastBuffer = this.getBinaryFast(id, options);
|
|
217
|
+
if (fastBuffer) {
|
|
218
|
+
if (fastBuffer.isGlobal || writeTxn)
|
|
219
|
+
return Uint8ArraySlice.call(fastBuffer, 0, this.lastSize)
|
|
220
|
+
fastBuffer.txn = (options && options.transaction);
|
|
221
|
+
options.transaction.refCount = (options.transaction.refCount || 0) + 1;
|
|
222
|
+
return fastBuffer;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
get(id, options) {
|
|
130
226
|
if (this.decoderCopies) {
|
|
131
227
|
// the decoder copies any data, so we can use the fast binary retrieval that overwrites the same buffer space
|
|
132
|
-
let bytes = this.getBinaryFast(id);
|
|
133
|
-
return bytes && this.decoder.decode(bytes);
|
|
228
|
+
let bytes = this.getBinaryFast(id, options);
|
|
229
|
+
return bytes && (bytes == UNMODIFIED ? UNMODIFIED : this.decoder.decode(bytes, options));
|
|
134
230
|
}
|
|
135
231
|
if (this.encoding == 'binary')
|
|
136
|
-
return this.getBinary(id);
|
|
232
|
+
return this.getBinary(id, options);
|
|
137
233
|
if (this.decoder) {
|
|
138
234
|
// the decoder potentially uses the data from the buffer in the future and needs a stable buffer
|
|
139
|
-
let bytes = this.getBinary(id);
|
|
140
|
-
return bytes && this.decoder.decode(bytes);
|
|
235
|
+
let bytes = this.getBinary(id, options);
|
|
236
|
+
return bytes && (bytes == UNMODIFIED ? UNMODIFIED : this.decoder.decode(bytes));
|
|
141
237
|
}
|
|
142
238
|
|
|
143
|
-
let result = this.getString(id);
|
|
239
|
+
let result = this.getString(id, options);
|
|
144
240
|
if (result) {
|
|
145
241
|
if (this.encoding == 'json')
|
|
146
242
|
return JSON.parse(result);
|
|
147
243
|
}
|
|
148
244
|
return result;
|
|
149
245
|
},
|
|
150
|
-
getEntry(id) {
|
|
151
|
-
let value = this.get(id);
|
|
246
|
+
getEntry(id, options) {
|
|
247
|
+
let value = this.get(id, options);
|
|
152
248
|
if (value !== undefined) {
|
|
153
249
|
if (this.useVersions)
|
|
154
250
|
return {
|
|
@@ -167,8 +263,11 @@ export function addReadMethods(LMDBStore, {
|
|
|
167
263
|
resetReadTxn();
|
|
168
264
|
},
|
|
169
265
|
_commitReadTxn() {
|
|
170
|
-
if (readTxn)
|
|
266
|
+
if (readTxn) {
|
|
267
|
+
readTxn.isCommitted = true
|
|
171
268
|
readTxn.commit();
|
|
269
|
+
}
|
|
270
|
+
lastReadTxnRef = null;
|
|
172
271
|
readTxnRenewed = null;
|
|
173
272
|
readTxn = null;
|
|
174
273
|
},
|
|
@@ -177,15 +276,12 @@ export function addReadMethods(LMDBStore, {
|
|
|
177
276
|
renewReadTxn(this);
|
|
178
277
|
},
|
|
179
278
|
doesExist(key, versionOrValue) {
|
|
180
|
-
if (!env.writeTxn)
|
|
181
|
-
readTxnRenewed ? readTxn : renewReadTxn(this);
|
|
182
279
|
if (versionOrValue == null) {
|
|
183
280
|
// undefined means the entry exists, null is used specifically to check for the entry *not* existing
|
|
184
281
|
return (this.getBinaryFast(key) === undefined) == (versionOrValue === null);
|
|
185
282
|
}
|
|
186
283
|
else if (this.useVersions) {
|
|
187
|
-
this.getBinaryFast(key);
|
|
188
|
-
return this.getBinaryFast(key) !== undefined && getLastVersion() === versionOrValue;
|
|
284
|
+
return this.getBinaryFast(key) !== undefined && (versionOrValue === IF_EXISTS || getLastVersion() === versionOrValue);
|
|
189
285
|
}
|
|
190
286
|
else {
|
|
191
287
|
if (versionOrValue && versionOrValue['\x10binary-data\x02'])
|
|
@@ -251,28 +347,39 @@ export function addReadMethods(LMDBStore, {
|
|
|
251
347
|
let cursor, cursorRenewId, cursorAddress;
|
|
252
348
|
let txn;
|
|
253
349
|
let flags = (includeValues ? 0x100 : 0) | (reverse ? 0x400 : 0) |
|
|
254
|
-
(valuesForKey ? 0x800 : 0) | (options.exactMatch ? 0x4000 : 0)
|
|
350
|
+
(valuesForKey ? 0x800 : 0) | (options.exactMatch ? 0x4000 : 0) |
|
|
351
|
+
(options.inclusiveEnd ? 0x8000 : 0) |
|
|
352
|
+
(options.exclusiveStart ? 0x10000 : 0);
|
|
255
353
|
let store = this;
|
|
256
354
|
function resetCursor() {
|
|
257
355
|
try {
|
|
258
356
|
if (cursor)
|
|
259
357
|
finishCursor();
|
|
260
|
-
let
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
358
|
+
let txnAddress;
|
|
359
|
+
txn = options.transaction
|
|
360
|
+
if (txn) {
|
|
361
|
+
if (txn.isDone) throw new Error('Can not iterate on range with transaction that is already' +
|
|
362
|
+
' done');
|
|
363
|
+
txnAddress = txn.address;
|
|
364
|
+
cursor = null;
|
|
365
|
+
} else {
|
|
366
|
+
let writeTxn = env.writeTxn;
|
|
367
|
+
if (writeTxn)
|
|
368
|
+
snapshot = false;
|
|
369
|
+
txn = env.writeTxn || options.transaction || (readTxnRenewed ? readTxn : renewReadTxn(store));
|
|
370
|
+
cursor = !writeTxn && db.availableCursor;
|
|
371
|
+
}
|
|
265
372
|
if (cursor) {
|
|
266
373
|
db.availableCursor = null;
|
|
267
374
|
flags |= 0x2000;
|
|
268
375
|
} else {
|
|
269
|
-
cursor = new Cursor(db);
|
|
376
|
+
cursor = new Cursor(db, txnAddress || 0);
|
|
270
377
|
}
|
|
271
378
|
cursorAddress = cursor.address;
|
|
272
|
-
txn.
|
|
379
|
+
txn.refCount = (txn.refCount || 0) + 1; // track transaction so we always use the same one
|
|
273
380
|
if (snapshot === false) {
|
|
274
381
|
cursorRenewId = renewId; // use shared read transaction
|
|
275
|
-
txn.
|
|
382
|
+
txn.renewingRefCount = (txn.renewingRefCount || 0) + 1; // need to know how many are renewing cursors
|
|
276
383
|
}
|
|
277
384
|
} catch(error) {
|
|
278
385
|
if (cursor) {
|
|
@@ -293,6 +400,9 @@ export function addReadMethods(LMDBStore, {
|
|
|
293
400
|
return count;
|
|
294
401
|
}
|
|
295
402
|
function position(offset) {
|
|
403
|
+
if (!env.address) {
|
|
404
|
+
throw new Error('Can not iterate on a closed database');
|
|
405
|
+
}
|
|
296
406
|
let keySize = currentKey === undefined ? 0 : store.writeKey(currentKey, keyBytes, 0);
|
|
297
407
|
let endAddress;
|
|
298
408
|
if (valuesForKey) {
|
|
@@ -311,7 +421,7 @@ export function addReadMethods(LMDBStore, {
|
|
|
311
421
|
} else {
|
|
312
422
|
throw new Error('Only key-based encoding is supported for start/end values');
|
|
313
423
|
let encoded = store.encoder.encode(options.start);
|
|
314
|
-
let bufferAddress = encoded.buffer.address || (encoded.buffer.address = getAddress(encoded) - encoded.byteOffset);
|
|
424
|
+
let bufferAddress = encoded.buffer.address || (encoded.buffer.address = getAddress(encoded.buffer) - encoded.byteOffset);
|
|
315
425
|
startAddress = bufferAddress + encoded.byteOffset;
|
|
316
426
|
}
|
|
317
427
|
}
|
|
@@ -323,9 +433,11 @@ export function addReadMethods(LMDBStore, {
|
|
|
323
433
|
function finishCursor() {
|
|
324
434
|
if (txn.isDone)
|
|
325
435
|
return;
|
|
436
|
+
if (iterable.onDone)
|
|
437
|
+
iterable.onDone()
|
|
326
438
|
if (cursorRenewId)
|
|
327
|
-
txn.
|
|
328
|
-
if (--txn.
|
|
439
|
+
txn.renewingRefCount--;
|
|
440
|
+
if (--txn.refCount <= 0 && txn.notCurrent) {
|
|
329
441
|
cursor.close();
|
|
330
442
|
txn.abort(); // this is no longer main read txn, abort it now that we are done
|
|
331
443
|
txn.isDone = true;
|
|
@@ -352,7 +464,7 @@ export function addReadMethods(LMDBStore, {
|
|
|
352
464
|
if (keySize <= 0 ||
|
|
353
465
|
(count++ >= limit)) {
|
|
354
466
|
if (count < 0)
|
|
355
|
-
lmdbError(count);
|
|
467
|
+
lmdbError(count);
|
|
356
468
|
finishCursor();
|
|
357
469
|
return ITERATOR_DONE;
|
|
358
470
|
}
|
|
@@ -367,24 +479,27 @@ export function addReadMethods(LMDBStore, {
|
|
|
367
479
|
if (includeValues) {
|
|
368
480
|
let value;
|
|
369
481
|
lastSize = keyBytesView.getUint32(0, true);
|
|
370
|
-
let
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
482
|
+
let bufferId = keyBytesView.getUint32(4, true);
|
|
483
|
+
let bytes;
|
|
484
|
+
if (bufferId) {
|
|
485
|
+
bytes = getMMapBuffer(bufferId, lastSize);
|
|
486
|
+
} else {
|
|
487
|
+
bytes = compression ? compression.getValueBytes : getValueBytes;
|
|
488
|
+
if (lastSize > bytes.maxLength) {
|
|
489
|
+
store.lastSize = lastSize;
|
|
490
|
+
asSafeBuffer = store.encoding == 'binary';
|
|
491
|
+
try {
|
|
492
|
+
bytes = store._returnLargeBuffer(() => getCurrentValue(cursorAddress));
|
|
493
|
+
} finally {
|
|
494
|
+
asSafeBuffer = false;
|
|
495
|
+
}
|
|
496
|
+
} else
|
|
497
|
+
bytes.length = lastSize;
|
|
498
|
+
}
|
|
384
499
|
if (store.decoder) {
|
|
385
500
|
value = store.decoder.decode(bytes, lastSize);
|
|
386
501
|
} else if (store.encoding == 'binary')
|
|
387
|
-
value = bytes.
|
|
502
|
+
value = bytes.isGlobal ? Uint8ArraySlice.call(bytes, 0, lastSize) : bytes;
|
|
388
503
|
else {
|
|
389
504
|
value = bytes.toString('utf8', 0, lastSize);
|
|
390
505
|
if (store.encoding == 'json' && value)
|
|
@@ -450,8 +565,8 @@ export function addReadMethods(LMDBStore, {
|
|
|
450
565
|
});
|
|
451
566
|
return promise;
|
|
452
567
|
},
|
|
453
|
-
getSharedBufferForGet(id) {
|
|
454
|
-
let txn =
|
|
568
|
+
getSharedBufferForGet(id, options) {
|
|
569
|
+
let txn = env.writeTxn || (options && options.transaction) || (readTxnRenewed ? readTxn : renewReadTxn(this));
|
|
455
570
|
this.lastSize = this.keyIsCompatibility ? txn.getBinaryShared(id) : this.db.get(this.writeKey(id, keyBytes, 0));
|
|
456
571
|
if (this.lastSize === -30798) { // not found code
|
|
457
572
|
return; //undefined
|
|
@@ -489,7 +604,13 @@ export function addReadMethods(LMDBStore, {
|
|
|
489
604
|
let bufferHolder = {};
|
|
490
605
|
let lastBuffer;
|
|
491
606
|
for (let key of keys) {
|
|
492
|
-
let position
|
|
607
|
+
let position
|
|
608
|
+
if (key && key.key !== undefined && key.value !== undefined) {
|
|
609
|
+
position = saveKey(key.value, this.writeKey, bufferHolder, maxKeySize, 0x80000000);
|
|
610
|
+
saveKey(key.key, this.writeKey, bufferHolder, maxKeySize);
|
|
611
|
+
} else {
|
|
612
|
+
position = saveKey(key, this.writeKey, bufferHolder, maxKeySize);
|
|
613
|
+
}
|
|
493
614
|
if (!startPosition)
|
|
494
615
|
startPosition = position;
|
|
495
616
|
if (bufferHolder.saveBuffer != lastBuffer) {
|
|
@@ -499,7 +620,9 @@ export function addReadMethods(LMDBStore, {
|
|
|
499
620
|
}
|
|
500
621
|
}
|
|
501
622
|
saveKey(undefined, this.writeKey, bufferHolder, maxKeySize);
|
|
623
|
+
outstandingReads++;
|
|
502
624
|
prefetch(this.dbAddress, startPosition, (error) => {
|
|
625
|
+
outstandingReads--;
|
|
503
626
|
if (error)
|
|
504
627
|
console.error('Error with prefetch', buffers, bufferHolder); // partly exists to keep the buffers pinned in memory
|
|
505
628
|
else
|
|
@@ -508,27 +631,44 @@ export function addReadMethods(LMDBStore, {
|
|
|
508
631
|
if (!callback)
|
|
509
632
|
return new Promise(resolve => callback = resolve);
|
|
510
633
|
},
|
|
634
|
+
useReadTransaction() {
|
|
635
|
+
let txn = readTxnRenewed ? readTxn : renewReadTxn(this);
|
|
636
|
+
if (!txn.use) {
|
|
637
|
+
throw new Error('Can not use read transaction from a closed database');
|
|
638
|
+
}
|
|
639
|
+
txn.use();
|
|
640
|
+
return txn;
|
|
641
|
+
},
|
|
511
642
|
close(callback) {
|
|
512
643
|
this.status = 'closing';
|
|
644
|
+
let txnPromise;
|
|
513
645
|
if (this.isRoot) {
|
|
514
|
-
if
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
renew() {
|
|
646
|
+
// if it is root, we need to abort and/or wait for transactions to finish
|
|
647
|
+
if (readTxn) readTxn.abort();
|
|
648
|
+
else readTxn = {};
|
|
649
|
+
readTxn.isDone = true;
|
|
650
|
+
Object.defineProperty(readTxn,'renew', {
|
|
651
|
+
value: () => {
|
|
521
652
|
throw new Error('Can not read from a closed database');
|
|
522
|
-
}
|
|
523
|
-
};
|
|
653
|
+
}, configurable: true
|
|
654
|
+
});
|
|
655
|
+
Object.defineProperty(readTxn,'use', {
|
|
656
|
+
value: () => {
|
|
657
|
+
throw new Error('Can not read from a closed database');
|
|
658
|
+
}, configurable: true
|
|
659
|
+
});
|
|
524
660
|
readTxnRenewed = null;
|
|
661
|
+
txnPromise = this._endWrites && this._endWrites();
|
|
525
662
|
}
|
|
526
|
-
let txnPromise = this._endWrites();
|
|
527
663
|
const doClose = () => {
|
|
528
|
-
this.db.close();
|
|
529
664
|
if (this.isRoot) {
|
|
665
|
+
if (outstandingReads > 0) {
|
|
666
|
+
return new Promise(resolve => setTimeout(() => resolve(doClose()), 1));
|
|
667
|
+
}
|
|
668
|
+
env.address = 0;
|
|
530
669
|
env.close();
|
|
531
|
-
}
|
|
670
|
+
} else
|
|
671
|
+
this.db.close();
|
|
532
672
|
this.status = 'closed';
|
|
533
673
|
if (callback)
|
|
534
674
|
callback();
|
|
@@ -541,18 +681,40 @@ export function addReadMethods(LMDBStore, {
|
|
|
541
681
|
}
|
|
542
682
|
},
|
|
543
683
|
getStats() {
|
|
544
|
-
readTxnRenewed ? readTxn : renewReadTxn(this);
|
|
545
|
-
|
|
546
|
-
|
|
684
|
+
let txn = env.writeTxn || (readTxnRenewed ? readTxn : renewReadTxn(this));
|
|
685
|
+
let dbStats = this.db.stat();
|
|
686
|
+
dbStats.root = env.stat();
|
|
687
|
+
Object.assign(dbStats, env.info());
|
|
688
|
+
dbStats.free = env.freeStat();
|
|
689
|
+
return dbStats;
|
|
690
|
+
},
|
|
547
691
|
});
|
|
548
692
|
let get = LMDBStore.prototype.get;
|
|
693
|
+
let lastReadTxnRef;
|
|
694
|
+
function getMMapBuffer(bufferId, size) {
|
|
695
|
+
let buffer = mmaps[bufferId];
|
|
696
|
+
if (!buffer) {
|
|
697
|
+
buffer = mmaps[bufferId] = getSharedBuffer(bufferId, env.address);
|
|
698
|
+
}
|
|
699
|
+
let offset = keyBytesView.getUint32(8, true);
|
|
700
|
+
return new Uint8Array(buffer, offset, size);
|
|
701
|
+
}
|
|
549
702
|
function renewReadTxn(store) {
|
|
703
|
+
if (!env.address) {
|
|
704
|
+
throw new Error('Can not renew a transaction from a closed database');
|
|
705
|
+
}
|
|
550
706
|
if (!readTxn) {
|
|
551
707
|
let retries = 0;
|
|
552
708
|
let waitArray;
|
|
553
709
|
do {
|
|
554
710
|
try {
|
|
555
|
-
|
|
711
|
+
let lastReadTxn = lastReadTxnRef && lastReadTxnRef.deref();
|
|
712
|
+
readTxn = new Txn(env, 0x20000, lastReadTxn && !lastReadTxn.isDone && lastReadTxn);
|
|
713
|
+
if (readTxn.address == 0) {
|
|
714
|
+
readTxn = lastReadTxn;
|
|
715
|
+
if (readTxn.notCurrent)
|
|
716
|
+
readTxn.notCurrent = false;
|
|
717
|
+
}
|
|
556
718
|
break;
|
|
557
719
|
} catch (error) {
|
|
558
720
|
if (error.message.includes('temporarily')) {
|
|
@@ -570,15 +732,20 @@ export function addReadMethods(LMDBStore, {
|
|
|
570
732
|
store.emit('begin-transaction');
|
|
571
733
|
return readTxn;
|
|
572
734
|
}
|
|
573
|
-
function resetReadTxn(
|
|
735
|
+
function resetReadTxn() {
|
|
574
736
|
renewId++;
|
|
575
737
|
if (readTxnRenewed) {
|
|
576
738
|
readTxnRenewed = null;
|
|
577
|
-
if (readTxn.
|
|
578
|
-
readTxn.
|
|
739
|
+
if (readTxn.refCount - (readTxn.renewingRefCount || 0) > 0) {
|
|
740
|
+
readTxn.notCurrent = true;
|
|
741
|
+
lastReadTxnRef = new WeakRef(readTxn);
|
|
579
742
|
readTxn = null;
|
|
580
|
-
} else
|
|
743
|
+
} else if (readTxn.address && !readTxn.isDone) {
|
|
581
744
|
resetTxn(readTxn.address);
|
|
745
|
+
} else {
|
|
746
|
+
console.warn('Attempt to reset an invalid read txn', readTxn);
|
|
747
|
+
throw new Error('Attempt to reset an invalid read txn');
|
|
748
|
+
}
|
|
582
749
|
}
|
|
583
750
|
}
|
|
584
751
|
}
|
|
@@ -588,3 +755,79 @@ export function makeReusableBuffer(size) {
|
|
|
588
755
|
Object.defineProperty(bytes, 'length', { value: size, writable: true, configurable: true });
|
|
589
756
|
return bytes;
|
|
590
757
|
}
|
|
758
|
+
|
|
759
|
+
Txn.prototype.done = function() {
|
|
760
|
+
this.refCount--;
|
|
761
|
+
if (this.refCount === 0 && this.notCurrent) {
|
|
762
|
+
this.abort();
|
|
763
|
+
this.isDone = true;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
Txn.prototype.use = function() {
|
|
767
|
+
this.refCount = (this.refCount || 0) + 1;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
let readInstructions, readCallbacks = new Map(), uint32Instructions, instructionsDataView = { setFloat64() {}, setUint32() {} }, instructionsAddress;
|
|
772
|
+
let savePosition = 8000;
|
|
773
|
+
let DYNAMIC_KEY_BUFFER_SIZE = 8192;
|
|
774
|
+
function allocateInstructionsBuffer() {
|
|
775
|
+
readInstructions = typeof Buffer != 'undefined' ? Buffer.alloc(DYNAMIC_KEY_BUFFER_SIZE) : new Uint8Array(DYNAMIC_KEY_BUFFER_SIZE);
|
|
776
|
+
uint32Instructions = new Int32Array(readInstructions.buffer, 0, readInstructions.buffer.byteLength >> 2);
|
|
777
|
+
uint32Instructions[2] = 0xf0000000; // indicates a new read task must be started
|
|
778
|
+
instructionsAddress = readInstructions.buffer.address = getAddress(readInstructions.buffer);
|
|
779
|
+
readInstructions.dataView = instructionsDataView = new DataView(readInstructions.buffer, readInstructions.byteOffset, readInstructions.byteLength);
|
|
780
|
+
savePosition = 0;
|
|
781
|
+
}
|
|
782
|
+
export function recordReadInstruction(txnAddress, dbi, key, writeKey, maxKeySize, callback) {
|
|
783
|
+
if (savePosition > 7800) {
|
|
784
|
+
allocateInstructionsBuffer();
|
|
785
|
+
}
|
|
786
|
+
let start = savePosition;
|
|
787
|
+
let keyPosition = savePosition + 16;
|
|
788
|
+
try {
|
|
789
|
+
savePosition = key === undefined ? keyPosition :
|
|
790
|
+
writeKey(key, readInstructions, keyPosition);
|
|
791
|
+
} catch (error) {
|
|
792
|
+
if (error.name == 'RangeError') {
|
|
793
|
+
if (8180 - start < maxKeySize) {
|
|
794
|
+
allocateInstructionsBuffer(); // try again:
|
|
795
|
+
return recordReadInstruction(txnAddress, dbi, key, writeKey, maxKeySize, callback);
|
|
796
|
+
}
|
|
797
|
+
throw new Error('Key was too large, max key size is ' + maxKeySize);
|
|
798
|
+
} else
|
|
799
|
+
throw error;
|
|
800
|
+
}
|
|
801
|
+
let length = savePosition - keyPosition;
|
|
802
|
+
if (length > maxKeySize) {
|
|
803
|
+
savePosition = start;
|
|
804
|
+
throw new Error('Key of size ' + length + ' was too large, max key size is ' + maxKeySize);
|
|
805
|
+
}
|
|
806
|
+
uint32Instructions[(start >> 2) + 3] = length; // save the length
|
|
807
|
+
uint32Instructions[(start >> 2) + 2] = dbi;
|
|
808
|
+
savePosition = (savePosition + 12) & 0xfffffc;
|
|
809
|
+
instructionsDataView.setFloat64(start, txnAddress, true);
|
|
810
|
+
let callbackId = addReadCallback(() => {
|
|
811
|
+
let position = start >> 2;
|
|
812
|
+
let rc = thisInstructions[position];
|
|
813
|
+
callback(rc, thisInstructions[position + 1], thisInstructions[position + 2], thisInstructions[position + 3]);
|
|
814
|
+
});
|
|
815
|
+
let thisInstructions = uint32Instructions;
|
|
816
|
+
//if (start === 0)
|
|
817
|
+
return startRead(instructionsAddress + start, callbackId, {}, 'read');
|
|
818
|
+
//else
|
|
819
|
+
//nextRead(start);
|
|
820
|
+
}
|
|
821
|
+
let nextCallbackId = 0;
|
|
822
|
+
let addReadCallback = globalThis.__lmdb_read_callback;
|
|
823
|
+
if (!addReadCallback) {
|
|
824
|
+
addReadCallback = globalThis.__lmdb_read_callback = function(callback) {
|
|
825
|
+
let callbackId = nextCallbackId++;
|
|
826
|
+
readCallbacks.set(callbackId, callback);
|
|
827
|
+
return callbackId;
|
|
828
|
+
};
|
|
829
|
+
setReadCallback(function(callbackId) {
|
|
830
|
+
readCallbacks.get(callbackId)();
|
|
831
|
+
readCallbacks.delete(callbackId);
|
|
832
|
+
})
|
|
833
|
+
}
|