@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.cjs
CHANGED
|
@@ -20,7 +20,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
20
20
|
}
|
|
21
21
|
return to;
|
|
22
22
|
};
|
|
23
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
24
24
|
value: mod,
|
|
25
25
|
enumerable: true
|
|
26
26
|
}) : target, mod));
|
|
@@ -91,6 +91,26 @@ const binding = req(locateBinding());
|
|
|
91
91
|
*/
|
|
92
92
|
const BackgroundError = binding.BackgroundError;
|
|
93
93
|
const config = binding.config;
|
|
94
|
+
/**
|
|
95
|
+
* Reads the live state of the process-wide `WriteBufferManager`: its budget,
|
|
96
|
+
* charged memory, mutable share, stall state, and attached column-family
|
|
97
|
+
* inventory. The manager is shared by every database and worker thread in the
|
|
98
|
+
* process.
|
|
99
|
+
*
|
|
100
|
+
* A WriteBufferManager stall does not pass through RocksDB's `WriteController`,
|
|
101
|
+
* so it is not reflected by `rocksdb.stall.micros`, `db.isWriteStalled()`, or
|
|
102
|
+
* the `'writeStall'` event. Use `stallActive` to distinguish this condition from
|
|
103
|
+
* an idle database.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* const wbm = getWriteBufferManagerStats();
|
|
108
|
+
* if (wbm.stallActive) {
|
|
109
|
+
* log.warn(`writes stalled for ${wbm.stallActiveMs}ms`);
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
const getWriteBufferManagerStats = binding.getWriteBufferManagerStats;
|
|
94
114
|
const FRESH_VERSION_FLAG$1 = binding.constants.FRESH_VERSION_FLAG;
|
|
95
115
|
const addGlobalListener = binding.addListener;
|
|
96
116
|
const removeGlobalListener = binding.removeListener;
|
|
@@ -139,6 +159,8 @@ const transactionLogMapCount = binding.transactionLogMapCount;
|
|
|
139
159
|
* disarm. Used by the ERR_TRY_AGAIN retry regression test.
|
|
140
160
|
*/
|
|
141
161
|
const forceTryAgainForTesting = binding.forceTryAgainForTesting;
|
|
162
|
+
/** Delays one selected watchdog join in the concurrent-shutdown regression test. */
|
|
163
|
+
const setWriteBufferManagerJoinDelayForTesting = binding.setWriteBufferManagerJoinDelayForTesting;
|
|
142
164
|
/**
|
|
143
165
|
* Creates a native file lock using the specified file path (`flock` on POSIX,
|
|
144
166
|
* `LockFileEx` on Windows), creating the file and any missing parent
|
|
@@ -667,14 +689,12 @@ function parseDuration(duration) {
|
|
|
667
689
|
num *= 1e3;
|
|
668
690
|
break;
|
|
669
691
|
case "m":
|
|
670
|
-
num *=
|
|
692
|
+
num *= 6e4;
|
|
671
693
|
break;
|
|
672
694
|
case "h":
|
|
673
|
-
num *=
|
|
674
|
-
break;
|
|
675
|
-
case "d":
|
|
676
|
-
num *= 1e3 * 60 * 60 * 24;
|
|
695
|
+
num *= 36e5;
|
|
677
696
|
break;
|
|
697
|
+
case "d": num *= 864e5;
|
|
678
698
|
}
|
|
679
699
|
result += num;
|
|
680
700
|
}
|
|
@@ -1273,7 +1293,15 @@ var DBIterator = class {
|
|
|
1273
1293
|
this.iterator.return?.();
|
|
1274
1294
|
return DONE_RESULT;
|
|
1275
1295
|
}
|
|
1276
|
-
|
|
1296
|
+
let result;
|
|
1297
|
+
try {
|
|
1298
|
+
result = this.iterator.next();
|
|
1299
|
+
} catch (err) {
|
|
1300
|
+
try {
|
|
1301
|
+
this.iterator.return?.();
|
|
1302
|
+
} catch {}
|
|
1303
|
+
throw err;
|
|
1304
|
+
}
|
|
1277
1305
|
if (result === ITERATOR_RESULT_DONE) return DONE_RESULT;
|
|
1278
1306
|
this.#yielded++;
|
|
1279
1307
|
const includeValues = this.#includeValues;
|
|
@@ -1377,10 +1405,10 @@ function createFixedBuffer(size) {
|
|
|
1377
1405
|
|
|
1378
1406
|
//#endregion
|
|
1379
1407
|
//#region src/store.ts
|
|
1380
|
-
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;
|
|
1408
|
+
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;
|
|
1381
1409
|
const KEY_BUFFER_SIZE = 4096;
|
|
1382
1410
|
const KEY_BUFFER = createFixedBuffer(KEY_BUFFER_SIZE);
|
|
1383
|
-
const VALUE_BUFFER = createFixedBuffer(
|
|
1411
|
+
const VALUE_BUFFER = createFixedBuffer(65536);
|
|
1384
1412
|
/**
|
|
1385
1413
|
* Backing buffer for the shared iterator state. Layout (Uint32Array view):
|
|
1386
1414
|
* [0] = key length written into KEY_BUFFER by the most recent iterator step
|
|
@@ -1388,7 +1416,7 @@ const VALUE_BUFFER = createFixedBuffer(64 * 1024);
|
|
|
1388
1416
|
*/
|
|
1389
1417
|
const ITERATOR_STATE_BUFFER = Buffer.allocUnsafeSlow(8);
|
|
1390
1418
|
const ITERATOR_STATE = new Uint32Array(ITERATOR_STATE_BUFFER.buffer, ITERATOR_STATE_BUFFER.byteOffset, 2);
|
|
1391
|
-
const MAX_KEY_SIZE =
|
|
1419
|
+
const MAX_KEY_SIZE = 1048576;
|
|
1392
1420
|
const SAVE_BUFFER_SIZE = 8192;
|
|
1393
1421
|
/**
|
|
1394
1422
|
* Normalizes the public `compression` option into the primitive fields the
|
|
@@ -1423,6 +1451,15 @@ function normalizeCompression(option) {
|
|
|
1423
1451
|
};
|
|
1424
1452
|
}
|
|
1425
1453
|
/**
|
|
1454
|
+
* Whether `codec` is a pre-constructed encoder/decoder instance that `open()`
|
|
1455
|
+
* would reuse as-is (rather than instantiate fresh from an `Encoder` factory).
|
|
1456
|
+
* Such an instance carries per-column-family mutable state (its `name`, msgpack
|
|
1457
|
+
* `structures`), so it cannot be shared across column families.
|
|
1458
|
+
*/
|
|
1459
|
+
function sharesMutableCodec(codec) {
|
|
1460
|
+
return codec != null && typeof codec === "object" && typeof codec.Encoder !== "function" && (typeof codec.encode === "function" || typeof codec.decode === "function");
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1426
1463
|
* A store wraps the `NativeDatabase` binding and database settings so that a
|
|
1427
1464
|
* single database instance can be shared between the main `RocksDatabase`
|
|
1428
1465
|
* instance and the `Transaction` instance.
|
|
@@ -1441,6 +1478,13 @@ var Store = class {
|
|
|
1441
1478
|
*/
|
|
1442
1479
|
#claimed = false;
|
|
1443
1480
|
/**
|
|
1481
|
+
* Shallow snapshot of the options this store was constructed with, used by
|
|
1482
|
+
* `createColumnFamilyStore()` to derive sibling column-family stores. Snapshot
|
|
1483
|
+
* (not the caller's object) so later mutations of the caller's options don't
|
|
1484
|
+
* leak into derived views.
|
|
1485
|
+
*/
|
|
1486
|
+
#columnFamilyOptions;
|
|
1487
|
+
/**
|
|
1444
1488
|
* The database instance.
|
|
1445
1489
|
*/
|
|
1446
1490
|
db;
|
|
@@ -1535,10 +1579,16 @@ var Store = class {
|
|
|
1535
1579
|
/**
|
|
1536
1580
|
* The bytes of recent memtable history to retain in memory for transaction
|
|
1537
1581
|
* conflict checking. `-1` derives the value from
|
|
1538
|
-
* `maxWriteBufferNumber * writeBufferSize`, except
|
|
1539
|
-
* `writeBufferManager
|
|
1540
|
-
* that manager and is only trimmable down to this target, so a
|
|
1541
|
-
* budget cannot hold
|
|
1582
|
+
* `maxWriteBufferNumber * writeBufferSize`, except when a
|
|
1583
|
+
* `writeBufferManager` is configured, where it derives `1`: retained history
|
|
1584
|
+
* is charged to that manager and is only trimmable down to this target, so a
|
|
1585
|
+
* target the budget cannot hold is memory the manager never reclaims, and
|
|
1586
|
+
* stalls writes permanently when `writeBufferManagerAllowStall` is on. Any
|
|
1587
|
+
* configured manager, not only a stalling one — that flag is mutable at
|
|
1588
|
+
* runtime while this value is fixed when the family is created. `1`, not `0`, because
|
|
1589
|
+
* RocksDB's transaction wrappers rewrite a `0` target to the derived value —
|
|
1590
|
+
* so `0` asks for the largest history rather than none, and an explicit `0`
|
|
1591
|
+
* is normalized to `1` for that reason. Set a positive number to size it
|
|
1542
1592
|
* yourself against the budget and the column-family count.
|
|
1543
1593
|
*/
|
|
1544
1594
|
maxWriteBufferSizeToMaintain;
|
|
@@ -1576,6 +1626,11 @@ var Store = class {
|
|
|
1576
1626
|
*/
|
|
1577
1627
|
path;
|
|
1578
1628
|
/**
|
|
1629
|
+
* The open database's resolved filesystem identity, read once from
|
|
1630
|
+
* `NativeDatabase.identityPath`. `undefined` until opened.
|
|
1631
|
+
*/
|
|
1632
|
+
identityPath;
|
|
1633
|
+
/**
|
|
1579
1634
|
* Whether to use pessimistic locking for transactions. When `true`,
|
|
1580
1635
|
* transactions will fail as soon as a conflict is detected. When `false`,
|
|
1581
1636
|
* transactions will only fail when `commit()` is called.
|
|
@@ -1589,6 +1644,13 @@ var Store = class {
|
|
|
1589
1644
|
*/
|
|
1590
1645
|
readOnly;
|
|
1591
1646
|
/**
|
|
1647
|
+
* The secondary instance's workspace directory when the database is opened
|
|
1648
|
+
* as a secondary (see `RocksDatabaseOptions.secondaryPath`); `undefined`
|
|
1649
|
+
* otherwise. A secondary is read-only, so `readOnly` is `true` whenever
|
|
1650
|
+
* this is set.
|
|
1651
|
+
*/
|
|
1652
|
+
secondaryPath;
|
|
1653
|
+
/**
|
|
1592
1654
|
* Encoder specific flag used to signal that the encoder should use a random
|
|
1593
1655
|
* access structure.
|
|
1594
1656
|
*/
|
|
@@ -1674,7 +1736,10 @@ var Store = class {
|
|
|
1674
1736
|
this.parallelismThreads = options?.parallelismThreads;
|
|
1675
1737
|
this.path = path;
|
|
1676
1738
|
this.pessimistic = options?.pessimistic ?? false;
|
|
1677
|
-
|
|
1739
|
+
const secondaryPath = options?.secondaryPath ?? void 0;
|
|
1740
|
+
if (secondaryPath !== void 0 && options?.readOnly === false) throw new Error("A secondary open is read-only; secondaryPath cannot be combined with readOnly: false");
|
|
1741
|
+
this.readOnly = options?.readOnly ?? secondaryPath !== void 0;
|
|
1742
|
+
this.secondaryPath = secondaryPath;
|
|
1678
1743
|
this.randomAccessStructure = options?.randomAccessStructure ?? false;
|
|
1679
1744
|
this.readKey = readKey;
|
|
1680
1745
|
this.sharedStructuresKey = options?.sharedStructuresKey;
|
|
@@ -1686,6 +1751,36 @@ var Store = class {
|
|
|
1686
1751
|
this.verificationTable = options?.verificationTable;
|
|
1687
1752
|
this.writeBufferSize = options?.writeBufferSize;
|
|
1688
1753
|
this.writeKey = writeKey;
|
|
1754
|
+
this.#columnFamilyOptions = options ? { ...options } : void 0;
|
|
1755
|
+
}
|
|
1756
|
+
/**
|
|
1757
|
+
* Creates an independent `Store` for another column family of the same
|
|
1758
|
+
* database, used by {@link RocksDatabase#use}. The returned store shares the
|
|
1759
|
+
* underlying database but must have its own codec state: a mutable
|
|
1760
|
+
* encoder/decoder instance cannot be shared across column families (opening a
|
|
1761
|
+
* view mutates the encoder's `name`, and clearing a view resets its
|
|
1762
|
+
* `structures`), so a pre-constructed instance is rejected here — supply an
|
|
1763
|
+
* encoder factory (`{ Encoder }`) or a named `encoding` instead.
|
|
1764
|
+
*
|
|
1765
|
+
* Override this in a `Store` subclass whose constructor cannot be recreated
|
|
1766
|
+
* from `(path, options)` (e.g. it takes injected dependencies) or that needs
|
|
1767
|
+
* to control how a view's codec state is built.
|
|
1768
|
+
*
|
|
1769
|
+
* @param name - The column family name for the derived store.
|
|
1770
|
+
* @param options - Options overriding this store's, for the derived store.
|
|
1771
|
+
* @returns A new, independent `Store` bound to `name`.
|
|
1772
|
+
*/
|
|
1773
|
+
createColumnFamilyStore(name, options) {
|
|
1774
|
+
const derived = {
|
|
1775
|
+
...this.#columnFamilyOptions,
|
|
1776
|
+
...options,
|
|
1777
|
+
name
|
|
1778
|
+
};
|
|
1779
|
+
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`.");
|
|
1780
|
+
const StoreClass = this.constructor;
|
|
1781
|
+
const store = new StoreClass(this.path, derived);
|
|
1782
|
+
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.`);
|
|
1783
|
+
return store;
|
|
1689
1784
|
}
|
|
1690
1785
|
/**
|
|
1691
1786
|
* Closes the database.
|
|
@@ -1867,6 +1962,7 @@ var Store = class {
|
|
|
1867
1962
|
let endUnencoded = options?.key ?? options?.end;
|
|
1868
1963
|
const includeValues = options?.values ?? true;
|
|
1869
1964
|
const reverse = options?.reverse ?? false;
|
|
1965
|
+
const txnId = this.getTxnId(options);
|
|
1870
1966
|
let exclusiveStart = options?.exclusiveStart ?? false;
|
|
1871
1967
|
let inclusiveEnd = options?.inclusiveEnd ?? false;
|
|
1872
1968
|
if (options?.key !== void 0) inclusiveEnd = true;
|
|
@@ -1885,13 +1981,15 @@ var Store = class {
|
|
|
1885
1981
|
startKeyEnd = this.writeKey(startUnencoded, keyBuffer, 0);
|
|
1886
1982
|
if (startKeyEnd === 0) throw new Error("Zero length key is not allowed");
|
|
1887
1983
|
}
|
|
1888
|
-
if (endUnencoded !== void 0)
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1984
|
+
if (endUnencoded !== void 0) {
|
|
1985
|
+
if (endUnencoded === startUnencoded) {
|
|
1986
|
+
endKeyStart = 0;
|
|
1987
|
+
endKeyEnd = startKeyEnd;
|
|
1988
|
+
} else {
|
|
1989
|
+
endKeyStart = startKeyEnd;
|
|
1990
|
+
endKeyEnd = this.writeKey(endUnencoded, keyBuffer, endKeyStart);
|
|
1991
|
+
if (endKeyEnd === endKeyStart) throw new Error("Zero length key is not allowed");
|
|
1992
|
+
}
|
|
1895
1993
|
}
|
|
1896
1994
|
let flags = 0;
|
|
1897
1995
|
if (reverse) flags |= ITERATOR_REVERSE_FLAG;
|
|
@@ -1900,8 +1998,9 @@ var Store = class {
|
|
|
1900
1998
|
if (includeValues) flags |= ITERATOR_INCLUDE_VALUES_FLAG;
|
|
1901
1999
|
if (includeValues && !this.decoderCopies) flags |= ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG;
|
|
1902
2000
|
if (context !== this.db) flags |= ITERATOR_CONTEXT_IS_TRANSACTION_FLAG;
|
|
2001
|
+
if (txnId !== void 0) flags |= ITERATOR_HAS_TRANSACTION_ID_FLAG;
|
|
1903
2002
|
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;
|
|
1904
|
-
return new _harperfast_extended_iterable.ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions), this, includeValues, options?.limit));
|
|
2003
|
+
return new _harperfast_extended_iterable.ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions, txnId), this, includeValues, options?.limit));
|
|
1905
2004
|
}
|
|
1906
2005
|
getSync(context, key, alwaysCreateNewBuffer = false, options) {
|
|
1907
2006
|
const keyParam = getKeyParam(this.encodeKey(key));
|
|
@@ -1922,9 +2021,12 @@ var Store = class {
|
|
|
1922
2021
|
*/
|
|
1923
2022
|
getTxnId(options) {
|
|
1924
2023
|
let txnId;
|
|
1925
|
-
|
|
1926
|
-
|
|
2024
|
+
const transaction = options?.transaction;
|
|
2025
|
+
if (!this.readOnly && transaction) {
|
|
2026
|
+
txnId = transaction.id;
|
|
1927
2027
|
if (txnId === void 0) throw new TypeError("Invalid transaction");
|
|
2028
|
+
if (transaction.store === void 0) throw new TypeError("Invalid transaction");
|
|
2029
|
+
if (this.identityPath !== void 0 && transaction.store.identityPath !== this.identityPath) throw new TypeError("Transaction belongs to a different database");
|
|
1928
2030
|
}
|
|
1929
2031
|
return txnId;
|
|
1930
2032
|
}
|
|
@@ -1982,7 +2084,10 @@ var Store = class {
|
|
|
1982
2084
|
* are performed.
|
|
1983
2085
|
*/
|
|
1984
2086
|
open() {
|
|
1985
|
-
if (this.db.opened)
|
|
2087
|
+
if (this.db.opened) {
|
|
2088
|
+
this.identityPath = this.db.identityPath;
|
|
2089
|
+
return true;
|
|
2090
|
+
}
|
|
1986
2091
|
const { compression, compressionLevel } = normalizeCompression(this.compression);
|
|
1987
2092
|
this.db.open(this.path, {
|
|
1988
2093
|
compression,
|
|
@@ -2001,6 +2106,7 @@ var Store = class {
|
|
|
2001
2106
|
noBlockCache: this.noBlockCache,
|
|
2002
2107
|
parallelismThreads: this.parallelismThreads,
|
|
2003
2108
|
readOnly: this.readOnly,
|
|
2109
|
+
secondaryPath: this.secondaryPath,
|
|
2004
2110
|
statsLevel: this.statsLevel,
|
|
2005
2111
|
transactionLogMaxAgeThreshold: this.transactionLogMaxAgeThreshold,
|
|
2006
2112
|
transactionLogMaxSize: this.transactionLogMaxSize,
|
|
@@ -2009,6 +2115,7 @@ var Store = class {
|
|
|
2009
2115
|
verificationTable: this.verificationTable,
|
|
2010
2116
|
writeBufferSize: this.writeBufferSize
|
|
2011
2117
|
});
|
|
2118
|
+
this.identityPath = this.db.identityPath;
|
|
2012
2119
|
return false;
|
|
2013
2120
|
}
|
|
2014
2121
|
putSync(context, key, value, options) {
|
|
@@ -2269,10 +2376,12 @@ var Transaction = class extends DBI {
|
|
|
2269
2376
|
return err;
|
|
2270
2377
|
}
|
|
2271
2378
|
/**
|
|
2272
|
-
* Returns the transaction
|
|
2273
|
-
* the transaction
|
|
2379
|
+
* Returns the transaction timestamp in milliseconds since the Unix epoch. It
|
|
2380
|
+
* defaults to a process-wide monotonic value assigned when the transaction
|
|
2381
|
+
* was created. A producer may use this value as its write identity; the
|
|
2382
|
+
* transaction log uses it as the batch key.
|
|
2274
2383
|
*
|
|
2275
|
-
* @returns The transaction
|
|
2384
|
+
* @returns The transaction timestamp in milliseconds.
|
|
2276
2385
|
*/
|
|
2277
2386
|
getTimestamp() {
|
|
2278
2387
|
return this.#txn.getTimestamp();
|
|
@@ -2284,9 +2393,14 @@ var Transaction = class extends DBI {
|
|
|
2284
2393
|
return this.#txn.id;
|
|
2285
2394
|
}
|
|
2286
2395
|
/**
|
|
2287
|
-
*
|
|
2396
|
+
* Overrides the transaction timestamp in milliseconds since the Unix epoch.
|
|
2397
|
+
* Call this before reading the timestamp or staging writes when adopting an
|
|
2398
|
+
* origin timestamp for replication or replay. Once a write or log entry is
|
|
2399
|
+
* staged, the timestamp is frozen, but reapplying the same timestamp remains
|
|
2400
|
+
* idempotent while the transaction is pending. The value must be finite,
|
|
2401
|
+
* positive, and below 8640000000000000.
|
|
2288
2402
|
*
|
|
2289
|
-
* @param timestamp - The timestamp to set in
|
|
2403
|
+
* @param timestamp - The timestamp to set in milliseconds.
|
|
2290
2404
|
*/
|
|
2291
2405
|
setTimestamp(timestamp) {
|
|
2292
2406
|
this.#txn.setTimestamp(timestamp);
|
|
@@ -2320,9 +2434,23 @@ function backgroundErrorSeverityName(severity) {
|
|
|
2320
2434
|
*/
|
|
2321
2435
|
var RocksDatabase = class RocksDatabase extends DBI {
|
|
2322
2436
|
/**
|
|
2323
|
-
* The name of the database.
|
|
2437
|
+
* The name of the database's column family.
|
|
2324
2438
|
*/
|
|
2325
2439
|
#name;
|
|
2440
|
+
/**
|
|
2441
|
+
* Weak cache of column-family views opened via `use()`, keyed by column
|
|
2442
|
+
* family name — mirroring `useLog`'s get-or-create semantics. The reference
|
|
2443
|
+
* is weak so a view is never pinned for this database's lifetime: an
|
|
2444
|
+
* unreferenced view can be collected (closing its own `DBHandle`), and the
|
|
2445
|
+
* next `use()` transparently recreates it. `#columnFamilyRegistry` deletes an
|
|
2446
|
+
* entry once its view is collected so a churn of distinct names (e.g.
|
|
2447
|
+
* `use(uuid())`) does not grow the map without bound.
|
|
2448
|
+
*/
|
|
2449
|
+
#columnFamilies = /* @__PURE__ */ new Map();
|
|
2450
|
+
#columnFamilyRegistry = new FinalizationRegistry((name) => {
|
|
2451
|
+
const ref = this.#columnFamilies.get(name);
|
|
2452
|
+
if (ref !== void 0 && ref.deref() === void 0) this.#columnFamilies.delete(name);
|
|
2453
|
+
});
|
|
2326
2454
|
constructor(pathOrStore, options) {
|
|
2327
2455
|
let store;
|
|
2328
2456
|
if (typeof pathOrStore === "string") store = new Store(pathOrStore, options);
|
|
@@ -2330,7 +2458,7 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2330
2458
|
else throw new TypeError("Invalid database path or store");
|
|
2331
2459
|
store.claim();
|
|
2332
2460
|
super(store);
|
|
2333
|
-
this.#name =
|
|
2461
|
+
this.#name = this.store.name;
|
|
2334
2462
|
}
|
|
2335
2463
|
/**
|
|
2336
2464
|
* Removes all data from the database asynchronously.
|
|
@@ -2549,6 +2677,40 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2549
2677
|
static notify(event, ...args) {
|
|
2550
2678
|
return globalNotify(event, args);
|
|
2551
2679
|
}
|
|
2680
|
+
/**
|
|
2681
|
+
* Advances a secondary instance to the primary's current state by tailing
|
|
2682
|
+
* and replaying the primary's MANIFEST and WAL. A secondary does not see
|
|
2683
|
+
* the primary's writes until this (or {@link catchUpWithPrimarySync}) is
|
|
2684
|
+
* called. Concurrent reads through this handle remain safe while the
|
|
2685
|
+
* catch-up runs.
|
|
2686
|
+
*
|
|
2687
|
+
* Only valid on a database opened with the `secondaryPath` option; throws
|
|
2688
|
+
* with code `ERR_NOT_SECONDARY` otherwise.
|
|
2689
|
+
*
|
|
2690
|
+
* Advances the **database** view only. Against a cross-process primary,
|
|
2691
|
+
* transaction-log reads keep serving the stores discovered at open (a store
|
|
2692
|
+
* the primary creates later, and its appends, need a reopen); a primary in
|
|
2693
|
+
* the same process shares the store registry, so its stores and appends are
|
|
2694
|
+
* visible immediately. Either way a log entry can describe data this
|
|
2695
|
+
* handle's database view does not have yet — the log write completes before
|
|
2696
|
+
* the RocksDB commit for every writer, so consumers must tolerate the log
|
|
2697
|
+
* leading the database.
|
|
2698
|
+
*
|
|
2699
|
+
* Await one call before starting the next: the replay holds a libuv worker
|
|
2700
|
+
* for its whole duration and concurrent calls queue on a per-database mutex
|
|
2701
|
+
* while holding theirs, so overlapping catch-ups on a backlogged follower
|
|
2702
|
+
* can exhaust the default four-thread pool and stall unrelated I/O.
|
|
2703
|
+
*/
|
|
2704
|
+
catchUpWithPrimary() {
|
|
2705
|
+
return new Promise((resolve, reject) => this.store.db.catchUpWithPrimary(resolve, reject));
|
|
2706
|
+
}
|
|
2707
|
+
/**
|
|
2708
|
+
* Synchronous version of {@link catchUpWithPrimary}. The replay runs on the
|
|
2709
|
+
* JS thread, so prefer the async form unless the caller is already blocking.
|
|
2710
|
+
*/
|
|
2711
|
+
catchUpWithPrimarySync() {
|
|
2712
|
+
this.store.db.catchUpWithPrimarySync();
|
|
2713
|
+
}
|
|
2552
2714
|
destroy() {
|
|
2553
2715
|
this.store.db.destroy();
|
|
2554
2716
|
}
|
|
@@ -2701,6 +2863,29 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2701
2863
|
return this.store.db.getDBProperty(propertyName);
|
|
2702
2864
|
}
|
|
2703
2865
|
/**
|
|
2866
|
+
* Whether RocksDB is currently applying write backpressure to this database —
|
|
2867
|
+
* either delaying (rate-limiting) or fully stopping writes. This is the
|
|
2868
|
+
* authoritative, live pull counterpart to the `'writeStall'`
|
|
2869
|
+
* [event](../README.md#event-writestall): the event pushes per-column-family
|
|
2870
|
+
* transitions (and is rate-limited), while this reads the current state on
|
|
2871
|
+
* demand and can never be stale.
|
|
2872
|
+
*
|
|
2873
|
+
* The write controller is database-wide (shared across every column family),
|
|
2874
|
+
* so this reflects the database as a whole, not a single column family — a
|
|
2875
|
+
* stall triggered by any column family stops writes for all of them. Reads
|
|
2876
|
+
* `rocksdb.is-write-stopped` and `rocksdb.actual-delayed-write-rate`.
|
|
2877
|
+
*
|
|
2878
|
+
* @example
|
|
2879
|
+
* ```typescript
|
|
2880
|
+
* db.on('writeStall', (cf) => {
|
|
2881
|
+
* if (db.isWriteStalled()) log.warn(`writes throttled/blocked (triggered by ${cf})`);
|
|
2882
|
+
* });
|
|
2883
|
+
* ```
|
|
2884
|
+
*/
|
|
2885
|
+
isWriteStalled() {
|
|
2886
|
+
return this.getDBIntProperty("rocksdb.is-write-stopped") === 1 || (this.getDBIntProperty("rocksdb.actual-delayed-write-rate") ?? 0) > 0;
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2704
2889
|
* Retrieves the estimated number of keys in the database. This is an alias
|
|
2705
2890
|
* for `db.estimateCount().count`; use `estimateCount()` for range support
|
|
2706
2891
|
* and a confidence indicator.
|
|
@@ -2878,18 +3063,29 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
2878
3063
|
return this.store.listLogs();
|
|
2879
3064
|
}
|
|
2880
3065
|
/**
|
|
2881
|
-
* The name of the database.
|
|
3066
|
+
* The name of the database's column family.
|
|
2882
3067
|
*/
|
|
2883
3068
|
get name() {
|
|
2884
3069
|
return this.#name;
|
|
2885
3070
|
}
|
|
2886
3071
|
/**
|
|
2887
|
-
* Whether the database is open in readonly mode.
|
|
3072
|
+
* Whether the database is open in readonly mode. Also `true` for a
|
|
3073
|
+
* secondary instance (see {@link secondaryPath}), which is read-only by
|
|
3074
|
+
* construction.
|
|
2888
3075
|
*/
|
|
2889
3076
|
get readOnly() {
|
|
2890
3077
|
return this.store.readOnly;
|
|
2891
3078
|
}
|
|
2892
3079
|
/**
|
|
3080
|
+
* The secondary instance's workspace directory when the database was opened
|
|
3081
|
+
* as a secondary (a read-only follower of a live primary — see the
|
|
3082
|
+
* `secondaryPath` open option), or `undefined` for a regular or plain
|
|
3083
|
+
* read-only open.
|
|
3084
|
+
*/
|
|
3085
|
+
get secondaryPath() {
|
|
3086
|
+
return this.store.secondaryPath;
|
|
3087
|
+
}
|
|
3088
|
+
/**
|
|
2893
3089
|
* Sugar method for opening a database.
|
|
2894
3090
|
*
|
|
2895
3091
|
* @param pathOrStore - The filesystem path to the database or a custom store.
|
|
@@ -3162,6 +3358,57 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
3162
3358
|
return this.store.unlock(key);
|
|
3163
3359
|
}
|
|
3164
3360
|
/**
|
|
3361
|
+
* Returns a `RocksDatabase` bound to the `name` column family of this same
|
|
3362
|
+
* database, opening (and creating, if missing) the column family on first
|
|
3363
|
+
* use. This is a factory — create-and-open sugar — not a stateful switch: the
|
|
3364
|
+
* returned view is an independent instance whose own reads/writes target its
|
|
3365
|
+
* column family, while sharing the underlying database (so a transaction,
|
|
3366
|
+
* backup, or checkpoint still spans every column family). Because the view
|
|
3367
|
+
* opens its own handle, this database need not itself be open — a discarded
|
|
3368
|
+
* parent (`new RocksDatabase(path).use('events')`) still yields a valid,
|
|
3369
|
+
* opened view.
|
|
3370
|
+
*
|
|
3371
|
+
* Get-or-create, backed by a weak cache: `db.use('events') === db.use('events')`
|
|
3372
|
+
* while the view is still referenced **and open**, and calling with this
|
|
3373
|
+
* database's own column-family name returns `this`. A view that has been
|
|
3374
|
+
* closed (or garbage-collected — the cache does not pin it) is transparently
|
|
3375
|
+
* recreated on the next `use()`. Views are independent handles: closing this
|
|
3376
|
+
* database does not close them, and vice versa — the underlying database
|
|
3377
|
+
* stays open until every handle is closed or collected.
|
|
3378
|
+
*
|
|
3379
|
+
* The view's store is derived by {@link Store#createColumnFamilyStore}, which
|
|
3380
|
+
* builds an independent store of the same class with its own codec state (so
|
|
3381
|
+
* views never share a mutable encoder/decoder) and inherits the options this
|
|
3382
|
+
* store was constructed with; pass `options` to override them for this column
|
|
3383
|
+
* family. A database configured with a pre-constructed encoder/decoder
|
|
3384
|
+
* instance cannot derive views (its state would be shared) — use an encoder
|
|
3385
|
+
* factory (`{ Encoder }`) or a named `encoding`, or override
|
|
3386
|
+
* `createColumnFamilyStore` on a custom `Store`.
|
|
3387
|
+
*
|
|
3388
|
+
* @param name - The column family name.
|
|
3389
|
+
* @param options - Options for the column family, overriding inherited ones.
|
|
3390
|
+
* @returns A `RocksDatabase` bound to the column family.
|
|
3391
|
+
*
|
|
3392
|
+
* @example
|
|
3393
|
+
* ```typescript
|
|
3394
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
3395
|
+
* const events = db.use('events');
|
|
3396
|
+
* await events.put('e1', payload);
|
|
3397
|
+
* await db.put('k', 'v'); // default column family, unaffected
|
|
3398
|
+
* ```
|
|
3399
|
+
*/
|
|
3400
|
+
use(name, options) {
|
|
3401
|
+
if (typeof name !== "string" || name === "") throw new TypeError("Column family name must be a non-empty string");
|
|
3402
|
+
if (name === this.#name) return this.open();
|
|
3403
|
+
const cached = this.#columnFamilies.get(name)?.deref();
|
|
3404
|
+
if (cached !== void 0 && cached.isOpen()) return cached;
|
|
3405
|
+
const columnFamily = new RocksDatabase(this.store.createColumnFamilyStore(name, options));
|
|
3406
|
+
columnFamily.open();
|
|
3407
|
+
this.#columnFamilies.set(name, new WeakRef(columnFamily));
|
|
3408
|
+
this.#columnFamilyRegistry.register(columnFamily, name);
|
|
3409
|
+
return columnFamily;
|
|
3410
|
+
}
|
|
3411
|
+
/**
|
|
3165
3412
|
* Excecutes a function using a thread-safe lock to ensure mutual
|
|
3166
3413
|
* exclusion.
|
|
3167
3414
|
*
|
|
@@ -3468,11 +3715,12 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
|
|
|
3468
3715
|
position += TRANSACTION_LOG_ENTRY_HEADER_SIZE;
|
|
3469
3716
|
let matchesRange;
|
|
3470
3717
|
if (foundExactStart) matchesRange = (!exclusiveStart || timestamp !== start) && timestamp < end;
|
|
3471
|
-
else if (exactStart)
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3718
|
+
else if (exactStart) {
|
|
3719
|
+
if (timestamp === start) {
|
|
3720
|
+
matchesRange = !exclusiveStart;
|
|
3721
|
+
foundExactStart = true;
|
|
3722
|
+
} else matchesRange = false;
|
|
3723
|
+
} else matchesRange = (exclusiveStart ? timestamp > start : timestamp >= start) && timestamp < end;
|
|
3476
3724
|
const entryStart = position;
|
|
3477
3725
|
position += length;
|
|
3478
3726
|
if (matchesRange) return {
|
|
@@ -3555,7 +3803,7 @@ function loadLastPosition(transactionLog, readUncommitted) {
|
|
|
3555
3803
|
//#region src/index.ts
|
|
3556
3804
|
const versions = {
|
|
3557
3805
|
rocksdb: version,
|
|
3558
|
-
"rocksdb-js": "2.
|
|
3806
|
+
"rocksdb-js": "2.9.1"
|
|
3559
3807
|
};
|
|
3560
3808
|
|
|
3561
3809
|
//#endregion
|
|
@@ -3573,6 +3821,7 @@ exports.constants = constants;
|
|
|
3573
3821
|
exports.coolTransactionLogs = coolTransactionLogs;
|
|
3574
3822
|
exports.currentThreadId = currentThreadId;
|
|
3575
3823
|
exports.fileLockRelease = fileLockRelease;
|
|
3824
|
+
exports.getWriteBufferManagerStats = getWriteBufferManagerStats;
|
|
3576
3825
|
exports.parseTransactionLog = parseTransactionLog;
|
|
3577
3826
|
exports.registryStatus = registryStatus;
|
|
3578
3827
|
exports.shutdown = shutdown;
|