@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.cjs
CHANGED
|
@@ -453,42 +453,62 @@ var DBI = class DBI {
|
|
|
453
453
|
|
|
454
454
|
//#endregion
|
|
455
455
|
//#region src/dbi-iterator.ts
|
|
456
|
+
const { ITERATOR_RESULT_DONE, ITERATOR_RESULT_FAST } = constants;
|
|
457
|
+
const DONE_RESULT = Object.freeze({
|
|
458
|
+
done: true,
|
|
459
|
+
value: void 0
|
|
460
|
+
});
|
|
456
461
|
/**
|
|
457
|
-
* Wraps
|
|
458
|
-
*
|
|
462
|
+
* Wraps the `NativeIterator` C++ binding, decoding keys and values from the
|
|
463
|
+
* shared key/value buffers (fast path) or from per-iteration buffers (slow
|
|
464
|
+
* fallback path used for oversized data or stable-buffer decoders).
|
|
465
|
+
*
|
|
466
|
+
* The native `next()` returns a primitive signal (and writes lengths to the
|
|
467
|
+
* shared `ITERATOR_STATE` buffer) instead of constructing a JS result object,
|
|
468
|
+
* so this class is responsible for building the `IteratorResult`.
|
|
459
469
|
*/
|
|
460
470
|
var DBIterator = class {
|
|
461
471
|
iterator;
|
|
462
472
|
store;
|
|
463
473
|
#includeValues;
|
|
464
|
-
constructor(iterator, store,
|
|
474
|
+
constructor(iterator, store, includeValues) {
|
|
465
475
|
this.iterator = iterator;
|
|
466
476
|
this.store = store;
|
|
467
|
-
this.#includeValues =
|
|
477
|
+
this.#includeValues = includeValues;
|
|
468
478
|
}
|
|
469
479
|
[Symbol.iterator]() {
|
|
470
480
|
return this;
|
|
471
481
|
}
|
|
472
|
-
next(
|
|
482
|
+
next() {
|
|
473
483
|
const result = this.iterator.next();
|
|
474
|
-
if (result
|
|
484
|
+
if (result === ITERATOR_RESULT_DONE) return DONE_RESULT;
|
|
485
|
+
const includeValues = this.#includeValues;
|
|
475
486
|
const value = {};
|
|
476
|
-
|
|
477
|
-
|
|
487
|
+
if (result === ITERATOR_RESULT_FAST) {
|
|
488
|
+
value.key = this.store.readKey(KEY_BUFFER, 0, ITERATOR_STATE[0]);
|
|
489
|
+
if (includeValues) {
|
|
490
|
+
VALUE_BUFFER.end = ITERATOR_STATE[1];
|
|
491
|
+
value.value = this.store.decodeValue(VALUE_BUFFER);
|
|
492
|
+
}
|
|
493
|
+
} else {
|
|
494
|
+
const slow = result;
|
|
495
|
+
value.key = this.store.decodeKey(slow.key);
|
|
496
|
+
if (includeValues && slow.value !== void 0) value.value = this.store.decodeValue(slow.value);
|
|
497
|
+
}
|
|
478
498
|
return {
|
|
479
499
|
done: false,
|
|
480
500
|
value
|
|
481
501
|
};
|
|
482
502
|
}
|
|
483
503
|
return(value) {
|
|
484
|
-
|
|
504
|
+
this.iterator.return?.();
|
|
485
505
|
return {
|
|
486
506
|
done: true,
|
|
487
507
|
value
|
|
488
508
|
};
|
|
489
509
|
}
|
|
490
510
|
throw(err) {
|
|
491
|
-
|
|
511
|
+
this.iterator.throw?.(err);
|
|
492
512
|
throw err;
|
|
493
513
|
}
|
|
494
514
|
};
|
|
@@ -563,10 +583,17 @@ function createFixedBuffer(size) {
|
|
|
563
583
|
|
|
564
584
|
//#endregion
|
|
565
585
|
//#region src/store.ts
|
|
566
|
-
const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG } = constants;
|
|
586
|
+
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;
|
|
567
587
|
const KEY_BUFFER_SIZE = 4096;
|
|
568
588
|
const KEY_BUFFER = createFixedBuffer(KEY_BUFFER_SIZE);
|
|
569
589
|
const VALUE_BUFFER = createFixedBuffer(64 * 1024);
|
|
590
|
+
/**
|
|
591
|
+
* Backing buffer for the shared iterator state. Layout (Uint32Array view):
|
|
592
|
+
* [0] = key length written into KEY_BUFFER by the most recent iterator step
|
|
593
|
+
* [1] = value length written into VALUE_BUFFER by the most recent step
|
|
594
|
+
*/
|
|
595
|
+
const ITERATOR_STATE_BUFFER = Buffer.allocUnsafeSlow(8);
|
|
596
|
+
const ITERATOR_STATE = new Uint32Array(ITERATOR_STATE_BUFFER.buffer, ITERATOR_STATE_BUFFER.byteOffset, 2);
|
|
570
597
|
const MAX_KEY_SIZE = 1024 * 1024;
|
|
571
598
|
const RESET_BUFFER_MODE = 1024;
|
|
572
599
|
const REUSE_BUFFER_MODE = 512;
|
|
@@ -745,6 +772,52 @@ var Store = class {
|
|
|
745
772
|
this.db.close();
|
|
746
773
|
}
|
|
747
774
|
/**
|
|
775
|
+
* Compacts the entire key range of the database asynchronously.
|
|
776
|
+
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
777
|
+
*
|
|
778
|
+
* @example
|
|
779
|
+
* ```typescript
|
|
780
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
781
|
+
* await db.compact();
|
|
782
|
+
* ```
|
|
783
|
+
*/
|
|
784
|
+
compact(options) {
|
|
785
|
+
let startBuffer;
|
|
786
|
+
let endBuffer;
|
|
787
|
+
if (options?.start !== void 0) {
|
|
788
|
+
const start = this.encodeKey(options.start);
|
|
789
|
+
startBuffer = Buffer.from(start.subarray(start.start, start.end));
|
|
790
|
+
}
|
|
791
|
+
if (options?.end !== void 0) {
|
|
792
|
+
const end = this.encodeKey(options.end);
|
|
793
|
+
endBuffer = Buffer.from(end.subarray(end.start, end.end));
|
|
794
|
+
}
|
|
795
|
+
return new Promise((resolve, reject) => this.db.compact(resolve, reject, startBuffer, endBuffer));
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Compacts the entire key range of the database synchronously.
|
|
799
|
+
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
800
|
+
*
|
|
801
|
+
* @example
|
|
802
|
+
* ```typescript
|
|
803
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
804
|
+
* db.compactSync();
|
|
805
|
+
* ```
|
|
806
|
+
*/
|
|
807
|
+
compactSync(options) {
|
|
808
|
+
let startBuffer;
|
|
809
|
+
let endBuffer;
|
|
810
|
+
if (options?.start !== void 0) {
|
|
811
|
+
const start = this.encodeKey(options.start);
|
|
812
|
+
startBuffer = Buffer.from(start.subarray(start.start, start.end));
|
|
813
|
+
}
|
|
814
|
+
if (options?.end !== void 0) {
|
|
815
|
+
const end = this.encodeKey(options.end);
|
|
816
|
+
endBuffer = Buffer.from(end.subarray(end.start, end.end));
|
|
817
|
+
}
|
|
818
|
+
this.db.compactSync(startBuffer, endBuffer);
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
748
821
|
* Decodes a key from the database.
|
|
749
822
|
*
|
|
750
823
|
* @param key - The key to decode.
|
|
@@ -832,27 +905,45 @@ var Store = class {
|
|
|
832
905
|
}
|
|
833
906
|
getRange(context, options) {
|
|
834
907
|
if (!this.db.opened) throw new Error("Database not open");
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
908
|
+
let startUnencoded = options?.key ?? options?.start;
|
|
909
|
+
let endUnencoded = options?.key ?? options?.end;
|
|
910
|
+
const includeValues = options?.values ?? true;
|
|
911
|
+
const reverse = options?.reverse ?? false;
|
|
912
|
+
let exclusiveStart = options?.exclusiveStart ?? false;
|
|
913
|
+
let inclusiveEnd = options?.inclusiveEnd ?? false;
|
|
914
|
+
if (options?.key !== void 0) inclusiveEnd = true;
|
|
915
|
+
if (reverse) {
|
|
916
|
+
const tmp = startUnencoded;
|
|
917
|
+
startUnencoded = endUnencoded;
|
|
918
|
+
endUnencoded = tmp;
|
|
919
|
+
exclusiveStart = options?.exclusiveStart ?? true;
|
|
920
|
+
inclusiveEnd = options?.inclusiveEnd ?? true;
|
|
840
921
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
922
|
+
const keyBuffer = this.keyBuffer;
|
|
923
|
+
let startKeyEnd = 0;
|
|
924
|
+
let endKeyStart = 0;
|
|
925
|
+
let endKeyEnd = 0;
|
|
926
|
+
if (startUnencoded !== void 0) {
|
|
927
|
+
startKeyEnd = this.writeKey(startUnencoded, keyBuffer, 0);
|
|
928
|
+
if (startKeyEnd === 0) throw new Error("Zero length key is not allowed");
|
|
847
929
|
}
|
|
848
|
-
if (
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
930
|
+
if (endUnencoded !== void 0) if (endUnencoded === startUnencoded) {
|
|
931
|
+
endKeyStart = 0;
|
|
932
|
+
endKeyEnd = startKeyEnd;
|
|
933
|
+
} else {
|
|
934
|
+
endKeyStart = startKeyEnd;
|
|
935
|
+
endKeyEnd = this.writeKey(endUnencoded, keyBuffer, endKeyStart);
|
|
936
|
+
if (endKeyEnd === endKeyStart) throw new Error("Zero length key is not allowed");
|
|
854
937
|
}
|
|
855
|
-
|
|
938
|
+
let flags = 0;
|
|
939
|
+
if (reverse) flags |= ITERATOR_REVERSE_FLAG;
|
|
940
|
+
if (exclusiveStart) flags |= ITERATOR_EXCLUSIVE_START_FLAG;
|
|
941
|
+
if (inclusiveEnd) flags |= ITERATOR_INCLUSIVE_END_FLAG;
|
|
942
|
+
if (includeValues) flags |= ITERATOR_INCLUDE_VALUES_FLAG;
|
|
943
|
+
if (includeValues && !this.decoderCopies) flags |= ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG;
|
|
944
|
+
if (context !== this.db) flags |= ITERATOR_CONTEXT_IS_TRANSACTION_FLAG;
|
|
945
|
+
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;
|
|
946
|
+
return new _harperfast_extended_iterable.ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions), this, includeValues));
|
|
856
947
|
}
|
|
857
948
|
getSync(context, key, alwaysCreateNewBuffer = false, options) {
|
|
858
949
|
const keyParam = getKeyParam(this.encodeKey(key));
|
|
@@ -1219,6 +1310,38 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1219
1310
|
this.store.close();
|
|
1220
1311
|
}
|
|
1221
1312
|
/**
|
|
1313
|
+
* Compacts the entire key range of the database asynchronously.
|
|
1314
|
+
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
1315
|
+
*
|
|
1316
|
+
* @example
|
|
1317
|
+
* ```typescript
|
|
1318
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
1319
|
+
* await db.compact();
|
|
1320
|
+
* ```
|
|
1321
|
+
*/
|
|
1322
|
+
compact(options) {
|
|
1323
|
+
return this.store.compact(options);
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Compacts the entire key range of the database synchronously.
|
|
1327
|
+
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
1328
|
+
*
|
|
1329
|
+
* @example
|
|
1330
|
+
* ```typescript
|
|
1331
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
1332
|
+
* db.compactSync();
|
|
1333
|
+
* ```
|
|
1334
|
+
*/
|
|
1335
|
+
compactSync(options) {
|
|
1336
|
+
return this.store.compactSync(options);
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Returns the list of column families in the RocksDB database.
|
|
1340
|
+
*/
|
|
1341
|
+
get columns() {
|
|
1342
|
+
return this.store.db.columns;
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1222
1345
|
* Set global database settings.
|
|
1223
1346
|
*
|
|
1224
1347
|
* @param options - The options for the database.
|
|
@@ -1294,6 +1417,19 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1294
1417
|
return this.store.db.getDBProperty(propertyName);
|
|
1295
1418
|
}
|
|
1296
1419
|
/**
|
|
1420
|
+
* Retrieves the estimated number of keys in the database.
|
|
1421
|
+
*
|
|
1422
|
+
* @example
|
|
1423
|
+
* ```typescript
|
|
1424
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
1425
|
+
* const estimated = db.getEstimatedKeyCount();
|
|
1426
|
+
* console.log(estimated);
|
|
1427
|
+
* ```
|
|
1428
|
+
*/
|
|
1429
|
+
getEstimatedKeyCount() {
|
|
1430
|
+
return this.getDBIntProperty("rocksdb.estimate-num-keys") ?? 0;
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1297
1433
|
* Returns the current timestamp as a monotonically increasing timestamp in
|
|
1298
1434
|
* milliseconds represented as a decimal number.
|
|
1299
1435
|
*
|
|
@@ -1432,6 +1568,7 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1432
1568
|
if (store.open()) return this;
|
|
1433
1569
|
store.db.setDefaultValueBuffer(VALUE_BUFFER);
|
|
1434
1570
|
store.db.setDefaultKeyBuffer(KEY_BUFFER);
|
|
1571
|
+
store.db.setIteratorState(ITERATOR_STATE_BUFFER);
|
|
1435
1572
|
/**
|
|
1436
1573
|
* The encoder initialization precedence is:
|
|
1437
1574
|
* 1. encoder.Encoder
|
|
@@ -1462,14 +1599,14 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1462
1599
|
return buffer && store.decoder?.decode ? store.decoder.decode(buffer) : void 0;
|
|
1463
1600
|
};
|
|
1464
1601
|
opts.saveStructures = (structures, isCompatible) => {
|
|
1465
|
-
return this.transactionSync((txn) => {
|
|
1602
|
+
return this.transactionSync((txn, _attempt) => {
|
|
1466
1603
|
const existingStructuresBuffer = this.getBinarySync(sharedStructuresKey);
|
|
1467
1604
|
const existingStructures = existingStructuresBuffer && store.decoder?.decode ? store.decoder.decode(existingStructuresBuffer) : void 0;
|
|
1468
1605
|
if (typeof isCompatible == "function") {
|
|
1469
1606
|
if (!isCompatible(existingStructures)) return false;
|
|
1470
1607
|
} else if (existingStructures && existingStructures.length !== isCompatible) return false;
|
|
1471
1608
|
txn.putSync(sharedStructuresKey, structures);
|
|
1472
|
-
});
|
|
1609
|
+
}, { retryOnBusy: true });
|
|
1473
1610
|
};
|
|
1474
1611
|
}
|
|
1475
1612
|
store.encoder = new EncoderClass({
|
|
@@ -1486,16 +1623,15 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1486
1623
|
};
|
|
1487
1624
|
store.decoder = store.encoder;
|
|
1488
1625
|
}
|
|
1489
|
-
if (typeof store.encoder?.writeKey === "function" && !store.encoder?.encode) {
|
|
1490
|
-
store.encoder
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
}
|
|
1626
|
+
if (typeof store.encoder?.writeKey === "function" && !store.encoder?.encode) store.encoder = {
|
|
1627
|
+
...store.encoder,
|
|
1628
|
+
encode: (value, _mode) => {
|
|
1629
|
+
const bytesWritten = store.writeKey(value, store.encodeBuffer, 0);
|
|
1630
|
+
return store.encodeBuffer.subarray(0, bytesWritten);
|
|
1631
|
+
},
|
|
1632
|
+
copyBuffers: true
|
|
1633
|
+
};
|
|
1634
|
+
if (store.encoder) store.encoder.name = this.#name;
|
|
1499
1635
|
if (store.decoder && store.decoder.needsStableBuffer !== true) store.decoderCopies = true;
|
|
1500
1636
|
if (store.decoder?.readKey && !store.decoder.decode) {
|
|
1501
1637
|
store.decoder.decode = (buffer) => {
|
|
@@ -1804,6 +1940,7 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
|
|
|
1804
1940
|
logBuffer.logId = 0;
|
|
1805
1941
|
logBuffer.size = 0;
|
|
1806
1942
|
logBuffer.dataView = new DataView(logBuffer.buffer);
|
|
1943
|
+
size = 0;
|
|
1807
1944
|
}
|
|
1808
1945
|
}
|
|
1809
1946
|
dataView = logBuffer.dataView;
|
|
@@ -1931,7 +2068,7 @@ function loadLastPosition(transactionLog, readUncommitted) {
|
|
|
1931
2068
|
//#region src/index.ts
|
|
1932
2069
|
const versions = {
|
|
1933
2070
|
rocksdb: version,
|
|
1934
|
-
"rocksdb-js": "1.
|
|
2071
|
+
"rocksdb-js": "1.2.0"
|
|
1935
2072
|
};
|
|
1936
2073
|
|
|
1937
2074
|
//#endregion
|