@harperfast/rocksdb-js 2.7.0 → 2.8.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 +299 -14
- package/dist/index.cjs +513 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +524 -15
- package/dist/index.d.mts +524 -15
- package/dist/index.mjs +511 -16
- package/dist/index.mjs.map +1 -1
- package/docs/stats.md +309 -268
- package/package.json +19 -20
package/README.md
CHANGED
|
@@ -11,6 +11,8 @@ A Node.js binding for the RocksDB library.
|
|
|
11
11
|
- Custom stores provide ability to override default database interactions
|
|
12
12
|
- Efficient binary key and value encoding
|
|
13
13
|
- Configurable block/blob compression (LZ4, Zstd, Zlib, and more)
|
|
14
|
+
- Observable background errors via the `'error'` event or `db.getLastError()`, with in-process
|
|
15
|
+
recovery (`db.resume()`)
|
|
14
16
|
- Access to internal RocksDB statistics
|
|
15
17
|
- Designed for Node.js and Bun on Linux, macOS, and Windows
|
|
16
18
|
|
|
@@ -53,10 +55,32 @@ Creates a new database instance.
|
|
|
53
55
|
when linked, else no compression). See [Compression](#compression). Throws if the algorithm is
|
|
54
56
|
not compiled into the native build — check [`supportedCompression`](#supportedcompression) for
|
|
55
57
|
the available list.
|
|
58
|
+
- `compressionForAllColumnFamilies: boolean` When `true`, applies `compression` to every column
|
|
59
|
+
family opened for the database rather than only the column family specified by `name`. Requires an explicit
|
|
60
|
+
`compression`. Defaults to `false`. See [Compression](#compression).
|
|
61
|
+
- `dbWriteBufferSize: number` The total memtable memory budget in bytes shared across all of the
|
|
62
|
+
database's column families. When the combined size of all memtables reaches this value, RocksDB
|
|
63
|
+
flushes the largest one. `0` (the default) disables this global trigger, so per-column-family
|
|
64
|
+
`writeBufferSize` alone drives flushing. This is distinct from the process-wide
|
|
65
|
+
[`writeBufferManagerSize`](#dbconfigoptions) config option. Database-wide, so it binds when the
|
|
66
|
+
path is first opened in this process: a later open of the same path — including from another
|
|
67
|
+
worker thread — keeps the first opener's value rather than overriding or rejecting it.
|
|
56
68
|
- `disableWAL: boolean` Whether to disable the RocksDB write ahead log. Defaults to `false`.
|
|
57
69
|
- `enableStats: boolean` When `true` and the database is open, RocksDB will captures stats that
|
|
58
70
|
are retrieved by calling `db.getStats()`. Enabling statistics imposes 5-10% in overhead.
|
|
59
71
|
Defaults to `false`.
|
|
72
|
+
- `infoLogLevel: number` The verbosity of RocksDB's informational logging (`LOG` /
|
|
73
|
+
`LOG.old.*`): `0` (debug), `1` (info), `2` (warn), `3` (error), `4` (fatal), or `5`
|
|
74
|
+
(header-only). Omit to leave RocksDB's own default (`INFO_LEVEL` in a release build of the
|
|
75
|
+
linked RocksDB library). See [`db.logOptions`](#dblogoptions-maxlogfilesize-number-infologlevel-number).
|
|
76
|
+
- `maxLogFileSize: number` The per-file size cap, in bytes, for informational log files (`LOG` /
|
|
77
|
+
`LOG.old.*`). RocksDB retains up to 5 of these files, so the total informational-log footprint
|
|
78
|
+
is bounded at roughly `5 * maxLogFileSize`. Defaults to 16 MB (an 80 MB bound), which stops
|
|
79
|
+
purely informational logging from growing without bound. A value of `0` is RocksDB's special
|
|
80
|
+
"single unbounded log file" mode — it **disables size-based rotation entirely**, so the log
|
|
81
|
+
can grow without limit; only set `0` if you deliberately want that (it forgoes the bounded
|
|
82
|
+
footprint this option otherwise provides). See
|
|
83
|
+
[`db.logOptions`](#dblogoptions-maxlogfilesize-number-infologlevel-number).
|
|
60
84
|
- `maxOpenFiles: number` The maximum number of table files RocksDB keeps open. `0` (the default)
|
|
61
85
|
derives a budget from the effective per-process open-file limit (an eighth of the limit —
|
|
62
86
|
several databases can share one process — clamped to `[1024, 262144]`); `-1` holds every table
|
|
@@ -64,6 +88,17 @@ Creates a new database instance.
|
|
|
64
88
|
compaction falls behind under sustained ingest); a positive `int32` is an explicit cap. Reads
|
|
65
89
|
only pay a reopen cost when the number of live table files exceeds the budget, so raise the
|
|
66
90
|
process fd limit (and with it the derived budget) for very large databases.
|
|
91
|
+
- `maxWriteBufferNumber: number` The maximum number of memtables that can be queued per column
|
|
92
|
+
family before writes stall. Higher values absorb write bursts while flushes catch up, at the
|
|
93
|
+
cost of memory (roughly `maxWriteBufferNumber * writeBufferSize` per column family). Defaults to
|
|
94
|
+
`16`.
|
|
95
|
+
- `maxWriteBufferSizeToMaintain: number` The number of bytes of recent memtable history to keep in
|
|
96
|
+
memory for transaction conflict checking. `-1` (the default) derives the value from
|
|
97
|
+
`maxWriteBufferNumber * writeBufferSize` (the RocksDB-recommended default for optimistic
|
|
98
|
+
transactions) — except when a stalling [`writeBufferManager`](#dbconfigoptions) is configured
|
|
99
|
+
(`writeBufferManagerSize > 0` with `writeBufferManagerAllowStall`), in which case it resolves to
|
|
100
|
+
`0` to avoid retaining memtable history the manager will never release. An explicit non-negative
|
|
101
|
+
value is always honored as-is.
|
|
67
102
|
- `name: string` The column family name. Defaults to `"default"`.
|
|
68
103
|
- `noBlockCache: boolean` When `true`, disables the block cache. Block caching is enabled by
|
|
69
104
|
default and the cache is shared across all database instances.
|
|
@@ -73,7 +108,10 @@ Creates a new database instance.
|
|
|
73
108
|
until commit. Defaults to `false`.
|
|
74
109
|
- `readOnly: boolean` When `true`, the database is opened in read-only mode. Read operations are
|
|
75
110
|
permitted. Write operations will throw an error with code `ERR_DATABASE_READONLY`. Transactions
|
|
76
|
-
are a no-op in read-only mode.
|
|
111
|
+
are a no-op in read-only mode. [`flush()`](#dbflushoptions-promisevoid),
|
|
112
|
+
[`flushSync()`](#dbflushsyncoptions-void), [`compact()`](#dbcompactoptions-promisevoid) and
|
|
113
|
+
[`compactSync()`](#dbcompactsyncoptions-void) are the exception: they have nothing to do when
|
|
114
|
+
there are no writes, so they succeed as no-ops rather than throwing.
|
|
77
115
|
- `statsLevel: StatsLevel` Controls which type of statistics to skip and reduce statistic
|
|
78
116
|
overhead. Defaults to `StatsLevel.ExceptDetailedTimers`.
|
|
79
117
|
- `store: Store` A custom store that handles all interaction between the `RocksDatabase` or
|
|
@@ -84,10 +122,9 @@ Creates a new database instance.
|
|
|
84
122
|
modified time to be older than the retention period before it is rotated to the next sequence
|
|
85
123
|
number. Value must be between `0.0` and `1.0`. A threshold of `0.0` means ignore age check.
|
|
86
124
|
Defaults to `0.75`.
|
|
87
|
-
- `transactionLogMaxSize: number` The maximum size of a transaction log file.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
rotated to the next sequence number. Defaults to 16 MB.
|
|
125
|
+
- `transactionLogMaxSize: number` The target maximum size of a transaction log file. Transactions
|
|
126
|
+
are never split across files: if the complete transaction does not fit, the log rotates before
|
|
127
|
+
writing it. A transaction written to an empty file may exceed the target. Defaults to 16 MB.
|
|
91
128
|
- `transactionLogRetention: string | number` The number of minutes to retain transaction logs
|
|
92
129
|
before purging. Defaults to `'3d'` (3 days).
|
|
93
130
|
- `transactionLogsPath: string` The path to store transaction logs. Defaults to
|
|
@@ -97,6 +134,9 @@ Creates a new database instance.
|
|
|
97
134
|
the verification slot for each written key. Enable this only for column families whose records
|
|
98
135
|
are cached (e.g. the primary column family of a table). Defaults to `false`. Requires
|
|
99
136
|
`verificationTableEntries` to be configured before the first database is opened.
|
|
137
|
+
- `writeBufferSize: number` The per-column-family memtable size in bytes at which the memtable is
|
|
138
|
+
sealed and flushed to an SST file. Smaller values produce more frequent, faster flushes; larger
|
|
139
|
+
values batch more writes per SST file at the cost of memory. Defaults to `16777216` (16 MB).
|
|
100
140
|
|
|
101
141
|
### `db.close()`
|
|
102
142
|
|
|
@@ -179,6 +219,18 @@ Returns `true` if the database is open, otherwise false.
|
|
|
179
219
|
console.log(db.isOpen()); // true or false
|
|
180
220
|
```
|
|
181
221
|
|
|
222
|
+
### `db.logOptions: { maxLogFileSize: number, infoLogLevel: number }`
|
|
223
|
+
|
|
224
|
+
Returns the informational-log settings currently in effect for this database, read live from
|
|
225
|
+
RocksDB. These are database-wide settings (not per-column-family). `maxLogFileSize` is the
|
|
226
|
+
per-file size cap for informational log files (`LOG` / `LOG.old.*`); `infoLogLevel` is the logging
|
|
227
|
+
verbosity. The database must be open.
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
const db = RocksDatabase.open('path/to/db', { maxLogFileSize: 4 * 1024 * 1024 });
|
|
231
|
+
console.log(db.logOptions); // { maxLogFileSize: 4194304, infoLogLevel: 1 }
|
|
232
|
+
```
|
|
233
|
+
|
|
182
234
|
### `db.name: string`
|
|
183
235
|
|
|
184
236
|
Returns the database column family's name.
|
|
@@ -278,9 +330,13 @@ await db.compact({ start: 'a', end: 'z' });
|
|
|
278
330
|
await db.compact({ bottommost: true });
|
|
279
331
|
```
|
|
280
332
|
|
|
333
|
+
On a [read-only](#new-rocksdatabasepath-options) database this is a no-op: arguments are still
|
|
334
|
+
validated, but the returned promise resolves without compacting rather than rejecting.
|
|
335
|
+
|
|
281
336
|
### `db.compactSync(options?): void`
|
|
282
337
|
|
|
283
|
-
Synchronous version of `compact()`.
|
|
338
|
+
Synchronous version of `compact()`. On a [read-only](#new-rocksdatabasepath-options) database it
|
|
339
|
+
validates its arguments and then returns without compacting, rather than throwing.
|
|
284
340
|
|
|
285
341
|
```typescript
|
|
286
342
|
db.compactSync();
|
|
@@ -321,23 +377,63 @@ db.dropSync();
|
|
|
321
377
|
db.close();
|
|
322
378
|
```
|
|
323
379
|
|
|
324
|
-
### `db.flush(): Promise<void>`
|
|
380
|
+
### `db.flush(options?): Promise<void>`
|
|
325
381
|
|
|
326
382
|
Flushes all in-memory data to disk asynchronously.
|
|
327
383
|
|
|
384
|
+
- `options: object`
|
|
385
|
+
- `allowWriteStall?: boolean` Whether the flush may proceed even though it will stall writes for
|
|
386
|
+
its duration. Defaults to `false`, which — despite how that reads — means the flush **waits**
|
|
387
|
+
until it can run without causing a stall, with no timeout: on a database stuck in a stall
|
|
388
|
+
condition (immutable-memtable backlog, L0 stop trigger, an exhausted `WriteBufferManager`
|
|
389
|
+
budget), the returned promise never settles, and since `flush()` runs on the libuv threadpool
|
|
390
|
+
(default size 4), a handful of concurrently stalled flushes can exhaust the pool and stall
|
|
391
|
+
every unrelated `fs`/`dns`/`crypto` call and cold-cache `get()` in the process, not only this
|
|
392
|
+
database's. Pass `true` up front, before issuing a flush you expect might stall, when it's a
|
|
393
|
+
durability gate you'd rather have stall writers than wait indefinitely — there's no way to
|
|
394
|
+
cancel an in-flight `flush()`, so this isn't a rescue for one already hung, and forcing the
|
|
395
|
+
memtable switch can itself prolong an existing L0 stop-trigger condition rather than clear it.
|
|
396
|
+
That cost is database-wide, covering every column family on the (process-global,
|
|
397
|
+
`worker_threads`-shared) database handle, not just the caller's — and it relocates the hang
|
|
398
|
+
rather than removing it: a stalled write blocks the database's single commit thread, which
|
|
399
|
+
dispatches every `Transaction.commit()` in order, so every commit behind it queues up too,
|
|
400
|
+
including ones from callers that never touched flush. This is a different knob from
|
|
401
|
+
`writeBufferManagerAllowStall` (see [`new RocksDatabase()`](#new-rocksdatabasepath-options)
|
|
402
|
+
options), with nearly opposite polarity: that one governs whether the `WriteBufferManager` may
|
|
403
|
+
stall writers at all, this one governs whether one manual flush is willing to cause a stall
|
|
404
|
+
rather than wait one out.
|
|
405
|
+
|
|
328
406
|
```typescript
|
|
329
407
|
await db.flush();
|
|
408
|
+
|
|
409
|
+
// Chosen up front, as a durability gate willing to pay the stall cost
|
|
410
|
+
await db.flush({ allowWriteStall: true });
|
|
330
411
|
```
|
|
331
412
|
|
|
332
|
-
|
|
413
|
+
On a [read-only](#new-rocksdatabasepath-options) database this is a no-op: the options bag is still
|
|
414
|
+
validated, but the returned promise resolves without flushing rather than rejecting.
|
|
415
|
+
|
|
416
|
+
### `db.flushSync(options?): void`
|
|
333
417
|
|
|
334
418
|
Flushes all in-memory data to disk synchronously. Note that this can be an expensive operation, so
|
|
335
419
|
it is recommended to use `flush()` if you want to keep the event loop free.
|
|
336
420
|
|
|
421
|
+
- `options: object` Same as [`flush()`](#dbflushoptions-promisevoid). The default
|
|
422
|
+
`allowWriteStall: false` wait is taken on the calling thread, which here is the JS thread — so
|
|
423
|
+
the hazard described there is strictly larger on this entry point, not smaller: instead of
|
|
424
|
+
parking one libuv pool worker it freezes the event loop outright, and it holds the in-flight
|
|
425
|
+
operation claim that `close()` waits on, so the database cannot be closed out from under it
|
|
426
|
+
either. Prefer `flush()` if there is any chance the database is in a stall condition.
|
|
427
|
+
|
|
337
428
|
```typescript
|
|
338
429
|
db.flushSync();
|
|
430
|
+
|
|
431
|
+
db.flushSync({ allowWriteStall: true });
|
|
339
432
|
```
|
|
340
433
|
|
|
434
|
+
On a [read-only](#new-rocksdatabasepath-options) database it validates its options and then returns
|
|
435
|
+
without flushing, rather than throwing.
|
|
436
|
+
|
|
341
437
|
### `db.get(key: Key, options?: GetOptions): MaybePromise<any>`
|
|
342
438
|
|
|
343
439
|
Retreives the value for a given key. If the key does not exist, it will resolve `undefined`.
|
|
@@ -384,13 +480,75 @@ the `expectedVersion` option is used.
|
|
|
384
480
|
### `db.getEstimatedKeyCount(): number`
|
|
385
481
|
|
|
386
482
|
Retrieves the estimated number of keys in the database. This is an alias for
|
|
387
|
-
`db.getDBIntProperty('rocksdb.estimate-num-keys')
|
|
483
|
+
`db.getDBIntProperty('rocksdb.estimate-num-keys')`; use `estimateCount()` for range support and a
|
|
484
|
+
confidence indicator.
|
|
388
485
|
|
|
389
486
|
```typescript
|
|
390
487
|
const estimated = db.getEstimatedKeyCount();
|
|
391
488
|
console.log(estimated);
|
|
392
489
|
```
|
|
393
490
|
|
|
491
|
+
### `db.estimateCount(options?: CountEstimateOptions): CountEstimate`
|
|
492
|
+
|
|
493
|
+
Estimates the number of keys in the database, or within a key range, returning
|
|
494
|
+
`{ count, confidence }`. Unlike `getKeysCount()`, this never iterates: the estimate is derived
|
|
495
|
+
from RocksDB statistics (memtable stats plus approximate SST sizes converted through the entry
|
|
496
|
+
density of the SSTs overlapping the range), so its cost scales with the number of SSTs overlapping
|
|
497
|
+
the range rather than the number of keys. Reading cold table properties can do I/O through the
|
|
498
|
+
table cache, so narrow ranges are preferable. A start-only range is computed as the
|
|
499
|
+
whole-database estimate minus the complement, so it does the work of the range _below_ `start`.
|
|
500
|
+
Accuracy improves with range size. Resolution is bounded by SST data-block granularity, so a range
|
|
501
|
+
narrower than a block is unreliable in either direction: it may over-report or report 0 for present
|
|
502
|
+
keys, and its low `confidence` is the signal. Recently deleted or overwritten entries may be counted
|
|
503
|
+
until compaction.
|
|
504
|
+
Estimates always reflect committed state; writes pending in a transaction are not included. Set
|
|
505
|
+
`reverse: true` to use `getRange()`'s reverse convention (`start` is the upper bound and `end` is
|
|
506
|
+
the lower bound). An inverted range (`start` ≥ `end`) returns
|
|
507
|
+
`{ count: 0, confidence: 1 }`.
|
|
508
|
+
|
|
509
|
+
`confidence` is a heuristic 0–1 indicator of how trustworthy `count` is — exactly 1 only when the
|
|
510
|
+
count is exact. It is derived from the estimate's resolution (data-block/memtable-sampling
|
|
511
|
+
granularity relative to the count), the tombstone fraction of the overlapping SSTs, and — for
|
|
512
|
+
start-only ranges — the error compounded by complement subtraction. Treat it as an ordering
|
|
513
|
+
signal (e.g. when to trust an estimate for query planning vs fall back to a heuristic), not a
|
|
514
|
+
statistical bound.
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
const { count, confidence } = db.estimateCount({ start: 'a', end: 'z' });
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### `db.createCountEstimator(options?: CountEstimatorOptions): CountEstimator`
|
|
521
|
+
|
|
522
|
+
Creates an estimator that progressively refines a range count estimate while the range is being
|
|
523
|
+
iterated — useful for reporting a total alongside a page of results without scanning the full
|
|
524
|
+
range. Before any traversal, `estimate()` returns the pure statistical estimate (same as
|
|
525
|
+
`estimateCount(range)`). As the caller reports progress with `advance(lastKey, count)` (e.g. once
|
|
526
|
+
per page), `estimate()` returns the exact traversed count plus a statistical estimate of the
|
|
527
|
+
remainder, calibrated by the observed ratio of actual-to-estimated entries over the portion
|
|
528
|
+
already traversed — so the count converges toward the exact total. `confidence` is the
|
|
529
|
+
exactness-weighted blend of the traversed portion and the remainder's confidence, so it approaches 1
|
|
530
|
+
as the exact portion grows, although a checkpoint may decrease when calibration makes a large
|
|
531
|
+
correction.
|
|
532
|
+
Each checkpoint reads committed state, so a traversal performed against a transaction snapshot may
|
|
533
|
+
be calibrated against data committed after that snapshot.
|
|
534
|
+
When traversal completes, call `finish()` and `estimate()` returns the exact count with
|
|
535
|
+
confidence 1. Reverse ranges follow `getRange`: set `start` to the upper bound and `end` to the
|
|
536
|
+
lower bound, then set `reverse: true`. The caller owns the progress contract: cursors must move
|
|
537
|
+
monotonically through the range and each entry must be reported exactly once.
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
const range = { start: 'a', end: 'z' };
|
|
541
|
+
const estimator = db.createCountEstimator(range);
|
|
542
|
+
let lastKey;
|
|
543
|
+
let pageSize = 0;
|
|
544
|
+
for (const { key } of db.getRange({ ...range, limit: 25 })) {
|
|
545
|
+
lastKey = key;
|
|
546
|
+
pageSize++;
|
|
547
|
+
}
|
|
548
|
+
estimator.advance(lastKey, pageSize);
|
|
549
|
+
const { count, confidence } = estimator.estimate();
|
|
550
|
+
```
|
|
551
|
+
|
|
394
552
|
### `db.getKeys(options?: IteratorOptions): ExtendedIterable`
|
|
395
553
|
|
|
396
554
|
Retrieves all keys within a range.
|
|
@@ -668,6 +826,15 @@ not committed after the configured number of coordinated retries, the transactio
|
|
|
668
826
|
an `ERR_TRANSACTION_ABANDONED` error. Coordinated retry requires the column family to be opened with
|
|
669
827
|
`verificationTable: true`.
|
|
670
828
|
|
|
829
|
+
That wait is bounded so a conflicting transaction that is never committed or aborted cannot block
|
|
830
|
+
the commit forever: if the write intent has not been released after `ROCKSDB_JS_PARK_TIMEOUT_MS`
|
|
831
|
+
(default `5000`), the commit resolves anyway and consumes a retry attempt exactly as a real release
|
|
832
|
+
would. A conflicting transaction held for longer than roughly `maxRetries` times that timeout
|
|
833
|
+
therefore ends in `ERR_TRANSACTION_ABANDONED` rather than waiting indefinitely. Deployments where
|
|
834
|
+
waiting is preferable to failing should raise the timeout; there is no way to disable the bound.
|
|
835
|
+
In particular `0` does not disable it: `0`, negative, and unparseable values all fall back to the
|
|
836
|
+
`5000` default, and a value between `1` and `49` is clamped up to `50`.
|
|
837
|
+
|
|
671
838
|
### Class: `Transaction`
|
|
672
839
|
|
|
673
840
|
The transaction callback is passed in a `Transaction` instance which contains all of the same data
|
|
@@ -744,6 +911,73 @@ await db.transaction(async (txn) => {
|
|
|
744
911
|
});
|
|
745
912
|
```
|
|
746
913
|
|
|
914
|
+
## Error Handling
|
|
915
|
+
|
|
916
|
+
### `db.getLastError(): BackgroundError | null`
|
|
917
|
+
|
|
918
|
+
Returns the most recent [`BackgroundError`](#event-error) observed on this database, or `null` when
|
|
919
|
+
none has occurred. This is the **pull** counterpart to the `'error'` [event](#event-error): use it
|
|
920
|
+
for an on-demand check (e.g. a health probe) or to catch an error that fired before a listener was
|
|
921
|
+
attached. The value is historical — it is **not** cleared by a successful
|
|
922
|
+
[`db.resume()`](#dbresume-void); reset it explicitly with
|
|
923
|
+
[`db.setLastError(null)`](#dbsetlasterrorerror-void). When the returned error's `writesDisabled` is
|
|
924
|
+
`true`, writes are stopped until recovery.
|
|
925
|
+
|
|
926
|
+
```typescript
|
|
927
|
+
const err = db.getLastError();
|
|
928
|
+
if (err?.writesDisabled) {
|
|
929
|
+
// ...free disk space, then...
|
|
930
|
+
db.resume();
|
|
931
|
+
}
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
### `db.setLastError(error?): void`
|
|
935
|
+
|
|
936
|
+
Sets or clears the last background error, mirroring the Win32 `SetLastError` / `GetLastError` pair.
|
|
937
|
+
|
|
938
|
+
- **Clear** — pass `null` (or no argument). [`db.getLastError()`](#dbgetlasterror-backgrounderror--null)
|
|
939
|
+
then returns `null` and no event fires. This is how you reset the error after handling or
|
|
940
|
+
recovering it (e.g. after [`db.resume()`](#dbresume-void)) — the equivalent of
|
|
941
|
+
`SetLastError(ERROR_SUCCESS)`.
|
|
942
|
+
- **Set** — pass an object (`{ message, severity?, severityName?, writesDisabled?, reason?, reasonName? }`;
|
|
943
|
+
`type` defaults to `'background'`). It is stored and the `'error'` [event](#event-error) fires with
|
|
944
|
+
the reconstructed [`BackgroundError`](#event-error). Useful for surfacing an application-level
|
|
945
|
+
"this database is unusable" state, and for deterministically exercising the error path in tests.
|
|
946
|
+
|
|
947
|
+
```typescript
|
|
948
|
+
// reset after recovery
|
|
949
|
+
db.resume();
|
|
950
|
+
db.setLastError(null);
|
|
951
|
+
|
|
952
|
+
// inject (e.g. in a test)
|
|
953
|
+
db.on('error', (err) => console.error(err.message));
|
|
954
|
+
db.setLastError({
|
|
955
|
+
message: 'disk quota exceeded',
|
|
956
|
+
severity: 2,
|
|
957
|
+
severityName: 'hard',
|
|
958
|
+
writesDisabled: true,
|
|
959
|
+
});
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
### `db.resume(): void`
|
|
963
|
+
|
|
964
|
+
Attempts to recover the database from a background error (see the `'error'` [event](#event-error))
|
|
965
|
+
by calling RocksDB's `DB::Resume()`. Call this after the underlying condition has cleared — e.g.
|
|
966
|
+
once disk space has been freed. On success writes are accepted again (and RocksDB can resume the
|
|
967
|
+
obsolete-file cleanup it was blocking); on failure — the condition has not actually cleared — it
|
|
968
|
+
throws with the RocksDB error and the database stays read-only. A no-op on a healthy database.
|
|
969
|
+
|
|
970
|
+
Runs synchronously and may briefly block, since recovery can re-flush memtables.
|
|
971
|
+
|
|
972
|
+
```typescript
|
|
973
|
+
db.on('error', (err) => {
|
|
974
|
+
if (err.writesDisabled) {
|
|
975
|
+
// ...free disk space, then...
|
|
976
|
+
db.resume();
|
|
977
|
+
}
|
|
978
|
+
});
|
|
979
|
+
```
|
|
980
|
+
|
|
747
981
|
## Events
|
|
748
982
|
|
|
749
983
|
### Event: `'aftercommit'`
|
|
@@ -770,6 +1004,57 @@ The `'committed'` event is emitted after the transaction has been written. When
|
|
|
770
1004
|
emitted, the transaction is still cleaning up. If you need to know when the transaction is fully
|
|
771
1005
|
complete, use the `'aftercommit'` event.
|
|
772
1006
|
|
|
1007
|
+
### Event: `'error'`
|
|
1008
|
+
|
|
1009
|
+
When a write fails at the filesystem level — a full disk, an exhausted quota — RocksDB records a
|
|
1010
|
+
background error and, for a hard-or-worse severity, stops accepting writes. The database emits an
|
|
1011
|
+
`'error'` event carrying a `BackgroundError` so a consumer can observe it and recover in-process
|
|
1012
|
+
instead of restarting. When `writesDisabled` is `true`, call
|
|
1013
|
+
[`db.resume()`](#dbresume-void) after the underlying condition clears. Register the listener with
|
|
1014
|
+
`db.on('error', ...)` before the database is put under load — or use the pull-based
|
|
1015
|
+
[`db.getLastError()`](#dbgetlasterror-backgrounderror--null) to catch an error that fired earlier.
|
|
1016
|
+
|
|
1017
|
+
`BackgroundError` is a real `Error` subclass, exported from the package, so both
|
|
1018
|
+
`err instanceof Error` and `err instanceof BackgroundError` hold. It extends `Error` with:
|
|
1019
|
+
|
|
1020
|
+
- `message: string` — the RocksDB error string.
|
|
1021
|
+
- `name: string` — always `'BackgroundError'`.
|
|
1022
|
+
- `type: string` — the error-class discriminator; always `'background'`.
|
|
1023
|
+
- `severity: number` — the RocksDB `Status::Severity`: `1` soft, `2` hard, `3` fatal,
|
|
1024
|
+
`4` unrecoverable.
|
|
1025
|
+
- `severityName: string` — `'soft'`, `'hard'`, `'fatal'`, or `'unrecoverable'`.
|
|
1026
|
+
- `writesDisabled: boolean` — whether RocksDB has disabled writes on the database (`severity >= 2`).
|
|
1027
|
+
Only then is `resume()` warranted; a soft error is auto-recoverable and leaves writes enabled.
|
|
1028
|
+
Distinct from opening the database in read-only mode.
|
|
1029
|
+
- `reason?: number` / `reasonName?: string` — the originating `BackgroundErrorReason`
|
|
1030
|
+
(e.g. `'flush'`, `'compaction'`), present when the error came from a reason-bearing callback.
|
|
1031
|
+
|
|
1032
|
+
```typescript
|
|
1033
|
+
import { BackgroundError } from '@harperfast/rocksdb-js';
|
|
1034
|
+
|
|
1035
|
+
db.on('error', (err) => {
|
|
1036
|
+
if (err instanceof BackgroundError && err.writesDisabled) {
|
|
1037
|
+
console.error(`writes disabled (${err.severityName}): ${err.message}`);
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
```typescript
|
|
1043
|
+
db.on('error', (err) => {
|
|
1044
|
+
if (err.writesDisabled) {
|
|
1045
|
+
// Hard-or-worse: RocksDB has disabled writes on this database. They stay
|
|
1046
|
+
// disabled until you clear the underlying condition and call db.resume().
|
|
1047
|
+
console.error(`database writes disabled (${err.severityName}): ${err.message}`);
|
|
1048
|
+
} else {
|
|
1049
|
+
// Soft error: writes are NOT disabled and RocksDB will auto-recover. This
|
|
1050
|
+
// is typically a transient background hiccup (e.g. a retryable I/O error
|
|
1051
|
+
// during flush or compaction), surfaced for visibility only — no action
|
|
1052
|
+
// is required.
|
|
1053
|
+
console.warn(`recoverable background error (${err.severityName}): ${err.message}`);
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
```
|
|
1057
|
+
|
|
773
1058
|
## Event API
|
|
774
1059
|
|
|
775
1060
|
`rocksdb-js` provides a EventEmitter-like API that lets you asynchronously notify events to one or
|
|
@@ -1681,7 +1966,7 @@ snapshots of a database. A backup covers the **entire database** — every colum
|
|
|
1681
1966
|
manifest, and (by default) the write-ahead log — so it is not scoped to an individual `Store`.
|
|
1682
1967
|
|
|
1683
1968
|
A backup can be written to a local **directory** (incremental, with a management API) or streamed to
|
|
1684
|
-
a
|
|
1969
|
+
a `WritableStream` as a tar archive with no intermediate copy on disk. See
|
|
1685
1970
|
[docs/backups.md](docs/backups.md) for a full guide covering both modes, restore, checkpoints, and
|
|
1686
1971
|
caveats.
|
|
1687
1972
|
|
|
@@ -1757,10 +2042,10 @@ required bytes — before any files are copied, so a full destination fails fast
|
|
|
1757
2042
|
through (a mid-copy failure can leave zero usable backups). The required size is estimated
|
|
1758
2043
|
conservatively as a full copy of the database's live files, plus the transaction-log snapshot when
|
|
1759
2044
|
`transactionLogs` is set; since a backup only ever copies files, this can never under-estimate.
|
|
1760
|
-
Incremental backups to a right-sized volume may therefore be over-rejected — set
|
|
1761
|
-
false` to skip the check. It also self-disables when free space can't be determined
|
|
1762
|
-
network filesystems report `0`), so it never blocks a backup on an untrustworthy number.
|
|
1763
|
-
directory-target backups are checked; the streaming backup path is unaffected.
|
|
2045
|
+
Incremental backups to a right-sized volume may therefore be over-rejected — set
|
|
2046
|
+
`checkDiskSpace: false` to skip the check. It also self-disables when free space can't be determined
|
|
2047
|
+
(e.g. some network filesystems report `0`), so it never blocks a backup on an untrustworthy number.
|
|
2048
|
+
Only directory-target backups are checked; the streaming backup path is unaffected.
|
|
1764
2049
|
|
|
1765
2050
|
### `db.backup(stream: WritableStream<Uint8Array>, options?: BackupStreamOptions): Promise<void>`
|
|
1766
2051
|
|