@optimystic/db-p2p 1.0.0-beta.2 → 1.0.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/src/cluster/block-transfer-service.d.ts +73 -1
- package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
- package/dist/src/cluster/block-transfer-service.js +70 -3
- package/dist/src/cluster/block-transfer-service.js.map +1 -1
- package/dist/src/cluster/block-transfer.d.ts +16 -1
- package/dist/src/cluster/block-transfer.d.ts.map +1 -1
- package/dist/src/cluster/block-transfer.js +73 -72
- package/dist/src/cluster/block-transfer.js.map +1 -1
- package/dist/src/cluster/client.d.ts +4 -6
- package/dist/src/cluster/client.d.ts.map +1 -1
- package/dist/src/cluster/client.js +8 -13
- package/dist/src/cluster/client.js.map +1 -1
- package/dist/src/cluster/cluster-policy.d.ts +2 -1
- package/dist/src/cluster/cluster-policy.d.ts.map +1 -1
- package/dist/src/cluster/cluster-policy.js.map +1 -1
- package/dist/src/cluster/cluster-repo.d.ts +172 -17
- package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
- package/dist/src/cluster/cluster-repo.js +553 -149
- package/dist/src/cluster/cluster-repo.js.map +1 -1
- package/dist/src/cluster/commit-proof.js +2 -2
- package/dist/src/cluster/race-resolution.d.ts +51 -7
- package/dist/src/cluster/race-resolution.d.ts.map +1 -1
- package/dist/src/cluster/race-resolution.js +71 -7
- package/dist/src/cluster/race-resolution.js.map +1 -1
- package/dist/src/cluster/rebalance-monitor.d.ts +67 -5
- package/dist/src/cluster/rebalance-monitor.d.ts.map +1 -1
- package/dist/src/cluster/rebalance-monitor.js +120 -26
- package/dist/src/cluster/rebalance-monitor.js.map +1 -1
- package/dist/src/cluster/spread-on-churn.d.ts.map +1 -1
- package/dist/src/cluster/spread-on-churn.js +34 -47
- package/dist/src/cluster/spread-on-churn.js.map +1 -1
- package/dist/src/cohort-topic/host.d.ts.map +1 -1
- package/dist/src/cohort-topic/host.js +8 -6
- package/dist/src/cohort-topic/host.js.map +1 -1
- package/dist/src/cohort-topic/membership-source.js +1 -1
- package/dist/src/cohort-topic/membership-source.js.map +1 -1
- package/dist/src/cohort-topic/peer-codec.d.ts.map +1 -1
- package/dist/src/cohort-topic/peer-codec.js +5 -2
- package/dist/src/cohort-topic/peer-codec.js.map +1 -1
- package/dist/src/cohort-topic/stream-util.d.ts +24 -3
- package/dist/src/cohort-topic/stream-util.d.ts.map +1 -1
- package/dist/src/cohort-topic/stream-util.js +36 -3
- package/dist/src/cohort-topic/stream-util.js.map +1 -1
- package/dist/src/cohort-topic/topic-router.d.ts +9 -0
- package/dist/src/cohort-topic/topic-router.d.ts.map +1 -1
- package/dist/src/cohort-topic/topic-router.js +12 -2
- package/dist/src/cohort-topic/topic-router.js.map +1 -1
- package/dist/src/dispute/client.d.ts.map +1 -1
- package/dist/src/dispute/client.js +15 -3
- package/dist/src/dispute/client.js.map +1 -1
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/libp2p-key-network.d.ts +78 -17
- package/dist/src/libp2p-key-network.d.ts.map +1 -1
- package/dist/src/libp2p-key-network.js +241 -147
- package/dist/src/libp2p-key-network.js.map +1 -1
- package/dist/src/libp2p-node-base.d.ts +35 -1
- package/dist/src/libp2p-node-base.d.ts.map +1 -1
- package/dist/src/libp2p-node-base.js +151 -26
- package/dist/src/libp2p-node-base.js.map +1 -1
- package/dist/src/libp2p-node-rn.d.ts +2 -2
- package/dist/src/libp2p-node-rn.d.ts.map +1 -1
- package/dist/src/libp2p-node-rn.js.map +1 -1
- package/dist/src/libp2p-node.d.ts +2 -2
- package/dist/src/libp2p-node.d.ts.map +1 -1
- package/dist/src/libp2p-node.js.map +1 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/logger.js +19 -7
- package/dist/src/logger.js.map +1 -1
- package/dist/src/matchmaking/query-transport.d.ts +3 -4
- package/dist/src/matchmaking/query-transport.d.ts.map +1 -1
- package/dist/src/matchmaking/query-transport.js +9 -9
- package/dist/src/matchmaking/query-transport.js.map +1 -1
- package/dist/src/network/network-manager-service.d.ts +10 -5
- package/dist/src/network/network-manager-service.d.ts.map +1 -1
- package/dist/src/network/network-manager-service.js +11 -2
- package/dist/src/network/network-manager-service.js.map +1 -1
- package/dist/src/network/relay-reservation.d.ts +170 -0
- package/dist/src/network/relay-reservation.d.ts.map +1 -0
- package/dist/src/network/relay-reservation.js +527 -0
- package/dist/src/network/relay-reservation.js.map +1 -0
- package/dist/src/pend-validation.d.ts +3 -2
- package/dist/src/pend-validation.d.ts.map +1 -1
- package/dist/src/pend-validation.js +3 -2
- package/dist/src/pend-validation.js.map +1 -1
- package/dist/src/protocol-client.d.ts +8 -1
- package/dist/src/protocol-client.d.ts.map +1 -1
- package/dist/src/protocol-client.js +11 -0
- package/dist/src/protocol-client.js.map +1 -1
- package/dist/src/reactivity/forwarder-host.d.ts +2 -1
- package/dist/src/reactivity/forwarder-host.d.ts.map +1 -1
- package/dist/src/reactivity/forwarder-host.js +2 -1
- package/dist/src/reactivity/forwarder-host.js.map +1 -1
- package/dist/src/reactivity/origination-manager.d.ts +3 -3
- package/dist/src/reactivity/origination-manager.js +3 -3
- package/dist/src/reactivity/recover-transport.d.ts +22 -14
- package/dist/src/reactivity/recover-transport.d.ts.map +1 -1
- package/dist/src/reactivity/recover-transport.js +32 -19
- package/dist/src/reactivity/recover-transport.js.map +1 -1
- package/dist/src/reactivity/subscription-manager.d.ts +2 -2
- package/dist/src/reactivity/topic-bytes.d.ts +6 -7
- package/dist/src/reactivity/topic-bytes.d.ts.map +1 -1
- package/dist/src/reactivity/topic-bytes.js +8 -9
- package/dist/src/reactivity/topic-bytes.js.map +1 -1
- package/dist/src/repo/client.d.ts +5 -2
- package/dist/src/repo/client.d.ts.map +1 -1
- package/dist/src/repo/client.js +49 -40
- package/dist/src/repo/client.js.map +1 -1
- package/dist/src/repo/cluster-coordinator.d.ts +119 -5
- package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
- package/dist/src/repo/cluster-coordinator.js +181 -29
- package/dist/src/repo/cluster-coordinator.js.map +1 -1
- package/dist/src/repo/coordinator-repo.d.ts +259 -76
- package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
- package/dist/src/repo/coordinator-repo.js +716 -328
- package/dist/src/repo/coordinator-repo.js.map +1 -1
- package/dist/src/repo/i-under-replication-ledger.d.ts +87 -0
- package/dist/src/repo/i-under-replication-ledger.d.ts.map +1 -0
- package/dist/src/repo/i-under-replication-ledger.js +2 -0
- package/dist/src/repo/i-under-replication-ledger.js.map +1 -0
- package/dist/src/repo/kv-under-replication-ledger.d.ts +91 -0
- package/dist/src/repo/kv-under-replication-ledger.d.ts.map +1 -0
- package/dist/src/repo/kv-under-replication-ledger.js +287 -0
- package/dist/src/repo/kv-under-replication-ledger.js.map +1 -0
- package/dist/src/repo/responsibility.d.ts +37 -0
- package/dist/src/repo/responsibility.d.ts.map +1 -0
- package/dist/src/repo/responsibility.js +37 -0
- package/dist/src/repo/responsibility.js.map +1 -0
- package/dist/src/repo/service.d.ts +44 -15
- package/dist/src/repo/service.d.ts.map +1 -1
- package/dist/src/repo/service.js +64 -27
- package/dist/src/repo/service.js.map +1 -1
- package/dist/src/repo/stuck-reservation.d.ts +127 -0
- package/dist/src/repo/stuck-reservation.d.ts.map +1 -0
- package/dist/src/repo/stuck-reservation.js +179 -0
- package/dist/src/repo/stuck-reservation.js.map +1 -0
- package/dist/src/repo/under-replication-drain.d.ts +208 -0
- package/dist/src/repo/under-replication-drain.d.ts.map +1 -0
- package/dist/src/repo/under-replication-drain.js +461 -0
- package/dist/src/repo/under-replication-drain.js.map +1 -0
- package/dist/src/rn.d.ts +5 -0
- package/dist/src/rn.d.ts.map +1 -1
- package/dist/src/rn.js +5 -0
- package/dist/src/rn.js.map +1 -1
- package/dist/src/storage/block-latch.d.ts +3 -2
- package/dist/src/storage/block-latch.d.ts.map +1 -1
- package/dist/src/storage/block-latch.js +7 -4
- package/dist/src/storage/block-latch.js.map +1 -1
- package/dist/src/storage/block-storage.d.ts +45 -3
- package/dist/src/storage/block-storage.d.ts.map +1 -1
- package/dist/src/storage/block-storage.js +156 -9
- package/dist/src/storage/block-storage.js.map +1 -1
- package/dist/src/storage/i-block-storage.d.ts +57 -5
- package/dist/src/storage/i-block-storage.d.ts.map +1 -1
- package/dist/src/storage/i-block-storage.js.map +1 -1
- package/dist/src/storage/pending-claim.d.ts +167 -0
- package/dist/src/storage/pending-claim.d.ts.map +1 -0
- package/dist/src/storage/pending-claim.js +156 -0
- package/dist/src/storage/pending-claim.js.map +1 -0
- package/dist/src/storage/raw-store-codec.d.ts +13 -0
- package/dist/src/storage/raw-store-codec.d.ts.map +1 -1
- package/dist/src/storage/raw-store-codec.js +24 -3
- package/dist/src/storage/raw-store-codec.js.map +1 -1
- package/dist/src/storage/restoration-coordinator.d.ts.map +1 -1
- package/dist/src/storage/restoration-coordinator.js +2 -1
- package/dist/src/storage/restoration-coordinator.js.map +1 -1
- package/dist/src/storage/ring-shift-coordinator.d.ts.map +1 -1
- package/dist/src/storage/ring-shift-coordinator.js +3 -3
- package/dist/src/storage/ring-shift-coordinator.js.map +1 -1
- package/dist/src/storage/storage-repo.d.ts +137 -5
- package/dist/src/storage/storage-repo.d.ts.map +1 -1
- package/dist/src/storage/storage-repo.js +273 -68
- package/dist/src/storage/storage-repo.js.map +1 -1
- package/dist/src/storage/struct.d.ts +58 -0
- package/dist/src/storage/struct.d.ts.map +1 -1
- package/dist/src/testing/mesh-harness.d.ts +92 -11
- package/dist/src/testing/mesh-harness.d.ts.map +1 -1
- package/dist/src/testing/mesh-harness.js +246 -103
- package/dist/src/testing/mesh-harness.js.map +1 -1
- package/package.json +2 -2
- package/readme.md +27 -3
- package/src/cluster/block-transfer-service.ts +132 -4
- package/src/cluster/block-transfer.ts +79 -84
- package/src/cluster/client.ts +115 -119
- package/src/cluster/cluster-policy.ts +2 -1
- package/src/cluster/cluster-repo.ts +3115 -2671
- package/src/cluster/commit-proof.ts +2 -2
- package/src/cluster/race-resolution.ts +76 -7
- package/src/cluster/rebalance-monitor.ts +677 -539
- package/src/cluster/spread-on-churn.ts +34 -54
- package/src/cohort-topic/host.ts +8 -6
- package/src/cohort-topic/membership-source.ts +1 -1
- package/src/cohort-topic/peer-codec.ts +34 -31
- package/src/cohort-topic/stream-util.ts +39 -4
- package/src/cohort-topic/topic-router.ts +12 -2
- package/src/dispute/client.ts +17 -7
- package/src/index.ts +64 -59
- package/src/libp2p-key-network.ts +1377 -1253
- package/src/libp2p-node-base.ts +186 -27
- package/src/libp2p-node-rn.ts +31 -30
- package/src/libp2p-node.ts +37 -36
- package/src/logger.ts +20 -7
- package/src/matchmaking/query-transport.ts +9 -9
- package/src/network/network-manager-service.ts +16 -5
- package/src/network/relay-reservation.ts +636 -0
- package/src/pend-validation.ts +3 -2
- package/src/protocol-client.ts +13 -1
- package/src/reactivity/forwarder-host.ts +2 -1
- package/src/reactivity/origination-manager.ts +3 -3
- package/src/reactivity/recover-transport.ts +39 -22
- package/src/reactivity/subscription-manager.ts +2 -2
- package/src/reactivity/topic-bytes.ts +35 -37
- package/src/repo/client.ts +172 -173
- package/src/repo/cluster-coordinator.ts +1296 -1113
- package/src/repo/coordinator-repo.ts +3087 -2687
- package/src/repo/i-under-replication-ledger.ts +89 -0
- package/src/repo/kv-under-replication-ledger.ts +302 -0
- package/src/repo/responsibility.ts +48 -0
- package/src/repo/service.ts +76 -39
- package/src/repo/stuck-reservation.ts +224 -0
- package/src/repo/under-replication-drain.ts +582 -0
- package/src/rn.ts +74 -69
- package/src/storage/block-latch.ts +7 -4
- package/src/storage/block-storage.ts +161 -10
- package/src/storage/i-block-storage.ts +60 -5
- package/src/storage/pending-claim.ts +200 -0
- package/src/storage/raw-store-codec.ts +26 -3
- package/src/storage/restoration-coordinator.ts +212 -211
- package/src/storage/ring-shift-coordinator.ts +271 -271
- package/src/storage/storage-repo.ts +311 -73
- package/src/storage/struct.ts +58 -0
- package/src/testing/mesh-harness.ts +329 -115
package/src/rn.ts
CHANGED
|
@@ -1,69 +1,74 @@
|
|
|
1
|
-
// React Native / browser entry point. `package.json` routes the `react-native` condition on `.`
|
|
2
|
-
// here, plus the explicit `./rn` subpath.
|
|
3
|
-
//
|
|
4
|
-
// NOTE: this entry re-exports exactly the same module set as `./index.js`, with
|
|
5
|
-
// `./libp2p-node.js` -> `./libp2p-node-rn.js` as the single substitution. Because the module set
|
|
6
|
-
// is identical, a class obtained from either entry is the *same* class object on Node, so
|
|
7
|
-
// `instanceof` holds across them; downstream code (e.g. sereus' `cached-storage.ts`) relies on
|
|
8
|
-
// that. Enforced from this side by `test/entry-parity.spec.ts` — keep the two files in step, and
|
|
9
|
-
// keep every line here a plain `export * from '...'` so that spec can compare them.
|
|
10
|
-
|
|
11
|
-
export * from './cluster/client.js';
|
|
12
|
-
export * from './cluster/client-signature-verifier.js';
|
|
13
|
-
export * from './cluster/cluster-repo.js';
|
|
14
|
-
export * from './cluster/cluster-policy.js';
|
|
15
|
-
export * from './cluster/commit-cert.js';
|
|
16
|
-
export * from './cluster/commit-proof.js';
|
|
17
|
-
export * from './cluster/service.js';
|
|
18
|
-
export * from './cluster/rebalance-monitor.js';
|
|
19
|
-
export * from './cluster/spread-on-churn.js';
|
|
20
|
-
export * from './cluster/block-transfer.js';
|
|
21
|
-
export * from './cluster/block-transfer-service.js';
|
|
22
|
-
export * from './inbound-authorization.js';
|
|
23
|
-
export * from './protocol-client.js';
|
|
24
|
-
export * from './repo/client.js';
|
|
25
|
-
export * from './repo/cluster-coordinator.js';
|
|
26
|
-
export * from './repo/coordinator-repo.js';
|
|
27
|
-
export * from './repo/
|
|
28
|
-
export * from './repo/
|
|
29
|
-
export * from './
|
|
30
|
-
export * from './
|
|
31
|
-
export * from './
|
|
32
|
-
export * from './
|
|
33
|
-
export * from './storage/
|
|
34
|
-
export * from './storage/
|
|
35
|
-
export * from './storage/
|
|
36
|
-
export * from './storage/
|
|
37
|
-
export * from './storage/
|
|
38
|
-
export * from './storage/
|
|
39
|
-
export * from './storage/
|
|
40
|
-
export * from './storage/
|
|
41
|
-
export * from './storage/
|
|
42
|
-
export * from './storage/
|
|
43
|
-
export * from './storage/
|
|
44
|
-
export * from './storage/storage
|
|
45
|
-
export * from './storage/
|
|
46
|
-
export * from './storage/
|
|
47
|
-
export * from './storage/
|
|
48
|
-
export * from './storage/
|
|
49
|
-
export * from './
|
|
50
|
-
export * from './
|
|
51
|
-
export * from './
|
|
52
|
-
export * from './
|
|
53
|
-
export * from './
|
|
54
|
-
export * from './
|
|
55
|
-
export * from './
|
|
56
|
-
export * from './
|
|
57
|
-
export * from './
|
|
58
|
-
export * from './
|
|
59
|
-
export * from './
|
|
60
|
-
export * from './
|
|
61
|
-
export * from './
|
|
62
|
-
export * from './
|
|
63
|
-
export * from './
|
|
64
|
-
export * from './
|
|
65
|
-
export * from './
|
|
66
|
-
export * from './
|
|
67
|
-
export * from './
|
|
68
|
-
export * from './
|
|
69
|
-
export * from './
|
|
1
|
+
// React Native / browser entry point. `package.json` routes the `react-native` condition on `.`
|
|
2
|
+
// here, plus the explicit `./rn` subpath.
|
|
3
|
+
//
|
|
4
|
+
// NOTE: this entry re-exports exactly the same module set as `./index.js`, with
|
|
5
|
+
// `./libp2p-node.js` -> `./libp2p-node-rn.js` as the single substitution. Because the module set
|
|
6
|
+
// is identical, a class obtained from either entry is the *same* class object on Node, so
|
|
7
|
+
// `instanceof` holds across them; downstream code (e.g. sereus' `cached-storage.ts`) relies on
|
|
8
|
+
// that. Enforced from this side by `test/entry-parity.spec.ts` — keep the two files in step, and
|
|
9
|
+
// keep every line here a plain `export * from '...'` so that spec can compare them.
|
|
10
|
+
|
|
11
|
+
export * from './cluster/client.js';
|
|
12
|
+
export * from './cluster/client-signature-verifier.js';
|
|
13
|
+
export * from './cluster/cluster-repo.js';
|
|
14
|
+
export * from './cluster/cluster-policy.js';
|
|
15
|
+
export * from './cluster/commit-cert.js';
|
|
16
|
+
export * from './cluster/commit-proof.js';
|
|
17
|
+
export * from './cluster/service.js';
|
|
18
|
+
export * from './cluster/rebalance-monitor.js';
|
|
19
|
+
export * from './cluster/spread-on-churn.js';
|
|
20
|
+
export * from './cluster/block-transfer.js';
|
|
21
|
+
export * from './cluster/block-transfer-service.js';
|
|
22
|
+
export * from './inbound-authorization.js';
|
|
23
|
+
export * from './protocol-client.js';
|
|
24
|
+
export * from './repo/client.js';
|
|
25
|
+
export * from './repo/cluster-coordinator.js';
|
|
26
|
+
export * from './repo/coordinator-repo.js';
|
|
27
|
+
export * from './repo/i-under-replication-ledger.js';
|
|
28
|
+
export * from './repo/kv-under-replication-ledger.js';
|
|
29
|
+
export * from './repo/under-replication-drain.js';
|
|
30
|
+
export * from './repo/responsibility.js';
|
|
31
|
+
export * from './repo/served-repo-proxy.js';
|
|
32
|
+
export * from './repo/service.js';
|
|
33
|
+
export * from './storage/block-storage.js';
|
|
34
|
+
export * from './storage/block-latch.js';
|
|
35
|
+
export * from './storage/store-identity.js';
|
|
36
|
+
export * from './storage/raw-store-driver.js';
|
|
37
|
+
export * from './storage/kv-raw-storage.js';
|
|
38
|
+
export * from './storage/shared-cache-pool.js';
|
|
39
|
+
export * from './storage/cached-store-driver.js';
|
|
40
|
+
export * from './storage/cached-raw-storage.js';
|
|
41
|
+
export * from './storage/with-read-cache.js';
|
|
42
|
+
export * from './storage/memory-store-driver.js';
|
|
43
|
+
export * from './storage/memory-storage.js';
|
|
44
|
+
export * from './storage/i-block-storage.js';
|
|
45
|
+
export * from './storage/i-raw-storage.js';
|
|
46
|
+
export * from './storage/struct.js';
|
|
47
|
+
export * from './storage/pending-claim.js';
|
|
48
|
+
export * from './storage/block-archive.js';
|
|
49
|
+
export * from './storage/storage-repo.js';
|
|
50
|
+
export * from './storage/restoration-coordinator.js';
|
|
51
|
+
export * from './storage/ring-selector.js';
|
|
52
|
+
export * from './storage/storage-monitor.js';
|
|
53
|
+
export * from './storage/arachnode-fret-adapter.js';
|
|
54
|
+
export * from './sync/protocol.js';
|
|
55
|
+
export * from './sync/client.js';
|
|
56
|
+
export * from './sync/service.js';
|
|
57
|
+
export * from './it-utility.js';
|
|
58
|
+
export * from './libp2p-key-network.js';
|
|
59
|
+
export * from './libp2p-node-rn.js';
|
|
60
|
+
export * from './optimystic-node.js';
|
|
61
|
+
export * from './routing/responsibility.js';
|
|
62
|
+
export * from './routing/libp2p-known-peers.js';
|
|
63
|
+
export * from './network/network-manager-service.js';
|
|
64
|
+
export * from './network/get-network-manager.js';
|
|
65
|
+
export * from './reputation/index.js';
|
|
66
|
+
export * from './dispute/index.js';
|
|
67
|
+
export * from './cohort-topic/index.js';
|
|
68
|
+
export * from './matchmaking/index.js';
|
|
69
|
+
export * from './reactivity/index.js';
|
|
70
|
+
export * from './cluster/i-transaction-state-store.js';
|
|
71
|
+
export * from './cluster/memory-transaction-state-store.js';
|
|
72
|
+
export * from './cluster/persistent-transaction-state-store.js';
|
|
73
|
+
export * from './storage/i-kv-store.js';
|
|
74
|
+
export * from './storage/memory-kv-store.js';
|
|
@@ -34,8 +34,9 @@ let expire!: (latch: BlockWriteLatch) => void;
|
|
|
34
34
|
/**
|
|
35
35
|
* Opaque proof that the bearer is executing inside {@link blockWriteLatchKey}`(blockId)`. Only
|
|
36
36
|
* {@link acquireBlockWriteLatch} (and {@link withBlockWriteLatch} through it) can construct one:
|
|
37
|
-
* the constructor is private and the module-scoped minter is assigned from a static
|
|
38
|
-
* the private constructor is callable — no cast, nothing outside this module can
|
|
37
|
+
* the constructor is private and the module-scoped minter is assigned from a static field
|
|
38
|
+
* initializer, where the private constructor is callable — no cast, nothing outside this module can
|
|
39
|
+
* build a token.
|
|
39
40
|
*
|
|
40
41
|
* A token is only valid while the latch it proves is actually held: releasing expires it, so a
|
|
41
42
|
* callback that stashes its token and writes after its scope closed is rejected instead of silently
|
|
@@ -54,10 +55,12 @@ export class BlockWriteLatch {
|
|
|
54
55
|
return this.#live;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
static {
|
|
58
|
+
// A static field initializer, not a `static { }` block: React Native's Metro/Babel bundling cannot
|
|
59
|
+
// transform static blocks, and this module ships in the RN bundle (lint enforces it).
|
|
60
|
+
static #wired = (() => {
|
|
58
61
|
mint = (blockId) => new BlockWriteLatch(blockId);
|
|
59
62
|
expire = (latch) => { latch.#live = false; };
|
|
60
|
-
}
|
|
63
|
+
})();
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BlockId, IBlock, Transform, ActionId, ActionRev, ActionTransform } from "@optimystic/db-core";
|
|
1
|
+
import type { BlockId, IBlock, Transform, ActionId, ActionRev, ActionTransform, BlockLineage } from "@optimystic/db-core";
|
|
2
2
|
import { applyTransform, canonicalJson, hashString } from "@optimystic/db-core";
|
|
3
3
|
import type { BlockCommitProof } from "../cluster/commit-proof.js";
|
|
4
4
|
import type { BlockArchive, BlockMetadata, RestoreCallback, RevisionRange } from "./struct.js";
|
|
@@ -6,6 +6,7 @@ import type { IRawStorage } from "./i-raw-storage.js";
|
|
|
6
6
|
import { mergeRanges } from "./helpers.js";
|
|
7
7
|
import { RevisionNotCoveredError, PendRevisionTakenError, type IBlockStorage } from "./i-block-storage.js";
|
|
8
8
|
import type { BlockWriteLatch } from "./block-latch.js";
|
|
9
|
+
import type { PendingClaim } from "./pending-claim.js";
|
|
9
10
|
import { createLogger } from "../logger.js";
|
|
10
11
|
|
|
11
12
|
const log = createLogger('block-storage');
|
|
@@ -155,9 +156,39 @@ export class BlockStorage implements IBlockStorage {
|
|
|
155
156
|
yield* this.storage.listPendingTransactions(this.blockId);
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
async
|
|
159
|
+
async listPendingClaims(): Promise<PendingClaim[]> {
|
|
160
|
+
const meta = await this.storage.getMetadata(this.blockId);
|
|
161
|
+
const claims: PendingClaim[] = [];
|
|
162
|
+
for await (const actionId of this.storage.listPendingTransactions(this.blockId)) {
|
|
163
|
+
claims.push(BlockStorage.claimOf(meta, actionId));
|
|
164
|
+
}
|
|
165
|
+
return claims;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async pendingClaimOf(actionId: ActionId): Promise<PendingClaim | undefined> {
|
|
169
|
+
// Joined against the record, exactly as the listing is: a metadata entry whose record is gone
|
|
170
|
+
// is inert (see BlockMetadata.pendingRevs) and must not read as a live claim.
|
|
171
|
+
if (await this.storage.getPendingTransaction(this.blockId, actionId) === undefined) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
return BlockStorage.claimOf(await this.storage.getMetadata(this.blockId), actionId);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** The claim `meta` describes for `actionId`'s (existing) record: its slot and its base, each
|
|
178
|
+
* present only when on file. */
|
|
179
|
+
private static claimOf(meta: BlockMetadata | undefined, actionId: ActionId): PendingClaim {
|
|
180
|
+
const rev = meta?.pendingRevs?.[actionId];
|
|
181
|
+
const baseRev = meta?.pendingBases?.[actionId];
|
|
182
|
+
return {
|
|
183
|
+
actionId,
|
|
184
|
+
...(rev === undefined ? {} : { rev }),
|
|
185
|
+
...(baseRev === undefined ? {} : { baseRev })
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async savePendingTransaction(actionId: ActionId, transform: Transform, rev: number | undefined, baseRev: number | undefined, latch: BlockWriteLatch): Promise<void> {
|
|
159
190
|
this.assertLatch(latch);
|
|
160
|
-
log('pend blockId=%s actionId=%s rev=%s', this.blockId, actionId, rev);
|
|
191
|
+
log('pend blockId=%s actionId=%s rev=%s baseRev=%s', this.blockId, actionId, rev, baseRev);
|
|
161
192
|
let meta = await this.storage.getMetadata(this.blockId);
|
|
162
193
|
// Refuse a record that could never be promoted (see IBlockStorage.savePendingTransaction).
|
|
163
194
|
// The metadata read above is unconditional anyway, so this costs one comparison and no I/O.
|
|
@@ -177,8 +208,15 @@ export class BlockStorage implements IBlockStorage {
|
|
|
177
208
|
// This read-then-seed is exactly the window a concurrent replica used to land in (the
|
|
178
209
|
// seed then erased its `latest`); the latch the caller holds is what closes it.
|
|
179
210
|
meta = { latest: undefined, ranges: [] };
|
|
180
|
-
await this.storage.saveMetadata(this.blockId, meta);
|
|
181
211
|
}
|
|
212
|
+
// Record the slot the record claims (see BlockMetadata.pendingRevs) and the base it was computed
|
|
213
|
+
// against (`pendingBases`) in the same metadata write that seeds a fresh block, BEFORE the record
|
|
214
|
+
// itself: a crash between the two leaves an inert entry with no record, whereas the other order
|
|
215
|
+
// would leave a record with no claim — which every reader treats as the strongest kind and would
|
|
216
|
+
// refuse rivals on more than it should — and with no base, which the read-driven promotion
|
|
217
|
+
// would then decline to apply. A redelivered pend for the same action overwrites all three.
|
|
218
|
+
BlockStorage.recordClaim(meta, actionId, { rev, baseRev });
|
|
219
|
+
await this.storage.saveMetadata(this.blockId, meta);
|
|
182
220
|
await this.storage.savePendingTransaction(this.blockId, actionId, transform);
|
|
183
221
|
}
|
|
184
222
|
|
|
@@ -186,6 +224,58 @@ export class BlockStorage implements IBlockStorage {
|
|
|
186
224
|
this.assertLatch(latch);
|
|
187
225
|
log('cancel blockId=%s actionId=%s', this.blockId, actionId);
|
|
188
226
|
await this.storage.deletePendingTransaction(this.blockId, actionId);
|
|
227
|
+
// Metadata is written only when the record had a claim to drop: a cancel of an absent or
|
|
228
|
+
// claim-less record (the common torn-cancel retry) stays a pure no-op on the metadata blob.
|
|
229
|
+
const meta = await this.storage.getMetadata(this.blockId);
|
|
230
|
+
if (meta && (meta.pendingRevs?.[actionId] !== undefined || meta.pendingBases?.[actionId] !== undefined)) {
|
|
231
|
+
BlockStorage.recordClaim(meta, actionId, undefined);
|
|
232
|
+
await this.storage.saveMetadata(this.blockId, meta);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Set (`claim` given) or clear (`undefined`) what `meta` says about `actionId`'s pending record —
|
|
238
|
+
* the slot it claims and the base it was computed against — keeping each map absent while it is
|
|
239
|
+
* empty. The two are always written together, so no path can drop a record's slot and leave its
|
|
240
|
+
* base behind, or the reverse: clearing is what every drop site calls — a delete, a promotion
|
|
241
|
+
* (`setLatest`), a same-action forward write (`saveForwardRevision`) and the dead-claim sweep.
|
|
242
|
+
*/
|
|
243
|
+
private static recordClaim(meta: BlockMetadata, actionId: ActionId, claim: { rev?: number; baseRev?: number } | undefined): void {
|
|
244
|
+
BlockStorage.setEntry(meta, 'pendingRevs', actionId, claim?.rev);
|
|
245
|
+
BlockStorage.setEntry(meta, 'pendingBases', actionId, claim?.baseRev);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** `meta[map][actionId] = value`, or removes the entry when `value` is undefined; the map itself
|
|
249
|
+
* is dropped from `meta` once empty, so an idle block's metadata carries neither key. */
|
|
250
|
+
private static setEntry(meta: BlockMetadata, map: 'pendingRevs' | 'pendingBases', actionId: ActionId, value: number | undefined): void {
|
|
251
|
+
const entries = { ...meta[map] };
|
|
252
|
+
if (value === undefined) delete entries[actionId];
|
|
253
|
+
else entries[actionId] = value;
|
|
254
|
+
if (Object.keys(entries).length === 0) delete meta[map];
|
|
255
|
+
else meta[map] = entries;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Every pending record claiming a revision at or below `latestRev` can never be promoted here:
|
|
260
|
+
* promotion needs `latest.rev < rev`, and `latest` only advances. Such a record is DEAD — a rival
|
|
261
|
+
* that lost the slot, or a torn write's leftover on a block a later commit has since moved past —
|
|
262
|
+
* and left in place it is reported as a live conflicting action to every reader of the block.
|
|
263
|
+
* Delete those records and drop their claims from `meta`, which the caller then saves; a record
|
|
264
|
+
* with no claim on file is left alone (its slot is unknown, so its death is unprovable here).
|
|
265
|
+
*
|
|
266
|
+
* Runs under the block's write latch on every path that advances `latest`, which is the one moment
|
|
267
|
+
* a record's death becomes provable. This is the locally decidable half of what backlog
|
|
268
|
+
* `debt-unpromotable-pending-records-need-a-sweep` asks for; the other half — a record whose slot
|
|
269
|
+
* the block has NOT reached, whose writer simply never came back — is not decidable from local
|
|
270
|
+
* state and is not touched here.
|
|
271
|
+
*/
|
|
272
|
+
private async sweepDeadClaims(meta: BlockMetadata, latestRev: number): Promise<void> {
|
|
273
|
+
for (const [actionId, rev] of Object.entries(meta.pendingRevs ?? {}) as [ActionId, number][]) {
|
|
274
|
+
if (rev > latestRev) continue;
|
|
275
|
+
await this.storage.deletePendingTransaction(this.blockId, actionId);
|
|
276
|
+
BlockStorage.recordClaim(meta, actionId, undefined);
|
|
277
|
+
log('sweep-dead-claim blockId=%s actionId=%s claimedRev=%d latestRev=%d', this.blockId, actionId, rev, latestRev);
|
|
278
|
+
}
|
|
189
279
|
}
|
|
190
280
|
|
|
191
281
|
async *listRevisions(startRev: number, endRev: number): AsyncIterable<ActionRev> {
|
|
@@ -228,7 +318,31 @@ export class BlockStorage implements IBlockStorage {
|
|
|
228
318
|
await this.storage.promotePendingTransaction(this.blockId, actionId);
|
|
229
319
|
}
|
|
230
320
|
|
|
231
|
-
async
|
|
321
|
+
async lineageOf({ actionId, rev }: ActionRev): Promise<BlockLineage> {
|
|
322
|
+
const meta = await this.storage.getMetadata(this.blockId);
|
|
323
|
+
const latest = meta?.latest;
|
|
324
|
+
if (!latest || latest.rev < rev) {
|
|
325
|
+
return 'behind';
|
|
326
|
+
}
|
|
327
|
+
if (latest.rev === rev) {
|
|
328
|
+
return latest.actionId === actionId ? 'contains' : 'excludes';
|
|
329
|
+
}
|
|
330
|
+
const heldBy = await this.storage.getRevision(this.blockId, rev);
|
|
331
|
+
if (heldBy !== undefined && heldBy !== actionId) {
|
|
332
|
+
return 'excludes';
|
|
333
|
+
}
|
|
334
|
+
// Past the revision. The index alone cannot answer from here: holding the action at `rev`
|
|
335
|
+
// does not prove `latest` was built from it (a replica taken since may descend from a base
|
|
336
|
+
// below `rev`), and holding nothing at `rev` does not prove it was not (a replica taken since
|
|
337
|
+
// may descend from it). Only a history derived HERE across `rev` settles it either way.
|
|
338
|
+
const floor = meta.lineageFloor;
|
|
339
|
+
if (floor === undefined || floor > rev) {
|
|
340
|
+
return 'unknown';
|
|
341
|
+
}
|
|
342
|
+
return heldBy === actionId ? 'contains' : 'excludes';
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async setLatest(latest: ActionRev, builtOnPrior: boolean, latch: BlockWriteLatch): Promise<void> {
|
|
232
346
|
this.assertLatch(latch);
|
|
233
347
|
const meta = await this.storage.getMetadata(this.blockId);
|
|
234
348
|
if (!meta) {
|
|
@@ -237,6 +351,7 @@ export class BlockStorage implements IBlockStorage {
|
|
|
237
351
|
// Capture the prior latest rev BEFORE overwriting: coverage anchors to the earliest held rev.
|
|
238
352
|
const prevRev = meta.latest?.rev;
|
|
239
353
|
meta.latest = latest;
|
|
354
|
+
meta.lineageFloor = BlockStorage.nextLineageFloor(meta.lineageFloor, prevRev, latest.rev, builtOnPrior);
|
|
240
355
|
// NOTE: re-sorts (mergeRanges) the whole ranges array on every commit; if a block ever
|
|
241
356
|
// accumulates many disjoint ranges and commits show as slow, keep a running merged structure.
|
|
242
357
|
// `getBlock(r)` is served by materializeBlock's DESCENDING walk (highest committed rev <= r).
|
|
@@ -252,6 +367,11 @@ export class BlockStorage implements IBlockStorage {
|
|
|
252
367
|
// before this call advances neither.
|
|
253
368
|
meta.ranges.unshift([prevRev ?? latest.rev]);
|
|
254
369
|
meta.ranges = mergeRanges(meta.ranges);
|
|
370
|
+
// The committing action's own record was just MOVED by `promotePendingTransaction`: drop its
|
|
371
|
+
// claim without a delete, so the sweep does not pay a raw-storage op on a record that is already
|
|
372
|
+
// gone. Any other record claiming a slot at or below the new latest is dead and swept.
|
|
373
|
+
BlockStorage.recordClaim(meta, latest.actionId, undefined);
|
|
374
|
+
await this.sweepDeadClaims(meta, latest.rev);
|
|
255
375
|
await this.storage.saveMetadata(this.blockId, meta);
|
|
256
376
|
}
|
|
257
377
|
|
|
@@ -265,6 +385,7 @@ export class BlockStorage implements IBlockStorage {
|
|
|
265
385
|
const currentRev = meta.latest?.rev ?? 0;
|
|
266
386
|
let maxRev = currentRev;
|
|
267
387
|
let maxActionId = meta.latest?.actionId;
|
|
388
|
+
let lineageFloor = meta.lineageFloor;
|
|
268
389
|
|
|
269
390
|
// Probe forward until we hit a gap or a revision whose action is not yet
|
|
270
391
|
// in the committed log (Crash-D2 state — retry-commit owns that advance).
|
|
@@ -273,6 +394,9 @@ export class BlockStorage implements IBlockStorage {
|
|
|
273
394
|
if (actionId === undefined) break;
|
|
274
395
|
const promoted = await this.storage.getTransaction(this.blockId, actionId);
|
|
275
396
|
if (promoted === undefined) break;
|
|
397
|
+
// Each recovered revision is a commit whose `setLatest` was lost, so it owes the floor
|
|
398
|
+
// exactly what that `setLatest` would have recorded.
|
|
399
|
+
lineageFloor = BlockStorage.nextLineageFloor(lineageFloor, maxRev === 0 ? undefined : maxRev, next, promoted.insert === undefined);
|
|
276
400
|
maxRev = next;
|
|
277
401
|
maxActionId = actionId;
|
|
278
402
|
}
|
|
@@ -280,6 +404,7 @@ export class BlockStorage implements IBlockStorage {
|
|
|
280
404
|
if (maxRev > currentRev && maxActionId !== undefined) {
|
|
281
405
|
const advanced: ActionRev = { rev: maxRev, actionId: maxActionId };
|
|
282
406
|
meta.latest = advanced;
|
|
407
|
+
meta.lineageFloor = lineageFloor;
|
|
283
408
|
// The lost setLatest would have merged each recovered revision's range; redo that
|
|
284
409
|
// here. Open-ended from currentRev+1 (see setLatest): every rev in (currentRev, maxRev]
|
|
285
410
|
// was verified present in the committed log above, and any rev > maxRev resolves via the
|
|
@@ -287,6 +412,13 @@ export class BlockStorage implements IBlockStorage {
|
|
|
287
412
|
// the prior [E, currentRev+1) (from the earlier setLatest) into one open-ended [E, +inf).
|
|
288
413
|
meta.ranges.unshift([currentRev + 1]);
|
|
289
414
|
meta.ranges = mergeRanges(meta.ranges);
|
|
415
|
+
// Each recovered revision's lost `setLatest` also owed this sweep. Unlike `setLatest`, it
|
|
416
|
+
// DELETES each recovered action's record rather than just dropping its claim: a pend checks
|
|
417
|
+
// only `latest`, so a same-action retry re-pended while the `setLatest` was owed leaves a
|
|
418
|
+
// pending record beside the committed one (reachable through `StorageRepo.recoverBlock`).
|
|
419
|
+
// Dropping only its claim would leave a claim-less record, the strongest kind of reservation,
|
|
420
|
+
// that nothing ever removes. Recover runs only after a crash, so the extra op costs nothing.
|
|
421
|
+
await this.sweepDeadClaims(meta, maxRev);
|
|
290
422
|
await this.storage.saveMetadata(this.blockId, meta);
|
|
291
423
|
log('recover blockId=%s advanced latest from rev=%d to rev=%d', this.blockId, currentRev, maxRev);
|
|
292
424
|
return { reconciled: true, latest: advanced };
|
|
@@ -404,11 +536,9 @@ export class BlockStorage implements IBlockStorage {
|
|
|
404
536
|
// record is not this writer's to delete. Both paths run under the block's write latch, so
|
|
405
537
|
// this deletion is already mutually exclusive with a live commit.
|
|
406
538
|
//
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
//
|
|
410
|
-
// committing action id differs, widen to a sweep over listPendingTransactions filtered by
|
|
411
|
-
// getTransaction.
|
|
539
|
+
// This same-action delete stays explicit even though the sweep below would usually cover it:
|
|
540
|
+
// Invariant P must hold for a record that has no claim on file (pended before claims were
|
|
541
|
+
// recorded), which the sweep — which reasons from claims — cannot see.
|
|
412
542
|
await this.storage.deletePendingTransaction(this.blockId, actionId);
|
|
413
543
|
|
|
414
544
|
// Seed metadata when absent, advance latest, and merge the covered range.
|
|
@@ -416,7 +546,16 @@ export class BlockStorage implements IBlockStorage {
|
|
|
416
546
|
if (!meta) {
|
|
417
547
|
meta = { latest: undefined, ranges: [] };
|
|
418
548
|
}
|
|
549
|
+
// Every OTHER record claiming a slot at or below the landing revision is dead too: the
|
|
550
|
+
// orphaned records a route that does not carry the committing action id used to leave behind
|
|
551
|
+
// (the cohort reconcile of a block a member fell behind on lands a later revision under a
|
|
552
|
+
// later action, and the missed action's record would otherwise stand forever).
|
|
553
|
+
BlockStorage.recordClaim(meta, actionId, undefined);
|
|
554
|
+
await this.sweepDeadClaims(meta, rev);
|
|
419
555
|
meta.latest = { rev, actionId };
|
|
556
|
+
// Content this node did not derive: nothing here says what it was built from, so the known
|
|
557
|
+
// lineage starts over at this revision (see BlockMetadata.lineageFloor).
|
|
558
|
+
meta.lineageFloor = rev;
|
|
420
559
|
// Open-ended coverage from the earliest held rev (see setLatest): the descending walk serves
|
|
421
560
|
// any rev >= the anchor. A prior latest at prevRev (< rev per the monotonic guard) is a
|
|
422
561
|
// materialized point, so anchor at prevRev; the first write (prevRev undefined) anchors at
|
|
@@ -758,6 +897,18 @@ export class BlockStorage implements IBlockStorage {
|
|
|
758
897
|
}
|
|
759
898
|
}
|
|
760
899
|
|
|
900
|
+
/**
|
|
901
|
+
* The lineage floor after a COMMIT lands `rev` on top of `prevRev` (see
|
|
902
|
+
* {@link BlockMetadata.lineageFloor}). A revision built on the prior content extends the known
|
|
903
|
+
* lineage downwards as far as it already reached — or, for metadata that predates the field,
|
|
904
|
+
* to the revision it was just built on, which is all this commit can vouch for. A revision that
|
|
905
|
+
* stands on its own (an insert replaces the block wholesale), and a block's first revision,
|
|
906
|
+
* start the lineage at themselves.
|
|
907
|
+
*/
|
|
908
|
+
private static nextLineageFloor(floor: number | undefined, prevRev: number | undefined, rev: number, builtOnPrior: boolean): number {
|
|
909
|
+
return builtOnPrior && prevRev !== undefined ? (floor ?? prevRev) : rev;
|
|
910
|
+
}
|
|
911
|
+
|
|
761
912
|
private inRanges(rev: number, ranges: RevisionRange[]): boolean {
|
|
762
913
|
return ranges.some(range =>
|
|
763
914
|
rev >= range[0] && (range[1] === undefined || rev < range[1])
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { BlockId, IBlock, Transform, ActionId, ActionRev } from "@optimystic/db-core";
|
|
1
|
+
import type { BlockId, IBlock, Transform, ActionId, ActionRev, BlockLineage } from "@optimystic/db-core";
|
|
2
2
|
import type { BlockCommitProof } from "../cluster/commit-proof.js";
|
|
3
3
|
import type { BlockWriteLatch } from "./block-latch.js";
|
|
4
|
+
import type { PendingClaim } from "./pending-claim.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Thrown by {@link IBlockStorage.getBlock} when the block has metadata here but the target revision
|
|
@@ -111,12 +112,44 @@ export interface IBlockStorage {
|
|
|
111
112
|
* under one multi-block write-latch hold, so every block it saves was observed under that same
|
|
112
113
|
* hold to satisfy `latest === undefined || latest.rev < rev`, and no writer can advance a block
|
|
113
114
|
* without its latch. A throw here means a caller reintroduced check-then-act.
|
|
115
|
+
*
|
|
116
|
+
* The revision is also KEPT, in the block's metadata (`BlockMetadata.pendingRevs`), so the record
|
|
117
|
+
* can later be read as a claim on a specific slot — see {@link listPendingClaims}.
|
|
118
|
+
*
|
|
119
|
+
* `baseRev` is the committed revision the record's update operations were computed against — the
|
|
120
|
+
* pend's `baseRevs[blockId]` — or `undefined` when the pend named none for this block (an
|
|
121
|
+
* inserted or deleted block, or a base the author did not know). Kept beside the revision
|
|
122
|
+
* (`BlockMetadata.pendingBases`), in the same metadata write, so that every later step that
|
|
123
|
+
* applies the record can refuse to apply it to a different version of the block — see
|
|
124
|
+
* {@link pendingClaimOf}. Stored as told: whether it matches this node's `latest` is decided
|
|
125
|
+
* where the record is APPLIED (`StorageRepo.internalCommit`, and the read-driven promotion in
|
|
126
|
+
* `StorageRepo.get`), never here.
|
|
114
127
|
*/
|
|
115
|
-
savePendingTransaction(actionId: ActionId, transform: Transform, rev: number | undefined, latch: BlockWriteLatch): Promise<void>;
|
|
128
|
+
savePendingTransaction(actionId: ActionId, transform: Transform, rev: number | undefined, baseRev: number | undefined, latch: BlockWriteLatch): Promise<void>;
|
|
116
129
|
|
|
117
|
-
/** Deletes a pending action */
|
|
130
|
+
/** Deletes a pending action, and the revision and base it was recorded as claiming. */
|
|
118
131
|
deletePendingTransaction(actionId: ActionId, latch: BlockWriteLatch): Promise<void>;
|
|
119
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Every pending record on this block, each with the revision it was pended at and the base it
|
|
135
|
+
* was computed against when those are known — the pending namespace joined against
|
|
136
|
+
* `BlockMetadata.pendingRevs` and `pendingBases`. This is the view the rival-pend checks read
|
|
137
|
+
* (`StorageRepo.pend`'s apply-time scan and `ClusterMember.validatePendOperations`' promise
|
|
138
|
+
* vote), because whether a record reserves the block against a given pend depends on the slot
|
|
139
|
+
* it claims measured against the pend's revision — and, at the vote of a cohort that can leave a
|
|
140
|
+
* member out, its base (`isReservationAgainst`) — not on its mere presence. Read-only; no latch.
|
|
141
|
+
*/
|
|
142
|
+
listPendingClaims(): Promise<PendingClaim[]>;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The claim of ONE pending record — `actionId`'s entry of {@link listPendingClaims} — or
|
|
146
|
+
* `undefined` when this block holds no pending record for the action. For the two apply sites
|
|
147
|
+
* (`StorageRepo.internalCommit` and the read-driven promotion in `StorageRepo.get`), which need
|
|
148
|
+
* one record's base on the hot commit path and must not enumerate every record to get it.
|
|
149
|
+
* Read-only; no latch of its own: both callers already hold the block's write latch.
|
|
150
|
+
*/
|
|
151
|
+
pendingClaimOf(actionId: ActionId): Promise<PendingClaim | undefined>;
|
|
152
|
+
|
|
120
153
|
/** Lists revisions in ascending or descending order between startRev and endRev (inclusive) */
|
|
121
154
|
listRevisions(startRev: number, endRev: number): AsyncIterable<ActionRev>;
|
|
122
155
|
|
|
@@ -152,8 +185,30 @@ export interface IBlockStorage {
|
|
|
152
185
|
*/
|
|
153
186
|
promotePendingTransaction(actionId: ActionId, latch: BlockWriteLatch): Promise<void>;
|
|
154
187
|
|
|
155
|
-
/**
|
|
156
|
-
|
|
188
|
+
/**
|
|
189
|
+
* Sets the latest revision information, as the last step of committing `latest` here.
|
|
190
|
+
*
|
|
191
|
+
* Call it only after {@link promotePendingTransaction} has moved `latest.actionId`'s record: it
|
|
192
|
+
* drops that action's claim without deleting a record, so a caller that skipped promotion would
|
|
193
|
+
* leave a claim-less pending record behind (see `BlockMetadata.pendingRevs`).
|
|
194
|
+
*
|
|
195
|
+
* `builtOnPrior` says how the revision's content was produced, which is what the block's known
|
|
196
|
+
* lineage depends on (see `BlockMetadata.lineageFloor`): `true` when this node applied the
|
|
197
|
+
* revision's transform to the content of its previous revision (an update-only or delete
|
|
198
|
+
* transform); `false` when the content stands on its own because the transform carried an
|
|
199
|
+
* `insert`. Required rather than defaulted: a caller that guessed `true` for an insert would let
|
|
200
|
+
* {@link lineageOf} vouch for history the content never came from.
|
|
201
|
+
*/
|
|
202
|
+
setLatest(latest: ActionRev, builtOnPrior: boolean, latch: BlockWriteLatch): Promise<void>;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* What THIS node's records say about whether the block's content at `latest` was built from the
|
|
206
|
+
* committed `target` — see `BlockLineage` in db-core for the four answers. Local and read-only:
|
|
207
|
+
* no latch, no peer fetch, no promotion. `unknown` is the honest answer whenever this node is
|
|
208
|
+
* past `target.rev` but took later content it did not derive itself (a replica, a restore);
|
|
209
|
+
* another cohort member that applied those revisions locally can still answer.
|
|
210
|
+
*/
|
|
211
|
+
lineageOf(target: ActionRev): Promise<BlockLineage>;
|
|
157
212
|
|
|
158
213
|
/**
|
|
159
214
|
* Persist a replica of a block received out-of-band (churn re-replication).
|