@harperfast/rocksdb-js 1.1.0 → 1.2.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 +114 -23
- package/bin/rocksdb-js.mjs +568 -0
- package/dist/index.cjs +179 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +138 -24
- package/dist/index.d.mts +138 -24
- package/dist/index.mjs +179 -42
- package/dist/index.mjs.map +1 -1
- package/package.json +19 -16
package/dist/index.mjs
CHANGED
|
@@ -428,42 +428,62 @@ var DBI = class DBI {
|
|
|
428
428
|
|
|
429
429
|
//#endregion
|
|
430
430
|
//#region src/dbi-iterator.ts
|
|
431
|
+
const { ITERATOR_RESULT_DONE, ITERATOR_RESULT_FAST } = constants;
|
|
432
|
+
const DONE_RESULT = Object.freeze({
|
|
433
|
+
done: true,
|
|
434
|
+
value: void 0
|
|
435
|
+
});
|
|
431
436
|
/**
|
|
432
|
-
* Wraps
|
|
433
|
-
*
|
|
437
|
+
* Wraps the `NativeIterator` C++ binding, decoding keys and values from the
|
|
438
|
+
* shared key/value buffers (fast path) or from per-iteration buffers (slow
|
|
439
|
+
* fallback path used for oversized data or stable-buffer decoders).
|
|
440
|
+
*
|
|
441
|
+
* The native `next()` returns a primitive signal (and writes lengths to the
|
|
442
|
+
* shared `ITERATOR_STATE` buffer) instead of constructing a JS result object,
|
|
443
|
+
* so this class is responsible for building the `IteratorResult`.
|
|
434
444
|
*/
|
|
435
445
|
var DBIterator = class {
|
|
436
446
|
iterator;
|
|
437
447
|
store;
|
|
438
448
|
#includeValues;
|
|
439
|
-
constructor(iterator, store,
|
|
449
|
+
constructor(iterator, store, includeValues) {
|
|
440
450
|
this.iterator = iterator;
|
|
441
451
|
this.store = store;
|
|
442
|
-
this.#includeValues =
|
|
452
|
+
this.#includeValues = includeValues;
|
|
443
453
|
}
|
|
444
454
|
[Symbol.iterator]() {
|
|
445
455
|
return this;
|
|
446
456
|
}
|
|
447
|
-
next(
|
|
457
|
+
next() {
|
|
448
458
|
const result = this.iterator.next();
|
|
449
|
-
if (result
|
|
459
|
+
if (result === ITERATOR_RESULT_DONE) return DONE_RESULT;
|
|
460
|
+
const includeValues = this.#includeValues;
|
|
450
461
|
const value = {};
|
|
451
|
-
|
|
452
|
-
|
|
462
|
+
if (result === ITERATOR_RESULT_FAST) {
|
|
463
|
+
value.key = this.store.readKey(KEY_BUFFER, 0, ITERATOR_STATE[0]);
|
|
464
|
+
if (includeValues) {
|
|
465
|
+
VALUE_BUFFER.end = ITERATOR_STATE[1];
|
|
466
|
+
value.value = this.store.decodeValue(VALUE_BUFFER);
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
const slow = result;
|
|
470
|
+
value.key = this.store.decodeKey(slow.key);
|
|
471
|
+
if (includeValues && slow.value !== void 0) value.value = this.store.decodeValue(slow.value);
|
|
472
|
+
}
|
|
453
473
|
return {
|
|
454
474
|
done: false,
|
|
455
475
|
value
|
|
456
476
|
};
|
|
457
477
|
}
|
|
458
478
|
return(value) {
|
|
459
|
-
|
|
479
|
+
this.iterator.return?.();
|
|
460
480
|
return {
|
|
461
481
|
done: true,
|
|
462
482
|
value
|
|
463
483
|
};
|
|
464
484
|
}
|
|
465
485
|
throw(err) {
|
|
466
|
-
|
|
486
|
+
this.iterator.throw?.(err);
|
|
467
487
|
throw err;
|
|
468
488
|
}
|
|
469
489
|
};
|
|
@@ -538,10 +558,17 @@ function createFixedBuffer(size) {
|
|
|
538
558
|
|
|
539
559
|
//#endregion
|
|
540
560
|
//#region src/store.ts
|
|
541
|
-
const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG } = constants;
|
|
561
|
+
const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_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;
|
|
542
562
|
const KEY_BUFFER_SIZE = 4096;
|
|
543
563
|
const KEY_BUFFER = createFixedBuffer(KEY_BUFFER_SIZE);
|
|
544
564
|
const VALUE_BUFFER = createFixedBuffer(64 * 1024);
|
|
565
|
+
/**
|
|
566
|
+
* Backing buffer for the shared iterator state. Layout (Uint32Array view):
|
|
567
|
+
* [0] = key length written into KEY_BUFFER by the most recent iterator step
|
|
568
|
+
* [1] = value length written into VALUE_BUFFER by the most recent step
|
|
569
|
+
*/
|
|
570
|
+
const ITERATOR_STATE_BUFFER = Buffer.allocUnsafeSlow(8);
|
|
571
|
+
const ITERATOR_STATE = new Uint32Array(ITERATOR_STATE_BUFFER.buffer, ITERATOR_STATE_BUFFER.byteOffset, 2);
|
|
545
572
|
const MAX_KEY_SIZE = 1024 * 1024;
|
|
546
573
|
const RESET_BUFFER_MODE = 1024;
|
|
547
574
|
const REUSE_BUFFER_MODE = 512;
|
|
@@ -720,6 +747,52 @@ var Store = class {
|
|
|
720
747
|
this.db.close();
|
|
721
748
|
}
|
|
722
749
|
/**
|
|
750
|
+
* Compacts the entire key range of the database asynchronously.
|
|
751
|
+
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* ```typescript
|
|
755
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
756
|
+
* await db.compact();
|
|
757
|
+
* ```
|
|
758
|
+
*/
|
|
759
|
+
compact(options) {
|
|
760
|
+
let startBuffer;
|
|
761
|
+
let endBuffer;
|
|
762
|
+
if (options?.start !== void 0) {
|
|
763
|
+
const start = this.encodeKey(options.start);
|
|
764
|
+
startBuffer = Buffer.from(start.subarray(start.start, start.end));
|
|
765
|
+
}
|
|
766
|
+
if (options?.end !== void 0) {
|
|
767
|
+
const end = this.encodeKey(options.end);
|
|
768
|
+
endBuffer = Buffer.from(end.subarray(end.start, end.end));
|
|
769
|
+
}
|
|
770
|
+
return new Promise((resolve, reject) => this.db.compact(resolve, reject, startBuffer, endBuffer));
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Compacts the entire key range of the database synchronously.
|
|
774
|
+
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
775
|
+
*
|
|
776
|
+
* @example
|
|
777
|
+
* ```typescript
|
|
778
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
779
|
+
* db.compactSync();
|
|
780
|
+
* ```
|
|
781
|
+
*/
|
|
782
|
+
compactSync(options) {
|
|
783
|
+
let startBuffer;
|
|
784
|
+
let endBuffer;
|
|
785
|
+
if (options?.start !== void 0) {
|
|
786
|
+
const start = this.encodeKey(options.start);
|
|
787
|
+
startBuffer = Buffer.from(start.subarray(start.start, start.end));
|
|
788
|
+
}
|
|
789
|
+
if (options?.end !== void 0) {
|
|
790
|
+
const end = this.encodeKey(options.end);
|
|
791
|
+
endBuffer = Buffer.from(end.subarray(end.start, end.end));
|
|
792
|
+
}
|
|
793
|
+
this.db.compactSync(startBuffer, endBuffer);
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
723
796
|
* Decodes a key from the database.
|
|
724
797
|
*
|
|
725
798
|
* @param key - The key to decode.
|
|
@@ -807,27 +880,45 @@ var Store = class {
|
|
|
807
880
|
}
|
|
808
881
|
getRange(context, options) {
|
|
809
882
|
if (!this.db.opened) throw new Error("Database not open");
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
883
|
+
let startUnencoded = options?.key ?? options?.start;
|
|
884
|
+
let endUnencoded = options?.key ?? options?.end;
|
|
885
|
+
const includeValues = options?.values ?? true;
|
|
886
|
+
const reverse = options?.reverse ?? false;
|
|
887
|
+
let exclusiveStart = options?.exclusiveStart ?? false;
|
|
888
|
+
let inclusiveEnd = options?.inclusiveEnd ?? false;
|
|
889
|
+
if (options?.key !== void 0) inclusiveEnd = true;
|
|
890
|
+
if (reverse) {
|
|
891
|
+
const tmp = startUnencoded;
|
|
892
|
+
startUnencoded = endUnencoded;
|
|
893
|
+
endUnencoded = tmp;
|
|
894
|
+
exclusiveStart = options?.exclusiveStart ?? true;
|
|
895
|
+
inclusiveEnd = options?.inclusiveEnd ?? true;
|
|
815
896
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
897
|
+
const keyBuffer = this.keyBuffer;
|
|
898
|
+
let startKeyEnd = 0;
|
|
899
|
+
let endKeyStart = 0;
|
|
900
|
+
let endKeyEnd = 0;
|
|
901
|
+
if (startUnencoded !== void 0) {
|
|
902
|
+
startKeyEnd = this.writeKey(startUnencoded, keyBuffer, 0);
|
|
903
|
+
if (startKeyEnd === 0) throw new Error("Zero length key is not allowed");
|
|
822
904
|
}
|
|
823
|
-
if (
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
905
|
+
if (endUnencoded !== void 0) if (endUnencoded === startUnencoded) {
|
|
906
|
+
endKeyStart = 0;
|
|
907
|
+
endKeyEnd = startKeyEnd;
|
|
908
|
+
} else {
|
|
909
|
+
endKeyStart = startKeyEnd;
|
|
910
|
+
endKeyEnd = this.writeKey(endUnencoded, keyBuffer, endKeyStart);
|
|
911
|
+
if (endKeyEnd === endKeyStart) throw new Error("Zero length key is not allowed");
|
|
829
912
|
}
|
|
830
|
-
|
|
913
|
+
let flags = 0;
|
|
914
|
+
if (reverse) flags |= ITERATOR_REVERSE_FLAG;
|
|
915
|
+
if (exclusiveStart) flags |= ITERATOR_EXCLUSIVE_START_FLAG;
|
|
916
|
+
if (inclusiveEnd) flags |= ITERATOR_INCLUSIVE_END_FLAG;
|
|
917
|
+
if (includeValues) flags |= ITERATOR_INCLUDE_VALUES_FLAG;
|
|
918
|
+
if (includeValues && !this.decoderCopies) flags |= ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG;
|
|
919
|
+
if (context !== this.db) flags |= ITERATOR_CONTEXT_IS_TRANSACTION_FLAG;
|
|
920
|
+
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;
|
|
921
|
+
return new ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions), this, includeValues));
|
|
831
922
|
}
|
|
832
923
|
getSync(context, key, alwaysCreateNewBuffer = false, options) {
|
|
833
924
|
const keyParam = getKeyParam(this.encodeKey(key));
|
|
@@ -1194,6 +1285,38 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1194
1285
|
this.store.close();
|
|
1195
1286
|
}
|
|
1196
1287
|
/**
|
|
1288
|
+
* Compacts the entire key range of the database asynchronously.
|
|
1289
|
+
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
1290
|
+
*
|
|
1291
|
+
* @example
|
|
1292
|
+
* ```typescript
|
|
1293
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
1294
|
+
* await db.compact();
|
|
1295
|
+
* ```
|
|
1296
|
+
*/
|
|
1297
|
+
compact(options) {
|
|
1298
|
+
return this.store.compact(options);
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Compacts the entire key range of the database synchronously.
|
|
1302
|
+
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
1303
|
+
*
|
|
1304
|
+
* @example
|
|
1305
|
+
* ```typescript
|
|
1306
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
1307
|
+
* db.compactSync();
|
|
1308
|
+
* ```
|
|
1309
|
+
*/
|
|
1310
|
+
compactSync(options) {
|
|
1311
|
+
return this.store.compactSync(options);
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1314
|
+
* Returns the list of column families in the RocksDB database.
|
|
1315
|
+
*/
|
|
1316
|
+
get columns() {
|
|
1317
|
+
return this.store.db.columns;
|
|
1318
|
+
}
|
|
1319
|
+
/**
|
|
1197
1320
|
* Set global database settings.
|
|
1198
1321
|
*
|
|
1199
1322
|
* @param options - The options for the database.
|
|
@@ -1269,6 +1392,19 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1269
1392
|
return this.store.db.getDBProperty(propertyName);
|
|
1270
1393
|
}
|
|
1271
1394
|
/**
|
|
1395
|
+
* Retrieves the estimated number of keys in the database.
|
|
1396
|
+
*
|
|
1397
|
+
* @example
|
|
1398
|
+
* ```typescript
|
|
1399
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
1400
|
+
* const estimated = db.getEstimatedKeyCount();
|
|
1401
|
+
* console.log(estimated);
|
|
1402
|
+
* ```
|
|
1403
|
+
*/
|
|
1404
|
+
getEstimatedKeyCount() {
|
|
1405
|
+
return this.getDBIntProperty("rocksdb.estimate-num-keys") ?? 0;
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1272
1408
|
* Returns the current timestamp as a monotonically increasing timestamp in
|
|
1273
1409
|
* milliseconds represented as a decimal number.
|
|
1274
1410
|
*
|
|
@@ -1407,6 +1543,7 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1407
1543
|
if (store.open()) return this;
|
|
1408
1544
|
store.db.setDefaultValueBuffer(VALUE_BUFFER);
|
|
1409
1545
|
store.db.setDefaultKeyBuffer(KEY_BUFFER);
|
|
1546
|
+
store.db.setIteratorState(ITERATOR_STATE_BUFFER);
|
|
1410
1547
|
/**
|
|
1411
1548
|
* The encoder initialization precedence is:
|
|
1412
1549
|
* 1. encoder.Encoder
|
|
@@ -1437,14 +1574,14 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1437
1574
|
return buffer && store.decoder?.decode ? store.decoder.decode(buffer) : void 0;
|
|
1438
1575
|
};
|
|
1439
1576
|
opts.saveStructures = (structures, isCompatible) => {
|
|
1440
|
-
return this.transactionSync((txn) => {
|
|
1577
|
+
return this.transactionSync((txn, _attempt) => {
|
|
1441
1578
|
const existingStructuresBuffer = this.getBinarySync(sharedStructuresKey);
|
|
1442
1579
|
const existingStructures = existingStructuresBuffer && store.decoder?.decode ? store.decoder.decode(existingStructuresBuffer) : void 0;
|
|
1443
1580
|
if (typeof isCompatible == "function") {
|
|
1444
1581
|
if (!isCompatible(existingStructures)) return false;
|
|
1445
1582
|
} else if (existingStructures && existingStructures.length !== isCompatible) return false;
|
|
1446
1583
|
txn.putSync(sharedStructuresKey, structures);
|
|
1447
|
-
});
|
|
1584
|
+
}, { retryOnBusy: true });
|
|
1448
1585
|
};
|
|
1449
1586
|
}
|
|
1450
1587
|
store.encoder = new EncoderClass({
|
|
@@ -1461,16 +1598,15 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1461
1598
|
};
|
|
1462
1599
|
store.decoder = store.encoder;
|
|
1463
1600
|
}
|
|
1464
|
-
if (typeof store.encoder?.writeKey === "function" && !store.encoder?.encode) {
|
|
1465
|
-
store.encoder
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
}
|
|
1601
|
+
if (typeof store.encoder?.writeKey === "function" && !store.encoder?.encode) store.encoder = {
|
|
1602
|
+
...store.encoder,
|
|
1603
|
+
encode: (value, _mode) => {
|
|
1604
|
+
const bytesWritten = store.writeKey(value, store.encodeBuffer, 0);
|
|
1605
|
+
return store.encodeBuffer.subarray(0, bytesWritten);
|
|
1606
|
+
},
|
|
1607
|
+
copyBuffers: true
|
|
1608
|
+
};
|
|
1609
|
+
if (store.encoder) store.encoder.name = this.#name;
|
|
1474
1610
|
if (store.decoder && store.decoder.needsStableBuffer !== true) store.decoderCopies = true;
|
|
1475
1611
|
if (store.decoder?.readKey && !store.decoder.decode) {
|
|
1476
1612
|
store.decoder.decode = (buffer) => {
|
|
@@ -1779,6 +1915,7 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
|
|
|
1779
1915
|
logBuffer.logId = 0;
|
|
1780
1916
|
logBuffer.size = 0;
|
|
1781
1917
|
logBuffer.dataView = new DataView(logBuffer.buffer);
|
|
1918
|
+
size = 0;
|
|
1782
1919
|
}
|
|
1783
1920
|
}
|
|
1784
1921
|
dataView = logBuffer.dataView;
|
|
@@ -1906,7 +2043,7 @@ function loadLastPosition(transactionLog, readUncommitted) {
|
|
|
1906
2043
|
//#region src/index.ts
|
|
1907
2044
|
const versions = {
|
|
1908
2045
|
rocksdb: version,
|
|
1909
|
-
"rocksdb-js": "1.
|
|
2046
|
+
"rocksdb-js": "1.2.0"
|
|
1910
2047
|
};
|
|
1911
2048
|
|
|
1912
2049
|
//#endregion
|