@ohos-ports/lmdb 2.5.3-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 (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +536 -0
  3. package/SECURITY.md +12 -0
  4. package/binding.gyp +111 -0
  5. package/build/Release/lmdb.node +0 -0
  6. package/caching.js +156 -0
  7. package/dependencies/lmdb/libraries/liblmdb/COPYRIGHT +20 -0
  8. package/dependencies/lmdb/libraries/liblmdb/Doxyfile +1631 -0
  9. package/dependencies/lmdb/libraries/liblmdb/LICENSE +47 -0
  10. package/dependencies/lmdb/libraries/liblmdb/Makefile +136 -0
  11. package/dependencies/lmdb/libraries/liblmdb/chacha8.c +183 -0
  12. package/dependencies/lmdb/libraries/liblmdb/chacha8.h +14 -0
  13. package/dependencies/lmdb/libraries/liblmdb/crypto.c +121 -0
  14. package/dependencies/lmdb/libraries/liblmdb/intro.doc +192 -0
  15. package/dependencies/lmdb/libraries/liblmdb/lmdb.h +1792 -0
  16. package/dependencies/lmdb/libraries/liblmdb/mdb.c +12429 -0
  17. package/dependencies/lmdb/libraries/liblmdb/mdb_copy.1 +74 -0
  18. package/dependencies/lmdb/libraries/liblmdb/mdb_copy.c +106 -0
  19. package/dependencies/lmdb/libraries/liblmdb/mdb_drop.1 +53 -0
  20. package/dependencies/lmdb/libraries/liblmdb/mdb_drop.c +154 -0
  21. package/dependencies/lmdb/libraries/liblmdb/mdb_dump.1 +94 -0
  22. package/dependencies/lmdb/libraries/liblmdb/mdb_dump.c +333 -0
  23. package/dependencies/lmdb/libraries/liblmdb/mdb_load.1 +97 -0
  24. package/dependencies/lmdb/libraries/liblmdb/mdb_load.c +530 -0
  25. package/dependencies/lmdb/libraries/liblmdb/mdb_stat.1 +83 -0
  26. package/dependencies/lmdb/libraries/liblmdb/mdb_stat.c +276 -0
  27. package/dependencies/lmdb/libraries/liblmdb/midl.c +452 -0
  28. package/dependencies/lmdb/libraries/liblmdb/midl.h +208 -0
  29. package/dependencies/lmdb/libraries/liblmdb/module.c +101 -0
  30. package/dependencies/lmdb/libraries/liblmdb/module.h +16 -0
  31. package/dependencies/lmdb/libraries/liblmdb/mtest.c +178 -0
  32. package/dependencies/lmdb/libraries/liblmdb/mtest2.c +124 -0
  33. package/dependencies/lmdb/libraries/liblmdb/mtest3.c +133 -0
  34. package/dependencies/lmdb/libraries/liblmdb/mtest4.c +168 -0
  35. package/dependencies/lmdb/libraries/liblmdb/mtest5.c +135 -0
  36. package/dependencies/lmdb/libraries/liblmdb/mtest6.c +141 -0
  37. package/dependencies/lmdb/libraries/liblmdb/mtest_enc.c +190 -0
  38. package/dependencies/lmdb/libraries/liblmdb/mtest_enc2.c +189 -0
  39. package/dependencies/lmdb/libraries/liblmdb/mtest_remap.c +177 -0
  40. package/dependencies/lmdb/libraries/liblmdb/sample-bdb.txt +73 -0
  41. package/dependencies/lmdb/libraries/liblmdb/sample-mdb.txt +62 -0
  42. package/dependencies/lmdb/libraries/liblmdb/tooltag +27 -0
  43. package/dependencies/lmdb-data-v1/libraries/liblmdb/COPYRIGHT +20 -0
  44. package/dependencies/lmdb-data-v1/libraries/liblmdb/Doxyfile +1631 -0
  45. package/dependencies/lmdb-data-v1/libraries/liblmdb/LICENSE +47 -0
  46. package/dependencies/lmdb-data-v1/libraries/liblmdb/Makefile +118 -0
  47. package/dependencies/lmdb-data-v1/libraries/liblmdb/intro.doc +192 -0
  48. package/dependencies/lmdb-data-v1/libraries/liblmdb/lmdb.h +1653 -0
  49. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb.c +11359 -0
  50. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.1 +61 -0
  51. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.c +84 -0
  52. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.1 +40 -0
  53. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.c +135 -0
  54. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.1 +81 -0
  55. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.c +319 -0
  56. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.1 +84 -0
  57. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.c +492 -0
  58. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.1 +70 -0
  59. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.c +264 -0
  60. package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.c +421 -0
  61. package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.h +200 -0
  62. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest.c +177 -0
  63. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest2.c +124 -0
  64. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest3.c +133 -0
  65. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest4.c +168 -0
  66. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest5.c +135 -0
  67. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest6.c +141 -0
  68. package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-bdb.txt +73 -0
  69. package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-mdb.txt +62 -0
  70. package/dependencies/lmdb-data-v1/libraries/liblmdb/tooltag +27 -0
  71. package/dependencies/lz4/LICENSE +11 -0
  72. package/dependencies/lz4/lib/LICENSE +24 -0
  73. package/dependencies/lz4/lib/README.md +137 -0
  74. package/dependencies/lz4/lib/dll/example/README.md +69 -0
  75. package/dependencies/lz4/lib/dll/example/fullbench-dll.sln +25 -0
  76. package/dependencies/lz4/lib/dll/example/fullbench-dll.vcxproj +182 -0
  77. package/dependencies/lz4/lib/dll/liblz4.def +62 -0
  78. package/dependencies/lz4/lib/liblz4-dll.rc.in +35 -0
  79. package/dependencies/lz4/lib/liblz4.pc.in +14 -0
  80. package/dependencies/lz4/lib/lz4.c +2495 -0
  81. package/dependencies/lz4/lib/lz4.h +774 -0
  82. package/dependencies/lz4/lib/lz4frame.c +1899 -0
  83. package/dependencies/lz4/lib/lz4frame.h +623 -0
  84. package/dependencies/lz4/lib/lz4frame_static.h +47 -0
  85. package/dependencies/lz4/lib/lz4hc.c +1615 -0
  86. package/dependencies/lz4/lib/lz4hc.h +413 -0
  87. package/dependencies/lz4/lib/xxhash.c +1030 -0
  88. package/dependencies/lz4/lib/xxhash.h +328 -0
  89. package/dependencies/v8/v8-fast-api-calls-v16.h +791 -0
  90. package/dependencies/v8/v8-fast-api-calls.h +888 -0
  91. package/dict/dict.txt +1 -0
  92. package/dict/dict2.txt +1 -0
  93. package/dist/index.cjs +2478 -0
  94. package/dist/index.cjs.map +1 -0
  95. package/index.d.ts +385 -0
  96. package/index.js +37 -0
  97. package/keys.js +102 -0
  98. package/level.js +27 -0
  99. package/native.js +82 -0
  100. package/node-index.js +28 -0
  101. package/open.js +414 -0
  102. package/package.json +70 -0
  103. package/read.js +590 -0
  104. package/rollup.config.js +12 -0
  105. package/src/compression.cpp +222 -0
  106. package/src/cursor.cpp +344 -0
  107. package/src/dbi.cpp +344 -0
  108. package/src/env.cpp +762 -0
  109. package/src/lmdb-js.cpp +64 -0
  110. package/src/lmdb-js.h +599 -0
  111. package/src/misc.cpp +324 -0
  112. package/src/ordered-binary.cpp +46 -0
  113. package/src/txn.cpp +257 -0
  114. package/src/v8-functions.cpp +166 -0
  115. package/src/windows.c +35 -0
  116. package/src/writer.cpp +452 -0
  117. package/util/RangeIterable.js +141 -0
  118. package/util/set-optional-deps.cjs +10 -0
  119. package/util/when.js +8 -0
  120. package/write.js +882 -0
package/read.js ADDED
@@ -0,0 +1,590 @@
1
+ import { RangeIterable } from './util/RangeIterable.js';
2
+ import { getAddress, Cursor, Txn, orderedBinary, lmdbError, getByBinary, detachBuffer, setGlobalBuffer, prefetch, iterate, position as doPosition, resetTxn, getCurrentValue, getCurrentShared, getStringByBinary, getSharedByBinary } from './native.js';
3
+ import { saveKey } from './keys.js';
4
+ const ITERATOR_DONE = { done: true, value: undefined };
5
+ const Uint8ArraySlice = Uint8Array.prototype.slice;
6
+ const Uint8A = typeof Buffer != 'undefined' ? Buffer.allocUnsafeSlow : Uint8Array
7
+ let getValueBytes = makeReusableBuffer(0);
8
+ const START_ADDRESS_POSITION = 4064;
9
+ const NEW_BUFFER_THRESHOLD = 0x8000;
10
+
11
+ export function addReadMethods(LMDBStore, {
12
+ maxKeySize, env, keyBytes, keyBytesView, getLastVersion
13
+ }) {
14
+ let readTxn, readTxnRenewed, asSafeBuffer = false;
15
+ let renewId = 1;
16
+ Object.assign(LMDBStore.prototype, {
17
+ getString(id) {
18
+ (env.writeTxn || (readTxnRenewed ? readTxn : renewReadTxn(this)));
19
+ let string = getStringByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0));
20
+ if (typeof string === 'number') { // indicates the buffer wasn't large enough
21
+ this._allocateGetBuffer(string);
22
+ // and then try again
23
+ string = getStringByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0));
24
+ }
25
+ if (string)
26
+ this.lastSize = string.length;
27
+ return string;
28
+ },
29
+ getBinaryFast(id) {
30
+ (env.writeTxn || (readTxnRenewed ? readTxn : renewReadTxn(this)));
31
+ let rc = this.lastSize = getByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0));
32
+ if (rc < 0) {
33
+ if (rc == -30798) // MDB_NOTFOUND
34
+ return; // undefined
35
+ if (rc == -30781 /*MDB_BAD_VALSIZE*/ && this.writeKey(id, keyBytes, 0) == 0)
36
+ throw new Error(id === undefined ?
37
+ 'A key is required for get, but is undefined' :
38
+ 'Zero length key is not allowed in LMDB');
39
+ if (rc == -30000) // int32 overflow, read uint32
40
+ rc = this.lastSize = keyBytesView.getUint32(0, true);
41
+ else
42
+ throw lmdbError(rc);
43
+ }
44
+ let compression = this.compression;
45
+ let bytes = compression ? compression.getValueBytes : getValueBytes;
46
+ if (rc > bytes.maxLength) {
47
+ // 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
+ return this._returnLargeBuffer(
49
+ () => getByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0)),
50
+ () => getSharedByBinary(this.dbAddress, this.writeKey(id, keyBytes, 0)));
51
+ }
52
+ bytes.length = this.lastSize;
53
+ return bytes;
54
+ },
55
+ _returnLargeBuffer(getFast, getShared) {
56
+ let bytes;
57
+ let compression = this.compression;
58
+ if (asSafeBuffer && this.lastSize > NEW_BUFFER_THRESHOLD) {
59
+ // used by getBinary to indicate it should create a dedicated buffer to receive this
60
+ let bytesToRestore
61
+ try {
62
+ if (compression) {
63
+ bytesToRestore = compression.getValueBytes;
64
+ let dictionary = compression.dictionary || [];
65
+ let dictLength = (dictionary.length >> 3) << 3;// make sure it is word-aligned
66
+ bytes = makeReusableBuffer(this.lastSize);
67
+ compression.setBuffer(bytes, this.lastSize, dictionary, dictLength);
68
+ compression.getValueBytes = bytes;
69
+ } else {
70
+ bytesToRestore = getValueBytes;
71
+ setGlobalBuffer(bytes = getValueBytes = makeReusableBuffer(this.lastSize));
72
+ }
73
+ getFast();
74
+ } finally {
75
+ if (compression) {
76
+ let dictLength = (compression.dictionary.length >> 3) << 3;
77
+ compression.setBuffer(bytesToRestore, bytesToRestore.maxLength, compression.dictionary, dictLength);
78
+ compression.getValueBytes = bytesToRestore;
79
+ } else {
80
+ setGlobalBuffer(bytesToRestore);
81
+ getValueBytes = bytesToRestore;
82
+ }
83
+ }
84
+ return bytes;
85
+ }
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
+ // grow our shared/static buffer to accomodate the size of the data
93
+ bytes = this._allocateGetBuffer(this.lastSize);
94
+ // and try again
95
+ getFast();
96
+ bytes.length = this.lastSize;
97
+ return bytes;
98
+ },
99
+ _allocateGetBuffer(lastSize) {
100
+ let newLength = Math.min(Math.max(lastSize * 2, 0x1000), 0xfffffff8);
101
+ let bytes;
102
+ if (this.compression) {
103
+ let dictionary = this.compression.dictionary || new Uint8A(0);
104
+ let dictLength = (dictionary.length >> 3) << 3;// make sure it is word-aligned
105
+ bytes = new Uint8A(newLength + dictLength);
106
+ bytes.set(dictionary) // copy dictionary into start
107
+ // the section after the dictionary is the target area for get values
108
+ bytes = bytes.subarray(dictLength);
109
+ this.compression.setBuffer(bytes, newLength, dictionary, dictLength);
110
+ bytes.maxLength = newLength;
111
+ Object.defineProperty(bytes, 'length', { value: newLength, writable: true, configurable: true });
112
+ this.compression.getValueBytes = bytes;
113
+ } else {
114
+ bytes = makeReusableBuffer(newLength);
115
+ setGlobalBuffer(getValueBytes = bytes);
116
+ }
117
+ bytes.isShared = true;
118
+ return bytes;
119
+ },
120
+ getBinary(id) {
121
+ try {
122
+ asSafeBuffer = true;
123
+ let fastBuffer = this.getBinaryFast(id);
124
+ return fastBuffer && (fastBuffer.isShared ? Uint8ArraySlice.call(fastBuffer, 0, this.lastSize) : fastBuffer);
125
+ } finally {
126
+ asSafeBuffer = false;
127
+ }
128
+ },
129
+ get(id) {
130
+ if (this.decoderCopies) {
131
+ // 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);
134
+ }
135
+ if (this.encoding == 'binary')
136
+ return this.getBinary(id);
137
+ if (this.decoder) {
138
+ // 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);
141
+ }
142
+
143
+ let result = this.getString(id);
144
+ if (result) {
145
+ if (this.encoding == 'json')
146
+ return JSON.parse(result);
147
+ }
148
+ return result;
149
+ },
150
+ getEntry(id) {
151
+ let value = this.get(id);
152
+ if (value !== undefined) {
153
+ if (this.useVersions)
154
+ return {
155
+ value,
156
+ version: getLastVersion(),
157
+ //size: this.lastSize
158
+ };
159
+ else
160
+ return {
161
+ value,
162
+ //size: this.lastSize
163
+ };
164
+ }
165
+ },
166
+ resetReadTxn() {
167
+ resetReadTxn();
168
+ },
169
+ _commitReadTxn() {
170
+ if (readTxn)
171
+ readTxn.commit();
172
+ readTxnRenewed = null;
173
+ readTxn = null;
174
+ },
175
+ ensureReadTxn() {
176
+ if (!env.writeTxn && !readTxnRenewed)
177
+ renewReadTxn(this);
178
+ },
179
+ doesExist(key, versionOrValue) {
180
+ if (!env.writeTxn)
181
+ readTxnRenewed ? readTxn : renewReadTxn(this);
182
+ if (versionOrValue == null) {
183
+ // undefined means the entry exists, null is used specifically to check for the entry *not* existing
184
+ return (this.getBinaryFast(key) === undefined) == (versionOrValue === null);
185
+ }
186
+ else if (this.useVersions) {
187
+ this.getBinaryFast(key);
188
+ return this.getBinaryFast(key) !== undefined && getLastVersion() === versionOrValue;
189
+ }
190
+ else {
191
+ if (versionOrValue && versionOrValue['\x10binary-data\x02'])
192
+ versionOrValue = versionOrValue['\x10binary-data\x02'];
193
+ else if (this.encoder)
194
+ versionOrValue = this.encoder.encode(versionOrValue);
195
+ if (typeof versionOrValue == 'string')
196
+ versionOrValue = Buffer.from(versionOrValue);
197
+ return this.getValuesCount(key, { start: versionOrValue, exactMatch: true}) > 0;
198
+ }
199
+ },
200
+ getValues(key, options) {
201
+ let defaultOptions = {
202
+ key,
203
+ valuesForKey: true
204
+ };
205
+ if (options && options.snapshot === false)
206
+ throw new Error('Can not disable snapshots for getValues');
207
+ return this.getRange(options ? Object.assign(defaultOptions, options) : defaultOptions);
208
+ },
209
+ getKeys(options) {
210
+ if (!options)
211
+ options = {};
212
+ options.values = false;
213
+ return this.getRange(options);
214
+ },
215
+ getCount(options) {
216
+ if (!options)
217
+ options = {};
218
+ options.onlyCount = true;
219
+ return this.getRange(options).iterate();
220
+ },
221
+ getKeysCount(options) {
222
+ if (!options)
223
+ options = {};
224
+ options.onlyCount = true;
225
+ options.values = false;
226
+ return this.getRange(options).iterate();
227
+ },
228
+ getValuesCount(key, options) {
229
+ if (!options)
230
+ options = {};
231
+ options.key = key;
232
+ options.valuesForKey = true;
233
+ options.onlyCount = true;
234
+ return this.getRange(options).iterate();
235
+ },
236
+ getRange(options) {
237
+ let iterable = new RangeIterable();
238
+ if (!options)
239
+ options = {};
240
+ let includeValues = options.values !== false;
241
+ let includeVersions = options.versions;
242
+ let valuesForKey = options.valuesForKey;
243
+ let limit = options.limit;
244
+ let db = this.db;
245
+ let snapshot = options.snapshot;
246
+ let compression = this.compression;
247
+ iterable.iterate = () => {
248
+ let currentKey = valuesForKey ? options.key : options.start;
249
+ const reverse = options.reverse;
250
+ let count = 0;
251
+ let cursor, cursorRenewId, cursorAddress;
252
+ let txn;
253
+ let flags = (includeValues ? 0x100 : 0) | (reverse ? 0x400 : 0) |
254
+ (valuesForKey ? 0x800 : 0) | (options.exactMatch ? 0x4000 : 0);
255
+ let store = this;
256
+ function resetCursor() {
257
+ try {
258
+ if (cursor)
259
+ finishCursor();
260
+ let writeTxn = env.writeTxn;
261
+ if (writeTxn)
262
+ snapshot = false;
263
+ txn = writeTxn || (readTxnRenewed ? readTxn : renewReadTxn(store));
264
+ cursor = !writeTxn && db.availableCursor;
265
+ if (cursor) {
266
+ db.availableCursor = null;
267
+ flags |= 0x2000;
268
+ } else {
269
+ cursor = new Cursor(db);
270
+ }
271
+ cursorAddress = cursor.address;
272
+ txn.cursorCount = (txn.cursorCount || 0) + 1; // track transaction so we always use the same one
273
+ if (snapshot === false) {
274
+ cursorRenewId = renewId; // use shared read transaction
275
+ txn.renewingCursorCount = (txn.renewingCursorCount || 0) + 1; // need to know how many are renewing cursors
276
+ }
277
+ } catch(error) {
278
+ if (cursor) {
279
+ try {
280
+ cursor.close();
281
+ } catch(error) { }
282
+ }
283
+ throw error;
284
+ }
285
+ }
286
+ resetCursor();
287
+ if (options.onlyCount) {
288
+ flags |= 0x1000;
289
+ let count = position(options.offset);
290
+ if (count < 0)
291
+ lmdbError(count);
292
+ finishCursor();
293
+ return count;
294
+ }
295
+ function position(offset) {
296
+ let keySize = currentKey === undefined ? 0 : store.writeKey(currentKey, keyBytes, 0);
297
+ let endAddress;
298
+ if (valuesForKey) {
299
+ if (options.start === undefined && options.end === undefined)
300
+ endAddress = 0;
301
+ else {
302
+ let startAddress;
303
+ if (store.encoder.writeKey) {
304
+ startAddress = saveKey(options.start, store.encoder.writeKey, iterable, maxKeySize);
305
+ keyBytesView.setFloat64(START_ADDRESS_POSITION, startAddress, true);
306
+ endAddress = saveKey(options.end, store.encoder.writeKey, iterable, maxKeySize);
307
+ } else if ((!options.start || options.start instanceof Uint8Array) && (!options.end || options.end instanceof Uint8Array)) {
308
+ startAddress = saveKey(options.start, orderedBinary.writeKey, iterable, maxKeySize);
309
+ keyBytesView.setFloat64(START_ADDRESS_POSITION, startAddress, true);
310
+ endAddress = saveKey(options.end, orderedBinary.writeKey, iterable, maxKeySize);
311
+ } else {
312
+ throw new Error('Only key-based encoding is supported for start/end values');
313
+ let encoded = store.encoder.encode(options.start);
314
+ let bufferAddress = encoded.buffer.address || (encoded.buffer.address = getAddress(encoded) - encoded.byteOffset);
315
+ startAddress = bufferAddress + encoded.byteOffset;
316
+ }
317
+ }
318
+ } else
319
+ endAddress = saveKey(options.end, store.writeKey, iterable, maxKeySize);
320
+ return doPosition(cursorAddress, flags, offset || 0, keySize, endAddress);
321
+ }
322
+
323
+ function finishCursor() {
324
+ if (txn.isDone)
325
+ return;
326
+ if (cursorRenewId)
327
+ txn.renewingCursorCount--;
328
+ if (--txn.cursorCount <= 0 && txn.onlyCursor) {
329
+ cursor.close();
330
+ txn.abort(); // this is no longer main read txn, abort it now that we are done
331
+ txn.isDone = true;
332
+ } else {
333
+ if (db.availableCursor || txn != readTxn) {
334
+ cursor.close();
335
+ } else { // try to reuse it
336
+ db.availableCursor = cursor;
337
+ db.cursorTxn = txn;
338
+ }
339
+ }
340
+ }
341
+ return {
342
+ next() {
343
+ let keySize, lastSize;
344
+ if (cursorRenewId && (cursorRenewId != renewId || txn.isDone)) {
345
+ resetCursor();
346
+ keySize = position(0);
347
+ }
348
+ if (count === 0) { // && includeValues) // on first entry, get current value if we need to
349
+ keySize = position(options.offset);
350
+ } else
351
+ keySize = iterate(cursorAddress);
352
+ if (keySize <= 0 ||
353
+ (count++ >= limit)) {
354
+ if (count < 0)
355
+ lmdbError(count);
356
+ finishCursor();
357
+ return ITERATOR_DONE;
358
+ }
359
+ if (!valuesForKey || snapshot === false) {
360
+ if (keySize > 20000) {
361
+ if (keySize > 0x1000000)
362
+ lmdbError(keySize - 0x100000000)
363
+ throw new Error('Invalid key size ' + keySize.toString(16))
364
+ }
365
+ currentKey = store.readKey(keyBytes, 32, keySize + 32);
366
+ }
367
+ if (includeValues) {
368
+ let value;
369
+ lastSize = keyBytesView.getUint32(0, true);
370
+ let bytes = compression ? compression.getValueBytes : getValueBytes;
371
+ if (lastSize > bytes.maxLength) {
372
+ store.lastSize = lastSize;
373
+ asSafeBuffer = store.encoding == 'binary';
374
+ try {
375
+ bytes = store._returnLargeBuffer(
376
+ () => getCurrentValue(cursorAddress),
377
+ () => getCurrentShared(cursorAddress)
378
+ );
379
+ } finally {
380
+ asSafeBuffer = false;
381
+ }
382
+ } else
383
+ bytes.length = lastSize;
384
+ if (store.decoder) {
385
+ value = store.decoder.decode(bytes, lastSize);
386
+ } else if (store.encoding == 'binary')
387
+ value = bytes.isShared ? Uint8ArraySlice.call(bytes, 0, lastSize) : bytes;
388
+ else {
389
+ value = bytes.toString('utf8', 0, lastSize);
390
+ if (store.encoding == 'json' && value)
391
+ value = JSON.parse(value);
392
+ }
393
+ if (includeVersions)
394
+ return {
395
+ value: {
396
+ key: currentKey,
397
+ value,
398
+ version: getLastVersion()
399
+ }
400
+ };
401
+ else if (valuesForKey)
402
+ return {
403
+ value
404
+ };
405
+ else
406
+ return {
407
+ value: {
408
+ key: currentKey,
409
+ value,
410
+ }
411
+ };
412
+ } else if (includeVersions) {
413
+ return {
414
+ value: {
415
+ key: currentKey,
416
+ version: getLastVersion()
417
+ }
418
+ };
419
+ } else {
420
+ return {
421
+ value: currentKey
422
+ };
423
+ }
424
+ },
425
+ return() {
426
+ finishCursor();
427
+ return ITERATOR_DONE;
428
+ },
429
+ throw() {
430
+ finishCursor();
431
+ return ITERATOR_DONE;
432
+ }
433
+ };
434
+ };
435
+ return iterable;
436
+ },
437
+
438
+ getMany(keys, callback) {
439
+ // this is an asynchronous get for multiple keys. It actually works by prefetching asynchronously,
440
+ // allowing a separate to absorb the potentially largest cost: hard page faults (and disk I/O).
441
+ // And then we just do standard sync gets (to deserialized data) to fulfil the callback/promise
442
+ // once the prefetch occurs
443
+ let promise = callback ? undefined : new Promise(resolve => callback = (error, results) => resolve(results));
444
+ this.prefetch(keys, () => {
445
+ let results = new Array(keys.length);
446
+ for (let i = 0, l = keys.length; i < l; i++) {
447
+ results[i] = get.call(this, keys[i]);
448
+ }
449
+ callback(null, results);
450
+ });
451
+ return promise;
452
+ },
453
+ getSharedBufferForGet(id) {
454
+ let txn = (env.writeTxn || (readTxnRenewed ? readTxn : renewReadTxn(this)));
455
+ this.lastSize = this.keyIsCompatibility ? txn.getBinaryShared(id) : this.db.get(this.writeKey(id, keyBytes, 0));
456
+ if (this.lastSize === -30798) { // not found code
457
+ return; //undefined
458
+ }
459
+ return this.lastSize;
460
+ this.lastSize = keyBytesView.getUint32(0, true);
461
+ let bufferIndex = keyBytesView.getUint32(12, true);
462
+ lastOffset = keyBytesView.getUint32(8, true);
463
+ let buffer = buffers[bufferIndex];
464
+ let startOffset;
465
+ if (!buffer || lastOffset < (startOffset = buffer.startOffset) || (lastOffset + this.lastSize > startOffset + 0x100000000)) {
466
+ if (buffer)
467
+ env.detachBuffer(buffer.buffer);
468
+ startOffset = (lastOffset >>> 16) * 0x10000;
469
+ console.log('make buffer for address', bufferIndex * 0x100000000 + startOffset);
470
+ buffer = buffers[bufferIndex] = Buffer.from(getBufferForAddress(bufferIndex * 0x100000000 + startOffset));
471
+ buffer.startOffset = startOffset;
472
+ }
473
+ lastOffset -= startOffset;
474
+ return buffer;
475
+ return buffer.slice(lastOffset, lastOffset + this.lastSize);/*Uint8ArraySlice.call(buffer, lastOffset, lastOffset + this.lastSize)*/
476
+ },
477
+ prefetch(keys, callback) {
478
+ if (!keys)
479
+ throw new Error('An array of keys must be provided');
480
+ if (!keys.length) {
481
+ if (callback) {
482
+ callback(null);
483
+ return;
484
+ } else
485
+ return Promise.resolve();
486
+ }
487
+ let buffers = [];
488
+ let startPosition;
489
+ let bufferHolder = {};
490
+ let lastBuffer;
491
+ for (let key of keys) {
492
+ let position = saveKey(key, this.writeKey, bufferHolder, maxKeySize);
493
+ if (!startPosition)
494
+ startPosition = position;
495
+ if (bufferHolder.saveBuffer != lastBuffer) {
496
+ buffers.push(bufferHolder);
497
+ lastBuffer = bufferHolder.saveBuffer;
498
+ bufferHolder = { saveBuffer: lastBuffer };
499
+ }
500
+ }
501
+ saveKey(undefined, this.writeKey, bufferHolder, maxKeySize);
502
+ prefetch(this.dbAddress, startPosition, (error) => {
503
+ if (error)
504
+ console.error('Error with prefetch', buffers, bufferHolder); // partly exists to keep the buffers pinned in memory
505
+ else
506
+ callback(null);
507
+ });
508
+ if (!callback)
509
+ return new Promise(resolve => callback = resolve);
510
+ },
511
+ close(callback) {
512
+ this.status = 'closing';
513
+ if (this.isRoot) {
514
+ if (readTxn) {
515
+ try {
516
+ readTxn.abort();
517
+ } catch(error) {}
518
+ }
519
+ readTxn = {
520
+ renew() {
521
+ throw new Error('Can not read from a closed database');
522
+ }
523
+ };
524
+ readTxnRenewed = null;
525
+ }
526
+ let txnPromise = this._endWrites();
527
+ const doClose = () => {
528
+ this.db.close();
529
+ if (this.isRoot) {
530
+ env.close();
531
+ }
532
+ this.status = 'closed';
533
+ if (callback)
534
+ callback();
535
+ }
536
+ if (txnPromise)
537
+ return txnPromise.then(doClose);
538
+ else {
539
+ doClose();
540
+ return Promise.resolve();
541
+ }
542
+ },
543
+ getStats() {
544
+ readTxnRenewed ? readTxn : renewReadTxn(this);
545
+ return this.db.stat();
546
+ }
547
+ });
548
+ let get = LMDBStore.prototype.get;
549
+ function renewReadTxn(store) {
550
+ if (!readTxn) {
551
+ let retries = 0;
552
+ let waitArray;
553
+ do {
554
+ try {
555
+ readTxn = new Txn(env, 0x20000);
556
+ break;
557
+ } catch (error) {
558
+ if (error.message.includes('temporarily')) {
559
+ if (!waitArray)
560
+ waitArray = new Int32Array(new SharedArrayBuffer(4), 0, 1);
561
+ Atomics.wait(waitArray, 0, 0, retries * 2);
562
+ } else
563
+ throw error;
564
+ }
565
+ } while (retries++ < 100);
566
+ }
567
+ // we actually don't renew here, we let the renew take place in the next
568
+ // lmdb native read/call so as to avoid an extra native call
569
+ readTxnRenewed = setTimeout(resetReadTxn, 0);
570
+ store.emit('begin-transaction');
571
+ return readTxn;
572
+ }
573
+ function resetReadTxn(hardReset) {
574
+ renewId++;
575
+ if (readTxnRenewed) {
576
+ readTxnRenewed = null;
577
+ if (readTxn.cursorCount - (readTxn.renewingCursorCount || 0) > 0) {
578
+ readTxn.onlyCursor = true;
579
+ readTxn = null;
580
+ } else
581
+ resetTxn(readTxn.address);
582
+ }
583
+ }
584
+ }
585
+ export function makeReusableBuffer(size) {
586
+ let bytes = typeof Buffer != 'undefined' ? Buffer.alloc(size) : new Uint8Array(size);
587
+ bytes.maxLength = size;
588
+ Object.defineProperty(bytes, 'length', { value: size, writable: true, configurable: true });
589
+ return bytes;
590
+ }
@@ -0,0 +1,12 @@
1
+ export default [
2
+ {
3
+ input: "node-index.js",
4
+ output: [
5
+ {
6
+ file: "dist/index.cjs",
7
+ format: "cjs",
8
+ sourcemap: true
9
+ }
10
+ ]
11
+ }
12
+ ];