@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/README.md CHANGED
@@ -74,6 +74,11 @@ Creates a new database instance.
74
74
  before purging. Defaults to `'3d'` (3 days).
75
75
  - `transactionLogsPath: string` The path to store transaction logs. Defaults to
76
76
  `"${db.path}/transaction_logs"`.
77
+ - `verificationTable: boolean` When `true`, this column family participates in the process-global
78
+ [Verification Table](#verification-table): transaction writes to this column family invalidate
79
+ the verification slot for each written key. Enable this only for column families whose records
80
+ are cached (e.g. the primary column family of a table). Defaults to `false`. Requires
81
+ `verificationTableEntries` to be configured before the first database is opened.
77
82
 
78
83
  ### `db.close()`
79
84
 
@@ -106,6 +111,11 @@ Sets global database settings.
106
111
  Defaults to 32MB. Set to `0` (zero) disables block cache for future opened databases. Existing
107
112
  block cache for any opened databases is resized immediately. Negative values throw an error.
108
113
  - `compactOnClose: boolean` When `true`, compacts the database on close. Defaults to `false`.
114
+ - `verificationTableEntries: number` The number of slots in the process-global
115
+ [Verification Table](#verification-table). Each slot is 8 bytes, so the default of `131072`
116
+ (128K) slots is 1 MB. Set to `0` to disable the verification table. This must be configured
117
+ before the first database is opened; once the table is materialized, attempts to change this
118
+ value throw.
109
119
  - `writeBufferManagerAllowStall: boolean` When `true`, writes are stalled once the manager's
110
120
  `buffer_size` is exceeded, providing a hard cap on memtable memory. When `false`, memtables are
111
121
  allowed to grow past the limit and flushes are simply scheduled more aggressively. Off by
@@ -305,9 +315,28 @@ assert.equal(result, 'foo');
305
315
 
306
316
  Note that all errors are returned as rejected promises.
307
317
 
318
+ See [`GetOptions`](#getoptions) for the available options.
319
+
320
+ When the `expectedVersion` option is set and the [Verification Table](#verification-table) records
321
+ a matching version for the key, `get()` returns the `FRESH_VERSION_FLAG` sentinel
322
+ (`constants.FRESH_VERSION_FLAG`) instead of reading the value — signalling that any value the
323
+ caller has already cached for this key is still fresh and no read was performed. Be sure to check
324
+ for this sentinel before treating the result as a value:
325
+
326
+ ```typescript
327
+ import { constants } from '@harperfast/rocksdb-js';
328
+
329
+ const result = db.get(key, { expectedVersion: cachedEntry.version });
330
+ if (result === constants.FRESH_VERSION_FLAG) {
331
+ // the cached value is still valid; no read occurred
332
+ return cachedEntry.value;
333
+ }
334
+ ```
335
+
308
336
  ### `db.getSync(key: Key, options?: GetOptions): any`
309
337
 
310
- Synchronous version of `get()`.
338
+ Synchronous version of `get()`. Like `get()`, this can return the `FRESH_VERSION_FLAG` sentinel when
339
+ the `expectedVersion` option is used.
311
340
 
312
341
  ### `db.getEstimatedKeyCount(): number`
313
342
 
@@ -564,6 +593,12 @@ The `attempt` parameter is the number of times the transaction has been retried.
564
593
 
565
594
  ### `TransactionOptions`
566
595
 
596
+ - `coordinatedRetry?: boolean` When `true`, an `IsBusy` conflict at commit time is retried
597
+ automatically instead of being rejected. Rather than retrying immediately and racing the
598
+ conflicting transaction again, the retry waits until the conflicting transaction has committed and
599
+ released its write intent, then re-runs the transaction body right away with no backoff delay.
600
+ Requires the column family to be opened with `verificationTable: true`. See
601
+ [Verification Table](#verification-table). Defaults to `false`.
567
602
  - `disableSnapshot?: boolean` Whether to disable snapshots. Defaults to `false`.
568
603
  - `maxRetries?: number` The maximum number of times to retry the transaction. Defaults to `3`.
569
604
  - `retryOnBusy?: boolean` Whether to retry the transaction if the commit fails with `IsBusy`.
@@ -582,6 +617,14 @@ transaction is not retried, a `ERR_TRANSACTION_ABANDONED` error will be thrown.
582
617
  Users should use the `attempt` transaction callback parameter to ensure duplicate transaction log
583
618
  entries are not added.
584
619
 
620
+ When `coordinatedRetry: true`, the retry behavior changes for `IsBusy` conflicts: instead of
621
+ rejecting (or retrying immediately and potentially conflicting again), the commit waits until the
622
+ conflicting transaction has committed and released its write intent, then re-runs the transaction
623
+ body immediately with no backoff. This is still bounded by `maxRetries` — if the transaction has
624
+ not committed after the configured number of coordinated retries, the transaction is abandoned with
625
+ an `ERR_TRANSACTION_ABANDONED` error. Coordinated retry requires the column family to be opened with
626
+ `verificationTable: true`.
627
+
585
628
  ### Class: `Transaction`
586
629
 
587
630
  The transaction callback is passed in a `Transaction` instance which contains all of the same data
@@ -804,35 +847,28 @@ same column family-level properties, but includes all internal tickers and histo
804
847
  Column family and ticker stat values are 64-bit unsigned integers and histogram values are
805
848
  `StatsHistogramData` objects.
806
849
 
850
+ The result also always includes a summarized, aggregate set of `txnlog.*` keys covering all of
851
+ the database's transaction logs. These are present regardless of whether statistics are enabled
852
+ and can be fetched individually with `db.getStat('txnlog.…')`. For detailed, per-log statistics —
853
+ including memory-map usage — use [`log.getStats()`](#loggetstats-transactionlogstats). All stat
854
+ names are documented in [docs/stats.md](docs/stats.md).
855
+
807
856
  ```typescript
808
857
  // get essential stats
809
858
  console.log(db.getStats());
810
859
 
811
860
  // get all stats
812
861
  console.log(db.getStats(true));
813
- ```
814
-
815
- ### `stats`
816
-
817
- An object containing stat specific constants including ticker and histogram names.
818
-
819
- #### `stats.histograms`
820
862
 
821
- An array of internal histogram stat names.
822
-
823
- ```typescript
824
- import { stats } from '@harperfast/rocksdb-js';
825
- console.log(stats.histograms);
863
+ // transaction log bytes across all logs
864
+ console.log(db.getStats()['txnlog.totalSizeBytes']);
826
865
  ```
827
866
 
828
- #### `stats.tickers`
867
+ ### `stats`
829
868
 
830
- An array of internal ticker stat names.
831
-
832
- ```typescript
833
- import { stats } from '@harperfast/rocksdb-js';
834
- console.log(stats.tickers);
835
- ```
869
+ An object containing stat-specific constants. The full catalog of available stat names (RocksDB
870
+ tickers, histograms, internal properties, and transaction log stats) is documented in
871
+ [docs/stats.md](docs/stats.md).
836
872
 
837
873
  #### `stats.StatsLevel`
838
874
 
@@ -960,6 +996,74 @@ Note: If the `callback` throws an error, Node.js suppress the error. Node.js 18.
960
996
  `--force-node-api-uncaught-exceptions-policy` flag which will cause errors to emit the
961
997
  `'uncaughtException'` event. Future Node.js releases will enable this flag by default.
962
998
 
999
+ ## Verification Table
1000
+
1001
+ The verification table is a process-global, fixed-size structure that lets an application cheaply
1002
+ check whether a value it has already cached is still fresh, without performing a full read. It is
1003
+ intended for read-heavy workloads where records carry a monotonically increasing numeric version.
1004
+
1005
+ Each record's version is the numeric value stored in the first 8 bytes of its value (interpreted as
1006
+ a big-endian float64). The table maps `(database, column family, key)` to a single 8-byte slot that
1007
+ holds the last-known version for that key. Because slots are addressed by a hash, distinct keys may
1008
+ share a slot; a collision only ever causes a conservative miss (a real read), never a stale value to
1009
+ be treated as fresh.
1010
+
1011
+ The freshness check works as follows:
1012
+
1013
+ 1. Pass `{ expectedVersion }` to `get()` / `getSync()`. If the slot currently records that version,
1014
+ the read is skipped and the `FRESH_VERSION_FLAG` sentinel is returned.
1015
+ 2. On a cold read, pass `{ populateVersion: true }` (or call `db.populateVersion()` afterward) to
1016
+ seed the slot with the version extracted from the value, so subsequent freshness checks hit.
1017
+
1018
+ Transaction writes to a column family opened with `verificationTable: true` invalidate the slot for
1019
+ each written key at write time, so a stale version can never survive a write. This is also what
1020
+ enables [`coordinatedRetry`](#transactionoptions): a conflicting transaction parks on the slot and
1021
+ retries once the write intent is released.
1022
+
1023
+ The table is **process-global** and backed by a single shared structure, so versions populated on
1024
+ the main thread are visible to `worker_threads` workers and vice versa.
1025
+
1026
+ ### Enabling the verification table
1027
+
1028
+ The table must be sized before the first database is opened, via the
1029
+ [`verificationTableEntries`](#dbconfigoptions) config option (default `131072` slots = 1 MB; set to
1030
+ `0` to disable). Then opt-in per column family with the `verificationTable: true` open option:
1031
+
1032
+ ```typescript
1033
+ import { RocksDatabase } from '@harperfast/rocksdb-js';
1034
+
1035
+ RocksDatabase.config({ verificationTableEntries: 128 * 1024 });
1036
+
1037
+ const db = RocksDatabase.open('path/to/db', { verificationTable: true });
1038
+ ```
1039
+
1040
+ Enable `verificationTable` only for column families whose records are cached (e.g. the primary
1041
+ column family of a table); enabling it adds per-write slot invalidation overhead.
1042
+
1043
+ ### `db.verifyVersion(key: Key, version: number): boolean`
1044
+
1045
+ Returns `true` when the verification table currently records `version` for `key` (in this database
1046
+ and column family), indicating a cached value with that version is still fresh. Returns `false`
1047
+ otherwise — including when the table is disabled. This is a cheap, synchronous check that performs
1048
+ no database read.
1049
+
1050
+ ```typescript
1051
+ if (db.verifyVersion(key, cachedEntry.version)) {
1052
+ return cachedEntry.value;
1053
+ }
1054
+ const value = db.getSync(key);
1055
+ db.populateVersion(key, extractVersion(value));
1056
+ ```
1057
+
1058
+ ### `db.populateVersion(key: Key, version: number): void`
1059
+
1060
+ Seeds the verification-table slot for `key` with `version`. This is typically called after a full
1061
+ read where the caller already knows the version. It has no effect if the slot is currently
1062
+ lock-tagged (a transaction is mid-write on that key) or if the verification table is disabled.
1063
+
1064
+ Passing `{ populateVersion: true }` to `get()` / `getSync()` performs the equivalent seeding
1065
+ automatically after a cold read, avoiding a separate call.
1066
+
963
1067
  ## Transaction Log
964
1068
 
965
1069
  A user controlled API for logging transactions. This API is designed to be generic so that you can
@@ -968,6 +1072,46 @@ log gets, puts, and deletes, but also arbitrary entries.
968
1072
  Transaction logs are isolated by the database path allowing different column families in the same
969
1073
  database to share the transaction log store, but not other databases.
970
1074
 
1075
+ ### Memory-Map Handling
1076
+
1077
+ Transaction log files are read through read-only memory maps. Understanding how these maps interact
1078
+ with system memory helps when interpreting [`log.getStats()`](#loggetstats-transactionlogstats)
1079
+ figures and process memory usage:
1080
+
1081
+ - **Maps are created lazily and live until the file is closed.** Writing log entries does not map
1082
+ anything; a log file is mapped the first time a `log.query()` reads from it. The native layer
1083
+ holds each file's map for the life of the file — it is released when the log file is purged or
1084
+ the database is closed, not by garbage collection. JS `Buffer` views over the map (including
1085
+ `entry.data`) hold an additional reference, so the underlying memory is never unmapped while a
1086
+ view is still reachable. `stats.memory.activeMaps` counts the maps currently held by the native
1087
+ layer.
1088
+ - **Mapped bytes are virtual, not resident.** Creating a map reserves address space only. A page
1089
+ consumes physical RAM (RSS) when it is first read (demand paging). Querying a multi-gigabyte log
1090
+ can show `memory.mappedBytes` in the gigabytes while actual memory usage barely moves.
1091
+ - **Queries are zero-copy.** The iterator returned by `log.query()` reads only each entry's small
1092
+ header; `entry.data` is a `Buffer` view directly into the map (no copy). Payload pages are
1093
+ faulted into memory only if and when the entry data is actually read.
1094
+ - **Resident pages are reclaimable.** Because the maps are read-only and file-backed, every
1095
+ resident page is "clean" — the kernel can evict it at any time under memory pressure and re-read
1096
+ it from disk on the next access. Mapped log data therefore lives in the page cache and cannot
1097
+ exhaust memory the way heap allocations can; a full scan of a log larger than RAM will simply
1098
+ cycle pages through the cache.
1099
+
1100
+ OS-specific differences:
1101
+
1102
+ - **POSIX (Linux and macOS):** The active write file is mapped at the full configured
1103
+ `transactionLogMaxSize` (an anonymous reservation with the file's contents overlaid on top), so
1104
+ `memory.mappedBytes` over-reports the active file; `memory.overlayBytes` is the file-backed
1105
+ portion and is the closer proxy for real consumption.
1106
+ - **macOS:** Activity Monitor's "Memory" column reports the physical footprint, which excludes
1107
+ clean file-backed pages — mapped log data is essentially invisible there even when resident. Use
1108
+ process RSS (e.g. `process.memoryUsage().rss`, `ps`, or `vmmap <pid>`) to observe it.
1109
+ - **Linux:** Resident map pages are visible in process RSS, and `/proc/<pid>/smaps` reports exact
1110
+ per-file `Rss`/`Pss` for each mapped `.txnlog` file.
1111
+ - **Windows:** Maps are created with `CreateFileMapping`/`MapViewOfFile` at the file's current
1112
+ size. There is no overlay mechanism, so `memory.overlayBytes` is always `0`, and the active
1113
+ write file's map is not cached because it is not growable.
1114
+
971
1115
  ### `db.listLogs(): string[]`
972
1116
 
973
1117
  Returns an array of log store names.
@@ -978,19 +1122,34 @@ const names = db.listLogs();
978
1122
 
979
1123
  ### `db.purgeLogs(options?): string[]`
980
1124
 
1125
+ ### `db.purgeLogs({ includeEntryCounts: true, ...options }): { path: string; entries: number }[]`
1126
+
981
1127
  Deletes transaction log files older than the `transactionLogRetention` (defaults to 3 days).
982
1128
 
983
1129
  - `options: object`
984
1130
  - `before?: number` Remove all transaction log files older than the specified timestamp.
985
1131
  - `destroy?: boolean` When `true`, deletes transaction log stores including all log sequence files
986
1132
  on disk.
1133
+ - `includeEntryCounts?: boolean` When `true`, counts the entries in each deleted log file and
1134
+ returns an array of `{ path, entries }` objects instead of an array of file paths. Counting reads
1135
+ each file before it is removed, so it is only performed when this option is enabled.
987
1136
  - `name?: string` The name of a store to limit the purging to.
988
1137
 
989
- Returns an array with the full path of each log file deleted.
1138
+ The method is overloaded so the return type follows `includeEntryCounts`: by default (omitted or
1139
+ `false`) it returns `string[]` — the full path of each log file deleted; when `includeEntryCounts` is
1140
+ `true` it returns `{ path: string; entries: number }[]`, each entry being the `path` of the deleted
1141
+ log file and the number of `entries` it held. Because of the overloads, the object-array form is
1142
+ returned directly when `includeEntryCounts: true` is passed as a literal, with no casting required.
990
1143
 
991
1144
  ```typescript
992
1145
  const removed = db.purgeLogs();
993
1146
  console.log(`Removed ${removed.length} log files`);
1147
+
1148
+ // Include the entry count for each deleted log file:
1149
+ const purged = db.purgeLogs({ includeEntryCounts: true });
1150
+ for (const { path, entries } of purged) {
1151
+ console.log(`Removed ${path} (${entries} entries)`);
1152
+ }
994
1153
  ```
995
1154
 
996
1155
  ### `db.useLog(name): TransactionLog`
@@ -1116,6 +1275,34 @@ for (const entry of rangeIter) {
1116
1275
  Returns the size of the given transaction log sequence file in bytes. Omit the sequence number to
1117
1276
  get the total size of all the transaction log sequence files for this log.
1118
1277
 
1278
+ #### `log.getStats(): TransactionLogStats`
1279
+
1280
+ Returns a detailed statistics snapshot for this transaction log, including file/transaction
1281
+ gauges, memory-map usage, recovery positions, purge/retention gauges, and lifetime counters. All
1282
+ sizes are in bytes; timestamps are milliseconds since the Unix epoch.
1283
+
1284
+ ```typescript
1285
+ const log = db.useLog('replication');
1286
+ const stats = log.getStats();
1287
+
1288
+ stats.fileCount; // number of sequence files on disk
1289
+ stats.totalSizeBytes; // total bytes across all sequence files
1290
+ stats.memory.mappedBytes; // bytes mapped into memory (virtual address space)
1291
+ stats.memory.overlayBytes; // POSIX file-backed overlay portion (0 on Windows)
1292
+ stats.replayGapBytes; // bytes between the last flushed position and the write head
1293
+ stats.purge.retainedUnflushedFiles; // files past retention but kept (not yet flushed to RocksDB)
1294
+ stats.totals.transactionsWritten; // lifetime count of transactions written
1295
+ ```
1296
+
1297
+ > **Memory note:** `memory.mappedBytes` is virtual address space — the active write file is mapped
1298
+ > at the full configured `transactionLogMaxSize` on POSIX, so it does not reflect resident memory.
1299
+ > `memory.overlayBytes` (POSIX only) is the file-backed portion and is the closer proxy for real
1300
+ > consumption.
1301
+
1302
+ The `purge.retainedUnflushedFiles` gauge is useful for diagnosing why logs are not being cleaned
1303
+ up: a file can be older than the retention period but still retained because its transactions have
1304
+ not yet been flushed to RocksDB (purging it would be unsafe for crash recovery).
1305
+
1119
1306
  ### Transaction Log Initialization
1120
1307
 
1121
1308
  When a database is opened, `rocksdb-js` will automatically discover the transaction log files. If
@@ -1198,6 +1385,109 @@ import { versions } from '@harperfast/rocksdb-js';
1198
1385
  console.log(versions); // { "rocksdb": "10.10.1", "rocksdb-js": "0.1.2" }
1199
1386
  ```
1200
1387
 
1388
+ ## Backups
1389
+
1390
+ Backups use RocksDB's `BackupEngine` to capture consistent, incremental, checksum-verified
1391
+ snapshots of a database. A backup covers the **entire database** — every column family, the
1392
+ manifest, and (by default) the write-ahead log — so it is not scoped to an individual `Store`.
1393
+
1394
+ Creating a backup is an instance method (`db.backup()`) because it needs a live database. The
1395
+ remaining operations act on a backup directory and do not require an open database, so they are
1396
+ grouped under the `backups` namespace export.
1397
+
1398
+ ```typescript
1399
+ import { RocksDatabase, backups } from '@harperfast/rocksdb-js';
1400
+
1401
+ const db = RocksDatabase.open('/path/to/database');
1402
+ await db.put('foo', 'bar');
1403
+
1404
+ // Create a backup, then restore it into a fresh directory.
1405
+ const id = await db.backup('/path/to/backups');
1406
+ await backups.restore('/path/to/backups', '/path/to/restored-db');
1407
+ ```
1408
+
1409
+ ### `db.backup(backupDir: string, options?: BackupOptions): Promise<number>`
1410
+
1411
+ Creates a new backup of the entire database into `backupDir`, creating parent directories as
1412
+ needed, and resolves with the new backup id (a monotonically increasing integer). Subsequent
1413
+ backups into the same directory are incremental — unchanged immutable files are shared rather than
1414
+ re-copied.
1415
+
1416
+ When the database was opened with `disableWAL`, the memtable is flushed before the backup by
1417
+ default so unflushed data is not lost; otherwise flushing follows `options.flushBeforeBackup`.
1418
+
1419
+ ```typescript
1420
+ const id = await db.backup('/path/to/backups', { metadata: 'nightly-2026-06-04' });
1421
+ ```
1422
+
1423
+ `BackupOptions`:
1424
+
1425
+ | Option | Type | Default | Description |
1426
+ | ------------------------- | --------- | ---------------------- | --------------------------------------------------------------------- |
1427
+ | `flushBeforeBackup` | `boolean` | `true` if WAL disabled | Flush the memtable before backing up. |
1428
+ | `metadata` | `string` | `''` | Application metadata stored with the backup, returned by `list()`. |
1429
+ | `shareTableFiles` | `boolean` | `true` | Share files between backups to enable incremental backups. |
1430
+ | `shareFilesWithChecksum` | `boolean` | `true` | Distinguish shared files by checksum to avoid cross-database clashes. |
1431
+ | `backupLogFiles` | `boolean` | `true` | Include write-ahead log files in the backup. |
1432
+ | `sync` | `boolean` | `true` | `fsync` backup files for crash consistency. |
1433
+ | `maxBackgroundOperations` | `number` | `1` | Number of background threads used to copy files. |
1434
+
1435
+ ### `backups.restore(backupDir: string, dbDir: string, options?: RestoreOptions): Promise<void>`
1436
+
1437
+ Restores a backup from `backupDir` into `dbDir` (creating parent directories as needed). The
1438
+ database must **not** be open at `dbDir`, and the default restore mode is **destructive** — it
1439
+ purges `dbDir` before restoring. Restoring into the backup directory itself is rejected.
1440
+
1441
+ ```typescript
1442
+ // Restore the latest backup.
1443
+ await backups.restore('/path/to/backups', '/path/to/restored-db');
1444
+
1445
+ // Restore a specific backup id without purging matching existing files.
1446
+ await backups.restore('/path/to/backups', '/path/to/restored-db', {
1447
+ backupId: 1,
1448
+ mode: 'keepLatestDbSessionIdFiles',
1449
+ });
1450
+ ```
1451
+
1452
+ `RestoreOptions`:
1453
+
1454
+ | Option | Type | Default | Description |
1455
+ | -------------- | --------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------ |
1456
+ | `backupId` | `number` | latest backup | The backup id to restore. |
1457
+ | `walDir` | `string` | `dbDir` | Directory to restore write-ahead log files into. |
1458
+ | `keepLogFiles` | `boolean` | `false` | Keep existing log files in `walDir` rather than overwriting. |
1459
+ | `mode` | `'purgeAllFiles' \| 'keepLatestDbSessionIdFiles' \| 'verifyChecksum'` | `'purgeAllFiles'` | The restore strategy (default purges the destination). |
1460
+
1461
+ ### `backups.list(backupDir: string): Promise<BackupInfo[]>`
1462
+
1463
+ Lists the non-corrupt backups in `backupDir`, ordered by id.
1464
+
1465
+ ```typescript
1466
+ const list = await backups.list('/path/to/backups');
1467
+ // [{ backupId: 1, timestamp: 1749000000, size: 4096, numberFiles: 3, appMetadata: '' }, ...]
1468
+ ```
1469
+
1470
+ Each `BackupInfo` contains `backupId`, `timestamp` (seconds since the epoch), `size` (bytes),
1471
+ `numberFiles`, and `appMetadata`.
1472
+
1473
+ ### `backups.delete(backupDir: string, backupId: number): Promise<void>`
1474
+
1475
+ Deletes a specific backup. Shared files are reference-counted and only removed once no remaining
1476
+ backup references them, so this is not equivalent to deleting files manually.
1477
+
1478
+ ### `backups.purge(backupDir: string, keepCount: number): Promise<void>`
1479
+
1480
+ Deletes all but the newest `keepCount` backups.
1481
+
1482
+ ### `backups.verify(backupDir: string, backupId: number, options?: { verifyWithChecksum?: boolean }): Promise<void>`
1483
+
1484
+ Verifies a backup's file sizes, and optionally their checksums (which requires reading all
1485
+ backed-up data). Resolves if the backup is intact and rejects otherwise.
1486
+
1487
+ ```typescript
1488
+ await backups.verify('/path/to/backups', 1, { verifyWithChecksum: true });
1489
+ ```
1490
+
1201
1491
  ## Custom Store
1202
1492
 
1203
1493
  The store is a class that sits between the `RocksDatabase` or `Transaction` instance and the native
@@ -1214,7 +1504,7 @@ The default `Store` contains the following methods which can be overridden:
1214
1504
  - `decodeValue(value)`
1215
1505
  - `encodeKey(key)`
1216
1506
  - `encodeValue(value)`
1217
- - `get(context, key, resolve, reject, txnId?)`
1507
+ - `get(context, key, alwaysCreateNewBuffer?, options?)`
1218
1508
  - `getCount(context, options?, txnId?)`
1219
1509
  - `getKeys(context, options?)`
1220
1510
  - `getKeysCount(context, options?)`
@@ -1225,11 +1515,13 @@ The default `Store` contains the following methods which can be overridden:
1225
1515
  - `isOpen()`
1226
1516
  - `listLogs()`
1227
1517
  - `open()`
1518
+ - `populateVersion(key, version)`
1228
1519
  - `putSync(context, key, value, options?)`
1229
1520
  - `removeSync(context, key, options?)`
1230
1521
  - `tryLock(key, onUnlocked?)`
1231
1522
  - `unlock(key)`
1232
1523
  - `useLog(context, name)`
1524
+ - `verifyVersion(key, version)`
1233
1525
  - `withLock(key, callback?)`
1234
1526
 
1235
1527
  To use it, extend the default `Store` and pass in an instance of your store into the `RocksDatabase`
@@ -1239,15 +1531,15 @@ constructor.
1239
1531
  import { RocksDatabase, Store } from '@harperfast/rocksdb-js';
1240
1532
 
1241
1533
  class MyStore extends Store {
1242
- get(context, key, resolve, reject, txnId) {
1243
- console.log('Getting:' key);
1244
- return super.get(context, key, resolve, reject, txnId);
1245
- }
1246
-
1247
- putSync(context, key, value, options) {
1248
- console.log('Putting:', key);
1249
- return super.putSync(context, key, value, options);
1250
- }
1534
+ get(context, key, alwaysCreateNewBuffer, options) {
1535
+ console.log('Getting:', key);
1536
+ return super.get(context, key, alwaysCreateNewBuffer, options);
1537
+ }
1538
+
1539
+ putSync(context, key, value, options) {
1540
+ console.log('Putting:', key);
1541
+ return super.putSync(context, key, value, options);
1542
+ }
1251
1543
  }
1252
1544
 
1253
1545
  const myStore = new MyStore('path/to/db');
@@ -1267,6 +1559,22 @@ console.log(await db.get('foo'));
1267
1559
 
1268
1560
  ## Interfaces
1269
1561
 
1562
+ ### `GetOptions`
1563
+
1564
+ Options for `get()`, `getSync()`, and the `getBinary*` methods.
1565
+
1566
+ - `options: object`
1567
+ - `expectedVersion: number` When set, the [Verification Table](#verification-table) is checked
1568
+ before reading. If the slot holds this version, the read is skipped and the
1569
+ `FRESH_VERSION_FLAG` sentinel is returned. After a database read, the slot is seeded with the
1570
+ version extracted from the value. Requires the column family to be opened with
1571
+ `verificationTable: true`.
1572
+ - `populateVersion: boolean` When `true`, after a database read the verification-table slot is
1573
+ seeded with the version extracted from the value, eliminating the need for a separate
1574
+ `db.populateVersion()` call on cold reads. Defaults to `false`.
1575
+ - `skipDecode: boolean` When `true`, the value is returned without being decoded. Defaults to
1576
+ `false`.
1577
+
1270
1578
  ### `RocksDBOptions`
1271
1579
 
1272
1580
  - `options: object`
@@ -1332,6 +1640,11 @@ Options:
1332
1640
 
1333
1641
  Available commands:
1334
1642
 
1643
+ - `backups <dir> [subcommand]` Manage database backups; with no subcommand or `ls`/`list`, lists the backups in
1644
+ `<dir>`. Subcommands: `backup` (create a backup of the open database), `restore <backup-id>`
1645
+ (restore into the open database after confirmation; unavailable in read-only mode),
1646
+ `verify <backup-id>` (checksum verification), `delete <backup-id>`, and `purge <keep-count>`
1647
+ (delete all but the newest backups). `delete` and `purge` report the recovered disk space.
1335
1648
  - `clear` Clear all data in the current column family
1336
1649
  - `columns` List column families
1337
1650
  - `compact` Compact the current column family