'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var fs = _interopDefault(require('fs')); var path = require('path'); var EventEmitter = _interopDefault(require('events')); var module$1 = require('module'); var url = require('url'); var index_js = require('weak-lru-cache/index.js'); var index_js$1 = require('ordered-binary/index.js'); var os = _interopDefault(require('os')); const require$1 = module$1.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href))); let nativeMethods, dirName = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)))).replace(/dist$/, ''); try { console.log(dirName); nativeMethods = require$1('node-gyp-build')(dirName); if (process.versions.modules == 93) require$1('v8').setFlagsFromString('--turbo-fast-api-calls'); } catch(error) { if (process.versions.modules == 93) { // use this abi version as the backup version without turbo-fast-api-calls enabled Object.defineProperty(process.versions, 'modules', { value: '92' }); try { nativeMethods = require$1('node-gyp-build')(dirName); } catch(secondError) { throw error } finally { Object.defineProperty(process.versions, 'modules', { value: '93' }); } } else throw error } const { Env, Cursor, Compression, getBufferForAddress, getAddress } = nativeMethods; let getLastVersion; const mapGet = Map.prototype.get; const CachingStore = Store => class extends Store { constructor(dbName, options) { super(dbName, options); if (!this.env.cacheCommitter) { this.env.cacheCommitter = true; this.on('aftercommit', ({ next, last }) => { do { let store = next.store; if (store) { if (next.flag & 1) next.store.cache.delete(next.key); // just delete it from the map else { let expirationPriority = next.valueSize >> 10; let cache = next.store.cache; let entry = mapGet.call(cache, next.key); if (entry) cache.used(entry, expirationPriority); // this will enter it into the LRFU } } } while (next != last && (next = next.next)) }); } this.db.cachingDb = this; this.cache = new index_js.WeakLRUCache(options.cache); } get(id, cacheMode) { let value = this.cache.getValue(id); if (value !== undefined) return value value = super.get(id); if (value && typeof value === 'object' && !cacheMode && typeof id !== 'object') { let entry = this.cache.setValue(id, value, this.lastSize >> 10); if (this.useVersions) { entry.version = getLastVersion(); } } return value } getEntry(id, cacheMode) { let entry = this.cache.get(id); if (entry) return entry let value = super.get(id); if (value === undefined) return if (value && typeof value === 'object' && !cacheMode && typeof id !== 'object') { entry = this.cache.setValue(id, value, this.lastSize >> 10); } else { entry = { value }; } if (this.useVersions) { entry.version = getLastVersion(); } return entry } putEntry(id, entry, ifVersion) { let result = super.put(id, entry.value, entry.version, ifVersion); if (typeof id === 'object') return result if (result && result.then) this.cache.setManually(id, entry); // set manually so we can keep it pinned in memory until it is committed else // sync operation, immediately add to cache this.cache.set(id, entry); } put(id, value, version, ifVersion) { // if (this.cache.get(id)) // if there is a cache entry, remove it from scheduledEntries and let result = super.put(id, value, version, ifVersion); if (typeof id !== 'object') { // sync operation, immediately add to cache, otherwise keep it pinned in memory until it is committed let entry = this.cache.setValue(id, value, result.isSync ? 0 : -1); if (version !== undefined) entry.version = typeof version === 'object' ? version.version : version; } return result } putSync(id, value, version, ifVersion) { if (id !== 'object') { // sync operation, immediately add to cache, otherwise keep it pinned in memory until it is committed if (value && typeof value === 'object') { let entry = this.cache.setValue(id, value); if (version !== undefined) { entry.version = typeof version === 'object' ? version.version : version; } } else // it is possible that a value used to exist here this.cache.delete(id); } return super.putSync(id, value, version, ifVersion) } remove(id, ifVersion) { this.cache.delete(id); return super.remove(id, ifVersion) } removeSync(id, ifVersion) { this.cache.delete(id); return super.removeSync(id, ifVersion) } clear() { this.cache.clear(); super.clear(); } childTransaction(execute) { throw new Error('Child transactions are not supported in caching stores') } }; function setGetLastVersion(get) { getLastVersion = get; } const SKIP = {}; if (!Symbol.asyncIterator) { Symbol.asyncIterator = Symbol.for('Symbol.asyncIterator'); } class ArrayLikeIterable { constructor(sourceArray) { if (sourceArray) { this[Symbol.iterator] = sourceArray[Symbol.iterator].bind(sourceArray); } } map(func) { let source = this; let result = new ArrayLikeIterable(); result[Symbol.iterator] = (async) => { let iterator = source[Symbol.iterator](async); return { next(resolvedResult) { let result; do { let iteratorResult; if (resolvedResult) { iteratorResult = resolvedResult; resolvedResult = null; // don't go in this branch on next iteration } else { iteratorResult = iterator.next(); if (iteratorResult.then) { return iteratorResult.then(iteratorResult => this.next(iteratorResult)) } } if (iteratorResult.done === true) { this.done = true; return iteratorResult } result = func(iteratorResult.value); if (result && result.then) { return result.then(result => result == SKIP ? this.next() : { value: result }) } } while(result == SKIP) return { value: result } }, return() { return iterator.return() }, throw() { return iterator.throw() } } }; return result } [Symbol.asyncIterator]() { return this[Symbol.iterator](true) } filter(func) { return this.map(element => func(element) ? element : SKIP) } forEach(callback) { let iterator = this[Symbol.iterator](); let result; while ((result = iterator.next()).done !== true) { callback(result.value); } } concat(secondIterable) { let concatIterable = new ArrayLikeIterable(); concatIterable[Symbol.iterator] = (async) => { let iterator = this[Symbol.iterator](); let isFirst = true; let concatIterator = { next() { let result = iterator.next(); if (isFirst && result.done) { isFirst = false; iterator = secondIterable[Symbol.iterator](async); return iterator.next() } return result }, return() { return iterator.return() }, throw() { return iterator.throw() } }; return concatIterator }; return concatIterable } toJSON() { if (this.asArray && this.asArray.forEach) { return this.asArray } throw new Error('Can not serialize async iteratables without first calling resolveJSON') //return Array.from(this) } get asArray() { if (this._asArray) return this._asArray let promise = new Promise((resolve, reject) => { let iterator = this[Symbol.iterator](true); let array = []; let iterable = this; function next(result) { while (result.done !== true) { if (result.then) { return result.then(next) } else { array.push(result.value); } result = iterator.next(); } array.iterable = iterable; resolve(iterable._asArray = array); } next(iterator.next()); }); promise.iterable = this; return this._asArray || (this._asArray = promise) } resolveData() { return this.asArray } } index_js$1.enableNullTermination(); const writeUint32Key = (key, target, start) => { (target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length))).setUint32(start, key, true); return start + 4 }; const readUint32Key = (target, start) => { return (target.dataView || (target.dataView = new DataView(target.buffer, 0, target.length))).getUint32(start, true) }; const writeBufferKey = (key, target, start) => { if (key.length > 1978) throw new Error('Key buffer is too long') target.set(key, start); return key.length + start }; const readBufferKey = (target, start, end) => { return Uint8ArraySlice.call(target, start, end) }; function applyKeyHandling(store) { if (store.encoding == 'ordered-binary') { store.encoder = store.decoder = { encode(value) { if (savePosition > 6200) allocateSaveBuffer(); let start = savePosition; savePosition = index_js$1.writeKey(value, saveBuffer, start); let buffer = saveBuffer.subarray(start, savePosition); savePosition = (savePosition + 7) & 0xfffff8; return buffer }, decode(buffer, end) { return index_js$1.readKey(buffer, 0, end) }, writeKey: index_js$1.writeKey, readKey: index_js$1.readKey, }; } if (store.keyIsUint32) { store.writeKey = writeUint32Key; store.readKey = readUint32Key; } else if (store.keyIsBuffer) { store.writeKey = writeBufferKey; store.readKey = readBufferKey; } else if (store.keyEncoder) { store.writeKey = store.keyEncoder.writeKey; store.readKey = store.keyEncoder.readKey; } else { store.writeKey = index_js$1.writeKey; store.readKey = index_js$1.readKey; } } let saveBuffer, saveDataView, saveDataAddress; let savePosition = 8000; function allocateSaveBuffer() { saveBuffer = Buffer.alloc(8192); saveBuffer.dataView = saveDataView = new DataView(saveBuffer.buffer, saveBuffer.byteOffset, saveBuffer.byteLength); saveBuffer.buffer.address = getAddress(saveBuffer.buffer); saveDataAddress = saveBuffer.buffer.address + saveBuffer.byteOffset; savePosition = 0; } function saveKey(key, writeKey, saveTo) { if (savePosition > 6200) { allocateSaveBuffer(); } let start = savePosition; savePosition = writeKey(key, saveBuffer, start + 4); saveDataView.setUint32(start, savePosition - start - 4, true); saveTo.saveBuffer = saveBuffer; savePosition = (savePosition + 7) & 0xfffff8; return start + saveDataAddress } const ITERATOR_DONE = { done: true, value: undefined }; function addQueryMethods(LMDBStore, { getReadTxn, env, keyBytes, keyBytesView, getLastVersion }) { let renewId = 1; LMDBStore.onReadReset = () => renewId++; Object.assign(LMDBStore.prototype, { getValues(key, options) { let defaultOptions = { key, valuesForKey: true }; if (options && options.snapshot === false) throw new Error('Can not disable snapshots for getValues') return this.getRange(options ? Object.assign(defaultOptions, options) : defaultOptions) }, getKeys(options) { if (!options) options = {}; options.values = false; return this.getRange(options) }, getCount(options) { if (!options) options = {}; options.onlyCount = true; return this.getRange(options)[Symbol.iterator]() }, getKeysCount(options) { if (!options) options = {}; options.onlyCount = true; options.values = false; return this.getRange(options)[Symbol.iterator]() }, getValuesCount(key, options) { if (!options) options = {}; options.key = key; options.valuesForKey = true; options.onlyCount = true; return this.getRange(options)[Symbol.iterator]() }, getRange(options) { let iterable = new ArrayLikeIterable(); if (!options) options = {}; let includeValues = options.values !== false; let includeVersions = options.versions; let valuesForKey = options.valuesForKey; let limit = options.limit; let db = this.db; let snapshot = options.snapshot; iterable[Symbol.iterator] = () => { let currentKey = valuesForKey ? options.key : options.start; const reverse = options.reverse; let count = 0; let cursor, cursorRenewId; let txn; let flags = (includeValues ? 0x100 : 0) | (reverse ? 0x400 : 0) | (valuesForKey ? 0x800 : 0) | (options.exactMatch ? 0x4000 : 0); function resetCursor() { try { if (cursor) finishCursor(); let writeTxn = env.writeTxn; txn = writeTxn || getReadTxn(); cursor = !writeTxn && db.availableCursor; if (cursor) { db.availableCursor = null; if (db.cursorTxn != txn) cursor.renew(); else// if (db.currentRenewId != renewId) flags |= 0x2000; } else { cursor = new Cursor(db); } txn.cursorCount = (txn.cursorCount || 0) + 1; // track transaction so we always use the same one if (snapshot === false) { cursorRenewId = renewId; // use shared read transaction txn.renewingCursorCount = (txn.renewingCursorCount || 0) + 1; // need to know how many are renewing cursors } } catch(error) { if (cursor) { try { cursor.close(); } catch(error) { } } throw error } } resetCursor(); let store = this; if (options.onlyCount) { flags |= 0x1000; let count = position(options.offset); finishCursor(); return count } function position(offset) { let keySize = store.writeKey(currentKey, keyBytes, 0); let endAddress; if (valuesForKey) { if (options.start === undefined && options.end === undefined) endAddress = 0; else { let startAddress; if (store.encoder.writeKey) { startAddress = saveKey(options.start, store.encoder.writeKey, iterable); keyBytesView.setFloat64(2000, startAddress, true); endAddress = saveKey(options.end, store.encoder.writeKey, iterable); } else if ((!options.start || options.start instanceof Uint8Array) && (!options.end || options.end instanceof Uint8Array)) { startAddress = saveKey(options.start, index_js$1.writeKey, iterable); keyBytesView.setFloat64(2000, startAddress, true); endAddress = saveKey(options.end, index_js$1.writeKey, iterable); } else { throw new Error('Only key-based encoding is supported for start/end values') } } } else endAddress = saveKey(options.end, store.writeKey, iterable); return cursor.position(flags, offset || 0, keySize, endAddress) } function finishCursor() { if (txn.isAborted) return if (cursorRenewId) txn.renewingCursorCount--; if (--txn.cursorCount <= 0 && txn.onlyCursor) { cursor.close(); txn.abort(); // this is no longer main read txn, abort it now that we are done txn.isAborted = true; } else { if (db.availableCursor || txn != getReadTxn()) cursor.close(); else { // try to reuse it db.availableCursor = cursor; db.cursorTxn = txn; } } } return { next() { let keySize, lastSize; if (cursorRenewId && cursorRenewId != renewId) { resetCursor(); keySize = position(0); } if (count === 0) { // && includeValues) // on first entry, get current value if we need to keySize = position(options.offset); } else keySize = cursor.iterate(); if (keySize === 0 || (count++ >= limit)) { finishCursor(); return ITERATOR_DONE } if (!valuesForKey || snapshot === false) currentKey = store.readKey(keyBytes, 32, keySize + 32); if (includeValues) { let value; lastSize = keyBytesView.getUint32(0, true); if (store.decoder) { value = store.decoder.decode(db.unsafeBuffer, lastSize); } else if (store.encoding == 'binary') value = Uint8ArraySlice.call(db.unsafeBuffer, 0, lastSize); else { value = store.db.unsafeBuffer.toString('utf8', 0, lastSize); if (store.encoding == 'json' && value) value = JSON.parse(value); } if (includeVersions) return { value: { key: currentKey, value, version: getLastVersion() } } else if (valuesForKey) return { value } else return { value: { key: currentKey, value, } } } else if (includeVersions) { return { value: { key: currentKey, version: getLastVersion() } } } else { return { value: currentKey } } }, return() { finishCursor(); return ITERATOR_DONE }, throw() { finishCursor(); return ITERATOR_DONE } } }; return iterable } }); } function when(promise, callback, errback) { if (promise && promise.then) { return errback ? promise.then(callback, errback) : promise.then(callback) } return callback(promise) } var backpressureArray; const MAX_KEY_SIZE = 1978; const WAITING_OPERATION = 0x400000; const BACKPRESSURE_THRESHOLD = 5000000; const TXN_DELIMITER = 0x20000000; const TXN_COMMITTED = 0x40000000; const FAILED_CONDITION = 0x200000; const SYNC_PROMISE_SUCCESS = Promise.resolve(true); const SYNC_PROMISE_FAIL = Promise.resolve(false); const ABORT = {}; const CALLBACK_THREW = {}; SYNC_PROMISE_SUCCESS.isSync = true; SYNC_PROMISE_FAIL.isSync = true; function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, useWritemap, eventTurnBatching, txnStartThreshold, batchStartThreshold, commitDelay }) { // stands for write instructions var dynamicBytes; function allocateInstructionBuffer() { dynamicBytes = Buffer.allocUnsafeSlow(0x10000); dynamicBytes.uint32 = new Uint32Array(dynamicBytes.buffer, 0, 0x10000 >> 2); dynamicBytes.uint32[0] = 0; dynamicBytes.float64 = new Float64Array(dynamicBytes.buffer, 0, 0x10000 >> 3); dynamicBytes.buffer.address = getAddress(dynamicBytes.buffer); dynamicBytes.address = dynamicBytes.buffer.address + dynamicBytes.byteOffset; dynamicBytes.position = 0; return dynamicBytes } var outstandingWriteCount = 0; var startAddress = 0; var writeTxn = null; var abortedNonChildTransactionWarn; var nextTxnCallbacks = []; var commitPromise; commitDelay = commitDelay || 0; eventTurnBatching = eventTurnBatching === false ? false : true; var enqueuedCommit; var afterCommitCallbacks = []; var beforeCommitCallbacks = []; var enqueuedEventTurnBatch; var batchDepth = 0; var writeBatchStart, outstandingBatchCount; txnStartThreshold = txnStartThreshold || 5; batchStartThreshold = batchStartThreshold || 1000; allocateInstructionBuffer(); dynamicBytes.uint32[0] = TXN_DELIMITER | TXN_COMMITTED; var txnResolution, lastQueuedResolution, nextResolution = { uint32: dynamicBytes.uint32, flagPosition: 0, }; var uncommittedResolution = { next: nextResolution }; var unwrittenResolution = nextResolution; function writeInstructions(flags, store, key, value, version, ifVersion) { let writeStatus; let targetBytes, position; let valueBuffer; if (flags & 2) { // encode first in case we have to write a shared structure if (store.encoder) { //if (!(value instanceof Uint8Array)) TODO: in a future version, directly store buffers that are provided valueBuffer = store.encoder.encode(value); if (typeof valueBuffer == 'string') valueBuffer = Buffer.from(valueBuffer); // TODO: Would be nice to write strings inline in the instructions } else if (typeof value == 'string') { valueBuffer = Buffer.from(value); // TODO: Would be nice to write strings inline in the instructions } else if (value instanceof Uint8Array) valueBuffer = value; else throw new Error('Invalid value to put in database ' + value + ' (' + (typeof value) +'), consider using encoder') } if (writeTxn) { targetBytes = fixedBuffer; position = 0; } else { if (eventTurnBatching && !enqueuedEventTurnBatch && batchDepth == 0) { enqueuedEventTurnBatch = setImmediate(() => { try { for (let i = 0, l = beforeCommitCallbacks.length; i < l; i++) { beforeCommitCallbacks[i](); } } catch(error) { console.error(error); } enqueuedEventTurnBatch = null; finishBatch(); batchDepth--; if (writeBatchStart) writeBatchStart(); // TODO: When we support delay start of batch, optionally don't delay this }); commitPromise = null; // reset the commit promise, can't know if it is really a new transaction prior to finishWrite being called writeBatchStart = writeInstructions(1, store); outstandingBatchCount = 0; batchDepth++; } targetBytes = dynamicBytes; position = targetBytes.position; } let uint32 = targetBytes.uint32, float64 = targetBytes.float64; let flagPosition = position << 1; // flagPosition is the 32-bit word starting position // don't increment Position until we are sure we don't have any key writing errors uint32[flagPosition + 1] = store.db.dbi; if (flags & 4) { let keyStartPosition = (position << 3) + 12; let endPosition; try { endPosition = store.writeKey(key, targetBytes, keyStartPosition); } catch(error) { targetBytes.fill(0, keyStartPosition); throw error } let keySize = endPosition - keyStartPosition; if (keySize > MAX_KEY_SIZE) { targetBytes.fill(0, keyStartPosition); throw new Error('Key size is too large') } uint32[flagPosition + 2] = keySize; position = (endPosition + 16) >> 3; if (flags & 2) { uint32[(position << 1) - 1] = valueBuffer.length; let valueArrayBuffer = valueBuffer.buffer; // record pointer to value buffer float64[position++] = (valueArrayBuffer.address || (valueArrayBuffer.address = getAddress(valueArrayBuffer))) + valueBuffer.byteOffset; if (store.compression && valueBuffer.length >= store.compression.threshold) { flags |= 0x100000; float64[position] = store.compression.address; if (!writeTxn) env.compress(targetBytes.buffer.address + (position << 3)); position++; } } if (ifVersion !== undefined) { if (ifVersion === null) flags |= 0x10; else { flags |= 0x100; float64[position++] = ifVersion; } } if (version !== undefined) { flags |= 0x200; float64[position++] = version || 0; } } else position++; targetBytes.position = position; //console.log('js write', (targetBytes.buffer.address + (flagPosition << 2)).toString(16), flags.toString(16)) if (writeTxn) { uint32[0] = flags; env.write(targetBytes.buffer.address); return () => (uint32[0] & FAILED_CONDITION) ? SYNC_PROMISE_FAIL : SYNC_PROMISE_SUCCESS } uint32[position << 1] = 0; // clear out the next slot let nextUint32; if (position > 0x1e00) { // 61440 bytes let lastPosition = position; let lastFloat64 = targetBytes.float64; let lastUint32 = targetBytes.uint32; targetBytes = allocateInstructionBuffer(); position = targetBytes.position; lastFloat64[lastPosition + 1] = targetBytes.buffer.address + position; lastUint32[lastPosition << 1] = 3; // pointer instruction //console.log('pointer from ', (lastFloat64.buffer.address + (lastPosition << 3)).toString(16), 'to', (targetBytes.buffer.address + position).toString(16), 'flag position', (uint32.buffer.address + (flagPosition << 2)).toString(16)) nextUint32 = targetBytes.uint32; } else nextUint32 = uint32; let newResolution = store.cache ? { uint32: nextUint32, flagPosition: position << 1, flag: 0, // TODO: eventually eliminate this, as we can probably signify success by zeroing the flagPosition valueBuffer, next: null, key, store, valueSize: 0, } : { uint32: nextUint32, flagPosition: position << 1, flag: 0, // TODO: eventually eliminate this, as we can probably signify success by zeroing the flagPosition valueBuffer, next: null, }; let resolution = nextResolution; resolution.next = newResolution; nextResolution = newResolution; let writtenBatchDepth = batchDepth; return () => { if (writtenBatchDepth) { // if we are in a batch, the transaction can't close, so we do the faster, // but non-deterministic updates, knowing that the write thread can // just poll for the status change if we miss a status update writeStatus = uint32[flagPosition]; uint32[flagPosition] = flags; if (writeBatchStart && !writeStatus) { outstandingBatchCount++; if (outstandingBatchCount > batchStartThreshold) { outstandingBatchCount = 0; writeBatchStart(); writeBatchStart = null; } } } else // otherwise the transaction could end at any time and we need to know the // deterministically if it is ending, so we can reset the commit promise // so we use the slower atomic operation writeStatus = Atomics.or(uint32, flagPosition, flags); outstandingWriteCount++; if (writeStatus & TXN_DELIMITER) { commitPromise = null; queueCommitResolution(resolution); if (!startAddress) startAddress = uint32.buffer.address + (flagPosition << 2); } if (writeStatus & WAITING_OPERATION) { // write thread is waiting //console.log('resume batch thread', uint32.buffer.address + (flagPosition << 2)) env.startWriting(0); } if (outstandingWriteCount > BACKPRESSURE_THRESHOLD) { console.log('backpressure'); if (!backpressureArray) backpressureArray = new Int8Array(new SharedArrayBuffer(4), 0, 1); Atomics.wait(backpressureArray, 0, 0, 1); } if (startAddress) { if (!enqueuedCommit && txnStartThreshold) { enqueuedCommit = commitDelay == 0 ? setImmediate(startWriting) : setTimeout(startWriting, commitDelay); } else if (outstandingWriteCount > txnStartThreshold) startWriting(); } if ((outstandingWriteCount & 7) === 0) resolveWrites(); if (store.cache) { resolution.key = key; resolution.store = store; resolution.valueSize = valueBuffer ? valueBuffer.length : 0; } resolution.valueBuffer = valueBuffer; lastQueuedResolution = resolution; if (ifVersion === undefined) { if (writtenBatchDepth > 1) return SYNC_PROMISE_SUCCESS // or return undefined? if (!commitPromise) { commitPromise = new Promise((resolve, reject) => { resolution.resolve = resolve; resolution.reject = reject; }); } return commitPromise } return new Promise((resolve, reject) => { resolution.resolve = resolve; resolution.reject = reject; }) } } function startWriting() { //console.log('start address ' + startAddress.toString(16), store.name) if (enqueuedCommit) { clearImmediate(enqueuedCommit); enqueuedCommit = null; } env.startWriting(startAddress, (status) => { //console.log('finished batch', store.name) if (dynamicBytes.uint32[dynamicBytes.position << 1] & TXN_DELIMITER) queueCommitResolution(nextResolution); resolveWrites(true); switch (status) { case 0: case 1: break; case 2: executeTxnCallbacks(); console.log('user callback'); break default: console.error(status); if (commitRejectPromise) { commitRejectPromise.reject(status); commitRejectPromise = null; } } }); startAddress = 0; } function queueCommitResolution(resolution) { if (!resolution.isTxn) { resolution.isTxn = true; if (txnResolution) { txnResolution.nextTxn = resolution; outstandingWriteCount = 0; } else txnResolution = resolution; } } function resolveWrites(async) { // clean up finished instructions let instructionStatus; while ((instructionStatus = unwrittenResolution.uint32[unwrittenResolution.flagPosition]) & 0x10000000) { //console.log('instructionStatus: ' + instructionStatus.toString(16)) if (unwrittenResolution.callbacks) { nextTxnCallbacks.push(unwrittenResolution.callbacks); unwrittenResolution.callbacks = null; } if (!unwrittenResolution.isTxn) unwrittenResolution.uint32 = null; unwrittenResolution.valueBuffer = null; unwrittenResolution.flag = instructionStatus; outstandingWriteCount--; unwrittenResolution = unwrittenResolution.next; } while (txnResolution && (instructionStatus = txnResolution.uint32[txnResolution.flagPosition] & 0xc0000000)) { if (instructionStatus & 0x80000000) rejectCommit(); else if (instructionStatus & TXN_COMMITTED) resolveCommit(async); } } function resolveCommit(async) { afterCommit(); if (async) resetReadTxn(); else queueMicrotask(resetReadTxn); // TODO: only do this if there are actually committed writes? do { if (uncommittedResolution.resolve) { let flag = uncommittedResolution.flag; if (flag < 0) uncommittedResolution.reject(new Error("Error occurred in write")); else if (flag & FAILED_CONDITION) { uncommittedResolution.resolve(false); } else uncommittedResolution.resolve(true); } } while((uncommittedResolution = uncommittedResolution.next) && uncommittedResolution != txnResolution) txnResolution = txnResolution.nextTxn; } var commitRejectPromise; function rejectCommit() { afterCommit(); if (!commitRejectPromise) { let rejectFunction; commitRejectPromise = new Promise((resolve, reject) => rejectFunction = reject); commitRejectPromise.reject = rejectFunction; } do { let flag = uncommittedResolution.flag & 0xf; let error = new Error("Commit failed (see commitError for details)"); error.commitError = commitRejectPromise; uncommittedResolution.reject(error); } while(uncommittedResolution = uncommittedResolution.next && uncommittedResolution != txnResolution) txnResolution = txnResolution.nextTxn; } function atomicStatus(uint32, flagPosition, newStatus) { if (batchDepth) { // if we are in a batch, the transaction can't close, so we do the faster, // but non-deterministic updates, knowing that the write thread can // just poll for the status change if we miss a status update let writeStatus = uint32[flagPosition]; uint32[flagPosition] = newStatus; return writeStatus } else // otherwise the transaction could end at any time and we need to know the // deterministically if it is ending, so we can reset the commit promise // so we use the slower atomic operation return Atomics.or(uint32, flagPosition, newStatus) } function afterCommit() { for (let i = 0, l = afterCommitCallbacks.length; i < l; i++) { afterCommitCallbacks[i]({ next: uncommittedResolution, last: unwrittenResolution}); } } async function executeTxnCallbacks() { env.beginTxn(0); env.writeTxn = writeTxn = {}; let promises; let txnCallbacks; for (let i = 0, l = nextTxnCallbacks.length; i < l; i++) { txnCallbacks = nextTxnCallbacks[i]; for (let i = 0, l = txnCallbacks.length; i < l; i++) { let userTxnCallback = txnCallbacks[i]; let asChild = userTxnCallback.asChild; if (asChild) { if (promises) { // must complete any outstanding transactions before proceeding await Promise.all(promises); promises = null; } env.beginTxn(1); // abortable try { let result = userTxnCallback.callback(); if (result && result.then) { await result; } if (result === ABORT) env.abortTxn(); else env.commitTxn(); txnCallbacks[i] = result; } catch(error) { env.abortTxn(); txnError(error, i); } } else { try { let result = userTxnCallback(); txnCallbacks[i] = result; if (result && result.then) { if (!promises) promises = []; promises.push(result.catch(() => {})); } } catch(error) { txnError(error, i); } } } } nextTxnCallbacks = []; if (promises) { // finish any outstanding commit functions await Promise.all(promises); } env.writeTxn = writeTxn = false; return env.commitTxn() function txnError(error, i) { (txnCallbacks.errors || (txnCallbacks.errors = []))[i] = error; txnCallbacks[i] = CALLBACK_THREW; } } function finishBatch() { dynamicBytes.uint32[(dynamicBytes.position + 1) << 1] = 0; // clear out the next slot let writeStatus = atomicStatus(dynamicBytes.uint32, (dynamicBytes.position++) << 1, 2); // atomically write the end block nextResolution.flagPosition += 2; if (writeStatus & WAITING_OPERATION) { env.startWriting(0); } } Object.assign(LMDBStore.prototype, { put(key, value, versionOrOptions, ifVersion) { let flags = 15; if (typeof versionOrOptions == 'object') { if (versionOrOptions.noOverwrite) flags |= 0x10; if (versionOrOptions.noDupData) flags |= 0x20; if (versionOrOptions.append) flags |= 0x20000; if (versionOrOptions.ifVersion != undefined) ifVersion = versionsOrOptions.ifVersion; versionOrOptions = versionOrOptions.version; } return writeInstructions(flags, this, key, value, this.useVersions ? versionOrOptions || 0 : undefined, ifVersion)() }, remove(key, ifVersionOrValue) { let flags = 13; let ifVersion, value; if (ifVersionOrValue !== undefined) { if (this.useVersions) ifVersion = ifVersionOrValue; else { flags = 14; value = ifVersionOrValue; } } return writeInstructions(flags, this, key, value, undefined, ifVersion)() }, ifNoExists(key, callback) { return this.ifVersion(key, null, callback) }, ifVersion(key, version, callback) { if (!callback) { return new Batch((operations, callback) => { let promise = this.ifVersion(key, version, operations); if (callback) promise.then(callback); return promise }) } if (writeTxn) { if (this.doesExist(key, version)) { callback(); return SYNC_PROMISE_SUCCESS } return SYNC_PROMISE_FAIL } let finishStartWrite = writeInstructions(typeof key === 'undefined' ? 1 : 4, this, key, undefined, undefined, version); let promise; batchDepth += 2; if (batchDepth > 2) promise = finishStartWrite(); else { writeBatchStart = () => { promise = finishStartWrite(); }; outstandingBatchCount = 0; } //console.warn('wrote start of ifVersion', this.path) try { if (typeof callback === 'function') { callback(); } else { for (let i = 0, l = callback.length; i < l; i++) { let operation = callback[i]; this[operation.type](operation.key, operation.value); } } } finally { //console.warn('writing end of ifVersion', this.path, (dynamicBytes.buffer.address + ((dynamicBytes.position + 1) << 3)).toString(16)) if (!promise) { finishBatch(); batchDepth -= 2; promise = finishStartWrite(); // finish write once all the operations have been written (and it hasn't been written prematurely) writeBatchStart = null; } else { batchDepth -= 2; finishBatch(); } } return promise }, batch(callbackOrOperations) { return this.ifVersion(undefined, undefined, callbackOrOperations) }, putSync(key, value, versionOrOptions, ifVersion) { if (writeTxn) return this.put(key, value, versionOrOptions, ifVersion) else return this.transactionSync(() => this.put(key, value, versionOrOptions, ifVersion) == SYNC_PROMISE_SUCCESS, { abortable: false }) }, removeSync(key, ifVersionOrValue) { if (writeTxn) return this.remove(key, ifVersionOrValue) else return this.transactionSync(() => this.remove(key, ifVersionOrValue) == SYNC_PROMISE_SUCCESS, { abortable: false }) }, transaction(callback, options) { if (options) { if (options.synchronousStart) return this.transactionSync(callback, options) if (options.abortable) return this.childTransaction(callback) } if (writeTxn) { // already nested in a transaction, just execute and return return callback() } return this.transactionAsync(callback) }, childTransaction(callback) { if (useWritemap) throw new Error('Child transactions are not supported in writemap mode') if (writeTxn) { env.beginTxn(1); // abortable try { return when(callback(), (result) => { if (result === ABORT) env.abortTxn(); else env.commitTxn(); return result }, (error) => { env.abortTxn(); throw error }) } catch(error) { env.abortTxn(); throw error } } return this.transactionAsync(callback, true) }, transactionAsync(callback, asChild) { let txnIndex; let txnCallbacks; if (!lastQueuedResolution || !lastQueuedResolution.callbacks) { txnCallbacks = [asChild ? { callback, asChild } : callback]; txnCallbacks.results = writeInstructions(8 | (this.strictAsyncOrder ? 0x100000 : 0), this)(); lastQueuedResolution.callbacks = txnCallbacks; txnIndex = 0; } else { txnCallbacks = lastQueuedResolution.callbacks; txnIndex = txnCallbacks.push(asChild ? { callback, asChild } : callback) - 1; } return txnCallbacks.results.then((results) => { let result = txnCallbacks[txnIndex]; if (result === CALLBACK_THREW) throw txnCallbacks.errors[txnIndex] return result }) }, transactionSync(callback, options) { if (writeTxn) { if (!useWritemap && !this.cache && !(options && options.abortable === false)) // already nested in a transaction, execute as child transaction (if possible) and return return this.childTransaction(callback) let result = callback(); // else just run in current transaction if (result == ABORT && !abortedNonChildTransactionWarn) { console.warn('Can not abort a transaction inside another transaction with ' + (this.cache ? 'caching enabled' : 'useWritemap enabled')); abortedNonChildTransactionWarn = true; } return result } try { this.transactions++; let flags = 0; if (!(options && options.abortable === false)) flags = 1; if (!(options && options.synchronousCommit === false)) flags |= 2; env.beginTxn(flags); writeTxn = env.writeTxn = {}; return when(callback(), (result) => { try { if (result === ABORT) env.abortTxn(); else { env.commitTxn(); resetReadTxn(); } return result } finally { env.writeTxn = writeTxn = null; } }, (error) => { try { env.abortTxn(); } catch(e) {} env.writeTxn = writeTxn = null; throw error }) } catch(error) { try { env.abortTxn(); } catch(e) {} env.writeTxn = writeTxn = null; throw error } }, on(event, callback) { if (event == 'beforecommit') { eventTurnBatching = true; beforeCommitCallbacks.push(callback); } else if (event == 'aftercommit') afterCommitCallbacks.push(callback); } }); LMDBStore.prototype.del = LMDBStore.prototype.remove; } class Batch extends Array { constructor(callback) { this.callback = callback; } put(key, value) { this.push({ type: 'put', key, value }); } del(key) { this.push({ type: 'del', key }); } clear() { this.splice(0, this.length); } write(callback) { this.callback(this, callback); } } const require$2 = module$1.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href))); setGetLastVersion(getLastVersion$1); const Uint8ArraySlice$1 = Uint8Array.prototype.slice; const keyBytes = Buffer.allocUnsafeSlow(2048); const keyBuffer = keyBytes.buffer; const keyBytesView = keyBytes.dataView = new DataView(keyBytes.buffer, 0, 2048); // max key size is actually 1978 keyBytes.uint32 = new Uint32Array(keyBuffer, 0, 512); keyBytes.float64 = new Float64Array(keyBuffer, 0, 256); keyBuffer.address = getAddress(keyBuffer); const DEFAULT_COMMIT_DELAY = 0; const allDbs = new Map(); const SYNC_PROMISE_RESULT = Promise.resolve(true); const SYNC_PROMISE_FAIL$1 = Promise.resolve(false); SYNC_PROMISE_RESULT.isSync = true; SYNC_PROMISE_FAIL$1.isSync = true; let defaultCompression; let lastSize; function open(path$1, options) { let env = new Env(); let scheduledTransactions; let scheduledOperations; let asyncTransactionAfter = true, asyncTransactionStrictOrder; let readTxn, writeTxn, readTxnRenewed; if (typeof path$1 == 'object' && !options) { options = path$1; path$1 = options.path; } let extension = path.extname(path$1); let name = path.basename(path$1, extension); let is32Bit = os.arch().endsWith('32'); let remapChunks = (options && options.remapChunks) || ((options && options.mapSize) ? (is32Bit && options.mapSize > 0x100000000) : // larger than fits in address space, must use dynamic maps is32Bit); // without a known map size, we default to being able to handle large data correctly/well*/ options = Object.assign({ path: path$1, noSubdir: Boolean(extension), isRoot: true, maxDbs: 12, remapChunks, keyBytes, // default map size limit of 4 exabytes when using remapChunks, since it is not preallocated and we can // make it super huge. mapSize: remapChunks ? 0x10000000000000 : 0x20000, // Otherwise we start small with 128KB }, options); if (options.asyncTransactionOrder == 'before') { console.warn('asyncTransactionOrder: "before" is deprecated'); asyncTransactionAfter = false; } else if (options.asyncTransactionOrder == 'strict') { asyncTransactionStrictOrder = true; asyncTransactionAfter = false; } if (!fs.existsSync(options.noSubdir ? path.dirname(path$1) : path$1)) fs.mkdirSync(options.noSubdir ? path.dirname(path$1) : path$1, { recursive: true }); if (options.compression) { if (options.compression == true) { if (defaultCompression) options.compression = defaultCompression; else defaultCompression = options.compression = new Compression({ threshold: 1000, dictionary: fs.readFileSync(new URL('./dict/dict.txt', (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)).replace(/dist[\\\/]index.cjs$/, ''))), }); defaultCompression.threshold = 1000; } else { let compressionOptions = Object.assign({ threshold: 1000, dictionary: fs.readFileSync(new URL('./dict/dict.txt', (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)).replace(/dist[\\\/]index.cjs$/, ''))), }, options.compression); options.compression = new Compression(compressionOptions); options.compression.threshold = compressionOptions.threshold; } } if (options && options.clearOnStart) { console.info('Removing', path$1); fs.removeSync(path$1); console.info('Removed', path$1); } let useWritemap = options.useWritemap; try { env.open(options); } catch(error) { throw error } env.readerCheck(); // clear out any stale entries function renewReadTxn() { if (readTxn) readTxn.renew(); else readTxn = env.beginTxn(0x20000); readTxnRenewed = setImmediate(resetReadTxn); return readTxn } function resetReadTxn() { if (readTxnRenewed) { LMDBStore.onReadReset(); readTxnRenewed = null; if (readTxn.cursorCount - (readTxn.renewingCursorCount || 0) > 0) { readTxn.onlyCursor = true; readTxn = null; } else readTxn.reset(); } } class LMDBStore extends EventEmitter { constructor(dbName, dbOptions) { super(); if (dbName === undefined) throw new Error('Database name must be supplied in name property (may be null for root database)') const openDB = () => { try { this.db = env.openDbi(Object.assign({ name: dbName, create: true, txn: env.writeTxn, }, dbOptions)); this.db.name = dbName || null; } catch(error) { handleError(error); } }; if (dbOptions.compression && !(dbOptions.compression instanceof Compression)) { if (dbOptions.compression == true && options.compression) dbOptions.compression = options.compression; // use the parent compression if available else dbOptions.compression = new Compression(Object.assign({ threshold: 1000, dictionary: fs.readFileSync(require$2.resolve('./dict/dict.txt')), }), dbOptions.compression); } if (dbOptions.dupSort && (dbOptions.useVersions || dbOptions.cache)) { throw new Error('The dupSort flag can not be combined with versions or caching') } openDB(); resetReadTxn(); // a read transaction becomes invalid after opening another db this.name = dbName; this.env = env; this.reads = 0; this.writes = 0; this.transactions = 0; this.averageTransactionTime = 5; if (dbOptions.syncBatchThreshold) console.warn('syncBatchThreshold is no longer supported'); if (dbOptions.immediateBatchThreshold) console.warn('immediateBatchThreshold is no longer supported'); this.commitDelay = DEFAULT_COMMIT_DELAY; Object.assign(this, { // these are the options that are inherited path: options.path, encoding: options.encoding, strictAsyncOrder: options.strictAsyncOrder, }, dbOptions); if (!this.encoding || this.encoding == 'msgpack' || this.encoding == 'cbor') { this.encoder = this.decoder = new (this.encoding == 'cbor' ? require$2('cbor-x').Encoder : require$2('msgpackr').Encoder) (Object.assign(this.sharedStructuresKey ? this.setupSharedStructures() : { copyBuffers: true // need to copy any embedded buffers that are found since we use unsafe buffers }, options, dbOptions)); } else if (this.encoding == 'json') { this.encoder = { encode: JSON.stringify, }; } applyKeyHandling(this); allDbs.set(dbName ? name + '-' + dbName : name, this); } openDB(dbName, dbOptions) { if (typeof dbName == 'object' && !dbOptions) { dbOptions = dbName; dbName = options.name; } else dbOptions = dbOptions || {}; try { return dbOptions.cache ? new (CachingStore(LMDBStore))(dbName, dbOptions) : new LMDBStore(dbName, dbOptions) } catch(error) { if (error.message.indexOf('MDB_DBS_FULL') > -1) { error.message += ' (increase your maxDbs option)'; } throw error } } transactionAsync(callback, asChild) { let lastOperation; if (scheduledOperations) { lastOperation = asyncTransactionAfter ? scheduledOperations.appendAsyncTxn : scheduledOperations[asyncTransactionStrictOrder ? scheduledOperations.length - 1 : 0]; } else { scheduledOperations = []; scheduledOperations.bytes = 0; } let transactionSet; let transactionSetIndex; if (lastOperation === true) { // continue last set of transactions transactionSetIndex = scheduledTransactions.length - 1; transactionSet = scheduledTransactions[transactionSetIndex]; } else { // for now we signify transactions as a true if (asyncTransactionAfter) // by default we add a flag to put transactions after other operations scheduledOperations.appendAsyncTxn = true; else if (asyncTransactionStrictOrder) scheduledOperations.push(true); else // in before mode, we put all the async transaction at the beginning scheduledOperations.unshift(true); if (!scheduledTransactions) { scheduledTransactions = []; } transactionSetIndex = scheduledTransactions.push(transactionSet = []) - 1; } let index = (transactionSet.push(asChild ? {asChild, callback } : callback) - 1) << 1; return this.scheduleCommit().results.then((results) => { let transactionResults = results.transactionResults[transactionSetIndex]; let error = transactionResults[index]; if (error) throw error return transactionResults[index + 1] }) } getSharedBufferForGet(id) { let txn = ( (readTxnRenewed ? readTxn : renewReadTxn())); lastSize = this.keyIsCompatibility ? txn.getBinaryShared(id) : this.db.get(this.writeKey(id, keyBytes, 0)); if (lastSize === 0xffffffff) { // not found code return //undefined } return lastSize } getSizeBinaryFast(id) { (env.writeTxn || (readTxnRenewed ? readTxn : renewReadTxn())); lastSize = this.db.getByBinary(this.writeKey(id, keyBytes, 0)); } getString(id) { (env.writeTxn || (readTxnRenewed ? readTxn : renewReadTxn())); let string = this.db.getStringByBinary(this.writeKey(id, keyBytes, 0)); if (string) lastSize = string.length; return string } getBinaryFast(id) { this.getSizeBinaryFast(id); return lastSize === 0xffffffff ? undefined : this.db.unsafeBuffer.subarray(0, lastSize) } getBinary(id) { this.getSizeBinaryFast(id); return lastSize === 0xffffffff ? undefined : Uint8ArraySlice$1.call(this.db.unsafeBuffer, 0, lastSize) } get(id) { if (this.decoder) { this.getSizeBinaryFast(id); return lastSize === 0xffffffff ? undefined : this.decoder.decode(this.db.unsafeBuffer, lastSize) } if (this.encoding == 'binary') return this.getBinary(id) let result = this.getString(id); if (result) { if (this.encoding == 'json') return JSON.parse(result) } return result } getEntry(id) { let value = this.get(id); if (value !== undefined) { if (this.useVersions) return { value, version: getLastVersion$1(), //size: lastSize } else return { value, //size: lastSize } } } resetReadTxn() { resetReadTxn(); } doesExist(key, versionOrValue) { let txn; try { if (env.writeTxn) { txn = env.writeTxn; } else { txn = readTxnRenewed ? readTxn : renewReadTxn(); } if (versionOrValue === undefined) { this.getSizeBinaryFast(key); return lastSize !== 0xffffffff } else if (this.useVersions) { this.getSizeBinaryFast(key); return lastSize !== 0xffffffff && matches(getLastVersion$1(), versionOrValue) } else { if (this.encoder) { versionOrValue = this.encoder.encode(versionOrValue); } if (typeof versionOrValue == 'string') versionOrValue = Buffer.from(versionOrValue); return this.getValuesCount(key, { start: versionOrValue, exactMatch: true}) > 0 } } catch(error) { return handleError(error) } } batch(operations) { /*if (writeTxn) { this.commitBatchNow(operations.map(operation => [this.db, operation.key, operation.value])) return Promise.resolve(true) }*/ let scheduledOperations = this.getScheduledOperations(); for (let operation of operations) { let value = operation.value; scheduledOperations.push([operation.key, value]); scheduledOperations.bytes += operation.key.length + (value && value.length || 0) + 200; } return this.scheduleCommit().unconditionalResults } backup(path) { return new Promise((resolve, reject) => env.copy(path, false, (error) => { if (error) { reject(error); } else { resolve(); } })) } close() { this.db.close(); if (this.isRoot) { if (readTxn) { try { readTxn.abort(); } catch(error) {} } readTxnRenewed = null; env.close(); } } getStats() { try { let stats = this.db.stat(readTxnRenewed ? readTxn : renewReadTxn()); return stats } catch(error) { return handleError(error) } } sync(callback) { return env.sync(callback || function(error) { if (error) { console.error(error); } }) } deleteDB() { this.transactionSync(() => this.db.drop({ justFreePages: false }) , { abortable: false }); } clear() { this.transactionSync(() => this.db.drop({ justFreePages: true }) , { abortable: false }); if (this.encoder && this.encoder.structures) this.encoder.structures = []; } readerCheck() { return env.readerCheck() } readerList() { return env.readerList().join('') } setupSharedStructures() { const getStructures = () => { let lastVersion; // because we are doing a read here, we may need to save and restore the lastVersion from the last read if (this.useVersions) lastVersion = getLastVersion$1(); try { let buffer = this.getBinary(this.sharedStructuresKey); if (this.useVersions) setLastVersion(lastVersion); return buffer ? this.encoder.decode(buffer) : [] } catch(error) { return handleError(error) } }; return { saveStructures: (structures, previousLength) => { return this.transactionSync(() => { let existingStructuresBuffer = this.getBinary(this.sharedStructuresKey); let existingStructures = existingStructuresBuffer ? this.encoder.decode(existingStructuresBuffer) : []; if (existingStructures.length != previousLength) return false // it changed, we need to indicate that we couldn't update this.put(this.sharedStructuresKey, structures); }, { abortable: false, synchronousCommit: false }) }, getStructures, copyBuffers: true // need to copy any embedded buffers that are found since we use unsafe buffers } } } // if caching class overrides putSync, don't want to double call the caching code const putSync = LMDBStore.prototype.putSync; const removeSync = LMDBStore.prototype.removeSync; addQueryMethods(LMDBStore, { env, getReadTxn() { return readTxnRenewed ? readTxn : renewReadTxn() }, saveKey: saveKey$1, keyBytes, keyBytesView, getLastVersion: getLastVersion$1 }); addWriteMethods(LMDBStore, { env, fixedBuffer: keyBytes, resetReadTxn, ...options }); return options.cache ? new (CachingStore(LMDBStore))(options.name || null, options) : new LMDBStore(options.name || null, options) function handleError(error, store, txn, retry) { try { if (writeTxn) writeTxn.abort(); } catch(error) {} if (error.message.startsWith('MDB_') && !(error.message.startsWith('MDB_KEYEXIST') || error.message.startsWith('MDB_NOTFOUND')) || error.message == 'The transaction is already closed.') { resetReadTxn(); // separate out cursor-based read txns try { if (readTxn) { readTxn.abort(); readTxn.isAborted = true; } } catch(error) {} readTxn = null; } if (error.message.startsWith('MDB_PROBLEM')) console.error(error); error.message = 'In database ' + name + ': ' + error.message; throw error } } function matches(previousVersion, ifVersion){ let matches; if (previousVersion) { if (ifVersion) { matches = previousVersion == ifVersion; } else { matches = false; } } else { matches = !ifVersion; } return matches } function getLastEntrySize() { return lastSize } function getLastVersion$1() { return keyBytesView.getFloat64(16, true) } function setLastVersion(version) { return keyBytesView.setFloat64(16, version, true) } let saveBuffer$1, saveDataView$1, saveDataAddress$1; let savePosition$1 = 8000; function allocateSaveBuffer$1() { saveBuffer$1 = Buffer.alloc(8192); saveBuffer$1.dataView = saveDataView$1 = new DataView(saveBuffer$1.buffer, saveBuffer$1.byteOffset, saveBuffer$1.byteLength); saveBuffer$1.buffer.address = getAddress(saveBuffer$1.buffer); saveDataAddress$1 = saveBuffer$1.buffer.address + saveBuffer$1.byteOffset; savePosition$1 = 0; } function saveKey$1(key, writeKey, saveTo) { if (savePosition$1 > 6200) { allocateSaveBuffer$1(); } let start = savePosition$1; savePosition$1 = writeKey(key, saveBuffer$1, start + 4); saveDataView$1.setUint32(start, savePosition$1 - start - 4, true); saveTo.saveBuffer = saveBuffer$1; savePosition$1 = (savePosition$1 + 7) & 0xfffff8; return start + saveDataAddress$1 } Object.defineProperty(exports, 'bufferToKeyValue', { enumerable: true, get: function () { return index_js$1.fromBufferKey; } }); Object.defineProperty(exports, 'compareKey', { enumerable: true, get: function () { return index_js$1.compareKeys; } }); Object.defineProperty(exports, 'compareKeys', { enumerable: true, get: function () { return index_js$1.compareKeys; } }); Object.defineProperty(exports, 'keyValueToBuffer', { enumerable: true, get: function () { return index_js$1.toBufferKey; } }); exports.ABORT = ABORT; exports.allDbs = allDbs; exports.getLastEntrySize = getLastEntrySize; exports.getLastVersion = getLastVersion$1; exports.open = open; exports.setLastVersion = setLastVersion; //# sourceMappingURL=index.cjs.map