@harperfast/rocksdb-js 1.1.1 → 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/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 an iterator, namely the `NativeIterator` class, and decodes the key
458
- * and value.
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, options) {
474
+ constructor(iterator, store, includeValues) {
465
475
  this.iterator = iterator;
466
476
  this.store = store;
467
- this.#includeValues = options?.values ?? true;
477
+ this.#includeValues = includeValues;
468
478
  }
469
479
  [Symbol.iterator]() {
470
480
  return this;
471
481
  }
472
- next(...[_value]) {
482
+ next() {
473
483
  const result = this.iterator.next();
474
- if (result.done) return result;
484
+ if (result === ITERATOR_RESULT_DONE) return DONE_RESULT;
485
+ const includeValues = this.#includeValues;
475
486
  const value = {};
476
- value.key = this.store.decodeKey(result.value.key);
477
- if (this.#includeValues) value.value = this.store.decodeValue(result.value.value);
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
- if (this.iterator.return) return this.iterator.return(value);
504
+ this.iterator.return?.();
485
505
  return {
486
506
  done: true,
487
507
  value
488
508
  };
489
509
  }
490
510
  throw(err) {
491
- if (this.iterator.throw) return this.iterator.throw(err);
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
- options = { ...options };
836
- const unencodedStartKey = options.key ?? options.start;
837
- if (unencodedStartKey !== void 0) {
838
- const start = this.encodeKey(unencodedStartKey);
839
- options.start = Buffer.from(start.subarray(start.start, start.end));
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
- if (options.key !== void 0) {
842
- options.end = options.start;
843
- options.inclusiveEnd = true;
844
- } else if (options.end !== void 0) {
845
- const end = this.encodeKey(options.end);
846
- options.end = Buffer.from(end.subarray(end.start, end.end));
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 (options.reverse) {
849
- const start = options.start;
850
- options.start = options.end;
851
- options.end = start;
852
- options.exclusiveStart = options.exclusiveStart ?? true;
853
- options.inclusiveEnd = options.inclusiveEnd ?? true;
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
- return new _harperfast_extended_iterable.ExtendedIterable(new DBIterator(new NativeIterator(context, options), this, options));
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,32 @@ 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
+ /**
1222
1339
  * Returns the list of column families in the RocksDB database.
1223
1340
  */
1224
1341
  get columns() {
@@ -1300,6 +1417,19 @@ var RocksDatabase = class RocksDatabase extends DBI {
1300
1417
  return this.store.db.getDBProperty(propertyName);
1301
1418
  }
1302
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
+ /**
1303
1433
  * Returns the current timestamp as a monotonically increasing timestamp in
1304
1434
  * milliseconds represented as a decimal number.
1305
1435
  *
@@ -1438,6 +1568,7 @@ var RocksDatabase = class RocksDatabase extends DBI {
1438
1568
  if (store.open()) return this;
1439
1569
  store.db.setDefaultValueBuffer(VALUE_BUFFER);
1440
1570
  store.db.setDefaultKeyBuffer(KEY_BUFFER);
1571
+ store.db.setIteratorState(ITERATOR_STATE_BUFFER);
1441
1572
  /**
1442
1573
  * The encoder initialization precedence is:
1443
1574
  * 1. encoder.Encoder
@@ -1809,6 +1940,7 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
1809
1940
  logBuffer.logId = 0;
1810
1941
  logBuffer.size = 0;
1811
1942
  logBuffer.dataView = new DataView(logBuffer.buffer);
1943
+ size = 0;
1812
1944
  }
1813
1945
  }
1814
1946
  dataView = logBuffer.dataView;
@@ -1936,7 +2068,7 @@ function loadLastPosition(transactionLog, readUncommitted) {
1936
2068
  //#region src/index.ts
1937
2069
  const versions = {
1938
2070
  rocksdb: version,
1939
- "rocksdb-js": "1.1.1"
2071
+ "rocksdb-js": "1.2.0"
1940
2072
  };
1941
2073
 
1942
2074
  //#endregion