@frostpillar/frostpillar-btree 0.2.7 → 0.2.9
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-JA.md +93 -59
- package/README.md +93 -59
- package/dist/InMemoryBTree.d.cts +45 -0
- package/dist/btree/autoScale.d.cts +11 -0
- package/dist/btree/bulkLoad.d.cts +5 -0
- package/dist/btree/deleteRange.d.cts +3 -0
- package/dist/btree/entry-lookup.d.cts +8 -0
- package/dist/btree/integrity-helpers.d.cts +6 -0
- package/dist/btree/integrity.d.cts +2 -0
- package/dist/btree/mutations.d.cts +10 -0
- package/dist/btree/navigation.d.cts +23 -0
- package/dist/btree/node-ops.d.cts +15 -0
- package/dist/btree/rangeQuery.d.cts +7 -0
- package/dist/btree/rebalance-branch.d.cts +4 -0
- package/dist/btree/rebalance.d.cts +7 -0
- package/dist/btree/serialization.d.cts +18 -0
- package/dist/btree/split.d.cts +3 -0
- package/dist/btree/stats.d.cts +2 -0
- package/dist/btree/traversal.d.cts +7 -0
- package/dist/btree/types.d.cts +110 -0
- package/dist/{chunk-UGGWGP4E.js → chunk-OFXDCKLC.js} +4 -3
- package/dist/concurrency/ConcurrentInMemoryBTree.d.cts +49 -0
- package/dist/concurrency/coordinator.d.cts +21 -0
- package/dist/concurrency/helpers.d.cts +34 -0
- package/dist/concurrency/index.d.cts +2 -0
- package/dist/concurrency/syncLogValidation.d.cts +2 -0
- package/dist/concurrency/types.d.cts +54 -0
- package/dist/concurrency/writeOps.d.cts +48 -0
- package/dist/core.cjs +4 -3
- package/dist/core.d.cts +4 -0
- package/dist/core.js +1 -1
- package/dist/errors.d.cts +12 -0
- package/dist/frostpillar-btree-core.min.js +1 -1
- package/dist/frostpillar-btree.min.js +1 -1
- package/dist/index.cjs +4 -3
- package/dist/index.d.cts +6 -0
- package/dist/index.js +1 -1
- package/package.json +21 -9
package/README-JA.md
CHANGED
|
@@ -359,6 +359,8 @@ tree.getPairOrNextLower(10); // { entryId: ..., key: 10, value: 'a' }(完全
|
|
|
359
359
|
|
|
360
360
|
#### イテレーション
|
|
361
361
|
|
|
362
|
+
> **注意:** イテレータはライブなツリーを読み取ります。反復中(`entries()`、`entriesReversed()`、`keys()`、`values()`、`forEach`、`for...of`)にツリーを変更した場合、反復中エントリの包含や訪問順序は実装依存です。反復しながら変更する必要がある場合は、先に `snapshot()` を取得してください。
|
|
363
|
+
|
|
362
364
|
**`entries()`** -- スナップショット配列を生成せず、昇順でエントリを遅延イテレーションします。
|
|
363
365
|
|
|
364
366
|
```ts
|
|
@@ -481,6 +483,24 @@ const tree = new InMemoryBTree<number, string>({
|
|
|
481
483
|
| `'reject'` | キーが既に存在する場合、`BTreeValidationError` をスローする。 | 一意インデックス / セット |
|
|
482
484
|
| `'allow'` | 同一キーの複数エントリを許可し、挿入順で並べる。 | マルチマップ / イベントログ / 優先度キュー |
|
|
483
485
|
|
|
486
|
+
#### 削除リバランスポリシー
|
|
487
|
+
|
|
488
|
+
`deleteRebalancePolicy` オプションで、削除時のリーフのリバランス頻度を制御できます。
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
const tree = new InMemoryBTree<number, string>({
|
|
492
|
+
compareKeys: (a, b) => a - b,
|
|
493
|
+
deleteRebalancePolicy: 'lazy', // デフォルトは 'standard'
|
|
494
|
+
});
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
| ポリシー | 動作 | 用途 |
|
|
498
|
+
| -------------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
|
499
|
+
| `'standard'`(デフォルト) | 削除でリーフが最小占有数(`ceil(maxLeafEntries / 2)`)を下回った時点でリバランスする。 | 読み書きバランス型ワークロード |
|
|
500
|
+
| `'lazy'` | リーフが `max(1, ceil(最小占有数 / 4))` を下回るまでリバランスを遅延し、大量削除時のマージ回数を削減する。 | 大量削除ワークロード、`autoScale` 併用 |
|
|
501
|
+
|
|
502
|
+
緩和されたしきい値はリーフのリバランス判定にのみ適用され、ブランチのリバランスは常に標準のしきい値を使用します。ポリシーが `'lazy'` の場合、`assertInvariants()` は緩和されたしきい値を満たすリーフを許容します。ポリシーは `clone()` と `toJSON()` / `fromJSON()` で維持されます。
|
|
503
|
+
|
|
484
504
|
#### 動作に関する注意事項
|
|
485
505
|
|
|
486
506
|
- `range(start, end)` はデフォルトで両端を含みます。`RangeBounds` で除外境界を指定できます。`start > end` の場合は `[]` を返します。
|
|
@@ -499,7 +519,7 @@ const tree = new InMemoryBTree<number, string>({
|
|
|
499
519
|
| 1,000,000+ | 512 | 256 |
|
|
500
520
|
|
|
501
521
|
- `autoScale` は `maxLeafEntries` / `maxBranchChildren` の明示指定と同時には使えません。
|
|
502
|
-
- `fromJSON` は `1,000,000`
|
|
522
|
+
- `fromJSON` は `1,000,000` 件を超えるエントリを含むペイロードを拒否します。`toJSON` はこの上限を強制しません。上限を超えるツリーもシリアライズ自体は成功しますが、生成されたペイロードは `fromJSON` で再インポートできません。大きなデータセットはエクスポート前に分割してください。
|
|
503
523
|
|
|
504
524
|
---
|
|
505
525
|
|
|
@@ -651,6 +671,18 @@ await localInstance.sync(); // 明示的に最新状態を取得
|
|
|
651
671
|
const value = await localInstance.get(1);
|
|
652
672
|
```
|
|
653
673
|
|
|
674
|
+
**`syncThenRead(fn)`** -- 読み取り中心のバッチ処理向けに、1 回の同期の後、単一の排他ロック内でローカルツリーに対して複数の読み取りを実行します。読み取りごとにストアへの往復コストを払う必要がなくなります。`readMode` が `'strong'` / `'local'` のどちらでも動作します(常に先に同期します)。コールバック内でツリーを変更しないでください。
|
|
675
|
+
|
|
676
|
+
```ts
|
|
677
|
+
const total = await instanceA.syncThenRead((tree) => {
|
|
678
|
+
let sum = 0;
|
|
679
|
+
tree.forEachRange(0, 100, (entry) => {
|
|
680
|
+
sum += entry.value.length;
|
|
681
|
+
});
|
|
682
|
+
return sum;
|
|
683
|
+
});
|
|
684
|
+
```
|
|
685
|
+
|
|
654
686
|
```ts
|
|
655
687
|
// インスタンス A が挿入
|
|
656
688
|
const insertedId = await instanceA.put(100, 'draft docs');
|
|
@@ -847,44 +879,45 @@ new InMemoryBTree<TKey, TValue>(config: InMemoryBTreeConfig<TKey>)
|
|
|
847
879
|
|
|
848
880
|
`InMemoryBTree` メソッドを `Promise` を返す非同期版として提供します。書き込みは shared store を介して協調し、`readMode` が `'strong'`(デフォルト)の場合は読み取り前に同期します。`readMode` が `'local'` の場合、読み取りは同期なしでローカルツリーに対して実行されます。
|
|
849
881
|
|
|
850
|
-
| メソッド | シグネチャ | 説明
|
|
851
|
-
| ------------------------ | -------------------------------------------------------------------------------------------------- |
|
|
852
|
-
| `sync` | `() => Promise<void>` | shared store の最新ログを取得して適用する。
|
|
853
|
-
| `
|
|
854
|
-
| `
|
|
855
|
-
| `
|
|
856
|
-
| `
|
|
857
|
-
| `
|
|
858
|
-
| `
|
|
859
|
-
| `
|
|
860
|
-
| `
|
|
861
|
-
| `
|
|
862
|
-
| `
|
|
863
|
-
| `
|
|
864
|
-
| `
|
|
865
|
-
| `
|
|
866
|
-
| `
|
|
867
|
-
| `
|
|
868
|
-
| `
|
|
869
|
-
| `
|
|
870
|
-
| `
|
|
871
|
-
| `
|
|
872
|
-
| `
|
|
873
|
-
| `
|
|
874
|
-
| `
|
|
875
|
-
| `
|
|
876
|
-
| `
|
|
877
|
-
| `
|
|
878
|
-
| `
|
|
879
|
-
| `
|
|
880
|
-
| `
|
|
881
|
-
| `
|
|
882
|
-
| `
|
|
883
|
-
| `
|
|
884
|
-
| `
|
|
885
|
-
| `
|
|
886
|
-
| `
|
|
887
|
-
| `
|
|
882
|
+
| メソッド | シグネチャ | 説明 |
|
|
883
|
+
| ------------------------ | -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
884
|
+
| `sync` | `() => Promise<void>` | shared store の最新ログを取得して適用する。 |
|
|
885
|
+
| `syncThenRead` | `<TResult>(fn: (tree: InMemoryBTree<TKey, TValue>) => TResult) => Promise<TResult>` | 1 回同期した後、単一の排他ロック内でローカルツリーに対して `fn` を実行する。 |
|
|
886
|
+
| `put` | `(key: TKey, value: TValue) => Promise<EntryId>` | 楽観的並行制御で挿入する。 |
|
|
887
|
+
| `putMany` | `(entries: readonly { key: TKey; value: TValue }[]) => Promise<EntryId[]>` | 楽観的並行制御で一括挿入する。 |
|
|
888
|
+
| `remove` | `(key: TKey) => Promise<BTreeEntry<TKey, TValue> \| null>` | 指定キーに一致する最初のエントリを削除する。 |
|
|
889
|
+
| `removeById` | `(entryId: EntryId) => Promise<BTreeEntry<TKey, TValue> \| null>` | ID でエントリを削除する。 |
|
|
890
|
+
| `peekById` | `(entryId: EntryId) => Promise<BTreeEntry<TKey, TValue> \| null>` | ID でエントリを参照する(事前に同期)。 |
|
|
891
|
+
| `updateById` | `(entryId: EntryId, value: TValue) => Promise<BTreeEntry<TKey, TValue> \| null>` | 楽観的並行制御で ID のエントリ値を更新する。 |
|
|
892
|
+
| `popFirst` | `() => Promise<BTreeEntry<TKey, TValue> \| null>` | 最小キーのエントリを削除して返す。 |
|
|
893
|
+
| `popLast` | `() => Promise<BTreeEntry<TKey, TValue> \| null>` | 最大キーのエントリを削除して返す。 |
|
|
894
|
+
| `deleteRange` | `(startKey: TKey, endKey: TKey, options?: RangeBounds) => Promise<number>` | 楽観的並行制御で範囲内のエントリを削除する。 |
|
|
895
|
+
| `clear` | `() => Promise<void>` | 楽観的並行制御で全エントリを削除する。 |
|
|
896
|
+
| `peekFirst` | `() => Promise<BTreeEntry<TKey, TValue> \| null>` | 最小キーのエントリを返す(事前に同期)。 |
|
|
897
|
+
| `peekLast` | `() => Promise<BTreeEntry<TKey, TValue> \| null>` | 最大キーのエントリを返す(事前に同期)。 |
|
|
898
|
+
| `findFirst` | `(key: TKey) => Promise<BTreeEntry<TKey, TValue> \| null>` | キーに一致する最初のエントリを返す(事前に同期)。 |
|
|
899
|
+
| `findLast` | `(key: TKey) => Promise<BTreeEntry<TKey, TValue> \| null>` | キーに一致する最後のエントリを返す(事前に同期)。 |
|
|
900
|
+
| `get` | `(key: TKey) => Promise<TValue \| null>` | キーの値を取得する(事前に同期)。 |
|
|
901
|
+
| `hasKey` | `(key: TKey) => Promise<boolean>` | キーの存在を確認する(事前に同期)。 |
|
|
902
|
+
| `count` | `(startKey: TKey, endKey: TKey, options?: RangeBounds) => Promise<number>` | 範囲内のエントリ数を返す(事前に同期)。 |
|
|
903
|
+
| `range` | `(startKey: TKey, endKey: TKey, options?: RangeBounds) => Promise<BTreeEntry<TKey, TValue>[]>` | 範囲クエリ(事前に同期)。 |
|
|
904
|
+
| `nextHigherKey` | `(key: TKey) => Promise<TKey \| null>` | 指定キーより大きい次のキー(事前に同期)。 |
|
|
905
|
+
| `nextLowerKey` | `(key: TKey) => Promise<TKey \| null>` | 指定キーより小さい次のキー(事前に同期)。 |
|
|
906
|
+
| `getPairOrNextLower` | `(key: TKey) => Promise<BTreeEntry<TKey, TValue> \| null>` | 一致または次に小さいエントリ(事前に同期)。 |
|
|
907
|
+
| `entries` | `() => Promise<BTreeEntry<TKey, TValue>[]>` | 全エントリを配列で返す(事前に同期)。 |
|
|
908
|
+
| `entriesReversed` | `() => Promise<BTreeEntry<TKey, TValue>[]>` | 全エントリを逆順で配列として返す(事前に同期)。 |
|
|
909
|
+
| `keys` | `() => Promise<TKey[]>` | 全キーを配列で返す(事前に同期)。 |
|
|
910
|
+
| `values` | `() => Promise<TValue[]>` | 全値を配列で返す(事前に同期)。 |
|
|
911
|
+
| `forEach` | `(callback: (entry: BTreeEntry<TKey, TValue>) => void) => Promise<void>` | 全エントリを反復する(事前に同期)。 |
|
|
912
|
+
| `forEachRange` | `(startKey, endKey, callback, options?) => Promise<void>` | 範囲内のエントリを反復する(事前に同期)。 |
|
|
913
|
+
| `snapshot` | `() => Promise<BTreeEntry<TKey, TValue>[]>` | 全エントリを返す(事前に同期)。 |
|
|
914
|
+
| `size` | `() => Promise<number>` | エントリ数を返す(事前に同期)。 |
|
|
915
|
+
| `getStats` | `() => Promise<BTreeStats>` | 構造統計を返す(事前に同期)。 |
|
|
916
|
+
| `assertInvariants` | `() => Promise<void>` | 構造的な整合性を検証する(事前に同期)。 |
|
|
917
|
+
| `clone` | `() => Promise<InMemoryBTree<TKey, TValue>>` | 独立したローカルコピーを返す(事前に同期)。 |
|
|
918
|
+
| `toJSON` | `() => Promise<BTreeJSON<TKey, TValue>>` | JSON にシリアライズする(事前に同期)。 |
|
|
919
|
+
| `fromJSON` (static) | `(json: BTreeJSON<TKey, TValue>, compareKeys: KeyComparator<TKey>) => InMemoryBTree<TKey, TValue>` | JSON からデシリアライズする(ローカルツリーを返す)。 |
|
|
920
|
+
| `[Symbol.asyncIterator]` | `() => AsyncIterableIterator<BTreeEntry<TKey, TValue>>` | 全エントリを非同期反復する(事前に同期)。 |
|
|
888
921
|
|
|
889
922
|
**コンストラクタ:**
|
|
890
923
|
|
|
@@ -894,26 +927,27 @@ new ConcurrentInMemoryBTree<TKey, TValue>(config: ConcurrentInMemoryBTreeConfig<
|
|
|
894
927
|
|
|
895
928
|
### エクスポートされる型
|
|
896
929
|
|
|
897
|
-
| 型 | 説明
|
|
898
|
-
| --------------------------------------------- |
|
|
899
|
-
| `EntryId` | エントリを識別するブランド型 `number`。
|
|
900
|
-
| `BTreeEntry<TKey, TValue>` | `{ entryId: EntryId; key: TKey; value: TValue }`
|
|
901
|
-
| `BTreeJSON<TKey, TValue>` | `toJSON()` が生成し `fromJSON()` が受け取る、バージョン付き JSON シリアライズ可能なペイロード。
|
|
902
|
-
| `BTreeStats` | `{ height: number; leafCount: number; branchCount: number; entryCount: number }`
|
|
903
|
-
| `KeyComparator<TKey>` | `(left: TKey, right: TKey) => number`
|
|
904
|
-
| `DuplicateKeyPolicy` | `'allow' \| 'reject' \| 'replace'`
|
|
905
|
-
| `
|
|
906
|
-
| `
|
|
907
|
-
| `
|
|
908
|
-
| `
|
|
909
|
-
| `
|
|
910
|
-
| `
|
|
911
|
-
| `
|
|
912
|
-
| `
|
|
913
|
-
| `
|
|
914
|
-
| `
|
|
915
|
-
|
|
916
|
-
|
|
930
|
+
| 型 | 説明 |
|
|
931
|
+
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
932
|
+
| `EntryId` | エントリを識別するブランド型 `number`。 |
|
|
933
|
+
| `BTreeEntry<TKey, TValue>` | `{ entryId: EntryId; key: TKey; value: TValue }` |
|
|
934
|
+
| `BTreeJSON<TKey, TValue>` | `toJSON()` が生成し `fromJSON()` が受け取る、バージョン付き JSON シリアライズ可能なペイロード。 |
|
|
935
|
+
| `BTreeStats` | `{ height: number; leafCount: number; branchCount: number; entryCount: number }` |
|
|
936
|
+
| `KeyComparator<TKey>` | `(left: TKey, right: TKey) => number` |
|
|
937
|
+
| `DuplicateKeyPolicy` | `'allow' \| 'reject' \| 'replace'` |
|
|
938
|
+
| `DeleteRebalancePolicy` | `'standard' \| 'lazy'` |
|
|
939
|
+
| `RangeBounds` | `{ lowerBound?: 'inclusive' \| 'exclusive'; upperBound?: 'inclusive' \| 'exclusive' }` |
|
|
940
|
+
| `InMemoryBTreeConfig<TKey>` | `{ compareKeys: KeyComparator<TKey>; maxLeafEntries?: number; maxBranchChildren?: number; duplicateKeys?: DuplicateKeyPolicy; enableEntryIdLookup?: boolean; autoScale?: boolean; deleteRebalancePolicy?: DeleteRebalancePolicy }` |
|
|
941
|
+
| `ReadMode` | `'strong' \| 'local'` |
|
|
942
|
+
| `ConcurrentInMemoryBTreeConfig<TKey, TValue>` | `InMemoryBTreeConfig<TKey>` を拡張し、`store: SharedTreeStore<TKey, TValue>`、`maxRetries?: number`、`maxSyncMutationsPerBatch?: number`、`readMode?: ReadMode` を追加。 |
|
|
943
|
+
| `SharedTreeStore<TKey, TValue>` | `getLogEntriesSince(version)` と `append(expectedVersion, mutations)` を持つインターフェース。 |
|
|
944
|
+
| `SharedTreeLog<TKey, TValue>` | `{ version: bigint; mutations: BTreeMutation<TKey, TValue>[] }` |
|
|
945
|
+
| `BTreeMutation<TKey, TValue>` | 判別共用体: `init`、`put`、`putMany`、`remove`、`removeById`、`updateById`、`popFirst`、`popLast`、`deleteRange`、`clear`。 |
|
|
946
|
+
| `BTreeValidationError` | コンパレータや設定の違反でスローされるエラー。 |
|
|
947
|
+
| `BTreeInvariantError` | ツリー構造の整合性違反でスローされるエラー。 |
|
|
948
|
+
| `BTreeConcurrencyError` | 並行処理コンフリクトやストア契約違反でスローされるエラー。 |
|
|
949
|
+
|
|
950
|
+
> **サブパスエクスポート:** `/core` サブパス(`@frostpillar/frostpillar-btree/core`)は単一プロセス向けの型のみエクスポートします: `InMemoryBTree`、`EntryId`、`BTreeEntry`、`BTreeJSON`、`BTreeStats`、`KeyComparator`、`DuplicateKeyPolicy`、`DeleteRebalancePolicy`、`RangeBounds`、`InMemoryBTreeConfig`、`BTreeValidationError`、`BTreeInvariantError`。並行処理関連のエクスポート(`ConcurrentInMemoryBTree`、`ConcurrentInMemoryBTreeConfig`、`ReadMode`、`SharedTreeStore`、`SharedTreeLog`、`BTreeMutation`、`BTreeConcurrencyError`)はメインエントリポイントからのみ利用できます。
|
|
917
951
|
|
|
918
952
|
---
|
|
919
953
|
|
package/README.md
CHANGED
|
@@ -359,6 +359,8 @@ tree.getPairOrNextLower(10); // { entryId: ..., key: 10, value: 'a' } (exact mat
|
|
|
359
359
|
|
|
360
360
|
#### Iterating
|
|
361
361
|
|
|
362
|
+
> **Note:** Iterators read the live tree. If you mutate the tree during traversal (`entries()`, `entriesReversed()`, `keys()`, `values()`, `forEach`, `for...of`), inclusion and visitation order of in-flight entries are implementation-defined. Take a `snapshot()` first when you need to mutate while traversing.
|
|
363
|
+
|
|
362
364
|
**`entries()`** -- lazily iterate all entries in ascending key order without allocating a snapshot array:
|
|
363
365
|
|
|
364
366
|
```ts
|
|
@@ -481,6 +483,24 @@ const tree = new InMemoryBTree<number, string>({
|
|
|
481
483
|
| `'reject'` | Throws `BTreeValidationError` if the key already exists. | Unique index / set |
|
|
482
484
|
| `'allow'` | Allows multiple entries with the same key, ordered by insertion time. | Multimap / event log / priority queue |
|
|
483
485
|
|
|
486
|
+
#### Delete Rebalance Policy
|
|
487
|
+
|
|
488
|
+
Control how aggressively delete operations rebalance leaves via the `deleteRebalancePolicy` option:
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
const tree = new InMemoryBTree<number, string>({
|
|
492
|
+
compareKeys: (a, b) => a - b,
|
|
493
|
+
deleteRebalancePolicy: 'lazy', // default: 'standard'
|
|
494
|
+
});
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
| Policy | Behavior | Use case |
|
|
498
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------ |
|
|
499
|
+
| `'standard'` (default) | Rebalances a leaf as soon as a delete drops it below the minimum occupancy (`ceil(maxLeafEntries / 2)`). | Balanced read/write workloads |
|
|
500
|
+
| `'lazy'` | Delays rebalancing until a leaf falls below `max(1, ceil(minimum occupancy / 4))`, reducing merge churn during mass deletions. | Mass-deletion workloads, `autoScale` |
|
|
501
|
+
|
|
502
|
+
The relaxed threshold applies to the leaf rebalance decision only; branch rebalancing always uses the standard threshold. `assertInvariants()` accepts leaves that satisfy the relaxed threshold when the policy is `'lazy'`. The policy is preserved by `clone()` and `toJSON()` / `fromJSON()`.
|
|
503
|
+
|
|
484
504
|
#### Behavior Notes
|
|
485
505
|
|
|
486
506
|
- `range(start, end)` is inclusive on both bounds by default. Pass `RangeBounds` to use exclusive bounds. Returns `[]` when `start > end`.
|
|
@@ -499,7 +519,7 @@ const tree = new InMemoryBTree<number, string>({
|
|
|
499
519
|
| 1,000,000+ | 512 | 256 |
|
|
500
520
|
|
|
501
521
|
- `autoScale` cannot be combined with explicit `maxLeafEntries` or `maxBranchChildren`.
|
|
502
|
-
- `fromJSON` rejects payloads with more than `1,000,000` entries.
|
|
522
|
+
- `fromJSON` rejects payloads with more than `1,000,000` entries. `toJSON` does not enforce this cap: a tree holding more entries serializes successfully, but the resulting payload cannot be re-imported via `fromJSON`. Split larger datasets before export.
|
|
503
523
|
|
|
504
524
|
---
|
|
505
525
|
|
|
@@ -651,6 +671,18 @@ await localInstance.sync(); // explicitly pull latest state
|
|
|
651
671
|
const value = await localInstance.get(1);
|
|
652
672
|
```
|
|
653
673
|
|
|
674
|
+
**`syncThenRead(fn)`** -- for read-heavy batches, sync once and run many reads against the local tree within a single exclusive lock, instead of paying a store round-trip per read. It works in both `'strong'` and `'local'` read modes (it always syncs first). Do not mutate the tree inside the callback:
|
|
675
|
+
|
|
676
|
+
```ts
|
|
677
|
+
const total = await instanceA.syncThenRead((tree) => {
|
|
678
|
+
let sum = 0;
|
|
679
|
+
tree.forEachRange(0, 100, (entry) => {
|
|
680
|
+
sum += entry.value.length;
|
|
681
|
+
});
|
|
682
|
+
return sum;
|
|
683
|
+
});
|
|
684
|
+
```
|
|
685
|
+
|
|
654
686
|
```ts
|
|
655
687
|
// Instance A inserts
|
|
656
688
|
const insertedId = await instanceA.put(100, 'draft docs');
|
|
@@ -847,44 +879,45 @@ new InMemoryBTree<TKey, TValue>(config: InMemoryBTreeConfig<TKey>)
|
|
|
847
879
|
|
|
848
880
|
Exposes `InMemoryBTree` methods as async equivalents returning `Promise`. Writes coordinate through the shared store; reads sync before returning when `readMode` is `'strong'` (the default). When `readMode` is `'local'`, reads execute against the local tree without syncing.
|
|
849
881
|
|
|
850
|
-
| Method | Signature | Description
|
|
851
|
-
| ------------------------ | -------------------------------------------------------------------------------------------------- |
|
|
852
|
-
| `sync` | `() => Promise<void>` | Fetch and apply the latest log entries from the shared store.
|
|
853
|
-
| `
|
|
854
|
-
| `
|
|
855
|
-
| `
|
|
856
|
-
| `
|
|
857
|
-
| `
|
|
858
|
-
| `
|
|
859
|
-
| `
|
|
860
|
-
| `
|
|
861
|
-
| `
|
|
862
|
-
| `
|
|
863
|
-
| `
|
|
864
|
-
| `
|
|
865
|
-
| `
|
|
866
|
-
| `
|
|
867
|
-
| `
|
|
868
|
-
| `
|
|
869
|
-
| `
|
|
870
|
-
| `
|
|
871
|
-
| `
|
|
872
|
-
| `
|
|
873
|
-
| `
|
|
874
|
-
| `
|
|
875
|
-
| `
|
|
876
|
-
| `
|
|
877
|
-
| `
|
|
878
|
-
| `
|
|
879
|
-
| `
|
|
880
|
-
| `
|
|
881
|
-
| `
|
|
882
|
-
| `
|
|
883
|
-
| `
|
|
884
|
-
| `
|
|
885
|
-
| `
|
|
886
|
-
| `
|
|
887
|
-
| `
|
|
882
|
+
| Method | Signature | Description |
|
|
883
|
+
| ------------------------ | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
884
|
+
| `sync` | `() => Promise<void>` | Fetch and apply the latest log entries from the shared store. |
|
|
885
|
+
| `syncThenRead` | `<TResult>(fn: (tree: InMemoryBTree<TKey, TValue>) => TResult) => Promise<TResult>` | Sync once, then run `fn` against the local tree within one exclusive lock. |
|
|
886
|
+
| `put` | `(key: TKey, value: TValue) => Promise<EntryId>` | Insert with optimistic concurrency. |
|
|
887
|
+
| `putMany` | `(entries: readonly { key: TKey; value: TValue }[]) => Promise<EntryId[]>` | Batch insert with optimistic concurrency. |
|
|
888
|
+
| `remove` | `(key: TKey) => Promise<BTreeEntry<TKey, TValue> \| null>` | Remove the first matching entry by key. |
|
|
889
|
+
| `removeById` | `(entryId: EntryId) => Promise<BTreeEntry<TKey, TValue> \| null>` | Remove a specific entry by ID. |
|
|
890
|
+
| `peekById` | `(entryId: EntryId) => Promise<BTreeEntry<TKey, TValue> \| null>` | Look up an entry by ID (syncs first). |
|
|
891
|
+
| `updateById` | `(entryId: EntryId, value: TValue) => Promise<BTreeEntry<TKey, TValue> \| null>` | Update an entry by ID with optimistic concurrency. |
|
|
892
|
+
| `popFirst` | `() => Promise<BTreeEntry<TKey, TValue> \| null>` | Remove and return the smallest entry. |
|
|
893
|
+
| `popLast` | `() => Promise<BTreeEntry<TKey, TValue> \| null>` | Remove and return the largest entry. |
|
|
894
|
+
| `deleteRange` | `(startKey: TKey, endKey: TKey, options?: RangeBounds) => Promise<number>` | Delete entries in range with optimistic concurrency. |
|
|
895
|
+
| `clear` | `() => Promise<void>` | Remove all entries with optimistic concurrency. |
|
|
896
|
+
| `peekFirst` | `() => Promise<BTreeEntry<TKey, TValue> \| null>` | Return the smallest entry (syncs first). |
|
|
897
|
+
| `peekLast` | `() => Promise<BTreeEntry<TKey, TValue> \| null>` | Return the largest entry (syncs first). |
|
|
898
|
+
| `findFirst` | `(key: TKey) => Promise<BTreeEntry<TKey, TValue> \| null>` | Return the first entry matching key (syncs first). |
|
|
899
|
+
| `findLast` | `(key: TKey) => Promise<BTreeEntry<TKey, TValue> \| null>` | Return the last entry matching key (syncs first). |
|
|
900
|
+
| `get` | `(key: TKey) => Promise<TValue \| null>` | Return value by key (syncs first). |
|
|
901
|
+
| `hasKey` | `(key: TKey) => Promise<boolean>` | Check key existence (syncs first). |
|
|
902
|
+
| `count` | `(startKey: TKey, endKey: TKey, options?: RangeBounds) => Promise<number>` | Count entries in range (syncs first). |
|
|
903
|
+
| `range` | `(startKey: TKey, endKey: TKey, options?: RangeBounds) => Promise<BTreeEntry<TKey, TValue>[]>` | Range query (syncs first). |
|
|
904
|
+
| `nextHigherKey` | `(key: TKey) => Promise<TKey \| null>` | Next key strictly greater (syncs first). |
|
|
905
|
+
| `nextLowerKey` | `(key: TKey) => Promise<TKey \| null>` | Next key strictly less (syncs first). |
|
|
906
|
+
| `getPairOrNextLower` | `(key: TKey) => Promise<BTreeEntry<TKey, TValue> \| null>` | Exact match or next lower (syncs first). |
|
|
907
|
+
| `entries` | `() => Promise<BTreeEntry<TKey, TValue>[]>` | Return all entries as array (syncs first). |
|
|
908
|
+
| `entriesReversed` | `() => Promise<BTreeEntry<TKey, TValue>[]>` | Return all entries in reverse as array (syncs first). |
|
|
909
|
+
| `keys` | `() => Promise<TKey[]>` | Return all keys as array (syncs first). |
|
|
910
|
+
| `values` | `() => Promise<TValue[]>` | Return all values as array (syncs first). |
|
|
911
|
+
| `forEach` | `(callback: (entry: BTreeEntry<TKey, TValue>) => void) => Promise<void>` | Iterate all entries (syncs first). |
|
|
912
|
+
| `forEachRange` | `(startKey, endKey, callback, options?) => Promise<void>` | Iterate entries in range (syncs first). |
|
|
913
|
+
| `snapshot` | `() => Promise<BTreeEntry<TKey, TValue>[]>` | Return all entries (syncs first). |
|
|
914
|
+
| `size` | `() => Promise<number>` | Return entry count (syncs first). |
|
|
915
|
+
| `getStats` | `() => Promise<BTreeStats>` | Return structural statistics (syncs first). |
|
|
916
|
+
| `assertInvariants` | `() => Promise<void>` | Assert structural integrity (syncs first). |
|
|
917
|
+
| `clone` | `() => Promise<InMemoryBTree<TKey, TValue>>` | Return an independent local copy (syncs first). |
|
|
918
|
+
| `toJSON` | `() => Promise<BTreeJSON<TKey, TValue>>` | Serialize to JSON (syncs first). |
|
|
919
|
+
| `fromJSON` (static) | `(json: BTreeJSON<TKey, TValue>, compareKeys: KeyComparator<TKey>) => InMemoryBTree<TKey, TValue>` | Deserialize from JSON (returns local tree). |
|
|
920
|
+
| `[Symbol.asyncIterator]` | `() => AsyncIterableIterator<BTreeEntry<TKey, TValue>>` | Async iteration over all entries (syncs first). |
|
|
888
921
|
|
|
889
922
|
**Constructor:**
|
|
890
923
|
|
|
@@ -894,26 +927,27 @@ new ConcurrentInMemoryBTree<TKey, TValue>(config: ConcurrentInMemoryBTreeConfig<
|
|
|
894
927
|
|
|
895
928
|
### Exported Types
|
|
896
929
|
|
|
897
|
-
| Type | Description
|
|
898
|
-
| --------------------------------------------- |
|
|
899
|
-
| `EntryId` | Branded `number` identifying a specific entry.
|
|
900
|
-
| `BTreeEntry<TKey, TValue>` | `{ entryId: EntryId; key: TKey; value: TValue }`
|
|
901
|
-
| `BTreeJSON<TKey, TValue>` | Versioned JSON-serializable payload produced by `toJSON()` and consumed by `fromJSON()`.
|
|
902
|
-
| `BTreeStats` | `{ height: number; leafCount: number; branchCount: number; entryCount: number }`
|
|
903
|
-
| `KeyComparator<TKey>` | `(left: TKey, right: TKey) => number`
|
|
904
|
-
| `DuplicateKeyPolicy` | `'allow' \| 'reject' \| 'replace'`
|
|
905
|
-
| `
|
|
906
|
-
| `
|
|
907
|
-
| `
|
|
908
|
-
| `
|
|
909
|
-
| `
|
|
910
|
-
| `
|
|
911
|
-
| `
|
|
912
|
-
| `
|
|
913
|
-
| `
|
|
914
|
-
| `
|
|
915
|
-
|
|
916
|
-
|
|
930
|
+
| Type | Description |
|
|
931
|
+
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
932
|
+
| `EntryId` | Branded `number` identifying a specific entry. |
|
|
933
|
+
| `BTreeEntry<TKey, TValue>` | `{ entryId: EntryId; key: TKey; value: TValue }` |
|
|
934
|
+
| `BTreeJSON<TKey, TValue>` | Versioned JSON-serializable payload produced by `toJSON()` and consumed by `fromJSON()`. |
|
|
935
|
+
| `BTreeStats` | `{ height: number; leafCount: number; branchCount: number; entryCount: number }` |
|
|
936
|
+
| `KeyComparator<TKey>` | `(left: TKey, right: TKey) => number` |
|
|
937
|
+
| `DuplicateKeyPolicy` | `'allow' \| 'reject' \| 'replace'` |
|
|
938
|
+
| `DeleteRebalancePolicy` | `'standard' \| 'lazy'` |
|
|
939
|
+
| `RangeBounds` | `{ lowerBound?: 'inclusive' \| 'exclusive'; upperBound?: 'inclusive' \| 'exclusive' }` |
|
|
940
|
+
| `InMemoryBTreeConfig<TKey>` | `{ compareKeys: KeyComparator<TKey>; maxLeafEntries?: number; maxBranchChildren?: number; duplicateKeys?: DuplicateKeyPolicy; enableEntryIdLookup?: boolean; autoScale?: boolean; deleteRebalancePolicy?: DeleteRebalancePolicy }` |
|
|
941
|
+
| `ReadMode` | `'strong' \| 'local'` |
|
|
942
|
+
| `ConcurrentInMemoryBTreeConfig<TKey, TValue>` | Extends `InMemoryBTreeConfig<TKey>` with `store: SharedTreeStore<TKey, TValue>`, `maxRetries?: number`, `maxSyncMutationsPerBatch?: number`, and `readMode?: ReadMode`. |
|
|
943
|
+
| `SharedTreeStore<TKey, TValue>` | Interface with `getLogEntriesSince(version)` and `append(expectedVersion, mutations)`. |
|
|
944
|
+
| `SharedTreeLog<TKey, TValue>` | `{ version: bigint; mutations: BTreeMutation<TKey, TValue>[] }` |
|
|
945
|
+
| `BTreeMutation<TKey, TValue>` | Discriminated union: `init`, `put`, `putMany`, `remove`, `removeById`, `updateById`, `popFirst`, `popLast`, `deleteRange`, `clear`. |
|
|
946
|
+
| `BTreeValidationError` | Error thrown for comparator or config violations. |
|
|
947
|
+
| `BTreeInvariantError` | Error thrown for tree structural integrity violations. |
|
|
948
|
+
| `BTreeConcurrencyError` | Error thrown for concurrency conflicts or store contract violations. |
|
|
949
|
+
|
|
950
|
+
> **Subpath exports:** The `/core` subpath (`@frostpillar/frostpillar-btree/core`) exports only single-process types: `InMemoryBTree`, `EntryId`, `BTreeEntry`, `BTreeJSON`, `BTreeStats`, `KeyComparator`, `DuplicateKeyPolicy`, `DeleteRebalancePolicy`, `RangeBounds`, `InMemoryBTreeConfig`, `BTreeValidationError`, and `BTreeInvariantError`. Concurrency-related exports (`ConcurrentInMemoryBTree`, `ConcurrentInMemoryBTreeConfig`, `ReadMode`, `SharedTreeStore`, `SharedTreeLog`, `BTreeMutation`, `BTreeConcurrencyError`) are available only from the main entry point.
|
|
917
951
|
|
|
918
952
|
---
|
|
919
953
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type BTreeJSON } from './btree/serialization.cjs';
|
|
2
|
+
import { type BTreeEntry, type BTreeStats, type DeleteRebalancePolicy, type DuplicateKeyPolicy, type EntryId, type InMemoryBTreeConfig, type KeyComparator, type RangeBounds } from './btree/types.cjs';
|
|
3
|
+
export type { BTreeEntry, BTreeJSON, BTreeStats, DeleteRebalancePolicy, DuplicateKeyPolicy, EntryId, InMemoryBTreeConfig, RangeBounds, };
|
|
4
|
+
export declare class InMemoryBTree<TKey, TValue> {
|
|
5
|
+
private readonly state;
|
|
6
|
+
constructor(config: InMemoryBTreeConfig<TKey>);
|
|
7
|
+
put(key: TKey, value: TValue): EntryId;
|
|
8
|
+
putMany(entries: readonly {
|
|
9
|
+
key: TKey;
|
|
10
|
+
value: TValue;
|
|
11
|
+
}[]): EntryId[];
|
|
12
|
+
remove(key: TKey): BTreeEntry<TKey, TValue> | null;
|
|
13
|
+
removeById(entryId: EntryId): BTreeEntry<TKey, TValue> | null;
|
|
14
|
+
peekById(entryId: EntryId): BTreeEntry<TKey, TValue> | null;
|
|
15
|
+
updateById(entryId: EntryId, value: TValue): BTreeEntry<TKey, TValue> | null;
|
|
16
|
+
popFirst(): BTreeEntry<TKey, TValue> | null;
|
|
17
|
+
peekFirst(): BTreeEntry<TKey, TValue> | null;
|
|
18
|
+
peekLast(): BTreeEntry<TKey, TValue> | null;
|
|
19
|
+
popLast(): BTreeEntry<TKey, TValue> | null;
|
|
20
|
+
clear(): void;
|
|
21
|
+
get(key: TKey): TValue | null;
|
|
22
|
+
hasKey(key: TKey): boolean;
|
|
23
|
+
findFirst(key: TKey): BTreeEntry<TKey, TValue> | null;
|
|
24
|
+
findLast(key: TKey): BTreeEntry<TKey, TValue> | null;
|
|
25
|
+
nextHigherKey(key: TKey): TKey | null;
|
|
26
|
+
nextLowerKey(key: TKey): TKey | null;
|
|
27
|
+
getPairOrNextLower(key: TKey): BTreeEntry<TKey, TValue> | null;
|
|
28
|
+
count(startKey: TKey, endKey: TKey, options?: RangeBounds): number;
|
|
29
|
+
deleteRange(startKey: TKey, endKey: TKey, options?: RangeBounds): number;
|
|
30
|
+
range(startKey: TKey, endKey: TKey, options?: RangeBounds): BTreeEntry<TKey, TValue>[];
|
|
31
|
+
entries(): IterableIterator<BTreeEntry<TKey, TValue>>;
|
|
32
|
+
entriesReversed(): IterableIterator<BTreeEntry<TKey, TValue>>;
|
|
33
|
+
keys(): IterableIterator<TKey>;
|
|
34
|
+
values(): IterableIterator<TValue>;
|
|
35
|
+
[Symbol.iterator](): IterableIterator<BTreeEntry<TKey, TValue>>;
|
|
36
|
+
forEachRange(startKey: TKey, endKey: TKey, callback: (entry: BTreeEntry<TKey, TValue>) => void, options?: RangeBounds): void;
|
|
37
|
+
forEach(callback: (entry: BTreeEntry<TKey, TValue>) => void, thisArg?: unknown): void;
|
|
38
|
+
snapshot(): BTreeEntry<TKey, TValue>[];
|
|
39
|
+
clone(): InMemoryBTree<TKey, TValue>;
|
|
40
|
+
toJSON(): BTreeJSON<TKey, TValue>;
|
|
41
|
+
static fromJSON<TKey, TValue>(json: BTreeJSON<TKey, TValue>, compareKeys: KeyComparator<TKey>): InMemoryBTree<TKey, TValue>;
|
|
42
|
+
size(): number;
|
|
43
|
+
assertInvariants(): void;
|
|
44
|
+
getStats(): BTreeStats;
|
|
45
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type BTreeState, type InMemoryBTreeConfig } from './types.cjs';
|
|
2
|
+
export declare const minOccupancy: (max: number) => number;
|
|
3
|
+
export declare const computeAutoScaleTier: (entryCount: number) => {
|
|
4
|
+
readonly maxLeaf: number;
|
|
5
|
+
readonly maxBranch: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const computeNextAutoScaleThreshold: (entryCount: number) => number;
|
|
8
|
+
export declare const createInitialState: <TKey, TValue>(config: InMemoryBTreeConfig<TKey>) => BTreeState<TKey, TValue>;
|
|
9
|
+
export declare const maybeAutoScale: <TKey, TValue>(state: BTreeState<TKey, TValue>) => void;
|
|
10
|
+
export declare const applyAutoScaleCapacitySnapshot: <TKey, TValue>(state: BTreeState<TKey, TValue>, maxLeafEntries: number, maxBranchChildren: number) => void;
|
|
11
|
+
export declare const resetAutoScaleToTier0: <TKey, TValue>(state: BTreeState<TKey, TValue>) => void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type BTreeEntry, type BTreeState, type EntryId, type LeafNode } from './types.cjs';
|
|
2
|
+
export declare const findLeafEntryBySequence: <TKey, TValue>(state: BTreeState<TKey, TValue>, userKey: TKey, sequence: number) => {
|
|
3
|
+
leaf: LeafNode<TKey, TValue>;
|
|
4
|
+
index: number;
|
|
5
|
+
} | null;
|
|
6
|
+
export declare const peekEntryById: <TKey, TValue>(state: BTreeState<TKey, TValue>, entryId: EntryId) => BTreeEntry<TKey, TValue> | null;
|
|
7
|
+
export declare const updateEntryById: <TKey, TValue>(state: BTreeState<TKey, TValue>, entryId: EntryId, newValue: TValue) => BTreeEntry<TKey, TValue> | null;
|
|
8
|
+
export declare const removeEntryById: <TKey, TValue>(state: BTreeState<TKey, TValue>, entryId: EntryId) => BTreeEntry<TKey, TValue> | null;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type BTreeNode, type BTreeState, type KeyComparator, type NodeKey } from './types.cjs';
|
|
2
|
+
export declare const nodeMinKey: <TKey, TValue>(node: BTreeNode<TKey, TValue>) => NodeKey<TKey> | null;
|
|
3
|
+
export declare const compareNodeKeys: <TKey>(comparator: KeyComparator<TKey>, leftKey: TKey, leftSeq: number, rightKey: TKey, rightSeq: number) => number;
|
|
4
|
+
export declare const assertReflexivityAsInvariant: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => void;
|
|
5
|
+
export declare const assertTransitivityAsInvariant: <TKey, TValue>(state: BTreeState<TKey, TValue>, first: TKey, second: TKey, third: TKey) => void;
|
|
6
|
+
export declare const validateLeafLinks: <TKey, TValue>(state: BTreeState<TKey, TValue>, expectedLeafCount: number) => void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type BTreeEntry, type BTreeState, type EntryId } from './types.cjs';
|
|
2
|
+
export { peekEntryById, removeEntryById, updateEntryById, } from './entry-lookup.cjs';
|
|
3
|
+
export declare const putEntry: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey, value: TValue) => EntryId;
|
|
4
|
+
export declare const popFirstEntry: <TKey, TValue>(state: BTreeState<TKey, TValue>) => BTreeEntry<TKey, TValue> | null;
|
|
5
|
+
export declare const popLastEntry: <TKey, TValue>(state: BTreeState<TKey, TValue>) => BTreeEntry<TKey, TValue> | null;
|
|
6
|
+
export declare const removeFirstMatchingEntry: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => BTreeEntry<TKey, TValue> | null;
|
|
7
|
+
export declare const putManyEntries: <TKey, TValue>(state: BTreeState<TKey, TValue>, entries: readonly {
|
|
8
|
+
key: TKey;
|
|
9
|
+
value: TValue;
|
|
10
|
+
}[]) => EntryId[];
|