@optimystic/db-core 0.14.0 → 0.16.2
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/src/blocks/block-store.d.ts +18 -1
- package/dist/src/blocks/block-store.d.ts.map +1 -1
- package/dist/src/blocks/helpers.d.ts +2 -2
- package/dist/src/blocks/helpers.d.ts.map +1 -1
- package/dist/src/blocks/helpers.js +2 -2
- package/dist/src/blocks/helpers.js.map +1 -1
- package/dist/src/btree/btree.d.ts +27 -6
- package/dist/src/btree/btree.d.ts.map +1 -1
- package/dist/src/btree/btree.js +104 -61
- package/dist/src/btree/btree.js.map +1 -1
- package/dist/src/chain/chain.d.ts.map +1 -1
- package/dist/src/chain/chain.js +11 -1
- package/dist/src/chain/chain.js.map +1 -1
- package/dist/src/cluster/index.d.ts +1 -0
- package/dist/src/cluster/index.d.ts.map +1 -1
- package/dist/src/cluster/index.js +1 -0
- package/dist/src/cluster/index.js.map +1 -1
- package/dist/src/cluster/membership.d.ts +49 -0
- package/dist/src/cluster/membership.d.ts.map +1 -0
- package/dist/src/cluster/membership.js +75 -0
- package/dist/src/cluster/membership.js.map +1 -0
- package/dist/src/cluster/structs.d.ts +50 -1
- package/dist/src/cluster/structs.d.ts.map +1 -1
- package/dist/src/cluster/structs.js +9 -1
- package/dist/src/cluster/structs.js.map +1 -1
- package/dist/src/cohort-topic/addressing.d.ts +8 -2
- package/dist/src/cohort-topic/addressing.d.ts.map +1 -1
- package/dist/src/cohort-topic/addressing.js +11 -3
- package/dist/src/cohort-topic/addressing.js.map +1 -1
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts +13 -7
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts.map +1 -1
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.js +17 -6
- package/dist/src/cohort-topic/antidos/bootstrap-evidence.js.map +1 -1
- package/dist/src/cohort-topic/antidos/replay-guard.d.ts +17 -0
- package/dist/src/cohort-topic/antidos/replay-guard.d.ts.map +1 -1
- package/dist/src/cohort-topic/antidos/replay-guard.js +33 -0
- package/dist/src/cohort-topic/antidos/replay-guard.js.map +1 -1
- package/dist/src/cohort-topic/antidos/topic-budget.d.ts +7 -0
- package/dist/src/cohort-topic/antidos/topic-budget.d.ts.map +1 -1
- package/dist/src/cohort-topic/antidos/topic-budget.js +8 -2
- package/dist/src/cohort-topic/antidos/topic-budget.js.map +1 -1
- package/dist/src/cohort-topic/coldstart.d.ts +34 -14
- package/dist/src/cohort-topic/coldstart.d.ts.map +1 -1
- package/dist/src/cohort-topic/coldstart.js +25 -11
- package/dist/src/cohort-topic/coldstart.js.map +1 -1
- package/dist/src/cohort-topic/gossip/bus.d.ts +12 -1
- package/dist/src/cohort-topic/gossip/bus.d.ts.map +1 -1
- package/dist/src/cohort-topic/gossip/bus.js +27 -1
- package/dist/src/cohort-topic/gossip/bus.js.map +1 -1
- package/dist/src/cohort-topic/gossip/view.d.ts +8 -0
- package/dist/src/cohort-topic/gossip/view.d.ts.map +1 -1
- package/dist/src/cohort-topic/gossip/view.js +17 -1
- package/dist/src/cohort-topic/gossip/view.js.map +1 -1
- package/dist/src/cohort-topic/member-engine.d.ts +10 -3
- package/dist/src/cohort-topic/member-engine.d.ts.map +1 -1
- package/dist/src/cohort-topic/member-engine.js +29 -14
- package/dist/src/cohort-topic/member-engine.js.map +1 -1
- package/dist/src/cohort-topic/membership/publisher.d.ts +14 -7
- package/dist/src/cohort-topic/membership/publisher.d.ts.map +1 -1
- package/dist/src/cohort-topic/membership/publisher.js +15 -27
- package/dist/src/cohort-topic/membership/publisher.js.map +1 -1
- package/dist/src/cohort-topic/membership/verifier.d.ts +35 -0
- package/dist/src/cohort-topic/membership/verifier.d.ts.map +1 -1
- package/dist/src/cohort-topic/membership/verifier.js +88 -3
- package/dist/src/cohort-topic/membership/verifier.js.map +1 -1
- package/dist/src/cohort-topic/promotion.d.ts +7 -0
- package/dist/src/cohort-topic/promotion.d.ts.map +1 -1
- package/dist/src/cohort-topic/promotion.js +16 -2
- package/dist/src/cohort-topic/promotion.js.map +1 -1
- package/dist/src/cohort-topic/registration/renewal.d.ts +18 -0
- package/dist/src/cohort-topic/registration/renewal.d.ts.map +1 -1
- package/dist/src/cohort-topic/registration/renewal.js +54 -0
- package/dist/src/cohort-topic/registration/renewal.js.map +1 -1
- package/dist/src/cohort-topic/registration/types.d.ts +12 -0
- package/dist/src/cohort-topic/registration/types.d.ts.map +1 -1
- package/dist/src/cohort-topic/registration/types.js +14 -0
- package/dist/src/cohort-topic/registration/types.js.map +1 -1
- package/dist/src/cohort-topic/service.d.ts +4 -3
- package/dist/src/cohort-topic/service.d.ts.map +1 -1
- package/dist/src/cohort-topic/service.js +38 -12
- package/dist/src/cohort-topic/service.js.map +1 -1
- package/dist/src/cohort-topic/sig/payloads.d.ts +23 -7
- package/dist/src/cohort-topic/sig/payloads.d.ts.map +1 -1
- package/dist/src/cohort-topic/sig/payloads.js +22 -6
- package/dist/src/cohort-topic/sig/payloads.js.map +1 -1
- package/dist/src/cohort-topic/traffic.d.ts +6 -0
- package/dist/src/cohort-topic/traffic.d.ts.map +1 -1
- package/dist/src/cohort-topic/traffic.js +16 -1
- package/dist/src/cohort-topic/traffic.js.map +1 -1
- package/dist/src/cohort-topic/walk.d.ts +22 -7
- package/dist/src/cohort-topic/walk.d.ts.map +1 -1
- package/dist/src/cohort-topic/walk.js +78 -18
- package/dist/src/cohort-topic/walk.js.map +1 -1
- package/dist/src/cohort-topic/wire/codec.d.ts +3 -1
- package/dist/src/cohort-topic/wire/codec.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/codec.js +7 -1
- package/dist/src/cohort-topic/wire/codec.js.map +1 -1
- package/dist/src/cohort-topic/wire/index.d.ts +1 -1
- package/dist/src/cohort-topic/wire/index.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/index.js +1 -1
- package/dist/src/cohort-topic/wire/index.js.map +1 -1
- package/dist/src/cohort-topic/wire/payloads.d.ts +5 -4
- package/dist/src/cohort-topic/wire/payloads.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/payloads.js +14 -5
- package/dist/src/cohort-topic/wire/payloads.js.map +1 -1
- package/dist/src/cohort-topic/wire/primitives.d.ts +65 -0
- package/dist/src/cohort-topic/wire/primitives.d.ts.map +1 -0
- package/dist/src/cohort-topic/wire/primitives.js +173 -0
- package/dist/src/cohort-topic/wire/primitives.js.map +1 -0
- package/dist/src/cohort-topic/wire/types.d.ts +132 -5
- package/dist/src/cohort-topic/wire/types.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/validate.d.ts +15 -5
- package/dist/src/cohort-topic/wire/validate.d.ts.map +1 -1
- package/dist/src/cohort-topic/wire/validate.js +146 -123
- package/dist/src/cohort-topic/wire/validate.js.map +1 -1
- package/dist/src/collection/collection.d.ts +23 -12
- package/dist/src/collection/collection.d.ts.map +1 -1
- package/dist/src/collection/collection.js +111 -35
- package/dist/src/collection/collection.js.map +1 -1
- package/dist/src/collection/struct.d.ts +37 -2
- package/dist/src/collection/struct.d.ts.map +1 -1
- package/dist/src/collection/struct.js +16 -1
- package/dist/src/collection/struct.js.map +1 -1
- package/dist/src/collections/tree/tree.d.ts +18 -1
- package/dist/src/collections/tree/tree.d.ts.map +1 -1
- package/dist/src/collections/tree/tree.js +36 -6
- package/dist/src/collections/tree/tree.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/log/log.d.ts +26 -3
- package/dist/src/log/log.d.ts.map +1 -1
- package/dist/src/log/log.js +34 -7
- package/dist/src/log/log.js.map +1 -1
- package/dist/src/log/struct.d.ts +5 -4
- package/dist/src/log/struct.d.ts.map +1 -1
- package/dist/src/log/struct.js.map +1 -1
- package/dist/src/matchmaking/wire.d.ts +2 -1
- package/dist/src/matchmaking/wire.d.ts.map +1 -1
- package/dist/src/matchmaking/wire.js +13 -92
- package/dist/src/matchmaking/wire.js.map +1 -1
- package/dist/src/network/i-key-network.d.ts +9 -0
- package/dist/src/network/i-key-network.d.ts.map +1 -1
- package/dist/src/network/i-repo.d.ts +8 -0
- package/dist/src/network/i-repo.d.ts.map +1 -1
- package/dist/src/network/struct.d.ts +10 -0
- package/dist/src/network/struct.d.ts.map +1 -1
- package/dist/src/reactivity/push-state.d.ts.map +1 -1
- package/dist/src/reactivity/push-state.js +4 -33
- package/dist/src/reactivity/push-state.js.map +1 -1
- package/dist/src/reactivity/wire-validate.d.ts +7 -22
- package/dist/src/reactivity/wire-validate.d.ts.map +1 -1
- package/dist/src/reactivity/wire-validate.js +7 -73
- package/dist/src/reactivity/wire-validate.js.map +1 -1
- package/dist/src/reactivity/wire.js +3 -3
- package/dist/src/reactivity/wire.js.map +1 -1
- package/dist/src/testing/async-wait.d.ts +23 -0
- package/dist/src/testing/async-wait.d.ts.map +1 -0
- package/dist/src/testing/async-wait.js +42 -0
- package/dist/src/testing/async-wait.js.map +1 -0
- package/dist/src/testing/index.d.ts +3 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +3 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/test-transactor.d.ts +44 -0
- package/dist/src/testing/test-transactor.d.ts.map +1 -0
- package/dist/src/testing/test-transactor.js +423 -0
- package/dist/src/testing/test-transactor.js.map +1 -0
- package/dist/src/transaction/actions-engine.d.ts +6 -3
- package/dist/src/transaction/actions-engine.d.ts.map +1 -1
- package/dist/src/transaction/actions-engine.js +8 -7
- package/dist/src/transaction/actions-engine.js.map +1 -1
- package/dist/src/transaction/coordinator.d.ts +43 -22
- package/dist/src/transaction/coordinator.d.ts.map +1 -1
- package/dist/src/transaction/coordinator.js +443 -178
- package/dist/src/transaction/coordinator.js.map +1 -1
- package/dist/src/transaction/errors.d.ts +82 -0
- package/dist/src/transaction/errors.d.ts.map +1 -0
- package/dist/src/transaction/errors.js +93 -0
- package/dist/src/transaction/errors.js.map +1 -0
- package/dist/src/transaction/index.d.ts +6 -3
- package/dist/src/transaction/index.d.ts.map +1 -1
- package/dist/src/transaction/index.js +4 -2
- package/dist/src/transaction/index.js.map +1 -1
- package/dist/src/transaction/operations-hash.d.ts +119 -0
- package/dist/src/transaction/operations-hash.d.ts.map +1 -0
- package/dist/src/transaction/operations-hash.js +180 -0
- package/dist/src/transaction/operations-hash.js.map +1 -0
- package/dist/src/transaction/read-dependency-collector.d.ts +43 -0
- package/dist/src/transaction/read-dependency-collector.d.ts.map +1 -0
- package/dist/src/transaction/read-dependency-collector.js +69 -0
- package/dist/src/transaction/read-dependency-collector.js.map +1 -0
- package/dist/src/transaction/session.d.ts +12 -3
- package/dist/src/transaction/session.d.ts.map +1 -1
- package/dist/src/transaction/session.js +35 -9
- package/dist/src/transaction/session.js.map +1 -1
- package/dist/src/transaction/transaction.d.ts +162 -1
- package/dist/src/transaction/transaction.d.ts.map +1 -1
- package/dist/src/transaction/transaction.js +85 -3
- package/dist/src/transaction/transaction.js.map +1 -1
- package/dist/src/transaction/validator.d.ts +3 -11
- package/dist/src/transaction/validator.d.ts.map +1 -1
- package/dist/src/transaction/validator.js +69 -28
- package/dist/src/transaction/validator.js.map +1 -1
- package/dist/src/transactor/network-transactor.d.ts +35 -0
- package/dist/src/transactor/network-transactor.d.ts.map +1 -1
- package/dist/src/transactor/network-transactor.js +146 -40
- package/dist/src/transactor/network-transactor.js.map +1 -1
- package/dist/src/transactor/transactor-source.d.ts +19 -5
- package/dist/src/transactor/transactor-source.d.ts.map +1 -1
- package/dist/src/transactor/transactor-source.js +43 -11
- package/dist/src/transactor/transactor-source.js.map +1 -1
- package/dist/src/transform/atomic-proxy.d.ts +35 -5
- package/dist/src/transform/atomic-proxy.d.ts.map +1 -1
- package/dist/src/transform/atomic-proxy.js +39 -7
- package/dist/src/transform/atomic-proxy.js.map +1 -1
- package/dist/src/transform/cache-source.d.ts +36 -5
- package/dist/src/transform/cache-source.d.ts.map +1 -1
- package/dist/src/transform/cache-source.js +84 -8
- package/dist/src/transform/cache-source.js.map +1 -1
- package/dist/src/transform/helpers.d.ts.map +1 -1
- package/dist/src/transform/helpers.js +8 -2
- package/dist/src/transform/helpers.js.map +1 -1
- package/dist/src/transform/tracker.d.ts +17 -2
- package/dist/src/transform/tracker.d.ts.map +1 -1
- package/dist/src/transform/tracker.js +66 -11
- package/dist/src/transform/tracker.js.map +1 -1
- package/dist/src/utility/backoff.d.ts +48 -0
- package/dist/src/utility/backoff.d.ts.map +1 -0
- package/dist/src/utility/backoff.js +60 -0
- package/dist/src/utility/backoff.js.map +1 -0
- package/dist/src/utility/pending.d.ts +1 -0
- package/dist/src/utility/pending.d.ts.map +1 -1
- package/dist/src/utility/pending.js +3 -1
- package/dist/src/utility/pending.js.map +1 -1
- package/package.json +4 -4
- package/src/blocks/block-store.ts +19 -1
- package/src/blocks/helpers.ts +3 -3
- package/src/btree/btree.ts +108 -63
- package/src/chain/chain.ts +11 -1
- package/src/cluster/index.ts +1 -0
- package/src/cluster/membership.ts +85 -0
- package/src/cluster/structs.ts +51 -1
- package/src/cohort-topic/addressing.ts +12 -4
- package/src/cohort-topic/antidos/bootstrap-evidence.ts +21 -9
- package/src/cohort-topic/antidos/replay-guard.ts +37 -0
- package/src/cohort-topic/antidos/topic-budget.ts +17 -2
- package/src/cohort-topic/coldstart.ts +48 -15
- package/src/cohort-topic/gossip/bus.ts +39 -2
- package/src/cohort-topic/gossip/view.ts +26 -1
- package/src/cohort-topic/member-engine.ts +36 -15
- package/src/cohort-topic/membership/publisher.ts +25 -33
- package/src/cohort-topic/membership/verifier.ts +119 -3
- package/src/cohort-topic/promotion.ts +23 -2
- package/src/cohort-topic/registration/renewal.ts +73 -1
- package/src/cohort-topic/registration/types.ts +15 -0
- package/src/cohort-topic/service.ts +41 -15
- package/src/cohort-topic/sig/payloads.ts +29 -9
- package/src/cohort-topic/traffic.ts +23 -1
- package/src/cohort-topic/walk.ts +95 -24
- package/src/cohort-topic/wire/codec.ts +12 -0
- package/src/cohort-topic/wire/index.ts +2 -0
- package/src/cohort-topic/wire/payloads.ts +14 -5
- package/src/cohort-topic/wire/primitives.ts +188 -0
- package/src/cohort-topic/wire/types.ts +136 -4
- package/src/cohort-topic/wire/validate.ts +168 -134
- package/src/collection/collection.ts +123 -40
- package/src/collection/struct.ts +44 -2
- package/src/collections/tree/tree.ts +42 -5
- package/src/index.ts +1 -0
- package/src/log/log.ts +37 -9
- package/src/log/struct.ts +5 -4
- package/src/matchmaking/wire.ts +25 -102
- package/src/network/i-key-network.ts +10 -0
- package/src/network/i-repo.ts +8 -0
- package/src/network/struct.ts +10 -0
- package/src/reactivity/push-state.ts +4 -37
- package/src/reactivity/wire-validate.ts +7 -81
- package/src/reactivity/wire.ts +3 -3
- package/src/testing/async-wait.ts +65 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/test-transactor.ts +468 -0
- package/src/transaction/actions-engine.ts +8 -6
- package/src/transaction/coordinator.ts +498 -229
- package/src/transaction/errors.ts +91 -0
- package/src/transaction/index.ts +23 -3
- package/src/transaction/operations-hash.ts +196 -0
- package/src/transaction/read-dependency-collector.ts +78 -0
- package/src/transaction/session.ts +37 -9
- package/src/transaction/transaction.ts +211 -4
- package/src/transaction/validator.ts +73 -48
- package/src/transactor/network-transactor.ts +164 -49
- package/src/transactor/transactor-source.ts +47 -12
- package/src/transform/atomic-proxy.ts +92 -49
- package/src/transform/cache-source.ts +87 -9
- package/src/transform/helpers.ts +8 -2
- package/src/transform/tracker.ts +69 -11
- package/src/utility/backoff.ts +95 -0
- package/src/utility/pending.ts +3 -1
- package/src/transaction/context.ts +0 -103
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import type { BlockType, IBlock, BlockId, BlockHeader, BlockOperation } from "./index.js";
|
|
2
|
+
/** Why a block was read, used to filter the optimistic-concurrency conflict (read) set.
|
|
3
|
+
*
|
|
4
|
+
* - `value` — the transaction's result depends on this block's CONTENT (a leaf/entry, a log
|
|
5
|
+
* entry, or an interior node whose keys/counts were used as data). Always retained.
|
|
6
|
+
* - `navigation` — an interior structural block (a B-tree branch) walked through ONLY to reach
|
|
7
|
+
* a separately-captured `value` read further down the same descent. May be dropped from the
|
|
8
|
+
* conflict set, because any concurrent restructuring that would change the queried result also
|
|
9
|
+
* bumps the revision of a `value` block that stays in the set (the target leaf). See
|
|
10
|
+
* docs/correctness.md Theorem 5.
|
|
11
|
+
*
|
|
12
|
+
* Defaults to `value` EVERYWHERE a read is captured, so an unclassified read is always retained
|
|
13
|
+
* (fail-safe): a forgotten tag can only cause an extra false-positive rejection, never a missed
|
|
14
|
+
* conflict. Only the B-tree point-lookup descent opts specific interior reads into `navigation`. */
|
|
15
|
+
export type ReadPurpose = 'value' | 'navigation';
|
|
2
16
|
export type BlockSource<T extends IBlock> = {
|
|
3
17
|
createBlockHeader(type: BlockType, newId?: BlockId): BlockHeader;
|
|
4
|
-
|
|
18
|
+
/** Fetch a block by id. `purpose` classifies WHY the block is being read for OCC read-set
|
|
19
|
+
* filtering (see {@link ReadPurpose}); it defaults to `value`, so existing callers that omit
|
|
20
|
+
* it capture a retained read exactly as before. */
|
|
21
|
+
tryGet(id: BlockId, purpose?: ReadPurpose): Promise<T | undefined>;
|
|
5
22
|
generateId(): BlockId;
|
|
6
23
|
};
|
|
7
24
|
export type BlockStore<T extends IBlock> = BlockSource<T> & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-store.d.ts","sourceRoot":"","sources":["../../../src/blocks/block-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1F,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,IAAI;IAC3C,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IACjE,MAAM,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"block-store.d.ts","sourceRoot":"","sources":["../../../src/blocks/block-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1F;;;;;;;;;;;;oGAYoG;AACpG,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,YAAY,CAAC;AAEjD,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,IAAI;IAC3C,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IACjE;;wDAEoD;IACpD,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACnE,UAAU,IAAI,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG;IAC3D,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,cAAc,GAAG,IAAI,CAAC;IACnD,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BlockOperation, IBlock, BlockId, BlockStore } from "../index.js";
|
|
2
|
-
export declare function get<T extends IBlock>(store: BlockStore<T>, id: BlockId): Promise<T>;
|
|
1
|
+
import type { BlockOperation, IBlock, BlockId, BlockStore, ReadPurpose } from "../index.js";
|
|
2
|
+
export declare function get<T extends IBlock>(store: BlockStore<T>, id: BlockId, purpose?: ReadPurpose): Promise<T>;
|
|
3
3
|
export declare function apply<T extends IBlock>(store: BlockStore<T>, block: IBlock, op: BlockOperation): void;
|
|
4
4
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/blocks/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/blocks/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG5F,wBAAsB,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAIhH;AAED,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,cAAc,QAG9F"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { applyOperation } from "../transform/helpers.js";
|
|
2
|
-
export async function get(store, id) {
|
|
3
|
-
const block = await store.tryGet(id);
|
|
2
|
+
export async function get(store, id, purpose) {
|
|
3
|
+
const block = await store.tryGet(id, purpose);
|
|
4
4
|
if (!block)
|
|
5
5
|
throw Error(`Missing block (${id})`);
|
|
6
6
|
return block;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/blocks/helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,GAAG,CAAmB,KAAoB,EAAE,EAAW;
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/blocks/helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,GAAG,CAAmB,KAAoB,EAAE,EAAW,EAAE,OAAqB;IACnG,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK;QAAE,MAAM,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACjD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,MAAM,UAAU,KAAK,CAAmB,KAAoB,EAAE,KAAa,EAAE,EAAkB;IAC9F,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1B,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -2,6 +2,7 @@ import { Path, type ITreeTrunk, type KeyRange, type getTrunkFunc } from "./index
|
|
|
2
2
|
import type { BlockId, BlockStore } from "../blocks/index.js";
|
|
3
3
|
import type { BranchNode, ITreeNode, LeafNode } from "./nodes.js";
|
|
4
4
|
import type { TreeBlock } from "./tree-block.js";
|
|
5
|
+
import { type AtomicScope } from "../transform/atomic-proxy.js";
|
|
5
6
|
export declare const NodeCapacity = 64;
|
|
6
7
|
/**
|
|
7
8
|
* Represents a lightweight B+(ish)Tree (data at leaves, but no linked list of leaves).
|
|
@@ -14,24 +15,29 @@ export declare class BTree<TKey, TEntry> {
|
|
|
14
15
|
readonly trunk: ITreeTrunk;
|
|
15
16
|
readonly keyFromEntry: (entry: TEntry) => TKey;
|
|
16
17
|
readonly compare: (a: TKey, b: TKey) => number;
|
|
18
|
+
readonly nodeCapacity: number;
|
|
17
19
|
protected _version: number;
|
|
18
20
|
private _proxy?;
|
|
19
21
|
/**
|
|
20
22
|
* @param [compare=(a: TKey, b: TKey) => a < b ? -1 : a > b ? 1 : 0] a comparison function for keys. The default uses < and > operators.
|
|
21
23
|
* @param [keyFromEntry=(entry: TEntry) => entry as unknown as TKey] a function to extract the key from an entry. The default assumes the key is the entry itself.
|
|
22
24
|
*/
|
|
23
|
-
constructor(store: BlockStore<ITreeNode>, trunk: ITreeTrunk, keyFromEntry?: (entry: TEntry) => TKey, compare?: (a: TKey, b: TKey) => number);
|
|
25
|
+
constructor(store: BlockStore<ITreeNode>, trunk: ITreeTrunk, keyFromEntry?: (entry: TEntry) => TKey, compare?: (a: TKey, b: TKey) => number, nodeCapacity?: number);
|
|
24
26
|
private atomic;
|
|
25
27
|
static createRoot(store: BlockStore<ITreeNode>): LeafNode<never>;
|
|
26
|
-
static create<TKey, TEntry>(store: BlockStore<ITreeNode | TreeBlock>, createTrunk: getTrunkFunc, keyFromEntry?: (entry: TEntry) => TKey, compare?: (a: TKey, b: TKey) => 0 | 1 | -1, newId?: BlockId): BTree<TKey, TEntry>;
|
|
28
|
+
static create<TKey, TEntry>(store: BlockStore<ITreeNode | TreeBlock>, createTrunk: getTrunkFunc, keyFromEntry?: (entry: TEntry) => TKey, compare?: (a: TKey, b: TKey) => 0 | 1 | -1, nodeCapacity?: number, newId?: BlockId): BTree<TKey, TEntry>;
|
|
27
29
|
/** @returns a path to the first entry (on = false if no entries) */
|
|
28
30
|
first(): Promise<Path<TKey, TEntry>>;
|
|
29
31
|
/** @returns a path to the last entry (on = false if no entries) */
|
|
30
32
|
last(): Promise<Path<TKey, TEntry>>;
|
|
31
33
|
/** Attempts to find the given key
|
|
32
34
|
* @returns Path to the key or the "crack" before it. If `on` is true on the resulting path, the key was found.
|
|
33
|
-
* If `on` is false, next() and prior() can attempt to move to the nearest match.
|
|
34
|
-
|
|
35
|
+
* If `on` is false, next() and prior() can attempt to move to the nearest match.
|
|
36
|
+
* @param navigate when true, the interior descent nodes are captured as droppable `navigation`
|
|
37
|
+
* reads (see {@link getPath}). DEFAULT false: `find` returns a Path a caller may use to seed a
|
|
38
|
+
* range scan (`ascending`/`next`), whose result depends on tree shape, so its structural reads
|
|
39
|
+
* must stay retained. Only {@link get} — a point lookup with no such escape — opts in. */
|
|
40
|
+
find(key: TKey, navigate?: boolean): Promise<Path<TKey, TEntry>>;
|
|
35
41
|
/** Retrieves the entry for the given key.
|
|
36
42
|
* Use find instead for a path to the key, the nearest match, or as a basis for navigation.
|
|
37
43
|
* @returns the entry for the given key if found; undefined otherwise. */
|
|
@@ -44,6 +50,11 @@ export declare class BTree<TKey, TEntry> {
|
|
|
44
50
|
range(range: KeyRange<TKey>): AsyncIterableIterator<Path<TKey, TEntry>>;
|
|
45
51
|
/** @returns true if the given path remains valid; false if the tree has been mutated, invalidating the path. */
|
|
46
52
|
isValid(path: Path<TKey, TEntry>): boolean;
|
|
53
|
+
/** Bump the version so every Path handed out before now reports invalid (see {@link isValid}).
|
|
54
|
+
* Needed when the tree's data was mutated through a DIFFERENT store binding than this instance —
|
|
55
|
+
* e.g. the tree collection's action handler writes through a per-action Atomic store, so this
|
|
56
|
+
* read-side btree never sees the mutation and must be told to invalidate outstanding paths. */
|
|
57
|
+
invalidatePaths(): void;
|
|
47
58
|
/**
|
|
48
59
|
* Adds a value to the tree. Be sure to check the result, as the tree does not allow duplicate keys.
|
|
49
60
|
* Added entries are frozen to ensure immutability
|
|
@@ -57,7 +68,7 @@ export declare class BTree<TKey, TEntry> {
|
|
|
57
68
|
* * on = false if update/insert failed.
|
|
58
69
|
* * wasUpdate = true, given path is not on an entry
|
|
59
70
|
* * else newEntry's new key already present; returned path is "near" existing entry */
|
|
60
|
-
updateAt(path: Path<TKey, TEntry>, newEntry: TEntry): Promise<[path: Path<TKey, TEntry>, wasUpdate: boolean]>;
|
|
71
|
+
updateAt(path: Path<TKey, TEntry>, newEntry: TEntry, parent?: AtomicScope): Promise<[path: Path<TKey, TEntry>, wasUpdate: boolean]>;
|
|
61
72
|
/** Inserts the entry if it doesn't exist, or updates it if it does.
|
|
62
73
|
* The entry is frozen to ensure immutability.
|
|
63
74
|
* @returns path to the new entry. on = true if existing; on = false if new. */
|
|
@@ -104,7 +115,17 @@ export declare class BTree<TKey, TEntry> {
|
|
|
104
115
|
private internalDescending;
|
|
105
116
|
private findFirst;
|
|
106
117
|
private findLast;
|
|
107
|
-
|
|
118
|
+
/** Descend from `node` toward `key`, building the path. When `navigate` is true this is a point
|
|
119
|
+
* lookup (from {@link get}): each interior branch read below the root is captured as a droppable
|
|
120
|
+
* `navigation` read, and the terminal leaf is upgraded back to a retained `value` read — the
|
|
121
|
+
* result depends only on the leaf, and any concurrent restructuring that would change the result
|
|
122
|
+
* also bumps the leaf's revision (Theorem 5), so the interior reads are redundant. When false
|
|
123
|
+
* (find/range/scan/write descents) every read stays `value` (retained). */
|
|
124
|
+
protected getPath(node: ITreeNode, key: TKey, navigate?: boolean): Promise<Path<TKey, TEntry>>;
|
|
125
|
+
/** Upgrade a captured read of `id` to a retained `value` read via the store chain's read
|
|
126
|
+
* collector (duck-typed — a no-op for stores without one, e.g. test doubles or log-walk
|
|
127
|
+
* caches). Used by a point lookup to pin its terminal leaf. */
|
|
128
|
+
private markReadValue;
|
|
108
129
|
private indexOfEntry;
|
|
109
130
|
protected indexOfKey(keys: TKey[], key: TKey): number;
|
|
110
131
|
private internalNext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"btree.d.ts","sourceRoot":"","sources":["../../../src/btree/btree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAG9D,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"btree.d.ts","sourceRoot":"","sources":["../../../src/btree/btree.ts"],"names":[],"mappings":"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"}
|
package/dist/src/btree/btree.js
CHANGED
|
@@ -14,30 +14,32 @@ export class BTree {
|
|
|
14
14
|
trunk;
|
|
15
15
|
keyFromEntry;
|
|
16
16
|
compare;
|
|
17
|
+
nodeCapacity;
|
|
17
18
|
_version = 0; // only for path invalidation
|
|
18
19
|
_proxy;
|
|
19
20
|
/**
|
|
20
21
|
* @param [compare=(a: TKey, b: TKey) => a < b ? -1 : a > b ? 1 : 0] a comparison function for keys. The default uses < and > operators.
|
|
21
22
|
* @param [keyFromEntry=(entry: TEntry) => entry as unknown as TKey] a function to extract the key from an entry. The default assumes the key is the entry itself.
|
|
22
23
|
*/
|
|
23
|
-
constructor(store, trunk, keyFromEntry = (entry) => entry, compare = (a, b) => a < b ? -1 : a > b ? 1 : 0) {
|
|
24
|
+
constructor(store, trunk, keyFromEntry = (entry) => entry, compare = (a, b) => a < b ? -1 : a > b ? 1 : 0, nodeCapacity = NodeCapacity) {
|
|
24
25
|
this.store = store;
|
|
25
26
|
this.trunk = trunk;
|
|
26
27
|
this.keyFromEntry = keyFromEntry;
|
|
27
28
|
this.compare = compare;
|
|
29
|
+
this.nodeCapacity = nodeCapacity;
|
|
28
30
|
}
|
|
29
|
-
atomic(fn) {
|
|
30
|
-
return this._proxy ? this._proxy.atomic(fn) : fn();
|
|
31
|
+
atomic(fn, parent) {
|
|
32
|
+
return this._proxy ? this._proxy.atomic(fn, parent) : fn(parent);
|
|
31
33
|
}
|
|
32
34
|
static createRoot(store) {
|
|
33
35
|
return newLeafNode(store, []);
|
|
34
36
|
}
|
|
35
|
-
static create(store, createTrunk, keyFromEntry = (entry) => entry, compare = (a, b) => a < b ? -1 : a > b ? 1 : 0, newId) {
|
|
37
|
+
static create(store, createTrunk, keyFromEntry = (entry) => entry, compare = (a, b) => a < b ? -1 : a > b ? 1 : 0, nodeCapacity = NodeCapacity, newId) {
|
|
36
38
|
const proxy = new AtomicProxy(store);
|
|
37
39
|
const root = BTree.createRoot(proxy);
|
|
38
40
|
proxy.insert(root);
|
|
39
41
|
const trunk = createTrunk(proxy, root.header.id, newId);
|
|
40
|
-
const tree = new BTree(proxy, trunk, keyFromEntry, compare);
|
|
42
|
+
const tree = new BTree(proxy, trunk, keyFromEntry, compare, nodeCapacity);
|
|
41
43
|
tree._proxy = proxy;
|
|
42
44
|
return tree;
|
|
43
45
|
}
|
|
@@ -51,15 +53,23 @@ export class BTree {
|
|
|
51
53
|
}
|
|
52
54
|
/** Attempts to find the given key
|
|
53
55
|
* @returns Path to the key or the "crack" before it. If `on` is true on the resulting path, the key was found.
|
|
54
|
-
* If `on` is false, next() and prior() can attempt to move to the nearest match.
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
* If `on` is false, next() and prior() can attempt to move to the nearest match.
|
|
57
|
+
* @param navigate when true, the interior descent nodes are captured as droppable `navigation`
|
|
58
|
+
* reads (see {@link getPath}). DEFAULT false: `find` returns a Path a caller may use to seed a
|
|
59
|
+
* range scan (`ascending`/`next`), whose result depends on tree shape, so its structural reads
|
|
60
|
+
* must stay retained. Only {@link get} — a point lookup with no such escape — opts in. */
|
|
61
|
+
async find(key, navigate = false) {
|
|
62
|
+
return await this.getPath(await this.trunk.get(), key, navigate);
|
|
57
63
|
}
|
|
58
64
|
/** Retrieves the entry for the given key.
|
|
59
65
|
* Use find instead for a path to the key, the nearest match, or as a basis for navigation.
|
|
60
66
|
* @returns the entry for the given key if found; undefined otherwise. */
|
|
61
67
|
async get(key) {
|
|
62
|
-
|
|
68
|
+
// Value-of-key point lookup: the result depends ONLY on the terminal leaf's content, so the
|
|
69
|
+
// interior descent nodes are pure navigation and are dropped from the OCC conflict set. The
|
|
70
|
+
// returned Path is consumed by `at` and discarded — it never seeds a scan — so navigate=true
|
|
71
|
+
// is safe here (unlike the public `find`).
|
|
72
|
+
return this.at(await this.find(key, /* navigate */ true));
|
|
63
73
|
}
|
|
64
74
|
/** @returns the entry for the given path if on an entry; undefined otherwise. */
|
|
65
75
|
at(path) {
|
|
@@ -97,6 +107,13 @@ export class BTree {
|
|
|
97
107
|
isValid(path) {
|
|
98
108
|
return path.version === this._version;
|
|
99
109
|
}
|
|
110
|
+
/** Bump the version so every Path handed out before now reports invalid (see {@link isValid}).
|
|
111
|
+
* Needed when the tree's data was mutated through a DIFFERENT store binding than this instance —
|
|
112
|
+
* e.g. the tree collection's action handler writes through a per-action Atomic store, so this
|
|
113
|
+
* read-side btree never sees the mutation and must be told to invalidate outstanding paths. */
|
|
114
|
+
invalidatePaths() {
|
|
115
|
+
++this._version;
|
|
116
|
+
}
|
|
100
117
|
/**
|
|
101
118
|
* Adds a value to the tree. Be sure to check the result, as the tree does not allow duplicate keys.
|
|
102
119
|
* Added entries are frozen to ensure immutability
|
|
@@ -119,7 +136,7 @@ export class BTree {
|
|
|
119
136
|
* * on = false if update/insert failed.
|
|
120
137
|
* * wasUpdate = true, given path is not on an entry
|
|
121
138
|
* * else newEntry's new key already present; returned path is "near" existing entry */
|
|
122
|
-
async updateAt(path, newEntry) {
|
|
139
|
+
async updateAt(path, newEntry, parent) {
|
|
123
140
|
return this.atomic(async () => {
|
|
124
141
|
this.validatePath(path);
|
|
125
142
|
if (path.on) {
|
|
@@ -130,7 +147,7 @@ export class BTree {
|
|
|
130
147
|
result[0].version = ++this._version;
|
|
131
148
|
}
|
|
132
149
|
return result;
|
|
133
|
-
});
|
|
150
|
+
}, parent);
|
|
134
151
|
}
|
|
135
152
|
/** Inserts the entry if it doesn't exist, or updates it if it does.
|
|
136
153
|
* The entry is frozen to ensure immutability.
|
|
@@ -155,11 +172,13 @@ export class BTree {
|
|
|
155
172
|
* @returns path to new entry and whether an update or insert attempted.
|
|
156
173
|
* If getUpdated callback returns a row that is already present, the resulting path will not be on. */
|
|
157
174
|
async merge(newEntry, getUpdated) {
|
|
158
|
-
return this.atomic(async () => {
|
|
159
|
-
const newKey =
|
|
175
|
+
return this.atomic(async (scope) => {
|
|
176
|
+
const newKey = this.keyFromEntry(newEntry);
|
|
160
177
|
const path = await this.find(newKey);
|
|
161
178
|
if (path.on) {
|
|
162
|
-
|
|
179
|
+
// Thread this scope into updateAt so the nested call joins this atomic batch
|
|
180
|
+
// (reuses the tracker) rather than opening/committing a second scope.
|
|
181
|
+
const result = await this.updateAt(path, getUpdated(this.getEntry(path)), scope); // Don't use internalUpdate - need to freeze and check for mutation
|
|
163
182
|
// Note: updateAt already increments version, so don't double-increment here
|
|
164
183
|
return result;
|
|
165
184
|
}
|
|
@@ -244,7 +263,7 @@ export class BTree {
|
|
|
244
263
|
/** @returns a path one step backward. on will be true if the path hasn't hit the end. */
|
|
245
264
|
async prior(path) {
|
|
246
265
|
const newPath = path.clone();
|
|
247
|
-
this.movePrior(newPath);
|
|
266
|
+
await this.movePrior(newPath);
|
|
248
267
|
return newPath;
|
|
249
268
|
}
|
|
250
269
|
/** Attempts to advance the given path one step backwards. (mutates the path) */
|
|
@@ -294,20 +313,39 @@ export class BTree {
|
|
|
294
313
|
}
|
|
295
314
|
return endPath;
|
|
296
315
|
}
|
|
297
|
-
|
|
316
|
+
/** Descend from `node` toward `key`, building the path. When `navigate` is true this is a point
|
|
317
|
+
* lookup (from {@link get}): each interior branch read below the root is captured as a droppable
|
|
318
|
+
* `navigation` read, and the terminal leaf is upgraded back to a retained `value` read — the
|
|
319
|
+
* result depends only on the leaf, and any concurrent restructuring that would change the result
|
|
320
|
+
* also bumps the leaf's revision (Theorem 5), so the interior reads are redundant. When false
|
|
321
|
+
* (find/range/scan/write descents) every read stays `value` (retained). */
|
|
322
|
+
async getPath(node, key, navigate = false) {
|
|
298
323
|
if (node.header.type === TreeLeafBlockType) {
|
|
299
324
|
const leaf = node;
|
|
325
|
+
if (navigate) {
|
|
326
|
+
// The leaf ends a point-lookup descent: its content is the load-bearing VALUE read.
|
|
327
|
+
// Its parent fetched it as `navigation` (a child's type is unknown before reading);
|
|
328
|
+
// upgrade it (value-wins) so it is retained while the interior nodes above are dropped.
|
|
329
|
+
this.markReadValue(leaf.header.id);
|
|
330
|
+
}
|
|
300
331
|
const [on, index] = this.indexOfEntry(leaf.entries, key);
|
|
301
332
|
return new Path([], leaf, index, on, this._version);
|
|
302
333
|
}
|
|
303
334
|
else {
|
|
304
335
|
const branch = node;
|
|
305
336
|
const index = this.indexOfKey(branch.partitions, key);
|
|
306
|
-
const
|
|
337
|
+
const child = await get(this.store, branch.nodes[index], navigate ? 'navigation' : 'value');
|
|
338
|
+
const path = await this.getPath(child, key, navigate);
|
|
307
339
|
path.branches.unshift(new PathBranch(branch, index));
|
|
308
340
|
return path;
|
|
309
341
|
}
|
|
310
342
|
}
|
|
343
|
+
/** Upgrade a captured read of `id` to a retained `value` read via the store chain's read
|
|
344
|
+
* collector (duck-typed — a no-op for stores without one, e.g. test doubles or log-walk
|
|
345
|
+
* caches). Used by a point lookup to pin its terminal leaf. */
|
|
346
|
+
markReadValue(id) {
|
|
347
|
+
this.store.markReadValue?.(id);
|
|
348
|
+
}
|
|
311
349
|
indexOfEntry(entries, key) {
|
|
312
350
|
let lo = 0;
|
|
313
351
|
let hi = entries.length - 1;
|
|
@@ -346,35 +384,36 @@ export class BTree {
|
|
|
346
384
|
if (!path.on) { // Attempt to move off of crack
|
|
347
385
|
path.on = path.branches.every(branch => branch.index >= 0 && branch.index < branch.node.nodes.length)
|
|
348
386
|
&& path.leafIndex >= 0 && path.leafIndex < path.leafNode.entries.length;
|
|
349
|
-
if (path.on) {
|
|
350
|
-
return;
|
|
387
|
+
if (path.on || path.leafIndex < path.leafNode.entries.length) {
|
|
388
|
+
return; // got on an entry, or an interior crack — nothing to advance into
|
|
351
389
|
}
|
|
390
|
+
// end-of-leaf crack (leafIndex === entries.length): fall through to branch-popping leaf-advance
|
|
352
391
|
}
|
|
353
|
-
else if (path.leafIndex
|
|
354
|
-
let popCount = 0;
|
|
355
|
-
let found = false;
|
|
356
|
-
const last = path.branches.length - 1;
|
|
357
|
-
while (popCount <= last && !found) {
|
|
358
|
-
const branch = path.branches[last - popCount];
|
|
359
|
-
if (branch.index === branch.node.partitions.length) // last node in branch
|
|
360
|
-
++popCount;
|
|
361
|
-
else
|
|
362
|
-
found = true;
|
|
363
|
-
}
|
|
364
|
-
if (!found) {
|
|
365
|
-
path.leafIndex = path.leafNode.entries.length; // after last row = end crack
|
|
366
|
-
path.on = false;
|
|
367
|
-
}
|
|
368
|
-
else {
|
|
369
|
-
path.branches.splice(-popCount, popCount);
|
|
370
|
-
const branch = path.branches.at(-1);
|
|
371
|
-
++branch.index;
|
|
372
|
-
this.moveToFirst(await get(this.store, branch.node.nodes[branch.index]), path);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
else {
|
|
392
|
+
else if (path.leafIndex < path.leafNode.entries.length - 1) {
|
|
376
393
|
++path.leafIndex;
|
|
377
394
|
path.on = true;
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
// on the last entry of the leaf, or off an end-of-leaf crack: advance into the next leaf
|
|
398
|
+
let popCount = 0;
|
|
399
|
+
let found = false;
|
|
400
|
+
const last = path.branches.length - 1;
|
|
401
|
+
while (popCount <= last && !found) {
|
|
402
|
+
const branch = path.branches[last - popCount];
|
|
403
|
+
if (branch.index === branch.node.partitions.length) // last node in branch
|
|
404
|
+
++popCount;
|
|
405
|
+
else
|
|
406
|
+
found = true;
|
|
407
|
+
}
|
|
408
|
+
if (!found) {
|
|
409
|
+
path.leafIndex = path.leafNode.entries.length; // after last row = end crack
|
|
410
|
+
path.on = false;
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
path.branches.splice(-popCount, popCount);
|
|
414
|
+
const branch = path.branches.at(-1);
|
|
415
|
+
++branch.index;
|
|
416
|
+
await this.moveToFirst(await get(this.store, branch.node.nodes[branch.index]), path);
|
|
378
417
|
}
|
|
379
418
|
}
|
|
380
419
|
async internalPrior(path) {
|
|
@@ -413,7 +452,7 @@ export class BTree {
|
|
|
413
452
|
if (this.compare(oldKey, newKey) !== 0) { // if key changed, delete and re-insert
|
|
414
453
|
let newPath = await this.internalInsert(newEntry);
|
|
415
454
|
if (newPath.on) { // insert succeeded
|
|
416
|
-
this.internalDelete(await this.find(oldKey)); // Re-find - the prior insert invalidated the path
|
|
455
|
+
await this.internalDelete(await this.find(oldKey)); // Re-find - the prior insert invalidated the path
|
|
417
456
|
newPath = await this.find(newKey); // Re-find- delete invalidated path
|
|
418
457
|
}
|
|
419
458
|
return [newPath, false];
|
|
@@ -463,7 +502,7 @@ export class BTree {
|
|
|
463
502
|
}
|
|
464
503
|
if (split) {
|
|
465
504
|
const newBranch = newBranchNode(this.store, [split.key], [await this.trunk.getId(), split.right.header.id]);
|
|
466
|
-
|
|
505
|
+
this.store.insert(newBranch);
|
|
467
506
|
await this.trunk.set(newBranch);
|
|
468
507
|
path.branches.unshift(new PathBranch(newBranch, split.indexDelta));
|
|
469
508
|
}
|
|
@@ -527,7 +566,7 @@ export class BTree {
|
|
|
527
566
|
}
|
|
528
567
|
leafInsert(path, entry) {
|
|
529
568
|
const { leafNode: leaf, leafIndex: index } = path;
|
|
530
|
-
if (leaf.entries.length <
|
|
569
|
+
if (leaf.entries.length < this.nodeCapacity) { // No split needed
|
|
531
570
|
apply(this.store, leaf, [entries$, index, 0, [entry]]);
|
|
532
571
|
return undefined;
|
|
533
572
|
}
|
|
@@ -555,7 +594,7 @@ export class BTree {
|
|
|
555
594
|
const pathBranch = path.branches[branchIndex];
|
|
556
595
|
const { index: splitIndex, node } = pathBranch;
|
|
557
596
|
pathBranch.index += split.indexDelta;
|
|
558
|
-
if (node.nodes.length <
|
|
597
|
+
if (node.nodes.length < this.nodeCapacity) { // no split needed
|
|
559
598
|
apply(this.store, node, [partitions$, splitIndex, 0, [split.key]]);
|
|
560
599
|
apply(this.store, node, [nodes$, splitIndex + 1, 0, [split.right.header.id]]);
|
|
561
600
|
return undefined;
|
|
@@ -572,6 +611,7 @@ export class BTree {
|
|
|
572
611
|
newNodes.splice(pathBranch.index + 1, 0, split.right.header.id);
|
|
573
612
|
}
|
|
574
613
|
const newBranch = newBranchNode(this.store, newPartitions, newNodes);
|
|
614
|
+
this.store.insert(newBranch);
|
|
575
615
|
// Delete partitions and nodes
|
|
576
616
|
const newPartition = node.partitions[midIndex - 1];
|
|
577
617
|
apply(this.store, node, [partitions$, midIndex - 1, newPartitions.length + 1, []]);
|
|
@@ -583,7 +623,7 @@ export class BTree {
|
|
|
583
623
|
return new Split(newPartition, newBranch, delta);
|
|
584
624
|
}
|
|
585
625
|
async rebalanceLeaf(path, depth) {
|
|
586
|
-
if (depth === 0 || path.leafNode.entries.length >= (
|
|
626
|
+
if (depth === 0 || path.leafNode.entries.length >= (this.nodeCapacity >>> 1)) {
|
|
587
627
|
return undefined;
|
|
588
628
|
}
|
|
589
629
|
const leaf = path.leafNode;
|
|
@@ -592,16 +632,16 @@ export class BTree {
|
|
|
592
632
|
const pNode = parent.node;
|
|
593
633
|
const rightSibId = pNode.nodes[pIndex + 1];
|
|
594
634
|
const rightSib = rightSibId ? (await get(this.store, rightSibId)) : undefined;
|
|
595
|
-
if (rightSib && rightSib.entries.length > (
|
|
635
|
+
if (rightSib && rightSib.entries.length > (this.nodeCapacity >>> 1)) { // Attempt to borrow from right sibling
|
|
596
636
|
const entry = rightSib.entries[0];
|
|
597
637
|
apply(this.store, rightSib, [entries$, 0, 1, []]);
|
|
598
638
|
apply(this.store, leaf, [entries$, leaf.entries.length, 0, [entry]]);
|
|
599
|
-
this.updatePartition(pIndex + 1, path, depth - 1, this.keyFromEntry(
|
|
639
|
+
this.updatePartition(pIndex + 1, path, depth - 1, this.keyFromEntry(rightSib.entries[0]));
|
|
600
640
|
return undefined;
|
|
601
641
|
}
|
|
602
642
|
const leftSibId = pNode.nodes[pIndex - 1];
|
|
603
643
|
const leftSib = leftSibId ? (await get(this.store, leftSibId)) : undefined;
|
|
604
|
-
if (leftSib && leftSib.entries.length > (
|
|
644
|
+
if (leftSib && leftSib.entries.length > (this.nodeCapacity >>> 1)) { // Attempt to borrow from left sibling
|
|
605
645
|
const entry = leftSib.entries[leftSib.entries.length - 1];
|
|
606
646
|
apply(this.store, leftSib, [entries$, leftSib.entries.length - 1, 1, []]);
|
|
607
647
|
apply(this.store, leaf, [entries$, 0, 0, [entry]]);
|
|
@@ -609,7 +649,7 @@ export class BTree {
|
|
|
609
649
|
path.leafIndex += 1;
|
|
610
650
|
return undefined;
|
|
611
651
|
}
|
|
612
|
-
if (rightSib && rightSib.entries.length + leaf.entries.length <=
|
|
652
|
+
if (rightSib && rightSib.entries.length + leaf.entries.length <= this.nodeCapacity) { // Attempt to merge right sibling into leaf (right sib deleted)
|
|
613
653
|
apply(this.store, leaf, [entries$, leaf.entries.length, 0, rightSib.entries]);
|
|
614
654
|
this.deletePartition(pNode, pIndex);
|
|
615
655
|
if (pIndex === 0) { // 0th node of parent, update parent key
|
|
@@ -618,7 +658,12 @@ export class BTree {
|
|
|
618
658
|
this.store.delete(rightSib.header.id);
|
|
619
659
|
return await this.rebalanceBranch(path, depth - 1);
|
|
620
660
|
}
|
|
621
|
-
if (leftSib && leftSib.entries.length + leaf.entries.length <=
|
|
661
|
+
if (leftSib && leftSib.entries.length + leaf.entries.length <= this.nodeCapacity) { // Attempt to merge into left sibling (leaf deleted)
|
|
662
|
+
// NOTE: this fixes leafIndex, but the parent-branch index up the path is left pointing at
|
|
663
|
+
// the now-deleted leaf's old slot (same tolerated-staleness class as rebalanceBranch's
|
|
664
|
+
// left-merge, part c). Harmless today because deleteAt version-bumps and abandons the
|
|
665
|
+
// returned path. A future path-reuse consumer must audit BOTH left-merge sites, not just
|
|
666
|
+
// rebalanceBranch.
|
|
622
667
|
path.leafNode = leftSib;
|
|
623
668
|
path.leafIndex += leftSib.entries.length;
|
|
624
669
|
apply(this.store, leftSib, [entries$, leftSib.entries.length, 0, leaf.entries]);
|
|
@@ -633,7 +678,7 @@ export class BTree {
|
|
|
633
678
|
if (depth === 0 && branch.partitions.length === 0) { // last node... collapse child into root
|
|
634
679
|
return path.branches[depth + 1]?.node ?? path.leafNode;
|
|
635
680
|
}
|
|
636
|
-
if (depth === 0 || (branch.nodes.length >=
|
|
681
|
+
if (depth === 0 || (branch.nodes.length >= this.nodeCapacity >>> 1)) {
|
|
637
682
|
return undefined;
|
|
638
683
|
}
|
|
639
684
|
const parent = path.branches.at(depth - 1);
|
|
@@ -641,7 +686,7 @@ export class BTree {
|
|
|
641
686
|
const pNode = parent.node;
|
|
642
687
|
const rightSibId = pNode.nodes[pIndex + 1];
|
|
643
688
|
const rightSib = rightSibId ? (await get(this.store, rightSibId)) : undefined;
|
|
644
|
-
if (rightSib && rightSib.nodes.length > (
|
|
689
|
+
if (rightSib && rightSib.nodes.length > (this.nodeCapacity >>> 1)) { // Attempt to borrow from right sibling
|
|
645
690
|
const node = rightSib.nodes[0];
|
|
646
691
|
const rightKey = rightSib.partitions[0];
|
|
647
692
|
this.insertPartition(branch, branch.partitions.length, pNode.partitions[pIndex], node);
|
|
@@ -651,7 +696,7 @@ export class BTree {
|
|
|
651
696
|
}
|
|
652
697
|
const leftSibId = pNode.nodes[pIndex - 1];
|
|
653
698
|
const leftSib = leftSibId ? (await get(this.store, leftSibId)) : undefined;
|
|
654
|
-
if (leftSib && leftSib.nodes.length > (
|
|
699
|
+
if (leftSib && leftSib.nodes.length > (this.nodeCapacity >>> 1)) { // Attempt to borrow from left sibling
|
|
655
700
|
const node = leftSib.nodes[leftSib.nodes.length - 1];
|
|
656
701
|
const pKey = leftSib.partitions[leftSib.partitions.length - 1];
|
|
657
702
|
this.insertPartition(branch, 0, pNode.partitions[pIndex - 1], node, 0);
|
|
@@ -660,26 +705,24 @@ export class BTree {
|
|
|
660
705
|
this.updatePartition(pIndex, path, depth - 1, pKey);
|
|
661
706
|
return undefined;
|
|
662
707
|
}
|
|
663
|
-
if (rightSib && rightSib.nodes.length + branch.nodes.length <=
|
|
708
|
+
if (rightSib && rightSib.nodes.length + branch.nodes.length <= this.nodeCapacity) { // Attempt to merge right sibling into self
|
|
664
709
|
const pKey = pNode.partitions[pIndex];
|
|
665
710
|
this.deletePartition(pNode, pIndex);
|
|
666
711
|
apply(this.store, branch, [partitions$, branch.partitions.length, 0, [pKey]]);
|
|
667
712
|
apply(this.store, branch, [partitions$, branch.partitions.length, 0, rightSib.partitions]);
|
|
668
713
|
apply(this.store, branch, [nodes$, branch.nodes.length, 0, rightSib.nodes]);
|
|
669
|
-
if (pIndex === 0 && pNode.partitions.length > 0) { // if parent is left edge, new right sibling is now the first partition
|
|
670
|
-
this.updatePartition(pIndex, path, depth - 1, pNode.partitions[0]);
|
|
671
|
-
}
|
|
672
714
|
this.store.delete(rightSib.header.id);
|
|
673
715
|
return this.rebalanceBranch(path, depth - 1);
|
|
674
716
|
}
|
|
675
|
-
if (leftSib && leftSib.nodes.length + branch.nodes.length <=
|
|
717
|
+
if (leftSib && leftSib.nodes.length + branch.nodes.length <= this.nodeCapacity) { // Attempt to merge self into left sibling
|
|
718
|
+
const leftLen = leftSib.nodes.length; // capture BEFORE the appends below shift it (see leaf path at rebalanceLeaf)
|
|
676
719
|
const pKey = pNode.partitions[pIndex - 1];
|
|
677
720
|
this.deletePartition(pNode, pIndex - 1);
|
|
678
721
|
apply(this.store, leftSib, [partitions$, leftSib.partitions.length, 0, [pKey]]);
|
|
679
722
|
apply(this.store, leftSib, [partitions$, leftSib.partitions.length, 0, branch.partitions]);
|
|
680
723
|
apply(this.store, leftSib, [nodes$, leftSib.nodes.length, 0, branch.nodes]);
|
|
681
724
|
pathBranch.node = leftSib;
|
|
682
|
-
pathBranch.index += leftSib
|
|
725
|
+
pathBranch.index += leftLen; // branch's children now sit after leftSib's original children
|
|
683
726
|
this.store.delete(branch.header.id);
|
|
684
727
|
return this.rebalanceBranch(path, depth - 1);
|
|
685
728
|
}
|