@harperfast/rocksdb-js 1.4.1 → 1.5.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 +26 -1
- package/dist/index.cjs +80 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -0
- package/dist/index.d.mts +42 -0
- package/dist/index.mjs +80 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -668,12 +668,25 @@ complete, use the `'aftercommit'` event.
|
|
|
668
668
|
## Event API
|
|
669
669
|
|
|
670
670
|
`rocksdb-js` provides a EventEmitter-like API that lets you asynchronously notify events to one or
|
|
671
|
-
more synchronous listener callbacks.
|
|
671
|
+
more synchronous listener callbacks. There are two types of events:
|
|
672
|
+
|
|
673
|
+
- Per-database events: scoped by database path.
|
|
674
|
+
- Process-global events: not scoped by database path.
|
|
672
675
|
|
|
673
676
|
Unlike `EventEmitter`, events are emitted asynchronously, but in the same order that the listeners
|
|
674
677
|
were added.
|
|
675
678
|
|
|
676
679
|
```typescript
|
|
680
|
+
// Process-global events
|
|
681
|
+
RocksDatabase.on('log.warn', console.warn);
|
|
682
|
+
|
|
683
|
+
RocksDatabase.on('foo', (...args) => {
|
|
684
|
+
console.log(args);
|
|
685
|
+
});
|
|
686
|
+
RocksDatabase.notify('foo', 'bar');
|
|
687
|
+
RocksDatabase.off('foo', callback);
|
|
688
|
+
|
|
689
|
+
// Per-database events
|
|
677
690
|
const callback = (name) => console.log(`Hi from ${name}`);
|
|
678
691
|
db.addListener('foo', callback);
|
|
679
692
|
db.notify('foo');
|
|
@@ -1103,6 +1116,18 @@ for (const entry of rangeIter) {
|
|
|
1103
1116
|
Returns the size of the given transaction log sequence file in bytes. Omit the sequence number to
|
|
1104
1117
|
get the total size of all the transaction log sequence files for this log.
|
|
1105
1118
|
|
|
1119
|
+
### Transaction Log Initialization
|
|
1120
|
+
|
|
1121
|
+
When a database is opened, `rocksdb-js` will automatically discover the transaction log files. If
|
|
1122
|
+
a corrupt transaction log file is detected, the `log.warn` event is emitted on the global
|
|
1123
|
+
`RocksDatabase` instance. This should be wired up prior to opening the database.
|
|
1124
|
+
|
|
1125
|
+
```typescript
|
|
1126
|
+
RocksDatabase.on('log.warn', console.warn);
|
|
1127
|
+
|
|
1128
|
+
const db = RocksDatabase.open('path/to/db');
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1106
1131
|
### Transaction Log Parser
|
|
1107
1132
|
|
|
1108
1133
|
#### `parseTransactionLog(file)`
|
package/dist/index.cjs
CHANGED
|
@@ -80,6 +80,10 @@ function locateBinding() {
|
|
|
80
80
|
}
|
|
81
81
|
const binding = req(locateBinding());
|
|
82
82
|
const config = binding.config;
|
|
83
|
+
const addGlobalListener = binding.addListener;
|
|
84
|
+
const removeGlobalListener = binding.removeListener;
|
|
85
|
+
const globalListenerCount = binding.listenerCount;
|
|
86
|
+
const globalNotify = binding.notify;
|
|
83
87
|
const constants = binding.constants;
|
|
84
88
|
const NativeDatabase = binding.Database;
|
|
85
89
|
const NativeIterator = binding.Iterator;
|
|
@@ -1386,6 +1390,60 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1386
1390
|
static config(options) {
|
|
1387
1391
|
config(options);
|
|
1388
1392
|
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Registers a process-wide event listener. Internal events emitted by the
|
|
1395
|
+
* native binding use namespaced keys (e.g. `'transactionLog:warning'`).
|
|
1396
|
+
*
|
|
1397
|
+
* Listeners are not tied to any specific database — they fire for every
|
|
1398
|
+
* matching event emitted in this process.
|
|
1399
|
+
*
|
|
1400
|
+
* @example
|
|
1401
|
+
* ```typescript
|
|
1402
|
+
* RocksDatabase.on('transactionLog:warning', (warning) => {
|
|
1403
|
+
* console.warn(warning);
|
|
1404
|
+
* });
|
|
1405
|
+
* ```
|
|
1406
|
+
*/
|
|
1407
|
+
static on(event, callback) {
|
|
1408
|
+
addGlobalListener(event, callback);
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* Alias for {@link RocksDatabase.on}, mirroring the Node `EventEmitter` API.
|
|
1412
|
+
*/
|
|
1413
|
+
static addListener(event, callback) {
|
|
1414
|
+
addGlobalListener(event, callback);
|
|
1415
|
+
}
|
|
1416
|
+
/**
|
|
1417
|
+
* Removes a previously-registered process-wide event listener. The
|
|
1418
|
+
* callback identity must match the one passed to {@link RocksDatabase.on}.
|
|
1419
|
+
*
|
|
1420
|
+
* @returns `true` if a matching listener was removed.
|
|
1421
|
+
*/
|
|
1422
|
+
static off(event, callback) {
|
|
1423
|
+
return removeGlobalListener(event, callback);
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* Alias for {@link RocksDatabase.off}, mirroring the Node `EventEmitter` API.
|
|
1427
|
+
*/
|
|
1428
|
+
static removeListener(event, callback) {
|
|
1429
|
+
return removeGlobalListener(event, callback);
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Returns the number of process-wide listeners registered for the given event.
|
|
1433
|
+
*/
|
|
1434
|
+
static listenerCount(event) {
|
|
1435
|
+
return globalListenerCount(event);
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Emits a process-wide event. Mostly intended for tests and as a peer to
|
|
1439
|
+
* {@link RocksDatabase.on} — native code should call `emitGlobalEvent` in
|
|
1440
|
+
* `napi/global_events.h` directly rather than round-tripping through JS.
|
|
1441
|
+
*
|
|
1442
|
+
* @returns `true` if there was at least one listener.
|
|
1443
|
+
*/
|
|
1444
|
+
static notify(event, ...args) {
|
|
1445
|
+
return globalNotify(event, args);
|
|
1446
|
+
}
|
|
1389
1447
|
destroy() {
|
|
1390
1448
|
this.store.db.destroy();
|
|
1391
1449
|
}
|
|
@@ -1859,7 +1917,7 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1859
1917
|
|
|
1860
1918
|
//#endregion
|
|
1861
1919
|
//#region src/parse-transaction-log.ts
|
|
1862
|
-
const { TRANSACTION_LOG_TOKEN } = constants;
|
|
1920
|
+
const { TRANSACTION_LOG_TOKEN, TRANSACTION_LOG_ENTRY_HEADER_SIZE: TRANSACTION_LOG_ENTRY_HEADER_SIZE$1 } = constants;
|
|
1863
1921
|
const MIN_VALID_TIMESTAMP = Date.UTC(2026, 0, 27);
|
|
1864
1922
|
const VALID_FLAGS_MASK = 1;
|
|
1865
1923
|
/**
|
|
@@ -1883,7 +1941,11 @@ function parseTransactionLog(path, options = {}) {
|
|
|
1883
1941
|
const buffer = Buffer.allocUnsafe(numBytes);
|
|
1884
1942
|
const bytesRead = (0, node_fs.readSync)(fileHandle, buffer, 0, numBytes, fileOffset);
|
|
1885
1943
|
fileOffset += bytesRead;
|
|
1886
|
-
if (bytesRead !== numBytes)
|
|
1944
|
+
if (bytesRead !== numBytes) {
|
|
1945
|
+
const previewBytes = Math.min(bytesRead, 64);
|
|
1946
|
+
const preview = buffer.subarray(0, previewBytes).toString("hex");
|
|
1947
|
+
throw new Error(`Expected to read ${numBytes} bytes but only read ${bytesRead}, file offset: ${fileOffset.toString(16)}, file size: ${size}, file path: ${path}, buffer (first ${previewBytes} bytes): ${preview}`);
|
|
1948
|
+
}
|
|
1887
1949
|
return buffer;
|
|
1888
1950
|
};
|
|
1889
1951
|
try {
|
|
@@ -1903,6 +1965,11 @@ function parseTransactionLog(path, options = {}) {
|
|
|
1903
1965
|
}
|
|
1904
1966
|
const length = read(4).readUInt32BE(0);
|
|
1905
1967
|
const flags = read(1).readUInt8(0);
|
|
1968
|
+
const remaining = size - fileOffset;
|
|
1969
|
+
if (length > remaining) {
|
|
1970
|
+
const entryOffset = fileOffset - TRANSACTION_LOG_ENTRY_HEADER_SIZE$1;
|
|
1971
|
+
throw new Error(`Corrupt entry at offset ${entryOffset.toString(16)}: declared length ${length} exceeds ${remaining} bytes remaining (file size: ${size})`);
|
|
1972
|
+
}
|
|
1906
1973
|
const data = read(length);
|
|
1907
1974
|
const entryAnomalies = [];
|
|
1908
1975
|
if (!Number.isFinite(timestamp) || timestamp < MIN_VALID_TIMESTAMP) entryAnomalies.push(`timestamp ${timestamp} predates 2026-01-27 (possible corruption)`);
|
|
@@ -2022,14 +2089,17 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
|
|
|
2022
2089
|
try {
|
|
2023
2090
|
timestamp = dataView.getFloat64(position);
|
|
2024
2091
|
} catch (error) {
|
|
2025
|
-
error.message += ` at position ${position} of log ${logBuffer.logId} (size=${size}, log buffer length=${logBuffer.length})`;
|
|
2092
|
+
error.message += ` at position ${position.toString(16)} of log ${logBuffer.logId} (size=${size}, log buffer length=${logBuffer.length})`;
|
|
2026
2093
|
throw error;
|
|
2027
2094
|
}
|
|
2028
2095
|
if (!timestamp) return {
|
|
2029
2096
|
done: true,
|
|
2030
2097
|
value: void 0
|
|
2031
2098
|
};
|
|
2099
|
+
const limit = readUncommitted ? logBuffer.length : size;
|
|
2100
|
+
if (position + TRANSACTION_LOG_ENTRY_HEADER_SIZE > limit) throw new RangeError(`Corrupt transaction log: truncated entry header at position ${position.toString(16)} of log ${logBuffer.logId} (available=${limit - position})`);
|
|
2032
2101
|
const length = dataView.getUint32(position + 8);
|
|
2102
|
+
if (position + TRANSACTION_LOG_ENTRY_HEADER_SIZE + length > limit) throw new RangeError(`Corrupt transaction log entry at position ${position.toString(16)} of log ${logBuffer.logId}: declared length ${length} overruns the log (limit=${limit})`);
|
|
2033
2103
|
position += TRANSACTION_LOG_ENTRY_HEADER_SIZE;
|
|
2034
2104
|
let matchesRange;
|
|
2035
2105
|
if (foundExactStart) matchesRange = (!exclusiveStart || timestamp !== start) && timestamp < end;
|
|
@@ -2052,7 +2122,12 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
|
|
|
2052
2122
|
const { logId: latestLogId, size: latestSize } = loadLastPosition(transactionLog, !!readUncommitted);
|
|
2053
2123
|
size = latestSize;
|
|
2054
2124
|
if (latestLogId > logBuffer.logId) {
|
|
2055
|
-
|
|
2125
|
+
const nextLogBuffer = getLogMemoryMap(transactionLog, logBuffer.logId + 1);
|
|
2126
|
+
if (!nextLogBuffer) return {
|
|
2127
|
+
done: true,
|
|
2128
|
+
value: void 0
|
|
2129
|
+
};
|
|
2130
|
+
logBuffer = nextLogBuffer;
|
|
2056
2131
|
dataView = logBuffer.dataView;
|
|
2057
2132
|
size = logBuffer.size;
|
|
2058
2133
|
if (size == void 0) {
|
|
@@ -2115,7 +2190,7 @@ function loadLastPosition(transactionLog, readUncommitted) {
|
|
|
2115
2190
|
//#region src/index.ts
|
|
2116
2191
|
const versions = {
|
|
2117
2192
|
rocksdb: version,
|
|
2118
|
-
"rocksdb-js": "1.
|
|
2193
|
+
"rocksdb-js": "1.5.0"
|
|
2119
2194
|
};
|
|
2120
2195
|
|
|
2121
2196
|
//#endregion
|