@harperfast/rocksdb-js 2.5.0 → 2.6.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 +102 -1
- package/dist/index.cjs +89 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +101 -3
- package/dist/index.d.mts +101 -3
- package/dist/index.mjs +89 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -14
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ A Node.js binding for the RocksDB library.
|
|
|
10
10
|
- Transaction log system for recording transaction related data
|
|
11
11
|
- Custom stores provide ability to override default database interactions
|
|
12
12
|
- Efficient binary key and value encoding
|
|
13
|
+
- Configurable block/blob compression (LZ4, Zstd, Zlib, and more)
|
|
13
14
|
- Access to internal RocksDB statistics
|
|
14
15
|
- Designed for Node.js and Bun on Linux, macOS, and Windows
|
|
15
16
|
|
|
@@ -43,6 +44,15 @@ Creates a new database instance.
|
|
|
43
44
|
- `path: string` The path to write the database files to. This path does not need to exist, but the
|
|
44
45
|
parent directories do.
|
|
45
46
|
- `options: object` [optional]
|
|
47
|
+
- `compression: string | { algorithm: string, level?: number }` The block/blob compression
|
|
48
|
+
algorithm for this column family. Pass an algorithm name — one of `'none'`, `'snappy'`,
|
|
49
|
+
`'zlib'`, `'bzip2'`, `'lz4'`, `'lz4hc'`, or `'zstd'` — or an object with an
|
|
50
|
+
`algorithm` and an optional `level` (forwarded to RocksDB's `compression_opts.level`; the
|
|
51
|
+
meaning is algorithm-specific). Applies to both SST data blocks and blob files (large values).
|
|
52
|
+
Defaults to `'lz4'` when the native build supports it, otherwise RocksDB's own default (Snappy
|
|
53
|
+
when linked, else no compression). See [Compression](#compression). Throws if the algorithm is
|
|
54
|
+
not compiled into the native build — check [`supportedCompression`](#supportedcompression) for
|
|
55
|
+
the available list.
|
|
46
56
|
- `disableWAL: boolean` Whether to disable the RocksDB write ahead log. Defaults to `false`.
|
|
47
57
|
- `enableStats: boolean` When `true` and the database is open, RocksDB will captures stats that
|
|
48
58
|
are retrieved by calling `db.getStats()`. Enabling statistics imposes 5-10% in overhead.
|
|
@@ -67,7 +77,8 @@ Creates a new database instance.
|
|
|
67
77
|
- `statsLevel: StatsLevel` Controls which type of statistics to skip and reduce statistic
|
|
68
78
|
overhead. Defaults to `StatsLevel.ExceptDetailedTimers`.
|
|
69
79
|
- `store: Store` A custom store that handles all interaction between the `RocksDatabase` or
|
|
70
|
-
`Transaction` instances and the native database interface.
|
|
80
|
+
`Transaction` instances and the native database interface. A store is bound to a single
|
|
81
|
+
`RocksDatabase` instance and cannot be shared between them. See [Custom Store](#custom-store) for
|
|
71
82
|
more information.
|
|
72
83
|
- `transactionLogMaxAgeThreshold: number` The threshold for the transaction log file's last
|
|
73
84
|
modified time to be older than the retention period before it is rotated to the next sequence
|
|
@@ -109,6 +120,18 @@ const db2 = new RocksDatabase('path/to/db', { name: 'users' });
|
|
|
109
120
|
console.log(db.columns); // ['default', 'users']
|
|
110
121
|
```
|
|
111
122
|
|
|
123
|
+
### `db.compression: { algorithm: string, level?: number }`
|
|
124
|
+
|
|
125
|
+
Returns the compression currently in effect for this database's column family, read live from
|
|
126
|
+
RocksDB. `algorithm` is a friendly name (e.g. `'lz4'`, `'zstd'`, `'none'`); `level` is present only
|
|
127
|
+
when a non-default compression level is set. The database must be open. See
|
|
128
|
+
[Compression](#compression).
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const db = RocksDatabase.open('path/to/db', { compression: { algorithm: 'zstd', level: 3 } });
|
|
132
|
+
console.log(db.compression); // { algorithm: 'zstd', level: 3 }
|
|
133
|
+
```
|
|
134
|
+
|
|
112
135
|
### `db.config(options)`
|
|
113
136
|
|
|
114
137
|
Sets global database settings.
|
|
@@ -911,6 +934,77 @@ An object is a record with the following properties:
|
|
|
911
934
|
- `standardDeviation: number` A double containing the standard deviation.
|
|
912
935
|
- `sum: number` An unsigned 64-bit integer containing the sum of all values.
|
|
913
936
|
|
|
937
|
+
## Compression
|
|
938
|
+
|
|
939
|
+
RocksDB compresses data blocks in SST files (and, in `rocksdb-js`, blob files that hold large
|
|
940
|
+
values) using a configurable algorithm. Compression trades CPU for disk space and, because it
|
|
941
|
+
reduces bytes read from disk, often improves read throughput on I/O-bound workloads.
|
|
942
|
+
|
|
943
|
+
The following algorithm names are recognized. Which ones are actually usable depends on the native
|
|
944
|
+
build — see **Availability** below.
|
|
945
|
+
|
|
946
|
+
| Name | Notes |
|
|
947
|
+
| -------- | ----------------------------------------------------------------------------- |
|
|
948
|
+
| `none` | No compression. Always available. |
|
|
949
|
+
| `snappy` | Fast, modest ratio. RocksDB's own stock default when linked. |
|
|
950
|
+
| `zlib` | Higher ratio, slower. Supports `level` (see zlib's manual). |
|
|
951
|
+
| `bzip2` | High ratio, slow; rarely worth it over zstd. |
|
|
952
|
+
| `lz4` | Very fast, modest ratio. `rocksdb-js` default when available. |
|
|
953
|
+
| `lz4hc` | LZ4 high-compression variant: better ratio, slower writes, same fast reads. |
|
|
954
|
+
| `zstd` | Best ratio-for-speed of the set; supports `level` (higher = smaller, slower). |
|
|
955
|
+
|
|
956
|
+
Set the algorithm per column family with the `compression` option when opening a database:
|
|
957
|
+
|
|
958
|
+
```typescript
|
|
959
|
+
// Algorithm name
|
|
960
|
+
const db = RocksDatabase.open('/path/to/db', { compression: 'zstd' });
|
|
961
|
+
|
|
962
|
+
// Or an object with an explicit level
|
|
963
|
+
const db2 = RocksDatabase.open('/path/to/db2', { compression: { algorithm: 'zstd', level: 3 } });
|
|
964
|
+
|
|
965
|
+
// Disable compression entirely
|
|
966
|
+
const db3 = RocksDatabase.open('/path/to/db3', { compression: 'none' });
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
**Default.** When `compression` is omitted, `rocksdb-js` defaults to **LZ4** if the native build
|
|
970
|
+
supports it. LZ4 is fast with a modest compression ratio, making it a good general-purpose default.
|
|
971
|
+
If LZ4 is not compiled in, the default falls back to RocksDB's own default — Snappy when it is
|
|
972
|
+
linked, otherwise no compression. (RocksDB's stock default is Snappy; `rocksdb-js` overrides it to
|
|
973
|
+
LZ4.) Read the algorithm actually in effect with the `db.compression` getter.
|
|
974
|
+
|
|
975
|
+
**Availability.** The set of algorithms depends on which compression libraries the native binding
|
|
976
|
+
was compiled against, so it varies by build. Always check
|
|
977
|
+
[`supportedCompression`](#supportedcompression) at runtime — opening with an unavailable algorithm
|
|
978
|
+
throws. `'none'` is always available.
|
|
979
|
+
|
|
980
|
+
**Scope and mutability.** Compression is genuinely **per-column-family**. Each `RocksDatabase`
|
|
981
|
+
targets one column family (`name`), and its `compression` applies only to that CF — opening one CF
|
|
982
|
+
never changes another's algorithm, regardless of open order. A column family keeps its own
|
|
983
|
+
compression across a close/reopen (a plain reopen inherits it); the algorithm is dynamically
|
|
984
|
+
changeable, so an explicit change governs files written afterward while existing SST/blob files keep
|
|
985
|
+
their original compression until rewritten by compaction. It also applies to blob files (large
|
|
986
|
+
values), whose compression otherwise defaults to none.
|
|
987
|
+
|
|
988
|
+
Because a column family's compression is fixed while it is open, if the same column family is opened
|
|
989
|
+
a second time in the same process (another `RocksDatabase` on the same path/`name`, including from a
|
|
990
|
+
`worker_thread`) with an **explicitly different** algorithm or level, the second open **throws** — a
|
|
991
|
+
plain reopen (no `compression`) instead inherits the live setting.
|
|
992
|
+
|
|
993
|
+
### `supportedCompression`
|
|
994
|
+
|
|
995
|
+
A module-level, frozen array of the compression algorithm names compiled into the loaded native
|
|
996
|
+
binding. The set is fixed for a given binary. `'none'` is always present.
|
|
997
|
+
|
|
998
|
+
```typescript
|
|
999
|
+
import { supportedCompression } from '@harperfast/rocksdb-js';
|
|
1000
|
+
|
|
1001
|
+
console.log(supportedCompression); // e.g. ['none', 'snappy', 'lz4', 'zstd']
|
|
1002
|
+
|
|
1003
|
+
if (supportedCompression.includes('zstd')) {
|
|
1004
|
+
// safe to open with { compression: 'zstd' }
|
|
1005
|
+
}
|
|
1006
|
+
```
|
|
1007
|
+
|
|
914
1008
|
## Exclusive Locking
|
|
915
1009
|
|
|
916
1010
|
`rocksdb-js` includes a handful of functions for executing thread-safe mutually exclusive functions.
|
|
@@ -1767,6 +1861,13 @@ await db.put('foo', 'bar');
|
|
|
1767
1861
|
console.log(await db.get('foo'));
|
|
1768
1862
|
```
|
|
1769
1863
|
|
|
1864
|
+
> [!NOTE]
|
|
1865
|
+
> A `Store` is bound to a single `RocksDatabase` instance. Passing a store that another
|
|
1866
|
+
> `RocksDatabase` already owns throws `Store is already in use by another RocksDatabase instance`.
|
|
1867
|
+
> The claim is durable across `db.close()`, so reopening the original owner does not release it.
|
|
1868
|
+
> (Sharing a store with the owning database's `Transaction` instances is expected and handled
|
|
1869
|
+
> internally.)
|
|
1870
|
+
|
|
1770
1871
|
> [!IMPORTANT]
|
|
1771
1872
|
> If your custom store overrides `putSync()` without calling `super.putSync()` and it performs its
|
|
1772
1873
|
> own `this.encodeKey(key)`, then you MUST encode the VALUE before you encode the KEY.
|
package/dist/index.cjs
CHANGED
|
@@ -87,6 +87,15 @@ const removeGlobalListener = binding.removeListener;
|
|
|
87
87
|
const globalListenerCount = binding.listenerCount;
|
|
88
88
|
const globalNotify = binding.notify;
|
|
89
89
|
const constants = binding.constants;
|
|
90
|
+
/**
|
|
91
|
+
* The friendly names of every compression algorithm compiled into the loaded
|
|
92
|
+
* RocksDB native binding, e.g. `['none', 'snappy', 'lz4', 'zstd']`. The set is
|
|
93
|
+
* fixed for a given binary (it depends on which compression libraries RocksDB
|
|
94
|
+
* was linked against), so this is a static list. `'none'` (no compression) is
|
|
95
|
+
* always present. Use it to validate a `compression` option or to pick an
|
|
96
|
+
* algorithm that is actually available at runtime.
|
|
97
|
+
*/
|
|
98
|
+
const supportedCompression = Object.freeze(binding.supportedCompression);
|
|
90
99
|
const NativeDatabase = binding.Database;
|
|
91
100
|
const NativeIterator = binding.Iterator;
|
|
92
101
|
const NativeTransaction = binding.Transaction;
|
|
@@ -1228,13 +1237,50 @@ const ITERATOR_STATE = new Uint32Array(ITERATOR_STATE_BUFFER.buffer, ITERATOR_ST
|
|
|
1228
1237
|
const MAX_KEY_SIZE = 1024 * 1024;
|
|
1229
1238
|
const SAVE_BUFFER_SIZE = 8192;
|
|
1230
1239
|
/**
|
|
1240
|
+
* Normalizes the public `compression` option into the primitive fields the
|
|
1241
|
+
* native layer expects. When `option` is omitted, returns an empty object and
|
|
1242
|
+
* lets the native layer apply the default (LZ4 when the build supports it, else
|
|
1243
|
+
* RocksDB's own default). Throws a `TypeError` for a malformed option and an
|
|
1244
|
+
* `Error` for an algorithm that isn't supported by this build.
|
|
1245
|
+
*/
|
|
1246
|
+
function normalizeCompression(option) {
|
|
1247
|
+
if (option === void 0 || option === null) return {};
|
|
1248
|
+
let algorithm;
|
|
1249
|
+
let level;
|
|
1250
|
+
if (typeof option === "string") algorithm = option;
|
|
1251
|
+
else if (typeof option === "object" && option.algorithm !== void 0) {
|
|
1252
|
+
algorithm = option.algorithm;
|
|
1253
|
+
if (option.level !== void 0 && option.level !== null) {
|
|
1254
|
+
const raw = option.level;
|
|
1255
|
+
const coerced = typeof raw === "number" ? raw : typeof raw === "string" && raw.trim() !== "" ? Number(raw) : NaN;
|
|
1256
|
+
if (!Number.isInteger(coerced) || coerced < -2147483648 || coerced > 2147483647) throw new TypeError(`compression level must be a 32-bit integer, got ${JSON.stringify(option.level)}`);
|
|
1257
|
+
level = coerced;
|
|
1258
|
+
}
|
|
1259
|
+
} else throw new TypeError("compression must be an algorithm name or an { algorithm, level } object");
|
|
1260
|
+
if (!supportedCompression.includes(algorithm)) throw new Error(`Unsupported compression algorithm "${algorithm}". This build supports: ${supportedCompression.join(", ")}`);
|
|
1261
|
+
return {
|
|
1262
|
+
compression: algorithm,
|
|
1263
|
+
compressionLevel: level
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1231
1267
|
* A store wraps the `NativeDatabase` binding and database settings so that a
|
|
1232
1268
|
* single database instance can be shared between the main `RocksDatabase`
|
|
1233
1269
|
* instance and the `Transaction` instance.
|
|
1234
1270
|
*
|
|
1235
|
-
*
|
|
1271
|
+
* A store is bound to a single `RocksDatabase` instance and must not be shared
|
|
1272
|
+
* between `RocksDatabase` instances. Each `RocksDatabase` claims its store on
|
|
1273
|
+
* construction (see `claim()`); passing a store that another `RocksDatabase`
|
|
1274
|
+
* already owns throws. (Sharing with the owning database's `Transaction`
|
|
1275
|
+
* instances is expected and allowed.)
|
|
1236
1276
|
*/
|
|
1237
1277
|
var Store = class {
|
|
1278
|
+
/**
|
|
1279
|
+
* Whether a `RocksDatabase` has claimed this store. Durable across
|
|
1280
|
+
* close/reopen (unlike the handle's open state), so a store reused after its
|
|
1281
|
+
* owner temporarily closed is still recognized as in-use. See `claim()`.
|
|
1282
|
+
*/
|
|
1283
|
+
#claimed = false;
|
|
1238
1284
|
/**
|
|
1239
1285
|
* The database instance.
|
|
1240
1286
|
*/
|
|
@@ -1249,6 +1295,11 @@ var Store = class {
|
|
|
1249
1295
|
*/
|
|
1250
1296
|
decoderCopies = false;
|
|
1251
1297
|
/**
|
|
1298
|
+
* The compression algorithm (or `{ algorithm, level }`) requested for this
|
|
1299
|
+
* store's column family. Normalized and applied when the database opens.
|
|
1300
|
+
*/
|
|
1301
|
+
compression;
|
|
1302
|
+
/**
|
|
1252
1303
|
* Whether to disable the write ahead log.
|
|
1253
1304
|
*/
|
|
1254
1305
|
disableWAL;
|
|
@@ -1406,6 +1457,7 @@ var Store = class {
|
|
|
1406
1457
|
if (options !== void 0 && options !== null && typeof options !== "object") throw new TypeError("Database options must be an object");
|
|
1407
1458
|
const { keyEncoding, readKey, writeKey } = initKeyEncoder(options?.keyEncoding, options?.keyEncoder);
|
|
1408
1459
|
this.db = new NativeDatabase();
|
|
1460
|
+
this.compression = options?.compression;
|
|
1409
1461
|
this.dbWriteBufferSize = options?.dbWriteBufferSize;
|
|
1410
1462
|
this.decoder = options?.decoder ?? null;
|
|
1411
1463
|
this.disableWAL = options?.disableWAL ?? false;
|
|
@@ -1445,6 +1497,16 @@ var Store = class {
|
|
|
1445
1497
|
this.db.close();
|
|
1446
1498
|
}
|
|
1447
1499
|
/**
|
|
1500
|
+
* Claims this store for a `RocksDatabase`. A store is bound to a single
|
|
1501
|
+
* database instance, so claiming a store that another `RocksDatabase` has
|
|
1502
|
+
* already claimed throws. The claim is durable across close/reopen, so a
|
|
1503
|
+
* store reused after its owner temporarily closed still throws.
|
|
1504
|
+
*/
|
|
1505
|
+
claim() {
|
|
1506
|
+
if (this.#claimed) throw new Error("Store is already in use by another RocksDatabase instance");
|
|
1507
|
+
this.#claimed = true;
|
|
1508
|
+
}
|
|
1509
|
+
/**
|
|
1448
1510
|
* Compacts the entire key range of the database asynchronously.
|
|
1449
1511
|
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
1450
1512
|
*
|
|
@@ -1706,7 +1768,10 @@ var Store = class {
|
|
|
1706
1768
|
*/
|
|
1707
1769
|
open() {
|
|
1708
1770
|
if (this.db.opened) return true;
|
|
1771
|
+
const { compression, compressionLevel } = normalizeCompression(this.compression);
|
|
1709
1772
|
this.db.open(this.path, {
|
|
1773
|
+
compression,
|
|
1774
|
+
compressionLevel,
|
|
1710
1775
|
dbWriteBufferSize: this.dbWriteBufferSize,
|
|
1711
1776
|
disableWAL: this.disableWAL,
|
|
1712
1777
|
enableStats: this.enableStats,
|
|
@@ -2008,9 +2073,12 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2008
2073
|
*/
|
|
2009
2074
|
#name;
|
|
2010
2075
|
constructor(pathOrStore, options) {
|
|
2011
|
-
|
|
2012
|
-
|
|
2076
|
+
let store;
|
|
2077
|
+
if (typeof pathOrStore === "string") store = new Store(pathOrStore, options);
|
|
2078
|
+
else if (pathOrStore instanceof Store) store = pathOrStore;
|
|
2013
2079
|
else throw new TypeError("Invalid database path or store");
|
|
2080
|
+
store.claim();
|
|
2081
|
+
super(store);
|
|
2014
2082
|
this.#name = options?.name ?? "default";
|
|
2015
2083
|
}
|
|
2016
2084
|
/**
|
|
@@ -2124,6 +2192,22 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2124
2192
|
return this.store.db.columns;
|
|
2125
2193
|
}
|
|
2126
2194
|
/**
|
|
2195
|
+
* The compression currently in effect for this database's column family, read
|
|
2196
|
+
* live from RocksDB, as `{ algorithm, level? }`. `algorithm` is a friendly
|
|
2197
|
+
* name (e.g. `'lz4'`, `'zstd'`, `'none'`); `level` is present only when a
|
|
2198
|
+
* non-default compression level is set. The database must be open. Defaults to
|
|
2199
|
+
* LZ4 when the native build supports it.
|
|
2200
|
+
*
|
|
2201
|
+
* @example
|
|
2202
|
+
* ```typescript
|
|
2203
|
+
* const db = RocksDatabase.open('/path/to/db', { compression: { algorithm: 'zstd', level: 3 } });
|
|
2204
|
+
* db.compression; // { algorithm: 'zstd', level: 3 }
|
|
2205
|
+
* ```
|
|
2206
|
+
*/
|
|
2207
|
+
get compression() {
|
|
2208
|
+
return this.store.db.getCompression();
|
|
2209
|
+
}
|
|
2210
|
+
/**
|
|
2127
2211
|
* Set global database settings.
|
|
2128
2212
|
*
|
|
2129
2213
|
* @param options - The options for the database.
|
|
@@ -2953,7 +3037,7 @@ function loadLastPosition(transactionLog, readUncommitted) {
|
|
|
2953
3037
|
//#region src/index.ts
|
|
2954
3038
|
const versions = {
|
|
2955
3039
|
rocksdb: version,
|
|
2956
|
-
"rocksdb-js": "2.
|
|
3040
|
+
"rocksdb-js": "2.6.0"
|
|
2957
3041
|
};
|
|
2958
3042
|
|
|
2959
3043
|
//#endregion
|
|
@@ -2972,6 +3056,7 @@ exports.parseTransactionLog = parseTransactionLog;
|
|
|
2972
3056
|
exports.registryStatus = registryStatus;
|
|
2973
3057
|
exports.shutdown = shutdown;
|
|
2974
3058
|
exports.stats = stats;
|
|
3059
|
+
exports.supportedCompression = supportedCompression;
|
|
2975
3060
|
exports.tryFileLock = tryFileLock;
|
|
2976
3061
|
exports.validateTransactionLogStore = validateTransactionLogStore;
|
|
2977
3062
|
exports.versions = versions;
|