@harperfast/rocksdb-js 2.11.0 → 2.13.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 +158 -27
- package/dist/index.cjs +322 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +178 -39
- package/dist/index.d.mts +178 -39
- package/dist/index.mjs +320 -67
- package/dist/index.mjs.map +1 -1
- package/docs/backups.md +27 -0
- package/docs/performance/mutex-contention.md +4 -3
- package/docs/stats.md +11 -4
- package/docs/steady-clock-design.md +1 -1
- package/docs/transaction-log.md +27 -7
- package/package.json +19 -18
package/README.md
CHANGED
|
@@ -46,6 +46,19 @@ Creates a new database instance.
|
|
|
46
46
|
- `path: string` The path to write the database files to. This path does not need to exist, but the
|
|
47
47
|
parent directories do.
|
|
48
48
|
- `options: object` [optional]
|
|
49
|
+
- `arenaBlockSize: number` The size in bytes of the blocks a column family's memtable allocates
|
|
50
|
+
from. Every column family that has been written to holds at least one block, and with a
|
|
51
|
+
`writeBufferManagerSize` set, those blocks count against that shared budget even when the
|
|
52
|
+
column family is idle — so with many column families, large blocks can use up most of a small
|
|
53
|
+
budget and cause constant tiny flushes. Defaults to `0`, which picks a size automatically: with
|
|
54
|
+
a write buffer manager, `writeBufferManagerSize / 2048`, but at least 64 KiB and at most
|
|
55
|
+
`writeBufferSize / 8` or 1 MiB, whichever is smaller (a 64 MiB budget gives 64 KiB, 512 MiB
|
|
56
|
+
gives 256 KiB, 2 GiB or more gives 1 MiB); without one, RocksDB's own default of
|
|
57
|
+
`writeBufferSize / 8` capped at 1 MiB (1 MiB at the default `writeBufferSize`). The automatic
|
|
58
|
+
size uses the manager's budget at the time the column family is opened. An explicit value is
|
|
59
|
+
used as given, except that RocksDB raises one below 4 KiB to 4 KiB. Like `writeBufferSize`,
|
|
60
|
+
this applies to every column family when a database is first opened in the process and to
|
|
61
|
+
column families created later; a column family that is already open keeps its size.
|
|
49
62
|
- `compression: string | { algorithm: string, level?: number }` The block/blob compression
|
|
50
63
|
algorithm for this column family. Pass an algorithm name — one of `'none'`, `'snappy'`,
|
|
51
64
|
`'zlib'`, `'bzip2'`, `'lz4'`, `'lz4hc'`, or `'zstd'` — or an object with an
|
|
@@ -119,9 +132,10 @@ Creates a new database instance.
|
|
|
119
132
|
- `readOnly: boolean` When `true`, the database is opened in read-only mode. Read operations are
|
|
120
133
|
permitted. Write operations will throw an error with code `ERR_DATABASE_READONLY`. Transactions
|
|
121
134
|
are a no-op in read-only mode. [`flush()`](#dbflushoptions-promisevoid),
|
|
122
|
-
[`flushSync()`](#dbflushsyncoptions-void), [`compact()`](#dbcompactoptions-promisevoid)
|
|
123
|
-
[`compactSync()`](#dbcompactsyncoptions-void) are the
|
|
124
|
-
there are no writes, so they succeed as no-ops rather
|
|
135
|
+
[`flushSync()`](#dbflushsyncoptions-void), [`compact()`](#dbcompactoptions-promisevoid),
|
|
136
|
+
[`compactSync()`](#dbcompactsyncoptions-void) and [`syncWal()`](#dbsyncwal-promisevoid) are the
|
|
137
|
+
exception: they have nothing to do when there are no writes, so they succeed as no-ops rather
|
|
138
|
+
than throwing.
|
|
125
139
|
|
|
126
140
|
A read-only open is a **point-in-time snapshot**: it never sees later writes. It is safe
|
|
127
141
|
against a quiescent database, but **unsafe against a live writer**: the open holds no reference
|
|
@@ -276,6 +290,17 @@ Sets global database settings.
|
|
|
276
290
|
callers could already produce it. With `1`, a database's async commits run one at a time in
|
|
277
291
|
the order `commit()` was called. Databases already open keep their limit.
|
|
278
292
|
- `compactOnClose: boolean` When `true`, compacts the database on close. Defaults to `false`.
|
|
293
|
+
- `transactionLogAbortMarkers: boolean` When `true`, a transaction that wrote its
|
|
294
|
+
transaction-log batch and then ends without committing (an `abort()`, a commit error it gives
|
|
295
|
+
up on, or a worker torn down with it pending) gets that batch marked aborted in place, and every
|
|
296
|
+
reader skips it; see [Abort markers](#abort-markers). Defaults to `false`, which behaves as
|
|
297
|
+
before. Read when a transaction starts and when it is reset for a retry.
|
|
298
|
+
- `transactionLogWriteIntents: boolean` When `true` with `transactionLogAbortMarkers` on, a
|
|
299
|
+
conflicting attempt is refused before it writes its batch when an older transaction holds a
|
|
300
|
+
write intent on one of its keys; see [Abort markers](#abort-markers). This shortens the worst
|
|
301
|
+
waits of transactions that overlap heavily, but adds retries and costs throughput when
|
|
302
|
+
transactions are large or contention is low. Defaults to `false`. Needs `verificationTable`.
|
|
303
|
+
Read with `transactionLogAbortMarkers`.
|
|
279
304
|
- `occValidation: 'parallel' | 'serial'` How writable optimistic databases opened after the call
|
|
280
305
|
validate commits for conflicts. Defaults to `'parallel'` (RocksDB's default). Databases already
|
|
281
306
|
open keep their policy. Pessimistic, read-only and secondary opens are unaffected.
|
|
@@ -328,6 +353,19 @@ Sets global database settings.
|
|
|
328
353
|
[`db.isWriteStalled()`](#dbiswritestalled-boolean) — see
|
|
329
354
|
[`getWriteBufferManagerStats()`](#getwritebuffermanagerstats-writebuffermanagerstats),
|
|
330
355
|
which also describes the watchdog that logs a sustained stall.
|
|
356
|
+
- `writeBufferManagerFlushPolicy: 'oldest' | 'largest' | 'largestAcrossDBs'` What the write
|
|
357
|
+
buffer manager flushes when it is over budget. `'oldest'` flushes the oldest memtable of the
|
|
358
|
+
database that is being written; `'largest'` its largest memtable (databases here are opened with
|
|
359
|
+
atomic flush, so this currently behaves like `'oldest'`); `'largestAcrossDBs'` has a background
|
|
360
|
+
thread flush whichever database holds the most memtable memory, whether or not it is being
|
|
361
|
+
written. When not set, the policy is `'largestAcrossDBs'` while
|
|
362
|
+
`writeBufferManagerAllowStall` is `true` and `'oldest'` otherwise, and it follows later changes
|
|
363
|
+
to `writeBufferManagerAllowStall`. With stalls allowed, `'oldest'` can stop writes permanently:
|
|
364
|
+
a write to one database waits for memory held by other databases that nothing is writing to,
|
|
365
|
+
so nothing flushes them. Without stalls, `'largestAcrossDBs'` has measured slower. Can be
|
|
366
|
+
changed while databases are open. Once set, the value stays in effect for the life of the
|
|
367
|
+
process; it is reported as `flushPolicy` by
|
|
368
|
+
[`getWriteBufferManagerStats()`](#getwritebuffermanagerstats-writebuffermanagerstats).
|
|
331
369
|
- `writeBufferManagerCostToCache: boolean` When `true`, memtable memory is "charged" against the
|
|
332
370
|
shared block cache so the block cache and write buffers draw from a single pool. During write
|
|
333
371
|
bursts the cache shrinks to make room for memtables; once memtables flush, the cache can grow
|
|
@@ -370,6 +408,8 @@ where the call was made.
|
|
|
370
408
|
- `mutableMemoryUsage: number` The share of `memoryUsage` held by active (mutable) memtables; the
|
|
371
409
|
rest is memtables awaiting flush plus retained write history.
|
|
372
410
|
- `allowStall: boolean`, `costToCache: boolean` The manager's configuration.
|
|
411
|
+
- `flushPolicy: 'oldest' | 'largest' | 'largestAcrossDBs'` The flush policy in effect (see
|
|
412
|
+
`writeBufferManagerFlushPolicy`); before a manager exists, the policy one would be created with.
|
|
373
413
|
- `stallActive: boolean` Whether the manager is currently stalling writes.
|
|
374
414
|
- `stallActiveMs: number` How long the current stall has been active; `0` when not stalled.
|
|
375
415
|
Sampled once a second by the watchdog, so `0` for a stall's first second and whenever
|
|
@@ -388,7 +428,7 @@ where the call was made.
|
|
|
388
428
|
|
|
389
429
|
`bufferSize`, `memoryUsage`, `mutableMemoryUsage`, `stallActive` and `stallActiveMs` are also in
|
|
390
430
|
[`db.getStats()`](#dbgetstatsall-boolean-rocksdbstats) and `db.getStat()` under the same
|
|
391
|
-
`writeBufferManager.` prefix, for scraping; `enabled`, `allowStall`, `costToCache`,
|
|
431
|
+
`writeBufferManager.` prefix, for scraping; `enabled`, `allowStall`, `costToCache`, `flushPolicy`,
|
|
392
432
|
`watchdogRunning`, and the column-family inventory are only here, because collecting them either
|
|
393
433
|
walks the database registry or isn't scrape-shaped.
|
|
394
434
|
|
|
@@ -806,6 +846,22 @@ db.flushSync({ allowWriteStall: true });
|
|
|
806
846
|
On a [read-only](#new-rocksdatabasepath-options) database it validates its options and then returns
|
|
807
847
|
without flushing, rather than throwing.
|
|
808
848
|
|
|
849
|
+
### `db.syncWal(): Promise<void>`
|
|
850
|
+
|
|
851
|
+
Syncs the write-ahead log to stable storage (`DB::SyncWAL`), so every WAL-backed write committed
|
|
852
|
+
before the call survives a power loss afterwards. Unlike [`flush()`](#dbflushoptions-promisevoid) it
|
|
853
|
+
writes no SST file and never stalls writers. Writes that skipped the WAL (`disableWAL`) and
|
|
854
|
+
transaction-log files, which keep their own durability, are not covered. RocksDB serializes
|
|
855
|
+
concurrent syncs of one WAL, so keep one in flight per database rather than queueing them on the
|
|
856
|
+
libuv threadpool.
|
|
857
|
+
|
|
858
|
+
```typescript
|
|
859
|
+
await db.syncWal();
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
On a [read-only](#new-rocksdatabasepath-options) database the returned promise resolves without
|
|
863
|
+
syncing.
|
|
864
|
+
|
|
809
865
|
### `db.get(key: Key, options?: GetOptions): MaybePromise<any>`
|
|
810
866
|
|
|
811
867
|
Retreives the value for a given key. If the key does not exist, it will resolve `undefined`.
|
|
@@ -1250,7 +1306,9 @@ The `attempt` parameter is the number of times the transaction has been retried.
|
|
|
1250
1306
|
- `disableSnapshot?: boolean` Whether to disable snapshots. Defaults to `false`.
|
|
1251
1307
|
- `maxRetries?: number` The maximum number of times to retry the transaction. Defaults to `3`.
|
|
1252
1308
|
- `retryOnBusy?: boolean` Whether to retry the transaction if the commit fails with `IsBusy`.
|
|
1253
|
-
Defaults to `true` when the transaction
|
|
1309
|
+
Defaults to `true` when the transaction wrote a transaction-log batch or was refused before
|
|
1310
|
+
writing one (`refusedBeforeLog`), otherwise `false`. With `false`, `db.transaction()` also
|
|
1311
|
+
commits without `coordinatedRetry`, so a conflict fails at once instead of waiting first.
|
|
1254
1312
|
|
|
1255
1313
|
### Transaction Retry Logic
|
|
1256
1314
|
|
|
@@ -1263,7 +1321,45 @@ a bad state and the transaction will need to be retried. If the max retries is r
|
|
|
1263
1321
|
transaction is not retried, a `ERR_TRANSACTION_ABANDONED` error will be thrown.
|
|
1264
1322
|
|
|
1265
1323
|
Users should use the `attempt` transaction callback parameter to ensure duplicate transaction log
|
|
1266
|
-
entries are not added.
|
|
1324
|
+
entries are not added. `txn.logWritten()` reports whether the batch is already in the log: a commit
|
|
1325
|
+
that conflicts after writing it keeps it for the retry, while an attempt refused before writing it
|
|
1326
|
+
(`err.refusedBeforeLog`, with `transactionLogAbortMarkers`) leaves nothing and must stage it again.
|
|
1327
|
+
|
|
1328
|
+
### Abort markers
|
|
1329
|
+
|
|
1330
|
+
With `RocksDatabase.config({ transactionLogAbortMarkers: true })`, a transaction's log batch is
|
|
1331
|
+
never left live when the transaction does not commit:
|
|
1332
|
+
|
|
1333
|
+
- A transaction that wrote its batch and then ends without committing has the batch marked aborted:
|
|
1334
|
+
bit `0x02` (`TRANSACTION_LOG_ENTRY_ABORTED_FLAG`) is set on its first entry, and the change is
|
|
1335
|
+
synced to disk before `abort()` returns or the batch stops holding back committed readers. Every
|
|
1336
|
+
reader skips the batch. `abort()` then no longer throws `ERR_TRANSACTION_ABANDONED`.
|
|
1337
|
+
- If the marker cannot be written or synced, `abort()` throws `ERR_TRANSACTION_ABORT_UNRESOLVED`
|
|
1338
|
+
(again on a second call), committed readers stay behind the batch, and the log refuses new batches
|
|
1339
|
+
until a retry on the next batch, database flush or close marks it.
|
|
1340
|
+
- Under `occValidation: 'parallel'` (the default), a retried optimistic commit that RocksDB's own
|
|
1341
|
+
conflict check shows would fail is refused before it writes its batch too, with
|
|
1342
|
+
`refusedBeforeLog` set (needs the RocksDB build this package pins). A first attempt skips the
|
|
1343
|
+
check, so commits that do not conflict pay nothing for it, and so does a retry whose batch an
|
|
1344
|
+
earlier attempt already wrote.
|
|
1345
|
+
- With `transactionLogWriteIntents: true` as well, a commit that finds an older transaction holding
|
|
1346
|
+
a write intent on one of its keys (with `verificationTable: true`) is refused before writing its
|
|
1347
|
+
batch, with `refusedBeforeLog` set on the
|
|
1348
|
+
error, or, if its batch is already written from an earlier attempt, before committing. With
|
|
1349
|
+
`coordinatedRetry` it waits for that transaction first. `commitSync()` never waits: it throws, and
|
|
1350
|
+
`transactionSync()` retries after a short backoff.
|
|
1351
|
+
- `txn.setParkDeadline(epochMs)` bounds those waits by the caller's own deadline.
|
|
1352
|
+
- `log.getStats().totals` reports `abortsMarked`, `abortMarkFailures`, and `watermarkPinnedUs` /
|
|
1353
|
+
`pinnedTransactions`: how long logged batches held committed readers back after their first
|
|
1354
|
+
conflict, until they committed or ended.
|
|
1355
|
+
- A backup waits for every batch it captures that has neither committed nor been aborted, and is
|
|
1356
|
+
refused if one is still unresolved after `ROCKSDB_JS_BACKUP_UNRESOLVED_WAIT_MS` (default
|
|
1357
|
+
`30000`).
|
|
1358
|
+
|
|
1359
|
+
A reader older than the release that added aborted-batch support shows an aborted batch as live, so
|
|
1360
|
+
turn this on only once every reader of the logs (replicas, restores, repair tools) has it. A batch
|
|
1361
|
+
whose transaction was still unresolved when the process crashed is not marked, and is replayed as
|
|
1362
|
+
before.
|
|
1267
1363
|
|
|
1268
1364
|
When `coordinatedRetry: true`, the retry behavior changes for `IsBusy` conflicts: instead of
|
|
1269
1365
|
rejecting (or retrying immediately and potentially conflicting again), the commit waits until the
|
|
@@ -1297,6 +1393,12 @@ operations methods as the `RocksDatabase` instance plus:
|
|
|
1297
1393
|
- `txn.commitSync()` Synchronously commits and closes the transaction.
|
|
1298
1394
|
- `txn.getTimestamp(): number` Retrieves the transaction timestamp in milliseconds as a decimal. It
|
|
1299
1395
|
defaults to a process-wide monotonic value assigned when the transaction was created.
|
|
1396
|
+
- `txn.lastConflictKind(): number` Why the most recent attempt was refused or retried, one of
|
|
1397
|
+
`ConflictKind`: `none` (0), `intentBeforeLog` (1), `intentAfterLog` (2), `atCommit` (3),
|
|
1398
|
+
`checkBeforeLog` (4).
|
|
1399
|
+
- `txn.logWritten(): boolean` Whether the transaction's batch is in the transaction log.
|
|
1400
|
+
- `txn.setParkDeadline(epochMs: number): void` Past this time a coordinated-retry wait resolves at
|
|
1401
|
+
once. `0` clears it.
|
|
1300
1402
|
- `txn.id: number` The read-only transaction ID. Transaction IDs are unique to the RocksDB database
|
|
1301
1403
|
path, regardless the database name/column family.
|
|
1302
1404
|
- `txn.setTimestamp(ts?: number): void` Overrides the transaction timestamp in milliseconds. If
|
|
@@ -1937,6 +2039,10 @@ Attempts to acquire a lock for a given key. If the lock is available, the functi
|
|
|
1937
2039
|
and the optional `onUnlocked` callback is never called. If the lock is not available, the function
|
|
1938
2040
|
returns `false` and the `onUnlocked` callback is queued until the lock is released.
|
|
1939
2041
|
|
|
2042
|
+
A queued `onUnlocked` callback keeps the thread's event loop alive until it is called, even when the
|
|
2043
|
+
lock is held by another thread. A thread with a callback queued on a lock that is never released
|
|
2044
|
+
will not exit on its own; closing the database that queued the callback does not cancel it.
|
|
2045
|
+
|
|
1940
2046
|
When a database is closed, all locks associated to it will be unlocked.
|
|
1941
2047
|
|
|
1942
2048
|
```typescript
|
|
@@ -1977,7 +2083,9 @@ db.unlock('foo'); // false, already unlocked
|
|
|
1977
2083
|
|
|
1978
2084
|
### `db.withLock(key: Key, callback: () => void | Promise<void>): Promise<void>`
|
|
1979
2085
|
|
|
1980
|
-
Runs a function with guaranteed exclusive access across all threads.
|
|
2086
|
+
Runs a function with guaranteed exclusive access across all threads. The returned promise rejects
|
|
2087
|
+
with the error if the callback throws or its promise rejects; the lock is released either way. A
|
|
2088
|
+
pending `withLock()` keeps the thread's event loop alive until its callback has run.
|
|
1981
2089
|
|
|
1982
2090
|
```typescript
|
|
1983
2091
|
await db.withLock('key', async () => {
|
|
@@ -2005,9 +2113,7 @@ await Promise.all([
|
|
|
2005
2113
|
]);
|
|
2006
2114
|
```
|
|
2007
2115
|
|
|
2008
|
-
Note:
|
|
2009
|
-
`--force-node-api-uncaught-exceptions-policy` flag which will cause errors to emit the
|
|
2010
|
-
`'uncaughtException'` event. Future Node.js releases will enable this flag by default.
|
|
2116
|
+
Note: Errors thrown by a `tryLock()` `onUnlocked` callback are discarded.
|
|
2011
2117
|
|
|
2012
2118
|
## File Locking
|
|
2013
2119
|
|
|
@@ -2199,20 +2305,21 @@ const names = db.listLogs();
|
|
|
2199
2305
|
|
|
2200
2306
|
### `db.purgeLogs({ includeEntryCounts: true, ...options }): { path: string; entries: number }[]`
|
|
2201
2307
|
|
|
2202
|
-
Deletes transaction log files older than the `transactionLogRetention` (defaults to 3 days).
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
`
|
|
2211
|
-
|
|
2308
|
+
Deletes transaction log files older than the `transactionLogRetention` (defaults to 3 days). A file
|
|
2309
|
+
is deleted only when it lies entirely at or before the flushed position recorded in `txn.state`, so
|
|
2310
|
+
every entry in it is already in RocksDB; that includes the file `txn.state` names and the file
|
|
2311
|
+
currently being written, so an idle, fully flushed store is left with no log files. Retention removes
|
|
2312
|
+
a contiguous prefix: the first file that is too new or holds an unflushed entry stops the run. When
|
|
2313
|
+
the flush position lags — `txn.state` stuck at an old sequence because RocksDB flushing is behind —
|
|
2314
|
+
every file after it is retained regardless of age; `purge.retainedUnflushedFiles` reports that case.
|
|
2315
|
+
While a backup with `transactionLogs` is copying a store's files, purges of that store are skipped
|
|
2316
|
+
(`purge.retentionPins` reports it). On a filesystem that rejects a directory fsync, the store's last
|
|
2317
|
+
file is kept, since `txn.state` could not be made durable before deleting it.
|
|
2318
|
+
Use `destroy: true` only to remove the store itself.
|
|
2212
2319
|
|
|
2213
2320
|
- `options: object`
|
|
2214
2321
|
- `before?: number` Remove transaction log files older than the specified timestamp, subject to
|
|
2215
|
-
the
|
|
2322
|
+
the flushed-position and contiguous-prefix rules above.
|
|
2216
2323
|
- `destroy?: boolean` When `true`, deletes transaction log stores including all log sequence files
|
|
2217
2324
|
on disk.
|
|
2218
2325
|
- `includeEntryCounts?: boolean` When `true`, counts the entries in each deleted log file and
|
|
@@ -2341,6 +2448,22 @@ The iterator produces an object with the log entry timestamp and data.
|
|
|
2341
2448
|
- `timestamp: number` The entry timestamp used to collate entries by transaction.
|
|
2342
2449
|
- `endTxn: boolean` This is `true` when the entry is the last entry in a transaction.
|
|
2343
2450
|
|
|
2451
|
+
`next()` can throw two errors that leave the iterator usable, so calling `next()` again continues
|
|
2452
|
+
past the problem. Other errors, such as a failure to open a segment, do not move the iterator, so
|
|
2453
|
+
retrying them without a fix fails the same way.
|
|
2454
|
+
|
|
2455
|
+
- `TransactionLogGapError`: the iterator reached segments it had not read yet and could not read
|
|
2456
|
+
them, usually because retention purged them while the reader lagged. Their entries are not in
|
|
2457
|
+
this log anymore, so a consumer that replicates the log should treat its copy as discontinuous
|
|
2458
|
+
(for example, by resyncing from a full copy) rather than continuing. Properties: `logId` (the
|
|
2459
|
+
last segment read), `resumeLogId` (the segment the next `next()` call reads), and
|
|
2460
|
+
`unavailableLogCount`. A new query positioned within the retained segments does not report the
|
|
2461
|
+
segments purged before its starting point.
|
|
2462
|
+
- `CorruptFrameError` (a `RangeError`): an entry's framing is broken. `resyncPosition` is where
|
|
2463
|
+
valid framing resumes, or `undefined` when nothing follows the break.
|
|
2464
|
+
|
|
2465
|
+
Both classes are exported from the package.
|
|
2466
|
+
|
|
2344
2467
|
```typescript
|
|
2345
2468
|
const log = db.useLog('foo');
|
|
2346
2469
|
const iter = log.query({});
|
|
@@ -2386,9 +2509,8 @@ stats.totals.transactionsWritten; // lifetime count of transactions written
|
|
|
2386
2509
|
|
|
2387
2510
|
The `purge.retainedUnflushedFiles` gauge is useful for diagnosing why logs are not being cleaned
|
|
2388
2511
|
up: a file can be older than the retention period but still retained because its transactions have
|
|
2389
|
-
not yet been flushed to RocksDB (purging it would be unsafe for crash recovery).
|
|
2390
|
-
|
|
2391
|
-
position — is not counted as purgeable even when it is old and fully flushed.
|
|
2512
|
+
not yet been flushed to RocksDB (purging it would be unsafe for crash recovery). An old, fully
|
|
2513
|
+
flushed current file counts as purgeable.
|
|
2392
2514
|
|
|
2393
2515
|
### Transaction Log Initialization
|
|
2394
2516
|
|
|
@@ -2495,7 +2617,7 @@ Contract:
|
|
|
2495
2617
|
`QueryPerformanceCounter` on Windows).
|
|
2496
2618
|
- **Origin and lifetime**: the origin is unspecified and fixed for the life of the process. Every
|
|
2497
2619
|
sample taken in the process is in one domain — the main thread and every `worker_threads` worker,
|
|
2498
|
-
including workers started or restarted at any later time, under Node
|
|
2620
|
+
including workers started or restarted at any later time, under Node and Bun alike. Samples
|
|
2499
2621
|
are not meaningful across processes or restarts, and are unrelated to the Unix epoch: never compare
|
|
2500
2622
|
them with `Date.now()`, `db.getMonotonicTimestamp()` or transaction timestamps.
|
|
2501
2623
|
- **Monotonic, not unique**: a sample taken after another (in real time, on any thread) is `>=` it.
|
|
@@ -2789,7 +2911,7 @@ backup references them, so this is not equivalent to deleting files manually.
|
|
|
2789
2911
|
|
|
2790
2912
|
Deletes all but the newest `keepCount` backups.
|
|
2791
2913
|
|
|
2792
|
-
### `backups.verify(backupDir: string, backupId: number, options?: { verifyWithChecksum?: boolean; verifyTransactionLogs?: boolean }): Promise<void>`
|
|
2914
|
+
### `backups.verify(backupDir: string, backupId: number, options?: { verifyWithChecksum?: boolean; verifyTables?: boolean; verifyTransactionLogs?: boolean }): Promise<void>`
|
|
2793
2915
|
|
|
2794
2916
|
Verifies a backup's file sizes, and optionally their checksums (which requires reading all
|
|
2795
2917
|
backed-up data). Resolves if the backup is intact and rejects otherwise.
|
|
@@ -2800,8 +2922,17 @@ When the backup was created with `transactionLogs: true`, the backup's transacti
|
|
|
2800
2922
|
log file's header and entry framing must be intact (snapshots are copied on committed entry
|
|
2801
2923
|
boundaries, so even a torn tail fails verification). Set `verifyTransactionLogs: false` to skip.
|
|
2802
2924
|
|
|
2925
|
+
Set `verifyTables: true` (default `false`) to also prove this build can read the backup's table
|
|
2926
|
+
files before you restore it. Each SST is opened in turn, one at a time, so file-descriptor use does
|
|
2927
|
+
not grow with the number of tables. Verification rejects, naming the file, when this build cannot
|
|
2928
|
+
decode a table's footer (for example a `format_version` written by a newer RocksDB) or its
|
|
2929
|
+
properties, or when the table records a compression algorithm this build does not support (see
|
|
2930
|
+
[`supportedCompression`](#supportedcompression)). Checksums cannot catch either case: the file is
|
|
2931
|
+
intact, just unreadable here, and RocksDB would otherwise fail on the first read after a restore.
|
|
2932
|
+
Blob files are not checked.
|
|
2933
|
+
|
|
2803
2934
|
```typescript
|
|
2804
|
-
await backups.verify('/path/to/backups', 1, { verifyWithChecksum: true });
|
|
2935
|
+
await backups.verify('/path/to/backups', 1, { verifyWithChecksum: true, verifyTables: true });
|
|
2805
2936
|
```
|
|
2806
2937
|
|
|
2807
2938
|
## Custom Store
|