@harperfast/rocksdb-js 2.0.0 → 2.2.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.
package/dist/index.mjs CHANGED
@@ -3,6 +3,7 @@ import { execSync } from "node:child_process";
3
3
  import { closeSync, openSync, readFileSync, readSync, readdirSync, statSync } from "node:fs";
4
4
  import { dirname, join, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
+ import { mkdir } from "node:fs/promises";
6
7
  import * as orderedBinary from "ordered-binary";
7
8
  import { ExtendedIterable } from "@harperfast/extended-iterable";
8
9
  import { Encoder } from "msgpackr";
@@ -55,6 +56,7 @@ function locateBinding() {
55
56
  }
56
57
  const binding = req(locateBinding());
57
58
  const config = binding.config;
59
+ const FRESH_VERSION_FLAG$1 = binding.constants.FRESH_VERSION_FLAG;
58
60
  const addGlobalListener = binding.addListener;
59
61
  const removeGlobalListener = binding.removeListener;
60
62
  const globalListenerCount = binding.listenerCount;
@@ -67,9 +69,95 @@ const TransactionLog = binding.TransactionLog;
67
69
  const registryStatus = binding.registryStatus;
68
70
  const shutdown = binding.shutdown;
69
71
  const currentThreadId = binding.currentThreadId;
72
+ /**
73
+ * Advises the kernel that the file-backed pages of every mapped transaction log
74
+ * are cold (Linux MADV_COLD), so they are reclaimed first under memory pressure
75
+ * without being freed — useful during replication catch-up, where a full read of
76
+ * the logs would otherwise inflate the container's reclaimable cache toward its
77
+ * cgroup limit. No-op on kernels < 5.4, macOS, and Windows.
78
+ *
79
+ * The transaction log registry is a process-global singleton shared across all
80
+ * worker threads, so a single call cools every worker's maps. Call it on an
81
+ * interval from one thread (e.g. an `unref()`ed timer on the main thread).
82
+ *
83
+ * @returns the number of maps cooled and total file-backed bytes advised.
84
+ */
85
+ const coolTransactionLogs = binding.coolTransactionLogs;
86
+ /**
87
+ * Number of live transaction-log memory maps across the process. Internal —
88
+ * used by tests to verify that releasing a frozen log's external buffer unmaps
89
+ * the underlying mapping rather than leaving it retained.
90
+ */
91
+ const transactionLogMapCount = binding.transactionLogMapCount;
92
+ const nativeBackupRestore = binding.backupRestore;
93
+ const nativeBackupList = binding.backupList;
94
+ const nativeBackupDelete = binding.backupDelete;
95
+ const nativeBackupPurge = binding.backupPurge;
96
+ const nativeBackupVerify = binding.backupVerify;
70
97
  const stats = binding.stats;
71
98
  const version = binding.version;
72
99
 
100
+ //#endregion
101
+ //#region src/backup.ts
102
+ /**
103
+ * Backup management operations that act on a backup directory and do not
104
+ * require an open database. To create a backup, use the `db.backup()` instance
105
+ * method instead (it needs a live database for a consistent snapshot).
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * import { backups } from '@harperfast/rocksdb-js';
110
+ *
111
+ * const id = await db.backup('/path/to/backups');
112
+ * db.close();
113
+ * await backups.restore('/path/to/backups', '/path/to/restored-db');
114
+ * ```
115
+ */
116
+ const backups = {
117
+ /**
118
+ * Restores a database from a backup directory into a (closed) database
119
+ * directory. The default mode purges the destination directory, so it must
120
+ * not point at a live database.
121
+ */
122
+ async restore(backupDir, dbDir, options) {
123
+ if (resolve(backupDir) === resolve(dbDir)) throw new Error("Backup directory and database directory must be different");
124
+ const walDir = options?.walDir ?? dbDir;
125
+ await mkdir(dbDir, { recursive: true });
126
+ if (walDir !== dbDir) await mkdir(walDir, { recursive: true });
127
+ return new Promise((resolve, reject) => nativeBackupRestore(resolve, reject, backupDir, dbDir, walDir, {
128
+ backupId: options?.backupId,
129
+ keepLogFiles: options?.keepLogFiles,
130
+ mode: options?.mode
131
+ }));
132
+ },
133
+ /**
134
+ * Lists the non-corrupt backups in a backup directory, ordered by id.
135
+ */
136
+ list(backupDir) {
137
+ return new Promise((resolve, reject) => nativeBackupList(resolve, reject, backupDir));
138
+ },
139
+ /**
140
+ * Deletes a specific backup. Shared files are reference-counted and only
141
+ * removed once no remaining backup references them.
142
+ */
143
+ delete(backupDir, backupId) {
144
+ return new Promise((resolve, reject) => nativeBackupDelete(resolve, reject, backupDir, backupId));
145
+ },
146
+ /**
147
+ * Deletes all but the newest `keepCount` backups.
148
+ */
149
+ purge(backupDir, keepCount) {
150
+ return new Promise((resolve, reject) => nativeBackupPurge(resolve, reject, backupDir, keepCount));
151
+ },
152
+ /**
153
+ * Verifies a backup's file sizes, and optionally their checksums (which
154
+ * requires reading all backed-up data).
155
+ */
156
+ verify(backupDir, backupId, options) {
157
+ return new Promise((resolve, reject) => nativeBackupVerify(resolve, reject, backupDir, backupId, options?.verifyWithChecksum ?? false));
158
+ }
159
+ };
160
+
73
161
  //#endregion
74
162
  //#region src/util.ts
75
163
  /**
@@ -188,11 +276,11 @@ var DBI = class DBI {
188
276
  */
189
277
  get(key, options) {
190
278
  if (this.store.decoderCopies) return when(() => this.getBinaryFast(key, options), (result) => {
191
- if (result === void 0) return;
279
+ if (result === void 0 || result === FRESH_VERSION_FLAG$1) return result;
192
280
  if (options?.skipDecode) return result;
193
281
  return this.store.decodeValue(result);
194
282
  });
195
- return when(() => this.getBinary(key, options), (result) => result === void 0 ? void 0 : this.store.encoding === "binary" || !this.store.decoder || options?.skipDecode ? result : this.store.decodeValue(result));
283
+ return when(() => this.getBinary(key, options), (result) => result === void 0 || result === FRESH_VERSION_FLAG$1 ? result : this.store.encoding === "binary" || !this.store.decoder || options?.skipDecode ? result : this.store.decodeValue(result));
196
284
  }
197
285
  /**
198
286
  * Retrieves the binary data for the given key. This is just like `get()`,
@@ -202,7 +290,7 @@ var DBI = class DBI {
202
290
  */
203
291
  getBinary(key, options) {
204
292
  if (!this.store.isOpen()) return Promise.reject(/* @__PURE__ */ new Error("Database not open"));
205
- return this.store.get(this._context, key, true, this.store.getTxnId(options));
293
+ return this.store.get(this._context, key, true, options);
206
294
  }
207
295
  /**
208
296
  * Synchronously retrieves the binary data for the given key.
@@ -223,7 +311,7 @@ var DBI = class DBI {
223
311
  */
224
312
  getBinaryFast(key, options) {
225
313
  if (!this.store.isOpen()) return Promise.reject(/* @__PURE__ */ new Error("Database not open"));
226
- return this.store.get(this._context, key, false, this.store.getTxnId(options));
314
+ return this.store.get(this._context, key, false, options);
227
315
  }
228
316
  /**
229
317
  * Synchronously retrieves the binary data for the given key using a
@@ -282,12 +370,12 @@ var DBI = class DBI {
282
370
  getSync(key, options) {
283
371
  if (this.store.decoderCopies) {
284
372
  const bytes = this.getBinaryFastSync(key, options);
285
- return bytes === void 0 ? void 0 : this.store.decodeValue(bytes);
373
+ return bytes === void 0 || bytes === FRESH_VERSION_FLAG$1 ? bytes : this.store.decodeValue(bytes);
286
374
  }
287
375
  if (this.store.encoding === "binary") return this.getBinarySync(key, options);
288
376
  if (this.store.decoder) {
289
377
  const result = this.getBinarySync(key, options);
290
- return result ? this.store.decodeValue(result) : void 0;
378
+ return !result || result === FRESH_VERSION_FLAG$1 ? result : this.store.decodeValue(result);
291
379
  }
292
380
  if (!this.store.isOpen()) throw new Error("Database not open");
293
381
  return this.store.decodeValue(this.store.getSync(this._context, key, true, options));
@@ -450,17 +538,25 @@ var DBIterator = class {
450
538
  iterator;
451
539
  store;
452
540
  #includeValues;
453
- constructor(iterator, store, includeValues) {
541
+ #limit;
542
+ #yielded = 0;
543
+ constructor(iterator, store, includeValues, limit) {
454
544
  this.iterator = iterator;
455
545
  this.store = store;
456
546
  this.#includeValues = includeValues;
547
+ this.#limit = limit ?? void 0;
457
548
  }
458
549
  [Symbol.iterator]() {
459
550
  return this;
460
551
  }
461
552
  next() {
553
+ if (this.#limit !== void 0 && this.#yielded >= this.#limit) {
554
+ this.iterator.return?.();
555
+ return DONE_RESULT;
556
+ }
462
557
  const result = this.iterator.next();
463
558
  if (result === ITERATOR_RESULT_DONE) return DONE_RESULT;
559
+ this.#yielded++;
464
560
  const includeValues = this.#includeValues;
465
561
  const value = {};
466
562
  if (result === ITERATOR_RESULT_FAST) {
@@ -562,7 +658,7 @@ function createFixedBuffer(size) {
562
658
 
563
659
  //#endregion
564
660
  //#region src/store.ts
565
- const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG, ITERATOR_REVERSE_FLAG, ITERATOR_INCLUSIVE_END_FLAG, ITERATOR_EXCLUSIVE_START_FLAG, ITERATOR_INCLUDE_VALUES_FLAG, ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG, ITERATOR_CONTEXT_IS_TRANSACTION_FLAG } = constants;
661
+ const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG, FRESH_VERSION_FLAG, POPULATE_VERSION_FLAG, ITERATOR_REVERSE_FLAG, ITERATOR_INCLUSIVE_END_FLAG, ITERATOR_EXCLUSIVE_START_FLAG, ITERATOR_INCLUDE_VALUES_FLAG, ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG, ITERATOR_CONTEXT_IS_TRANSACTION_FLAG } = constants;
566
662
  const KEY_BUFFER_SIZE = 4096;
567
663
  const KEY_BUFFER = createFixedBuffer(KEY_BUFFER_SIZE);
568
664
  const VALUE_BUFFER = createFixedBuffer(64 * 1024);
@@ -721,6 +817,10 @@ var Store = class {
721
817
  */
722
818
  transactionLogsPath;
723
819
  /**
820
+ * Whether this store's column family participates in the VerificationTable.
821
+ */
822
+ verificationTable;
823
+ /**
724
824
  * The per-column-family memtable size in bytes at which the memtable is
725
825
  * sealed and flushed.
726
826
  */
@@ -767,6 +867,7 @@ var Store = class {
767
867
  this.transactionLogMaxSize = options?.transactionLogMaxSize;
768
868
  this.transactionLogRetention = options?.transactionLogRetention;
769
869
  this.transactionLogsPath = options?.transactionLogsPath;
870
+ this.verificationTable = options?.verificationTable;
770
871
  this.writeBufferSize = options?.writeBufferSize;
771
872
  this.writeKey = writeKey;
772
873
  }
@@ -800,6 +901,20 @@ var Store = class {
800
901
  return new Promise((resolve, reject) => this.db.compact(resolve, reject, startBuffer, endBuffer));
801
902
  }
802
903
  /**
904
+ * Creates a backup of the entire database (all column families) into the
905
+ * given directory and resolves with the new backup id. Parent directories
906
+ * are created as needed. See `backups` for restore and management.
907
+ *
908
+ * @example
909
+ * ```typescript
910
+ * const id = await db.backup('/path/to/backups');
911
+ * ```
912
+ */
913
+ async backup(backupDir, options) {
914
+ await mkdir(backupDir, { recursive: true });
915
+ return new Promise((resolve, reject) => this.db.backup(resolve, reject, backupDir, options));
916
+ }
917
+ /**
803
918
  * Compacts the entire key range of the database synchronously.
804
919
  * This triggers manual compaction which removes tombstones and reclaims space.
805
920
  *
@@ -872,16 +987,19 @@ var Store = class {
872
987
  if (value instanceof Uint8Array) return value;
873
988
  throw new Error(`Invalid value put in database (${typeof value}), consider using an encoder`);
874
989
  }
875
- get(context, key, alwaysCreateNewBuffer = false, txnId) {
990
+ get(context, key, alwaysCreateNewBuffer = false, options) {
876
991
  const keyParam = getKeyParam(this.encodeKey(key));
877
992
  let flags = 0;
878
993
  if (alwaysCreateNewBuffer) flags |= ALWAYS_CREATE_NEW_BUFFER_FLAG;
879
- if (this.readOnly) txnId = void 0;
880
- const result = context.getSync(keyParam, flags | ONLY_IF_IN_MEMORY_CACHE_FLAG, txnId);
994
+ if (options?.populateVersion) flags |= POPULATE_VERSION_FLAG;
995
+ const txnId = this.getTxnId(options);
996
+ const expectedVersion = options?.expectedVersion;
997
+ const result = context.getSync(keyParam, flags | ONLY_IF_IN_MEMORY_CACHE_FLAG, txnId, expectedVersion);
881
998
  if (typeof result === "number") {
882
999
  if (result === NOT_IN_MEMORY_CACHE_FLAG) return new Promise((resolve, reject) => {
883
- context.get(keyParam, resolve, reject, txnId);
1000
+ context.get(keyParam, resolve, reject, txnId, expectedVersion);
884
1001
  });
1002
+ if (result === FRESH_VERSION_FLAG) return result;
885
1003
  VALUE_BUFFER.end = result;
886
1004
  return VALUE_BUFFER;
887
1005
  }
@@ -948,14 +1066,16 @@ var Store = class {
948
1066
  if (includeValues && !this.decoderCopies) flags |= ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG;
949
1067
  if (context !== this.db) flags |= ITERATOR_CONTEXT_IS_TRANSACTION_FLAG;
950
1068
  const advancedOptions = options !== void 0 && (options.adaptiveReadahead !== void 0 || options.asyncIO !== void 0 || options.autoReadaheadSize !== void 0 || options.backgroundPurgeOnIteratorCleanup !== void 0 || options.fillCache !== void 0 || options.readaheadSize !== void 0 || options.tailing !== void 0) ? options : void 0;
951
- return new ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions), this, includeValues));
1069
+ return new ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions), this, includeValues, options?.limit));
952
1070
  }
953
1071
  getSync(context, key, alwaysCreateNewBuffer = false, options) {
954
1072
  const keyParam = getKeyParam(this.encodeKey(key));
955
1073
  let flags = 0;
956
1074
  if (alwaysCreateNewBuffer) flags |= ALWAYS_CREATE_NEW_BUFFER_FLAG;
957
- const result = context.getSync(keyParam, flags, this.getTxnId(options));
1075
+ if (options?.populateVersion) flags |= POPULATE_VERSION_FLAG;
1076
+ const result = context.getSync(keyParam, flags, this.getTxnId(options), options?.expectedVersion);
958
1077
  if (typeof result === "number") {
1078
+ if (result === FRESH_VERSION_FLAG) return result;
959
1079
  VALUE_BUFFER.end = result;
960
1080
  return VALUE_BUFFER;
961
1081
  }
@@ -1044,6 +1164,7 @@ var Store = class {
1044
1164
  transactionLogMaxSize: this.transactionLogMaxSize,
1045
1165
  transactionLogRetentionMs: this.transactionLogRetention ? parseDuration(this.transactionLogRetention) : void 0,
1046
1166
  transactionLogsPath: this.transactionLogsPath,
1167
+ verificationTable: this.verificationTable,
1047
1168
  writeBufferSize: this.writeBufferSize
1048
1169
  });
1049
1170
  return false;
@@ -1093,6 +1214,25 @@ var Store = class {
1093
1214
  return context.useLog(String(name));
1094
1215
  }
1095
1216
  /**
1217
+ * Checks the process-global verification table for a fresh version match
1218
+ * on `key`. Returns `true` when the table currently records `version` for
1219
+ * this database+column-family. Provides a fast cache-freshness check
1220
+ * before falling back to a full read.
1221
+ */
1222
+ verifyVersion(key, version) {
1223
+ const keyParam = getKeyParam(this.encodeKey(key));
1224
+ return this.db.verifyVersion(keyParam, version);
1225
+ }
1226
+ /**
1227
+ * Seeds the verification-table slot for `key` with `version`. Has no
1228
+ * effect if the slot is currently lock-tagged or the table is disabled.
1229
+ * Useful after a full read where the caller already knows the version.
1230
+ */
1231
+ populateVersion(key, version) {
1232
+ const keyParam = getKeyParam(this.encodeKey(key));
1233
+ this.db.populateVersion(keyParam, version);
1234
+ }
1235
+ /**
1096
1236
  * Acquires a lock on the given key and calls the callback.
1097
1237
  *
1098
1238
  * @param key - The key to lock.
@@ -1120,6 +1260,13 @@ function getKeyParam(keyBuffer) {
1120
1260
 
1121
1261
  //#endregion
1122
1262
  //#region src/transaction.ts
1263
+ /**
1264
+ * Sentinel value returned by `commit()` when `coordinatedRetry: true` and the
1265
+ * transaction encountered an IsBusy conflict. The native layer parks on VT
1266
+ * slots and resolves only after the conflicting transaction releases its write
1267
+ * intent, so callers should retry immediately without any backoff delay.
1268
+ */
1269
+ const RETRY_NOW = constants.RETRY_NOW_VALUE;
1123
1270
  var TransactionAlreadyAbortedError = class extends Error {
1124
1271
  code = "ERR_ALREADY_ABORTED";
1125
1272
  };
@@ -1180,13 +1327,16 @@ var Transaction = class extends DBI {
1180
1327
  }
1181
1328
  /**
1182
1329
  * Commit the transaction.
1330
+ *
1331
+ * Returns `RETRY_NOW` when `coordinatedRetry: true` and an IsBusy conflict
1332
+ * was detected. The caller should retry the transaction body immediately.
1183
1333
  */
1184
1334
  async commit() {
1185
1335
  try {
1186
- await new Promise((resolve, reject) => {
1336
+ if (await new Promise((resolve, reject) => {
1187
1337
  this.notify("beforecommit");
1188
1338
  this.#txn.commit(resolve, reject);
1189
- });
1339
+ }) === RETRY_NOW) return RETRY_NOW;
1190
1340
  } catch (err) {
1191
1341
  throw this.#handleCommitError(err);
1192
1342
  } finally {
@@ -1332,6 +1482,26 @@ var RocksDatabase = class RocksDatabase extends DBI {
1332
1482
  return this.store.compact(options);
1333
1483
  }
1334
1484
  /**
1485
+ * Creates a backup of the entire database (all column families) into the
1486
+ * given directory, creating parent directories as needed, and resolves with
1487
+ * the new backup id. Use the `backups` namespace to restore, list, delete,
1488
+ * purge, or verify backups.
1489
+ *
1490
+ * When the database was opened with `disableWAL`, the memtable is flushed
1491
+ * before the backup by default so unflushed data is not lost.
1492
+ *
1493
+ * @example
1494
+ * ```typescript
1495
+ * import { backups } from '@harperfast/rocksdb-js';
1496
+ *
1497
+ * const db = RocksDatabase.open('/path/to/database');
1498
+ * const id = await db.backup('/path/to/backups');
1499
+ * ```
1500
+ */
1501
+ backup(backupDir, options) {
1502
+ return this.store.backup(backupDir, options);
1503
+ }
1504
+ /**
1335
1505
  * Compacts the entire key range of the database synchronously.
1336
1506
  * This triggers manual compaction which removes tombstones and reclaims space.
1337
1507
  *
@@ -1519,17 +1689,8 @@ var RocksDatabase = class RocksDatabase extends DBI {
1519
1689
  getStat(statName) {
1520
1690
  return this.store.db.getStat(statName);
1521
1691
  }
1522
- /**
1523
- * Gets the RocksDB statistics. Requires statistics to be enabled.
1524
- *
1525
- * @example
1526
- * ```typescript
1527
- * const db = RocksDatabase.open('/path/to/database');
1528
- * const stats = db.getStats();
1529
- * ```
1530
- */
1531
1692
  getStats(all = false) {
1532
- return this.store.db.getStats(all);
1693
+ return all ? this.store.db.getStats(true) : this.store.db.getStats(false);
1533
1694
  }
1534
1695
  /**
1535
1696
  * Gets or creates a buffer that can be shared across worker threads.
@@ -1572,6 +1733,30 @@ var RocksDatabase = class RocksDatabase extends DBI {
1572
1733
  }
1573
1734
  async ifNoExists(_key) {}
1574
1735
  /**
1736
+ * Checks the process-global verification table for a fresh version match
1737
+ * on `key`. Returns `true` when the table currently records `version`. Use
1738
+ * this as a fast cache-freshness check before falling back to a full read:
1739
+ *
1740
+ * ```typescript
1741
+ * if (db.verifyVersion(key, cachedEntry.version)) {
1742
+ * return cachedEntry.value;
1743
+ * }
1744
+ * const value = db.getSync(key);
1745
+ * db.populateVersion(key, extractVersion(value));
1746
+ * ```
1747
+ */
1748
+ verifyVersion(key, version) {
1749
+ return this.store.verifyVersion(key, version);
1750
+ }
1751
+ /**
1752
+ * Seeds the verification-table slot for `key` with `version`. Has no
1753
+ * effect if the slot is currently lock-tagged or if the verification
1754
+ * table is disabled.
1755
+ */
1756
+ populateVersion(key, version) {
1757
+ this.store.populateVersion(key, version);
1758
+ }
1759
+ /**
1575
1760
  * Returns whether the database is open.
1576
1761
  *
1577
1762
  * @returns `true` if the database is open, `false` otherwise.
@@ -1711,9 +1896,6 @@ var RocksDatabase = class RocksDatabase extends DBI {
1711
1896
  get path() {
1712
1897
  return this.store.path;
1713
1898
  }
1714
- /**
1715
- * Purges transaction logs.
1716
- */
1717
1899
  purgeLogs(options) {
1718
1900
  return this.store.db.purgeLogs(options);
1719
1901
  }
@@ -1749,13 +1931,19 @@ var RocksDatabase = class RocksDatabase extends DBI {
1749
1931
  } catch (callbackErr) {
1750
1932
  return this.#abortTransaction(txn, callbackErr);
1751
1933
  }
1934
+ let commitResult;
1752
1935
  try {
1753
- await txn.commit();
1754
- return result;
1936
+ commitResult = await txn.commit();
1755
1937
  } catch (commitErr) {
1756
1938
  if (commitErr instanceof TransactionAlreadyAbortedError) return;
1757
- if (commitErr instanceof TransactionIsBusyError && (options?.retryOnBusy ?? commitErr.hasLog) && attempt <= maxRetries) continue;
1939
+ if (commitErr instanceof TransactionIsBusyError && (options?.retryOnBusy ?? commitErr.hasLog) && attempt < maxRetries) continue;
1758
1940
  this.#abandonTransaction(txn, commitErr);
1941
+ return;
1942
+ }
1943
+ if (commitResult !== RETRY_NOW) return result;
1944
+ if (attempt >= maxRetries) {
1945
+ this.#abandonTransaction(txn, /* @__PURE__ */ new Error(`Transaction did not commit after ${maxRetries} coordinated retries`));
1946
+ return;
1759
1947
  }
1760
1948
  }
1761
1949
  }
@@ -2068,7 +2256,7 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
2068
2256
  done: true,
2069
2257
  value: void 0
2070
2258
  };
