@harperfast/rocksdb-js 2.6.1 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,6 +57,18 @@ Creates a new database instance.
57
57
  - `enableStats: boolean` When `true` and the database is open, RocksDB will captures stats that
58
58
  are retrieved by calling `db.getStats()`. Enabling statistics imposes 5-10% in overhead.
59
59
  Defaults to `false`.
60
+ - `infoLogLevel: number` The verbosity of RocksDB's informational logging (`LOG` /
61
+ `LOG.old.*`): `0` (debug), `1` (info), `2` (warn), `3` (error), `4` (fatal), or `5`
62
+ (header-only). Omit to leave RocksDB's own default (`INFO_LEVEL` in a release build of the
63
+ linked RocksDB library). See [`db.logOptions`](#dblogoptions-maxlogfilesize-number-infologlevel-number).
64
+ - `maxLogFileSize: number` The per-file size cap, in bytes, for informational log files (`LOG` /
65
+ `LOG.old.*`). RocksDB retains up to 5 of these files, so the total informational-log footprint
66
+ is bounded at roughly `5 * maxLogFileSize`. Defaults to 16 MB (an 80 MB bound), which stops
67
+ purely informational logging from growing without bound. A value of `0` is RocksDB's special
68
+ "single unbounded log file" mode — it **disables size-based rotation entirely**, so the log
69
+ can grow without limit; only set `0` if you deliberately want that (it forgoes the bounded
70
+ footprint this option otherwise provides). See
71
+ [`db.logOptions`](#dblogoptions-maxlogfilesize-number-infologlevel-number).
60
72
  - `maxOpenFiles: number` The maximum number of table files RocksDB keeps open. `0` (the default)
61
73
  derives a budget from the effective per-process open-file limit (an eighth of the limit —
62
74
  several databases can share one process — clamped to `[1024, 262144]`); `-1` holds every table
@@ -128,10 +140,24 @@ when a non-default compression level is set. The database must be open. See
128
140
  [Compression](#compression).
129
141
 
130
142
  ```typescript
131
- const db = RocksDatabase.open('path/to/db', { compression: { algorithm: 'zstd', level: 3 } });
143
+ const db = RocksDatabase.open('path/to/db', {
144
+ compression: { algorithm: 'zstd', level: 3 },
145
+ });
132
146
  console.log(db.compression); // { algorithm: 'zstd', level: 3 }
133
147
  ```
134
148
 
149
+ ### `db.logOptions: { maxLogFileSize: number, infoLogLevel: number }`
150
+
151
+ Returns the informational-log settings currently in effect for this database, read live from
152
+ RocksDB. These are database-wide settings (not per-column-family). `maxLogFileSize` is the
153
+ per-file size cap for informational log files (`LOG` / `LOG.old.*`); `infoLogLevel` is the logging
154
+ verbosity. The database must be open.
155
+
156
+ ```typescript
157
+ const db = RocksDatabase.open('path/to/db', { maxLogFileSize: 4 * 1024 * 1024 });
158
+ console.log(db.logOptions); // { maxLogFileSize: 4194304, infoLogLevel: 1 }
159
+ ```
160
+
135
161
  ### `db.config(options)`
136
162
 
137
163
  Sets global database settings.
@@ -260,11 +286,20 @@ per database path can be performed at a time.
260
286
  - `options: object`
261
287
  - `start?: Key` The start key of the range to compact.
262
288
  - `end?: Key` The end key of the range to compact.
289
+ - `bottommost?: boolean` Also compact the bottommost level, rewriting every file in range.
290
+ RocksDB skips that level by default when no compaction filter is installed, and it holds most
291
+ of the data — so an ordinary compaction leaves it untouched. Because a changed
292
+ [`compression`](#compression) algorithm governs only newly written files, this is the way to
293
+ re-encode data that already exists. It rewrites the whole range regardless of whether RocksDB
294
+ considers it worthwhile, so it costs as much as the data is large. Defaults to `false`.
263
295
 
264
296
  ```typescript
265
297
  await db.compact();
266
298
 
267
299
  await db.compact({ start: 'a', end: 'z' });
300
+
301
+ // Re-encode everything already on disk under the column family's current codec
302
+ await db.compact({ bottommost: true });
268
303
  ```
269
304
 
270
305
  ### `db.compactSync(options?): void`
@@ -275,6 +310,8 @@ Synchronous version of `compact()`.
275
310
  db.compactSync();
276
311
 
277
312
  db.compactSync({ start: 'a', end: 'z' });
313
+
314
+ db.compactSync({ bottommost: true });
278
315
  ```
279
316
 
280
317
  ### `db.destroy(): void`
@@ -660,6 +697,9 @@ an `ERR_TRANSACTION_ABANDONED` error. Coordinated retry requires the column fami
660
697
  The transaction callback is passed in a `Transaction` instance which contains all of the same data
661
698
  operations methods as the `RocksDatabase` instance plus:
662
699
 
700
+ - `txn.abandonWrites(): void` Releases the staged writes' verification-table write intents without
701
+ closing the transaction, and bars any further writes or commit. Reads (including read-your-own-writes)
702
+ keep working until the transaction is aborted.
663
703
  - `txn.abort()` Rolls back and closes the transaction. This method is automatically called after the
664
704
  transaction callback returns, so you shouldn't need to call it, but it's ok to do so. Once called,
665
705
  no further transaction operations are permitted. Calling this method multiple times has no effect.
@@ -673,6 +713,22 @@ operations methods as the `RocksDatabase` instance plus:
673
713
  a timestamp, it will set the timestamp to the current time. The value must be in seconds with
674
714
  higher precision in the decimal.
675
715
 
716
+ #### `txn.abandonWrites(): void`
717
+
718
+ Releases the staged writes' verification-table (VT) write intents without closing the transaction,
719
+ and bars any further writes or commit (`commit()`/`commitSync()`/`put()`/`remove()`, including
720
+ database-context writes via `{ transaction: txn }`, all reject once called). Reads — including
721
+ read-your-own-writes — keep working until the transaction is aborted. Idempotent, and a no-op after
722
+ `abort()`.
723
+
724
+ Scope is VT intents only: RocksDB's own transaction locks (pessimistic mode) are still held until
725
+ the transaction is aborted.
726
+
727
+ This is for a transaction kept open only for its outstanding read iterators after its writes were
728
+ already committed elsewhere (e.g. replayed onto another transaction) — it lets the intents release
729
+ early so other writers' coordinated-retry commits stop parking on them, instead of waiting for the
730
+ handle's eventual `abort()`.
731
+
676
732
  #### `txn.abort(): void`
677
733
 
678
734
  Rolls back and closes the transaction. This method is automatically called after the transaction
@@ -960,7 +1016,9 @@ Set the algorithm per column family with the `compression` option when opening a
960
1016
  const db = RocksDatabase.open('/path/to/db', { compression: 'zstd' });
961
1017
 
962
1018
  // Or an object with an explicit level
963
- const db2 = RocksDatabase.open('/path/to/db2', { compression: { algorithm: 'zstd', level: 3 } });
1019
+ const db2 = RocksDatabase.open('/path/to/db2', {
1020
+ compression: { algorithm: 'zstd', level: 3 },
1021
+ });
964
1022
 
965
1023
  // Disable compression entirely
966
1024
  const db3 = RocksDatabase.open('/path/to/db3', { compression: 'none' });
@@ -977,6 +1035,37 @@ was compiled against, so it varies by build. Always check
977
1035
  [`supportedCompression`](#supportedcompression) at runtime — opening with an unavailable algorithm
978
1036
  throws. `'none'` is always available.
979
1037
 
1038
+ **Changing the codec of data already written.** Setting `compression` affects files written from
1039
+ that point on. Existing SST and blob files keep the codec they were written with until something
1040
+ rewrites them. An ordinary `compact()` can re-encode non-bottommost levels, but RocksDB leaves the
1041
+ bottommost level alone unless a compaction filter is installed — and that is where most of the data
1042
+ sits, so a plain compaction will not rewrite all existing data. Use
1043
+ [`compact({ bottommost: true })`](#dbcompactoptions-promisevoid) to force the rewrite, once per
1044
+ column family you want migrated. Note also that omitting `compression` on a column family that
1045
+ already exists **inherits** its current codec rather than applying the default — the default
1046
+ applies only when the family is created.
1047
+
1048
+ **Adopting a codec across a whole database.** Compression is chosen per column family, and RocksDB
1049
+ opens every family of a database in one call — so by default the families you did not name keep
1050
+ their persisted algorithm. If your first open targets some other family (a catalog, say), the rest
1051
+ are already open at their old algorithm before you can ask for a new one, and a family's compression
1052
+ cannot be changed while it is open. Pass `compressionForAllColumnFamilies: true` to apply the
1053
+ requested algorithm to all of them instead:
1054
+
1055
+ ```typescript
1056
+ // Every column family in this database adopts lz4, not just 'catalog'
1057
+ const db = RocksDatabase.open('/path/to/db', {
1058
+ name: 'catalog',
1059
+ compression: 'lz4',
1060
+ compressionForAllColumnFamilies: true,
1061
+ });
1062
+ ```
1063
+
1064
+ It requires an explicit `compression`, and only takes effect on the open that creates the database
1065
+ handle — later opens of the same path reuse that handle. As always the algorithm governs newly
1066
+ written files; use [`compact({ bottommost: true })`](#dbcompactoptions-promisevoid) to rewrite what
1067
+ is already there.
1068
+
980
1069
  **Scope and mutability.** Compression is genuinely **per-column-family**. Each `RocksDatabase`
981
1070
  targets one column family (`name`), and its `compression` applies only to that CF — opening one CF
982
1071
  never changes another's algorithm, regardless of open order. A column family keeps its own
@@ -1661,7 +1750,9 @@ live database directory would write backup files on top of RocksDB's own files.
1661
1750
  before anything is written.
1662
1751
 
1663
1752
  ```typescript
1664
- const id = await db.backup('/path/to/backups', { metadata: 'nightly-2026-06-04' });
1753
+ const id = await db.backup('/path/to/backups', {
1754
+ metadata: 'nightly-2026-06-04',
1755
+ });
1665
1756
  ```
1666
1757
 
1667
1758
  `BackupOptions`:
@@ -1711,7 +1802,9 @@ await db.backup(Writable.toWeb(createWriteStream('/path/to/backup.tar')));
1711
1802
  // Restore: `tar -xf backup.tar -C /restored`, then open '/restored'.
1712
1803
 
1713
1804
  // Or gzip it (`tar -xzf backup.tar.gz` to restore):
1714
- await db.backup(Writable.toWeb(createWriteStream('/path/to/backup.tar.gz')), { gzip: true });
1805
+ await db.backup(Writable.toWeb(createWriteStream('/path/to/backup.tar.gz')), {
1806
+ gzip: true,
1807
+ });
1715
1808
  ```
1716
1809
 
1717
1810
  `BackupStreamOptions`:
package/dist/index.cjs CHANGED
@@ -1305,6 +1305,11 @@ var Store = class {
1305
1305
  */
1306
1306
  compression;
1307
1307
  /**
1308
+ * Whether `compression` applies to every column family in the database rather than just this
1309
+ * store's. See `RocksDatabaseOptions.compressionForAllColumnFamilies`.
1310
+ */
1311
+ compressionForAllColumnFamilies = false;
1312
+ /**
1308
1313
  * Whether to disable the write ahead log.
1309
1314
  */
1310
1315
  disableWAL;
@@ -1331,6 +1336,11 @@ var Store = class {
1331
1336
  */
1332
1337
  freezeData;
1333
1338
  /**
1339
+ * Verbosity of RocksDB's informational logging (`info_log_level`). Omit to
1340
+ * leave RocksDB's own default.
1341
+ */
1342
+ infoLogLevel;
1343
+ /**
1334
1344
  * Reusable buffer for encoding keys.
1335
1345
  */
1336
1346
  keyBuffer;
@@ -1343,6 +1353,16 @@ var Store = class {
1343
1353
  */
1344
1354
  maxKeySize;
1345
1355
  /**
1356
+ * Per-file size cap (bytes) for informational log files (`LOG` /
1357
+ * `LOG.old.*`). Bounds total informational-log footprint to roughly `5 *
1358
+ * maxLogFileSize` (RocksDB retains up to 5 of these files). A value of `0`
1359
+ * is RocksDB's "single unbounded log file" mode: it disables size-based
1360
+ * rotation, so the log can grow without limit — set it only if you want that.
1361
+ *
1362
+ * @default 16777216 (16MB)
1363
+ */
1364
+ maxLogFileSize;
1365
+ /**
1346
1366
  * The maximum number of table files RocksDB keeps open. `0` (the default)
1347
1367
  * derives a budget from the effective per-process open-file limit (an
1348
1368
  * eighth of the limit — several databases can share one process — clamped
@@ -1361,13 +1381,26 @@ var Store = class {
1361
1381
  /**
1362
1382
  * The bytes of recent memtable history to retain in memory for transaction
1363
1383
  * conflict checking. `-1` derives the value from
1364
- * `maxWriteBufferNumber * writeBufferSize`.
1384
+ * `maxWriteBufferNumber * writeBufferSize`, except under a stalling
1385
+ * `writeBufferManager`, where it derives `0`: retained history is charged to
1386
+ * that manager and is only trimmable down to this target, so a target the
1387
+ * budget cannot hold stalls writes permanently. Set a number to size it
1388
+ * yourself against the budget and the column-family count.
1365
1389
  */
1366
1390
  maxWriteBufferSizeToMaintain;
1367
1391
  /**
1368
1392
  * The total memtable budget in bytes across all column families. When the
1369
- * sum of memtables reaches this size, RocksDB flushes the largest one. `0`
1370
- * disables the global trigger so per-CF `writeBufferSize` drives flushing.
1393
+ * sum of memtables reaches this size, RocksDB flushes the largest one.
1394
+ * Defaults to `0`, which disables the global trigger so per-CF
1395
+ * `writeBufferSize` drives flushing.
1396
+ *
1397
+ * Set this only if you know your column-family count: it is one budget split
1398
+ * across all of them, so a value that suits a few families starves many. To
1399
+ * bound total memtable memory instead, configure a WriteBufferManager.
1400
+ *
1401
+ * Database-wide, so it binds when the path is first opened in this process:
1402
+ * a later open of the same path — including from another worker thread —
1403
+ * keeps the first opener's value rather than overriding or rejecting it.
1371
1404
  */
1372
1405
  dbWriteBufferSize;
1373
1406
  /**
@@ -1463,6 +1496,7 @@ var Store = class {
1463
1496
  const { keyEncoding, readKey, writeKey } = initKeyEncoder(options?.keyEncoding, options?.keyEncoder);
1464
1497
  this.db = new NativeDatabase();
1465
1498
  this.compression = options?.compression;
1499
+ this.compressionForAllColumnFamilies = options?.compressionForAllColumnFamilies === true;
1466
1500
  this.dbWriteBufferSize = options?.dbWriteBufferSize;
1467
1501
  this.decoder = options?.decoder ?? null;
1468
1502
  this.disableWAL = options?.disableWAL ?? false;
@@ -1471,9 +1505,11 @@ var Store = class {
1471
1505
  this.encoder = options?.encoder ?? null;
1472
1506
  this.encoding = options?.encoding ?? null;
1473
1507
  this.freezeData = options?.freezeData ?? false;
1508
+ this.infoLogLevel = options?.infoLogLevel;
1474
1509
  this.keyBuffer = KEY_BUFFER;
1475
1510
  this.keyEncoding = keyEncoding;
1476
1511
  this.maxKeySize = options?.maxKeySize ?? MAX_KEY_SIZE;
1512
+ this.maxLogFileSize = options?.maxLogFileSize;
1477
1513
  this.maxOpenFiles = options?.maxOpenFiles;
1478
1514
  this.maxWriteBufferNumber = options?.maxWriteBufferNumber;
1479
1515
  this.maxWriteBufferSizeToMaintain = options?.maxWriteBufferSizeToMaintain;
@@ -1532,7 +1568,7 @@ var Store = class {
1532
1568
  const end = this.encodeKey(options.end);
1533
1569
  endBuffer = Buffer.from(end.subarray(end.start, end.end));
1534
1570
  }
1535
- return new Promise((resolve, reject) => this.db.compact(resolve, reject, startBuffer, endBuffer));
1571
+ return new Promise((resolve, reject) => this.db.compact(resolve, reject, startBuffer, endBuffer, options?.bottommost === true));
1536
1572
  }
1537
1573
  async backup(target, options) {
1538
1574
  if (typeof target !== "string" && typeof target?.getWriter === "function") return backupToStream(this.db, target, options);
@@ -1560,7 +1596,7 @@ var Store = class {
1560
1596
  const end = this.encodeKey(options.end);
1561
1597
  endBuffer = Buffer.from(end.subarray(end.start, end.end));
1562
1598
  }
1563
- this.db.compactSync(startBuffer, endBuffer);
1599
+ this.db.compactSync(startBuffer, endBuffer, options?.bottommost === true);
1564
1600
  }
1565
1601
  /**
1566
1602
  * Decodes a key from the database.
@@ -1777,9 +1813,12 @@ var Store = class {
1777
1813
  this.db.open(this.path, {
1778
1814
  compression,
1779
1815
  compressionLevel,
1816
+ compressionForAllColumnFamilies: this.compressionForAllColumnFamilies,
1780
1817
  dbWriteBufferSize: this.dbWriteBufferSize,
1781
1818
  disableWAL: this.disableWAL,
1782
1819
  enableStats: this.enableStats,
1820
+ infoLogLevel: this.infoLogLevel,
1821
+ maxLogFileSize: this.maxLogFileSize,
1783
1822
  maxOpenFiles: this.maxOpenFiles,
1784
1823
  maxWriteBufferNumber: this.maxWriteBufferNumber,
1785
1824
  maxWriteBufferSizeToMaintain: this.maxWriteBufferSizeToMaintain,
@@ -1959,7 +1998,7 @@ var Transaction = class extends DBI {
1959
1998
  if (store.readOnly) {
1960
1999
  super(store);
1961
2000
  this.#txn = { id: 0 };
1962
- this.abort = this.commitSync = this.setTimestamp = () => {};
2001
+ this.abandonWrites = this.abort = this.commitSync = this.setTimestamp = () => {};
1963
2002
  this.commit = async () => {};
1964
2003
  this.getTimestamp = () => 0;
1965
2004
  } else {
@@ -1969,6 +2008,17 @@ var Transaction = class extends DBI {
1969
2008
  }
1970
2009
  }
1971
2010
  /**
2011
+ * Release the staged writes' verification-table write intents without
2012
+ * closing the transaction, barring any later commit or write. For a
2013
+ * transaction kept open only for its outstanding read iterators after the
2014
+ * writes were replayed onto another transaction: otherwise other writers'
2015
+ * coordinated-retry commits park on those intents until it is aborted.
2016
+ * Reads keep working, including read-your-own-writes.
2017
+ */
2018
+ abandonWrites() {
2019
+ this.#txn.abandonWrites();
2020
+ }
2021
+ /**
1972
2022
  * Abort the transaction.
1973
2023
  */
1974
2024
  abort() {
@@ -2213,6 +2263,24 @@ var RocksDatabase = class RocksDatabase extends DBI {
2213
2263
  return this.store.db.getCompression();
2214
2264
  }
2215
2265
  /**
2266
+ * The informational-log settings currently in effect for this database,
2267
+ * read live from RocksDB, as `{ maxLogFileSize, infoLogLevel }`. These are
2268
+ * database-wide settings (not per-column-family): `maxLogFileSize` bounds
2269
+ * each retained `LOG` / `LOG.old.*` file's size (defaults to 16MB, so with
2270
+ * RocksDB's `keep_log_file_num = 5` the total footprint is bounded at
2271
+ * roughly 80MB); `infoLogLevel` is the logging verbosity. The database must
2272
+ * be open.
2273
+ *
2274
+ * @example
2275
+ * ```typescript
2276
+ * const db = RocksDatabase.open('/path/to/db', { maxLogFileSize: 4 * 1024 * 1024 });
2277
+ * db.logOptions; // { maxLogFileSize: 4194304, infoLogLevel: 1 }
2278
+ * ```
2279
+ */
2280
+ get logOptions() {
2281
+ return this.store.db.getLogOptions();
2282
+ }
2283
+ /**
2216
2284
  * Set global database settings.
2217
2285
  *
2218
2286
  * @param options - The options for the database.
@@ -3042,7 +3110,7 @@ function loadLastPosition(transactionLog, readUncommitted) {
3042
3110
  //#region src/index.ts
3043
3111
  const versions = {
3044
3112
  rocksdb: version,
3045
- "rocksdb-js": "2.6.1"
3113
+ "rocksdb-js": "2.7.1"
3046
3114
  };
3047
3115
 
3048
3116
  //#endregion