@harperfast/rocksdb-js 2.8.0 → 2.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +357 -27
- package/dist/index.cjs +290 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +327 -38
- package/dist/index.d.mts +327 -38
- package/dist/index.mjs +289 -41
- package/dist/index.mjs.map +1 -1
- package/docs/stats.md +46 -1
- package/docs/transaction-log.md +18 -5
- package/docs/transaction-timestamp-integrity-design.md +123 -0
- package/package.json +19 -19
package/dist/index.mjs
CHANGED
|
@@ -66,6 +66,26 @@ const binding = req(locateBinding());
|
|
|
66
66
|
*/
|
|
67
67
|
const BackgroundError = binding.BackgroundError;
|
|
68
68
|
const config = binding.config;
|
|
69
|
+
/**
|
|
70
|
+
* Reads the live state of the process-wide `WriteBufferManager`: its budget,
|
|
71
|
+
* charged memory, mutable share, stall state, and attached column-family
|
|
72
|
+
* inventory. The manager is shared by every database and worker thread in the
|
|
73
|
+
* process.
|
|
74
|
+
*
|
|
75
|
+
* A WriteBufferManager stall does not pass through RocksDB's `WriteController`,
|
|
76
|
+
* so it is not reflected by `rocksdb.stall.micros`, `db.isWriteStalled()`, or
|
|
77
|
+
* the `'writeStall'` event. Use `stallActive` to distinguish this condition from
|
|
78
|
+
* an idle database.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const wbm = getWriteBufferManagerStats();
|
|
83
|
+
* if (wbm.stallActive) {
|
|
84
|
+
* log.warn(`writes stalled for ${wbm.stallActiveMs}ms`);
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
const getWriteBufferManagerStats = binding.getWriteBufferManagerStats;
|
|
69
89
|
const FRESH_VERSION_FLAG$1 = binding.constants.FRESH_VERSION_FLAG;
|
|
70
90
|
const addGlobalListener = binding.addListener;
|
|
71
91
|
const removeGlobalListener = binding.removeListener;
|
|
@@ -114,6 +134,8 @@ const transactionLogMapCount = binding.transactionLogMapCount;
|
|
|
114
134
|
* disarm. Used by the ERR_TRY_AGAIN retry regression test.
|
|
115
135
|
*/
|
|
116
136
|
const forceTryAgainForTesting = binding.forceTryAgainForTesting;
|
|
137
|
+
/** Delays one selected watchdog join in the concurrent-shutdown regression test. */
|
|
138
|
+
const setWriteBufferManagerJoinDelayForTesting = binding.setWriteBufferManagerJoinDelayForTesting;
|
|
117
139
|
/**
|
|
118
140
|
* Creates a native file lock using the specified file path (`flock` on POSIX,
|
|
119
141
|
* `LockFileEx` on Windows), creating the file and any missing parent
|
|
@@ -642,14 +664,12 @@ function parseDuration(duration) {
|
|
|
642
664
|
num *= 1e3;
|
|
643
665
|
break;
|
|
644
666
|
case "m":
|
|
645
|
-
num *=
|
|
667
|
+
num *= 6e4;
|
|
646
668
|
break;
|
|
647
669
|
case "h":
|
|
648
|
-
num *=
|
|
649
|
-
break;
|
|
650
|
-
case "d":
|
|
651
|
-
num *= 1e3 * 60 * 60 * 24;
|
|
670
|
+
num *= 36e5;
|
|
652
671
|
break;
|
|
672
|
+
case "d": num *= 864e5;
|
|
653
673
|
}
|
|
654
674
|
result += num;
|
|
655
675
|
}
|
|
@@ -1248,7 +1268,15 @@ var DBIterator = class {
|
|
|
1248
1268
|
this.iterator.return?.();
|
|
1249
1269
|
return DONE_RESULT;
|
|
1250
1270
|
}
|
|
1251
|
-
|
|
1271
|
+
let result;
|
|
1272
|
+
try {
|
|
1273
|
+
result = this.iterator.next();
|
|
1274
|
+
} catch (err) {
|
|
1275
|
+
try {
|
|
1276
|
+
this.iterator.return?.();
|
|
1277
|
+
} catch {}
|
|
1278
|
+
throw err;
|
|
1279
|
+
}
|
|
1252
1280
|
if (result === ITERATOR_RESULT_DONE) return DONE_RESULT;
|
|
1253
1281
|
this.#yielded++;
|
|
1254
1282
|
const includeValues = this.#includeValues;
|
|
@@ -1352,10 +1380,10 @@ function createFixedBuffer(size) {
|
|
|
1352
1380
|
|
|
1353
1381
|
//#endregion
|
|
1354
1382
|
//#region src/store.ts
|
|
1355
|
-
const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG, FRESH_VERSION_FLAG, POPULATE_VERSION_FLAG, ITERATOR_REVERSE_FLAG, ITERATOR_INCLUSIVE_END_FLAG, ITERATOR_EXCLUSIVE_START_FLAG, ITERATOR_INCLUDE_VALUES_FLAG, ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG, ITERATOR_CONTEXT_IS_TRANSACTION_FLAG } = constants;
|
|
1383
|
+
const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG, FRESH_VERSION_FLAG, POPULATE_VERSION_FLAG, ITERATOR_REVERSE_FLAG, ITERATOR_INCLUSIVE_END_FLAG, ITERATOR_EXCLUSIVE_START_FLAG, ITERATOR_INCLUDE_VALUES_FLAG, ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG, ITERATOR_CONTEXT_IS_TRANSACTION_FLAG, ITERATOR_HAS_TRANSACTION_ID_FLAG } = constants;
|
|
1356
1384
|
const KEY_BUFFER_SIZE = 4096;
|
|
1357
1385
|
const KEY_BUFFER = createFixedBuffer(KEY_BUFFER_SIZE);
|
|
1358
|
-
const VALUE_BUFFER = createFixedBuffer(
|
|
1386
|
+
const VALUE_BUFFER = createFixedBuffer(65536);
|
|
1359
1387
|
/**
|
|
1360
1388
|
* Backing buffer for the shared iterator state. Layout (Uint32Array view):
|
|
1361
1389
|
* [0] = key length written into KEY_BUFFER by the most recent iterator step
|
|
@@ -1363,7 +1391,7 @@ const VALUE_BUFFER = createFixedBuffer(64 * 1024);
|
|
|
1363
1391
|
*/
|
|
1364
1392
|
const ITERATOR_STATE_BUFFER = Buffer.allocUnsafeSlow(8);
|
|
1365
1393
|
const ITERATOR_STATE = new Uint32Array(ITERATOR_STATE_BUFFER.buffer, ITERATOR_STATE_BUFFER.byteOffset, 2);
|
|
1366
|
-
const MAX_KEY_SIZE =
|
|
1394
|
+
const MAX_KEY_SIZE = 1048576;
|
|
1367
1395
|
const SAVE_BUFFER_SIZE = 8192;
|
|
1368
1396
|
/**
|
|
1369
1397
|
* Normalizes the public `compression` option into the primitive fields the
|
|
@@ -1398,6 +1426,15 @@ function normalizeCompression(option) {
|
|
|
1398
1426
|
};
|
|
1399
1427
|
}
|
|
1400
1428
|
/**
|
|
1429
|
+
* Whether `codec` is a pre-constructed encoder/decoder instance that `open()`
|
|
1430
|
+
* would reuse as-is (rather than instantiate fresh from an `Encoder` factory).
|
|
1431
|
+
* Such an instance carries per-column-family mutable state (its `name`, msgpack
|
|
1432
|
+
* `structures`), so it cannot be shared across column families.
|
|
1433
|
+
*/
|
|
1434
|
+
function sharesMutableCodec(codec) {
|
|
1435
|
+
return codec != null && typeof codec === "object" && typeof codec.Encoder !== "function" && (typeof codec.encode === "function" || typeof codec.decode === "function");
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1401
1438
|
* A store wraps the `NativeDatabase` binding and database settings so that a
|
|
1402
1439
|
* single database instance can be shared between the main `RocksDatabase`
|
|
1403
1440
|
* instance and the `Transaction` instance.
|
|
@@ -1416,6 +1453,13 @@ var Store = class {
|
|
|
1416
1453
|
*/
|
|
1417
1454
|
#claimed = false;
|
|
1418
1455
|
/**
|
|
1456
|
+
* Shallow snapshot of the options this store was constructed with, used by
|
|
1457
|
+
* `createColumnFamilyStore()` to derive sibling column-family stores. Snapshot
|
|
1458
|
+
* (not the caller's object) so later mutations of the caller's options don't
|
|
1459
|
+
* leak into derived views.
|
|
1460
|
+
*/
|
|
1461
|
+
#columnFamilyOptions;
|
|
1462
|
+
/**
|
|
1419
1463
|
* The database instance.
|
|
1420
1464
|
*/
|
|
1421
1465
|
db;
|
|
@@ -1510,10 +1554,16 @@ var Store = class {
|
|
|
1510
1554
|
/**
|
|
1511
1555
|
* The bytes of recent memtable history to retain in memory for transaction
|
|
1512
1556
|
* conflict checking. `-1` derives the value from
|
|
1513
|
-
* `maxWriteBufferNumber * writeBufferSize`, except
|
|
1514
|
-
* `writeBufferManager
|
|
1515
|
-
* that manager and is only trimmable down to this target, so a
|
|
1516
|
-
* budget cannot hold
|
|
1557
|
+
* `maxWriteBufferNumber * writeBufferSize`, except when a
|
|
1558
|
+
* `writeBufferManager` is configured, where it derives `1`: retained history
|
|
1559
|
+
* is charged to that manager and is only trimmable down to this target, so a
|
|
1560
|
+
* target the budget cannot hold is memory the manager never reclaims, and
|
|
1561
|
+
* stalls writes permanently when `writeBufferManagerAllowStall` is on. Any
|
|
1562
|
+
* configured manager, not only a stalling one — that flag is mutable at
|
|
1563
|
+
* runtime while this value is fixed when the family is created. `1`, not `0`, because
|
|
1564
|
+
* RocksDB's transaction wrappers rewrite a `0` target to the derived value —
|
|
1565
|
+
* so `0` asks for the largest history rather than none, and an explicit `0`
|
|
1566
|
+
* is normalized to `1` for that reason. Set a positive number to size it
|
|
1517
1567
|
* yourself against the budget and the column-family count.
|
|
1518
1568
|
*/
|
|
1519
1569
|
maxWriteBufferSizeToMaintain;
|
|
@@ -1551,6 +1601,11 @@ var Store = class {
|
|
|
1551
1601
|
*/
|
|
1552
1602
|
path;
|
|
1553
1603
|
/**
|
|
1604
|
+
* The open database's resolved filesystem identity, read once from
|
|
1605
|
+
* `NativeDatabase.identityPath`. `undefined` until opened.
|
|
1606
|
+
*/
|
|
1607
|
+
identityPath;
|
|
1608
|
+
/**
|
|
1554
1609
|
* Whether to use pessimistic locking for transactions. When `true`,
|
|
1555
1610
|
* transactions will fail as soon as a conflict is detected. When `false`,
|
|
1556
1611
|
* transactions will only fail when `commit()` is called.
|
|
@@ -1564,6 +1619,13 @@ var Store = class {
|
|
|
1564
1619
|
*/
|
|
1565
1620
|
readOnly;
|
|
1566
1621
|
/**
|
|
1622
|
+
* The secondary instance's workspace directory when the database is opened
|
|
1623
|
+
* as a secondary (see `RocksDatabaseOptions.secondaryPath`); `undefined`
|
|
1624
|
+
* otherwise. A secondary is read-only, so `readOnly` is `true` whenever
|
|
1625
|
+
* this is set.
|
|
1626
|
+
*/
|
|
1627
|
+
secondaryPath;
|
|
1628
|
+
/**
|
|
1567
1629
|
* Encoder specific flag used to signal that the encoder should use a random
|
|
1568
1630
|
* access structure.
|
|
1569
1631
|
*/
|
|
@@ -1649,7 +1711,10 @@ var Store = class {
|
|
|
1649
1711
|
this.parallelismThreads = options?.parallelismThreads;
|
|
1650
1712
|
this.path = path;
|
|
1651
1713
|
this.pessimistic = options?.pessimistic ?? false;
|
|
1652
|
-
|
|
1714
|
+
const secondaryPath = options?.secondaryPath ?? void 0;
|
|
1715
|
+
if (secondaryPath !== void 0 && options?.readOnly === false) throw new Error("A secondary open is read-only; secondaryPath cannot be combined with readOnly: false");
|
|
1716
|
+
this.readOnly = options?.readOnly ?? secondaryPath !== void 0;
|
|
1717
|
+
this.secondaryPath = secondaryPath;
|
|
1653
1718
|
this.randomAccessStructure = options?.randomAccessStructure ?? false;
|
|
1654
1719
|
this.readKey = readKey;
|
|
1655
1720
|
this.sharedStructuresKey = options?.sharedStructuresKey;
|
|
@@ -1661,6 +1726,36 @@ var Store = class {
|
|
|
1661
1726
|
this.verificationTable = options?.verificationTable;
|
|
1662
1727
|
this.writeBufferSize = options?.writeBufferSize;
|
|
1663
1728
|
this.writeKey = writeKey;
|
|
1729
|
+
this.#columnFamilyOptions = options ? { ...options } : void 0;
|
|
1730
|
+
}
|
|
1731
|
+
/**
|
|
1732
|
+
* Creates an independent `Store` for another column family of the same
|
|
1733
|
+
* database, used by {@link RocksDatabase#use}. The returned store shares the
|
|
1734
|
+
* underlying database but must have its own codec state: a mutable
|
|
1735
|
+
* encoder/decoder instance cannot be shared across column families (opening a
|
|
1736
|
+
* view mutates the encoder's `name`, and clearing a view resets its
|
|
1737
|
+
* `structures`), so a pre-constructed instance is rejected here — supply an
|
|
1738
|
+
* encoder factory (`{ Encoder }`) or a named `encoding` instead.
|
|
1739
|
+
*
|
|
1740
|
+
* Override this in a `Store` subclass whose constructor cannot be recreated
|
|
1741
|
+
* from `(path, options)` (e.g. it takes injected dependencies) or that needs
|
|
1742
|
+
* to control how a view's codec state is built.
|
|
1743
|
+
*
|
|
1744
|
+
* @param name - The column family name for the derived store.
|
|
1745
|
+
* @param options - Options overriding this store's, for the derived store.
|
|
1746
|
+
* @returns A new, independent `Store` bound to `name`.
|
|
1747
|
+
*/
|
|
1748
|
+
createColumnFamilyStore(name, options) {
|
|
1749
|
+
const derived = {
|
|
1750
|
+
...this.#columnFamilyOptions,
|
|
1751
|
+
...options,
|
|
1752
|
+
name
|
|
1753
|
+
};
|
|
1754
|
+
if (sharesMutableCodec(derived.encoder) || sharesMutableCodec(derived.decoder)) throw new Error("Cannot derive a column family view from a Store configured with a pre-constructed encoder/decoder instance — its mutable state would be shared across column families. Provide an encoder factory (`{ Encoder }`) or a named `encoding`, or override `Store#createColumnFamilyStore`.");
|
|
1755
|
+
const StoreClass = this.constructor;
|
|
1756
|
+
const store = new StoreClass(this.path, derived);
|
|
1757
|
+
if (store.name !== name) throw new Error(`Store#createColumnFamilyStore produced a store bound to "${store.name}" instead of "${name}"; a custom Store must forward options to super() or override this method.`);
|
|
1758
|
+
return store;
|
|
1664
1759
|
}
|
|
1665
1760
|
/**
|
|
1666
1761
|
* Closes the database.
|
|
@@ -1842,6 +1937,7 @@ var Store = class {
|
|
|
1842
1937
|
let endUnencoded = options?.key ?? options?.end;
|
|
1843
1938
|
const includeValues = options?.values ?? true;
|
|
1844
1939
|
const reverse = options?.reverse ?? false;
|
|
1940
|
+
const txnId = this.getTxnId(options);
|
|
1845
1941
|
let exclusiveStart = options?.exclusiveStart ?? false;
|
|
1846
1942
|
let inclusiveEnd = options?.inclusiveEnd ?? false;
|
|
1847
1943
|
if (options?.key !== void 0) inclusiveEnd = true;
|
|
@@ -1860,13 +1956,15 @@ var Store = class {
|
|
|
1860
1956
|
startKeyEnd = this.writeKey(startUnencoded, keyBuffer, 0);
|
|
1861
1957
|
if (startKeyEnd === 0) throw new Error("Zero length key is not allowed");
|
|
1862
1958
|
}
|
|
1863
|
-
if (endUnencoded !== void 0)
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1959
|
+
if (endUnencoded !== void 0) {
|
|
1960
|
+
if (endUnencoded === startUnencoded) {
|
|
1961
|
+
endKeyStart = 0;
|
|
1962
|
+
endKeyEnd = startKeyEnd;
|
|
1963
|
+
} else {
|
|
1964
|
+
endKeyStart = startKeyEnd;
|
|
1965
|
+
endKeyEnd = this.writeKey(endUnencoded, keyBuffer, endKeyStart);
|
|
1966
|
+
if (endKeyEnd === endKeyStart) throw new Error("Zero length key is not allowed");
|
|
1967
|
+
}
|
|
1870
1968
|
}
|
|
1871
1969
|
let flags = 0;
|
|
1872
1970
|
if (reverse) flags |= ITERATOR_REVERSE_FLAG;
|
|
@@ -1875,8 +1973,9 @@ var Store = class {
|
|
|
1875
1973
|
if (includeValues) flags |= ITERATOR_INCLUDE_VALUES_FLAG;
|
|
1876
1974
|
if (includeValues && !this.decoderCopies) flags |= ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG;
|
|
1877
1975
|
if (context !== this.db) flags |= ITERATOR_CONTEXT_IS_TRANSACTION_FLAG;
|
|
1976
|
+
if (txnId !== void 0) flags |= ITERATOR_HAS_TRANSACTION_ID_FLAG;
|
|
1878
1977
|
const advancedOptions = options !== void 0 && (options.adaptiveReadahead !== void 0 || options.asyncIO !== void 0 || options.autoReadaheadSize !== void 0 || options.backgroundPurgeOnIteratorCleanup !== void 0 || options.fillCache !== void 0 || options.readaheadSize !== void 0 || options.tailing !== void 0) ? options : void 0;
|
|
1879
|
-
return new ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions), this, includeValues, options?.limit));
|
|
1978
|
+
return new ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions, txnId), this, includeValues, options?.limit));
|
|
1880
1979
|
}
|
|
1881
1980
|
getSync(context, key, alwaysCreateNewBuffer = false, options) {
|
|
1882
1981
|
const keyParam = getKeyParam(this.encodeKey(key));
|
|
@@ -1897,9 +1996,12 @@ var Store = class {
|
|
|
1897
1996
|
*/
|
|
1898
1997
|
getTxnId(options) {
|
|
1899
1998
|
let txnId;
|
|
1900
|
-
|
|
1901
|
-
|
|
1999
|
+
const transaction = options?.transaction;
|
|
2000
|
+
if (!this.readOnly && transaction) {
|
|
2001
|
+
txnId = transaction.id;
|
|
1902
2002
|
if (txnId === void 0) throw new TypeError("Invalid transaction");
|
|
2003
|
+
if (transaction.store === void 0) throw new TypeError("Invalid transaction");
|
|
2004
|
+
if (this.identityPath !== void 0 && transaction.store.identityPath !== this.identityPath) throw new TypeError("Transaction belongs to a different database");
|
|
1903
2005
|
}
|
|
1904
2006
|
return txnId;
|
|
1905
2007
|
}
|
|
@@ -1957,7 +2059,10 @@ var Store = class {
|
|
|
1957
2059
|
* are performed.
|
|
1958
2060
|
*/
|
|
1959
2061
|
open() {
|
|
1960
|
-
if (this.db.opened)
|
|
2062
|
+
if (this.db.opened) {
|
|
2063
|
+
this.identityPath = this.db.identityPath;
|
|
2064
|
+
return true;
|
|
2065
|
+
}
|
|
1961
2066
|
const { compression, compressionLevel } = normalizeCompression(this.compression);
|
|
1962
2067
|
this.db.open(this.path, {
|
|
1963
2068
|
compression,
|
|
@@ -1976,6 +2081,7 @@ var Store = class {
|
|
|
1976
2081
|
noBlockCache: this.noBlockCache,
|
|
1977
2082
|
parallelismThreads: this.parallelismThreads,
|
|
1978
2083
|
readOnly: this.readOnly,
|
|
2084
|
+
secondaryPath: this.secondaryPath,
|
|
1979
2085
|
statsLevel: this.statsLevel,
|
|
1980
2086
|
transactionLogMaxAgeThreshold: this.transactionLogMaxAgeThreshold,
|
|
1981
2087
|
transactionLogMaxSize: this.transactionLogMaxSize,
|
|
@@ -1984,6 +2090,7 @@ var Store = class {
|
|
|
1984
2090
|
verificationTable: this.verificationTable,
|
|
1985
2091
|
writeBufferSize: this.writeBufferSize
|
|
1986
2092
|
});
|
|
2093
|
+
this.identityPath = this.db.identityPath;
|
|
1987
2094
|
return false;
|
|
1988
2095
|
}
|
|
1989
2096
|
putSync(context, key, value, options) {
|
|
@@ -2244,10 +2351,12 @@ var Transaction = class extends DBI {
|
|
|
2244
2351
|
return err;
|
|
2245
2352
|
}
|
|
2246
2353
|
/**
|
|
2247
|
-
* Returns the transaction
|
|
2248
|
-
* the transaction
|
|
2354
|
+
* Returns the transaction timestamp in milliseconds since the Unix epoch. It
|
|
2355
|
+
* defaults to a process-wide monotonic value assigned when the transaction
|
|
2356
|
+
* was created. A producer may use this value as its write identity; the
|
|
2357
|
+
* transaction log uses it as the batch key.
|
|
2249
2358
|
*
|
|
2250
|
-
* @returns The transaction
|
|
2359
|
+
* @returns The transaction timestamp in milliseconds.
|
|
2251
2360
|
*/
|
|
2252
2361
|
getTimestamp() {
|
|
2253
2362
|
return this.#txn.getTimestamp();
|
|
@@ -2259,9 +2368,14 @@ var Transaction = class extends DBI {
|
|
|
2259
2368
|
return this.#txn.id;
|
|
2260
2369
|
}
|
|
2261
2370
|
/**
|
|
2262
|
-
*
|
|
2371
|
+
* Overrides the transaction timestamp in milliseconds since the Unix epoch.
|
|
2372
|
+
* Call this before reading the timestamp or staging writes when adopting an
|
|
2373
|
+
* origin timestamp for replication or replay. Once a write or log entry is
|
|
2374
|
+
* staged, the timestamp is frozen, but reapplying the same timestamp remains
|
|
2375
|
+
* idempotent while the transaction is pending. The value must be finite,
|
|
2376
|
+
* positive, and below 8640000000000000.
|
|
2263
2377
|
*
|
|
2264
|
-
* @param timestamp - The timestamp to set in
|
|
2378
|
+
* @param timestamp - The timestamp to set in milliseconds.
|
|
2265
2379
|
*/
|
|
2266
2380
|
setTimestamp(timestamp) {
|
|
2267
2381
|
this.#txn.setTimestamp(timestamp);
|
|
@@ -2295,9 +2409,23 @@ function backgroundErrorSeverityName(severity) {
|
|
|
2295
2409
|
*/
|
|
2296
2410
|
var RocksDatabase = class RocksDatabase extends DBI {
|
|
2297
2411
|
/**
|
|
2298
|
-
* The name of the database.
|
|
2412
|
+
* The name of the database's column family.
|
|
2299
2413
|
*/
|
|
2300
2414
|
#name;
|
|
2415
|
+
/**
|
|
2416
|
+
* Weak cache of column-family views opened via `use()`, keyed by column
|
|
2417
|
+
* family name — mirroring `useLog`'s get-or-create semantics. The reference
|
|
2418
|
+
* is weak so a view is never pinned for this database's lifetime: an
|
|
2419
|
+
* unreferenced view can be collected (closing its own `DBHandle`), and the
|
|
2420
|
+
* next `use()` transparently recreates it. `#columnFamilyRegistry` deletes an
|
|
2421
|
+
* entry once its view is collected so a churn of distinct names (e.g.
|
|
2422
|
+
* `use(uuid())`) does not grow the map without bound.
|
|
2423
|
+
*/
|
|
2424
|
+
#columnFamilies = /* @__PURE__ */ new Map();
|
|
2425
|
+
#columnFamilyRegistry = new FinalizationRegistry((name) => {
|
|
2426
|
+
const ref = this.#columnFamilies.get(name);
|
|
2427
|
+
if (ref !== void 0 && ref.deref() === void 0) this.#columnFamilies.delete(name);
|
|
2428
|
+
});
|
|
2301
2429
|
constructor(pathOrStore, options) {
|
|
2302
2430
|
let store;
|
|
2303
2431
|
if (typeof pathOrStore === "string") store = new Store(pathOrStore, options);
|
|
@@ -2305,7 +2433,7 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2305
2433
|
else throw new TypeError("Invalid database path or store");
|
|
2306
2434
|
store.claim();
|
|
2307
2435
|
super(store);
|
|
2308
|
-
this.#name =
|
|
2436
|
+
this.#name = this.store.name;
|
|
2309
2437
|
}
|
|
2310
2438
|
/**
|
|
2311
2439
|
* Removes all data from the database asynchronously.
|
|
@@ -2524,6 +2652,40 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2524
2652
|
static notify(event, ...args) {
|
|
2525
2653
|
return globalNotify(event, args);
|
|
2526
2654
|
}
|
|
2655
|
+
/**
|
|
2656
|
+
* Advances a secondary instance to the primary's current state by tailing
|
|
2657
|
+
* and replaying the primary's MANIFEST and WAL. A secondary does not see
|
|
2658
|
+
* the primary's writes until this (or {@link catchUpWithPrimarySync}) is
|
|
2659
|
+
* called. Concurrent reads through this handle remain safe while the
|
|
2660
|
+
* catch-up runs.
|
|
2661
|
+
*
|
|
2662
|
+
* Only valid on a database opened with the `secondaryPath` option; throws
|
|
2663
|
+
* with code `ERR_NOT_SECONDARY` otherwise.
|
|
2664
|
+
*
|
|
2665
|
+
* Advances the **database** view only. Against a cross-process primary,
|
|
2666
|
+
* transaction-log reads keep serving the stores discovered at open (a store
|
|
2667
|
+
* the primary creates later, and its appends, need a reopen); a primary in
|
|
2668
|
+
* the same process shares the store registry, so its stores and appends are
|
|
2669
|
+
* visible immediately. Either way a log entry can describe data this
|
|
2670
|
+
* handle's database view does not have yet — the log write completes before
|
|
2671
|
+
* the RocksDB commit for every writer, so consumers must tolerate the log
|
|
2672
|
+
* leading the database.
|
|
2673
|
+
*
|
|
2674
|
+
* Await one call before starting the next: the replay holds a libuv worker
|
|
2675
|
+
* for its whole duration and concurrent calls queue on a per-database mutex
|
|
2676
|
+
* while holding theirs, so overlapping catch-ups on a backlogged follower
|
|
2677
|
+
* can exhaust the default four-thread pool and stall unrelated I/O.
|
|
2678
|
+
*/
|
|
2679
|
+
catchUpWithPrimary() {
|
|
2680
|
+
return new Promise((resolve, reject) => this.store.db.catchUpWithPrimary(resolve, reject));
|
|
2681
|
+
}
|
|
2682
|
+
/**
|
|
2683
|
+
* Synchronous version of {@link catchUpWithPrimary}. The replay runs on the
|
|
2684
|
+
* JS thread, so prefer the async form unless the caller is already blocking.
|
|
2685
|
+
*/
|
|
2686
|
+
catchUpWithPrimarySync() {
|
|
2687
|
+
this.store.db.catchUpWithPrimarySync();
|
|
2688
|
+
}
|
|
2527
2689
|
destroy() {
|
|
2528
2690
|
this.store.db.destroy();
|
|
2529
2691
|
}
|
|
@@ -2676,6 +2838,29 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2676
2838
|
return this.store.db.getDBProperty(propertyName);
|
|
2677
2839
|
}
|
|
2678
2840
|
/**
|
|
2841
|
+
* Whether RocksDB is currently applying write backpressure to this database —
|
|
2842
|
+
* either delaying (rate-limiting) or fully stopping writes. This is the
|
|
2843
|
+
* authoritative, live pull counterpart to the `'writeStall'`
|
|
2844
|
+
* [event](../README.md#event-writestall): the event pushes per-column-family
|
|
2845
|
+
* transitions (and is rate-limited), while this reads the current state on
|
|
2846
|
+
* demand and can never be stale.
|
|
2847
|
+
*
|
|
2848
|
+
* The write controller is database-wide (shared across every column family),
|
|
2849
|
+
* so this reflects the database as a whole, not a single column family — a
|
|
2850
|
+
* stall triggered by any column family stops writes for all of them. Reads
|
|
2851
|
+
* `rocksdb.is-write-stopped` and `rocksdb.actual-delayed-write-rate`.
|
|
2852
|
+
*
|
|
2853
|
+
* @example
|
|
2854
|
+
* ```typescript
|
|
2855
|
+
* db.on('writeStall', (cf) => {
|
|
2856
|
+
* if (db.isWriteStalled()) log.warn(`writes throttled/blocked (triggered by ${cf})`);
|
|
2857
|
+
* });
|
|
2858
|
+
* ```
|
|
2859
|
+
*/
|
|
2860
|
+
isWriteStalled() {
|
|
2861
|
+
return this.getDBIntProperty("rocksdb.is-write-stopped") === 1 || (this.getDBIntProperty("rocksdb.actual-delayed-write-rate") ?? 0) > 0;
|
|
2862
|
+
}
|
|
2863
|
+
/**
|
|
2679
2864
|
* Retrieves the estimated number of keys in the database. This is an alias
|
|
2680
2865
|
* for `db.estimateCount().count`; use `estimateCount()` for range support
|
|
2681
2866
|
* and a confidence indicator.
|
|
@@ -2853,18 +3038,29 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2853
3038
|
return this.store.listLogs();
|
|
2854
3039
|
}
|
|
2855
3040
|
/**
|
|
2856
|
-
* The name of the database.
|
|
3041
|
+
* The name of the database's column family.
|
|
2857
3042
|
*/
|
|
2858
3043
|
get name() {
|
|
2859
3044
|
return this.#name;
|
|
2860
3045
|
}
|
|
2861
3046
|
/**
|
|
2862
|
-
* Whether the database is open in readonly mode.
|
|
3047
|
+
* Whether the database is open in readonly mode. Also `true` for a
|
|
3048
|
+
* secondary instance (see {@link secondaryPath}), which is read-only by
|
|
3049
|
+
* construction.
|
|
2863
3050
|
*/
|
|
2864
3051
|
get readOnly() {
|
|
2865
3052
|
return this.store.readOnly;
|
|
2866
3053
|
}
|
|
2867
3054
|
/**
|
|
3055
|
+
* The secondary instance's workspace directory when the database was opened
|
|
3056
|
+
* as a secondary (a read-only follower of a live primary — see the
|
|
3057
|
+
* `secondaryPath` open option), or `undefined` for a regular or plain
|
|
3058
|
+
* read-only open.
|
|
3059
|
+
*/
|
|
3060
|
+
get secondaryPath() {
|
|
3061
|
+
return this.store.secondaryPath;
|
|
3062
|
+
}
|
|
3063
|
+
/**
|
|
2868
3064
|
* Sugar method for opening a database.
|
|
2869
3065
|
*
|
|
2870
3066
|
* @param pathOrStore - The filesystem path to the database or a custom store.
|
|
@@ -3137,6 +3333,57 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
3137
3333
|
return this.store.unlock(key);
|
|
3138
3334
|
}
|
|
3139
3335
|
/**
|
|
3336
|
+
* Returns a `RocksDatabase` bound to the `name` column family of this same
|
|
3337
|
+
* database, opening (and creating, if missing) the column family on first
|
|
3338
|
+
* use. This is a factory — create-and-open sugar — not a stateful switch: the
|
|
3339
|
+
* returned view is an independent instance whose own reads/writes target its
|
|
3340
|
+
* column family, while sharing the underlying database (so a transaction,
|
|
3341
|
+
* backup, or checkpoint still spans every column family). Because the view
|
|
3342
|
+
* opens its own handle, this database need not itself be open — a discarded
|
|
3343
|
+
* parent (`new RocksDatabase(path).use('events')`) still yields a valid,
|
|
3344
|
+
* opened view.
|
|
3345
|
+
*
|
|
3346
|
+
* Get-or-create, backed by a weak cache: `db.use('events') === db.use('events')`
|
|
3347
|
+
* while the view is still referenced **and open**, and calling with this
|
|
3348
|
+
* database's own column-family name returns `this`. A view that has been
|
|
3349
|
+
* closed (or garbage-collected — the cache does not pin it) is transparently
|
|
3350
|
+
* recreated on the next `use()`. Views are independent handles: closing this
|
|
3351
|
+
* database does not close them, and vice versa — the underlying database
|
|
3352
|
+
* stays open until every handle is closed or collected.
|
|
3353
|
+
*
|
|
3354
|
+
* The view's store is derived by {@link Store#createColumnFamilyStore}, which
|
|
3355
|
+
* builds an independent store of the same class with its own codec state (so
|
|
3356
|
+
* views never share a mutable encoder/decoder) and inherits the options this
|
|
3357
|
+
* store was constructed with; pass `options` to override them for this column
|
|
3358
|
+
* family. A database configured with a pre-constructed encoder/decoder
|
|
3359
|
+
* instance cannot derive views (its state would be shared) — use an encoder
|
|
3360
|
+
* factory (`{ Encoder }`) or a named `encoding`, or override
|
|
3361
|
+
* `createColumnFamilyStore` on a custom `Store`.
|
|
3362
|
+
*
|
|
3363
|
+
* @param name - The column family name.
|
|
3364
|
+
* @param options - Options for the column family, overriding inherited ones.
|
|
3365
|
+
* @returns A `RocksDatabase` bound to the column family.
|
|
3366
|
+
*
|
|
3367
|
+
* @example
|
|
3368
|
+
* ```typescript
|
|
3369
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
3370
|
+
* const events = db.use('events');
|
|
3371
|
+
* await events.put('e1', payload);
|
|
3372
|
+
* await db.put('k', 'v'); // default column family, unaffected
|
|
3373
|
+
* ```
|
|
3374
|
+
*/
|
|
3375
|
+
use(name, options) {
|
|
3376
|
+
if (typeof name !== "string" || name === "") throw new TypeError("Column family name must be a non-empty string");
|
|
3377
|
+
if (name === this.#name) return this.open();
|
|
3378
|
+
const cached = this.#columnFamilies.get(name)?.deref();
|
|
3379
|
+
if (cached !== void 0 && cached.isOpen()) return cached;
|
|
3380
|
+
const columnFamily = new RocksDatabase(this.store.createColumnFamilyStore(name, options));
|
|
3381
|
+
columnFamily.open();
|
|
3382
|
+
this.#columnFamilies.set(name, new WeakRef(columnFamily));
|
|
3383
|
+
this.#columnFamilyRegistry.register(columnFamily, name);
|
|
3384
|
+
return columnFamily;
|
|
3385
|
+
}
|
|
3386
|
+
/**
|
|
3140
3387
|
* Excecutes a function using a thread-safe lock to ensure mutual
|
|
3141
3388
|
* exclusion.
|
|
3142
3389
|
*
|
|
@@ -3443,11 +3690,12 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
|
|
|
3443
3690
|
position += TRANSACTION_LOG_ENTRY_HEADER_SIZE;
|
|
3444
3691
|
let matchesRange;
|
|
3445
3692
|
if (foundExactStart) matchesRange = (!exclusiveStart || timestamp !== start) && timestamp < end;
|
|
3446
|
-
else if (exactStart)
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3693
|
+
else if (exactStart) {
|
|
3694
|
+
if (timestamp === start) {
|
|
3695
|
+
matchesRange = !exclusiveStart;
|
|
3696
|
+
foundExactStart = true;
|
|
3697
|
+
} else matchesRange = false;
|
|
3698
|
+
} else matchesRange = (exclusiveStart ? timestamp > start : timestamp >= start) && timestamp < end;
|
|
3451
3699
|
const entryStart = position;
|
|
3452
3700
|
position += length;
|
|
3453
3701
|
if (matchesRange) return {
|
|
@@ -3530,9 +3778,9 @@ function loadLastPosition(transactionLog, readUncommitted) {
|
|
|
3530
3778
|
//#region src/index.ts
|
|
3531
3779
|
const versions = {
|
|
3532
3780
|
rocksdb: version,
|
|
3533
|
-
"rocksdb-js": "2.
|
|
3781
|
+
"rocksdb-js": "2.9.1"
|
|
3534
3782
|
};
|
|
3535
3783
|
|
|
3536
3784
|
//#endregion
|
|
3537
|
-
export { BackgroundError, CorruptFrameError, CountEstimator, DBI, DBIterator, RocksDatabase, Store, Transaction, TransactionLog, backups, constants, coolTransactionLogs, currentThreadId, fileLockRelease, parseTransactionLog, registryStatus, shutdown, stats, supportedCompression, tryFileLock, validateTransactionLogStore, versions };
|
|
3785
|
+
export { BackgroundError, CorruptFrameError, CountEstimator, DBI, DBIterator, RocksDatabase, Store, Transaction, TransactionLog, backups, constants, coolTransactionLogs, currentThreadId, fileLockRelease, getWriteBufferManagerStats, parseTransactionLog, registryStatus, shutdown, stats, supportedCompression, tryFileLock, validateTransactionLogStore, versions };
|
|
3538
3786
|
//# sourceMappingURL=index.mjs.map
|