2071
- const limit = readUncommitted ? logBuffer.length : size;
2259
+ const limit = readUncommitted ? logBuffer.length : Math.min(size, logBuffer.length);
2072
2260
  if (position + TRANSACTION_LOG_ENTRY_HEADER_SIZE > limit) throw new RangeError(`Corrupt transaction log: truncated entry header at position ${position.toString(16)} of log ${logBuffer.logId} (available=${limit - position})`);
2073
2261
  const length = dataView.getUint32(position + 8);
2074
2262
  if (position + TRANSACTION_LOG_ENTRY_HEADER_SIZE + length > limit) throw new RangeError(`Corrupt transaction log entry at position ${position.toString(16)} of log ${logBuffer.logId}: declared length ${length} overruns the log (limit=${limit})`);
@@ -2162,9 +2350,9 @@ function loadLastPosition(transactionLog, readUncommitted) {
2162
2350
  //#region src/index.ts
2163
2351
  const versions = {
2164
2352
  rocksdb: version,
2165
- "rocksdb-js": "2.0.0"
2353
+ "rocksdb-js": "2.2.0"
2166
2354
  };
2167
2355
 
2168
2356
  //#endregion
2169
- export { DBI, DBIterator, RocksDatabase, Store, Transaction, TransactionLog, constants, currentThreadId, parseTransactionLog, registryStatus, shutdown, stats, versions };
2357
+ export { DBI, DBIterator, RocksDatabase, Store, Transaction, TransactionLog, backups, constants, coolTransactionLogs, currentThreadId, parseTransactionLog, registryStatus, shutdown, stats, versions };
2170
2358
  //# sourceMappingURL=index.mjs.map