@optimystic/db-core 0.24.1 → 0.25.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/blocks/helpers.d.ts +5 -0
- package/dist/src/blocks/helpers.d.ts.map +1 -1
- package/dist/src/blocks/helpers.js +12 -0
- package/dist/src/blocks/helpers.js.map +1 -1
- package/dist/src/cluster/membership.d.ts +7 -0
- package/dist/src/cluster/membership.d.ts.map +1 -1
- package/dist/src/cluster/membership.js +12 -8
- package/dist/src/cluster/membership.js.map +1 -1
- package/dist/src/cluster/structs.d.ts +27 -1
- package/dist/src/cluster/structs.d.ts.map +1 -1
- package/dist/src/cluster/structs.js.map +1 -1
- package/dist/src/collection/action.d.ts +14 -0
- package/dist/src/collection/action.d.ts.map +1 -1
- package/dist/src/collection/action.js +16 -1
- package/dist/src/collection/action.js.map +1 -1
- package/dist/src/collection/collection.d.ts +273 -4
- package/dist/src/collection/collection.d.ts.map +1 -1
- package/dist/src/collection/collection.js +427 -30
- package/dist/src/collection/collection.js.map +1 -1
- package/dist/src/collections/tree/tree.d.ts +16 -1
- package/dist/src/collections/tree/tree.d.ts.map +1 -1
- package/dist/src/collections/tree/tree.js +19 -0
- 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/network/i-repo.d.ts +11 -1
- package/dist/src/network/i-repo.d.ts.map +1 -1
- package/dist/src/network/stale-failure.d.ts +21 -0
- package/dist/src/network/stale-failure.d.ts.map +1 -1
- package/dist/src/network/stale-failure.js +22 -0
- package/dist/src/network/stale-failure.js.map +1 -1
- package/dist/src/network/struct.d.ts +66 -21
- package/dist/src/network/struct.d.ts.map +1 -1
- package/dist/src/network/struct.js.map +1 -1
- package/dist/src/testing/test-transactor.d.ts +22 -0
- package/dist/src/testing/test-transactor.d.ts.map +1 -1
- package/dist/src/testing/test-transactor.js +44 -5
- package/dist/src/testing/test-transactor.js.map +1 -1
- package/dist/src/transaction/coordinator.d.ts +20 -0
- package/dist/src/transaction/coordinator.d.ts.map +1 -1
- package/dist/src/transaction/coordinator.js +256 -113
- package/dist/src/transaction/coordinator.js.map +1 -1
- package/dist/src/transaction/operations-hash.d.ts +1 -1
- package/dist/src/transaction/operations-hash.js +1 -1
- package/dist/src/transaction/transaction.d.ts +4 -2
- package/dist/src/transaction/transaction.d.ts.map +1 -1
- package/dist/src/transactor/network-transactor.d.ts +21 -1
- package/dist/src/transactor/network-transactor.d.ts.map +1 -1
- package/dist/src/transactor/network-transactor.js +122 -29
- package/dist/src/transactor/network-transactor.js.map +1 -1
- package/dist/src/transactor/transactor-source.d.ts +11 -5
- package/dist/src/transactor/transactor-source.d.ts.map +1 -1
- package/dist/src/transactor/transactor-source.js +16 -8
- package/dist/src/transactor/transactor-source.js.map +1 -1
- package/dist/src/transform/cache-source.d.ts +13 -0
- package/dist/src/transform/cache-source.d.ts.map +1 -1
- package/dist/src/transform/cache-source.js +18 -0
- package/dist/src/transform/cache-source.js.map +1 -1
- package/dist/src/transform/digest.d.ts +18 -0
- package/dist/src/transform/digest.d.ts.map +1 -0
- package/dist/src/transform/digest.js +65 -0
- package/dist/src/transform/digest.js.map +1 -0
- package/dist/src/transform/index.d.ts +1 -0
- package/dist/src/transform/index.d.ts.map +1 -1
- package/dist/src/transform/index.js +1 -0
- package/dist/src/transform/index.js.map +1 -1
- package/dist/src/transform/tracker.d.ts +16 -0
- package/dist/src/transform/tracker.d.ts.map +1 -1
- package/dist/src/transform/tracker.js +40 -1
- package/dist/src/transform/tracker.js.map +1 -1
- package/dist/src/utility/canonical-json.d.ts +11 -0
- package/dist/src/utility/canonical-json.d.ts.map +1 -0
- package/dist/src/utility/canonical-json.js +15 -0
- package/dist/src/utility/canonical-json.js.map +1 -0
- package/dist/src/utility/lru-map.d.ts +2 -0
- package/dist/src/utility/lru-map.d.ts.map +1 -1
- package/dist/src/utility/lru-map.js +4 -0
- package/dist/src/utility/lru-map.js.map +1 -1
- package/package.json +2 -1
- package/src/blocks/helpers.ts +26 -13
- package/src/cluster/membership.ts +87 -85
- package/src/cluster/structs.ts +28 -1
- package/src/collection/action.ts +17 -0
- package/src/collection/collection.ts +1129 -688
- package/src/collections/tree/tree.ts +341 -320
- package/src/index.ts +24 -23
- package/src/network/i-repo.ts +59 -46
- package/src/network/stale-failure.ts +67 -43
- package/src/network/struct.ts +332 -270
- package/src/testing/test-transactor.ts +680 -638
- package/src/transaction/coordinator.ts +1266 -1110
- package/src/transaction/operations-hash.ts +1 -1
- package/src/transaction/transaction.ts +4 -2
- package/src/transactor/network-transactor.ts +123 -32
- package/src/transactor/transactor-source.ts +17 -9
- package/src/transform/cache-source.ts +20 -0
- package/src/transform/digest.ts +72 -0
- package/src/transform/index.ts +1 -0
- package/src/transform/tracker.ts +42 -1
- package/src/utility/canonical-json.ts +16 -0
- package/src/utility/lru-map.ts +5 -0
package/src/index.ts
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
export * from "./blocks/index.js";
|
|
2
|
-
export * from "./btree/index.js";
|
|
3
|
-
export * from "./chain/index.js";
|
|
4
|
-
export * from "./cluster/index.js";
|
|
5
|
-
export * from "./cohort-topic/index.js";
|
|
6
|
-
export * from "./collection/index.js";
|
|
7
|
-
export * from "./collections/index.js";
|
|
8
|
-
export * from "./log/index.js";
|
|
9
|
-
export * from "./matchmaking/index.js";
|
|
10
|
-
export * from "./network/index.js";
|
|
11
|
-
export * from "./reactivity/index.js";
|
|
12
|
-
export * from "./transaction/index.js";
|
|
13
|
-
export * from "./transactor/index.js";
|
|
14
|
-
export * from "./transform/index.js";
|
|
15
|
-
export * from "./utility/
|
|
16
|
-
export * from "./utility/
|
|
17
|
-
export * from "./utility/
|
|
18
|
-
export * from "./utility/
|
|
19
|
-
export * from "./utility/
|
|
20
|
-
export * from "./utility/
|
|
21
|
-
export * from "./utility/
|
|
22
|
-
export * from "./utility/
|
|
23
|
-
export * from "./utility/
|
|
1
|
+
export * from "./blocks/index.js";
|
|
2
|
+
export * from "./btree/index.js";
|
|
3
|
+
export * from "./chain/index.js";
|
|
4
|
+
export * from "./cluster/index.js";
|
|
5
|
+
export * from "./cohort-topic/index.js";
|
|
6
|
+
export * from "./collection/index.js";
|
|
7
|
+
export * from "./collections/index.js";
|
|
8
|
+
export * from "./log/index.js";
|
|
9
|
+
export * from "./matchmaking/index.js";
|
|
10
|
+
export * from "./network/index.js";
|
|
11
|
+
export * from "./reactivity/index.js";
|
|
12
|
+
export * from "./transaction/index.js";
|
|
13
|
+
export * from "./transactor/index.js";
|
|
14
|
+
export * from "./transform/index.js";
|
|
15
|
+
export * from "./utility/canonical-json.js";
|
|
16
|
+
export * from "./utility/groupby.js";
|
|
17
|
+
export * from "./utility/hash-string.js";
|
|
18
|
+
export * from "./utility/latches.js";
|
|
19
|
+
export * from "./utility/nameof.js";
|
|
20
|
+
export * from "./utility/ensured.js";
|
|
21
|
+
export * from "./utility/pending.js";
|
|
22
|
+
export * from "./utility/block-id-to-bytes.js";
|
|
23
|
+
export * from "./utility/lru-map.js";
|
|
24
|
+
export * from "./utility/backoff.js";
|
package/src/network/i-repo.ts
CHANGED
|
@@ -1,46 +1,59 @@
|
|
|
1
|
-
import type { ActionBlocks, CommitResult, GetBlockResults, PendResult, PendRequest, BlockGets, BlockId, ActionId } from "../index.js";
|
|
2
|
-
|
|
3
|
-
export type MessageOptions = {
|
|
4
|
-
expiration?: number;
|
|
5
|
-
signal?: AbortSignal;
|
|
6
|
-
/**
|
|
7
|
-
* Per-peer dial deadline in ms. Bounds only the dial portion of a call, so
|
|
8
|
-
* an unreachable peer fails fast and the caller's retry loop can re-pick
|
|
9
|
-
* a different coordinator. Independent of `expiration` (the overall budget):
|
|
10
|
-
* a 30s transaction with `dialTimeoutMs: 3000` can afford ten 3s dial
|
|
11
|
-
* attempts against different peers. Once a dial succeeds, the response wait
|
|
12
|
-
* is bound by the remaining `expiration` budget. Undefined means "do not
|
|
13
|
-
* impose a separate dial cap; the overall budget is the cap".
|
|
14
|
-
*/
|
|
15
|
-
dialTimeoutMs?: number;
|
|
16
|
-
/**
|
|
17
|
-
* Blocks this coordinator is responsible for driving through consensus. Threaded
|
|
18
|
-
* from {@link NetworkTransactor.pend}'s batch (which consolidates several blocks
|
|
19
|
-
* onto one coordinating peer) into {@link CoordinatorRepo.pend}, which uses it to
|
|
20
|
-
* pick the cluster anchor. Absent on bare per-block paths, which fall back to the
|
|
21
|
-
* transforms' own block ids.
|
|
22
|
-
*/
|
|
23
|
-
coordinatingBlockIds?: BlockId[];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export type RepoCommitRequest = {
|
|
27
|
-
blockIds: BlockId[];
|
|
28
|
-
actionId: ActionId;
|
|
29
|
-
rev: number;
|
|
30
|
-
/**
|
|
31
|
-
* The collection's chain tail block id (the {@link CommitRequest.tailId}). Optional on the per-block
|
|
32
|
-
* repo operation: the transactor threads the committing collection's tail through every per-block
|
|
33
|
-
* commit so the coordinator carries it into the consensus commit op, letting the committing node's
|
|
34
|
-
* `StorageRepo.commit` stamp it onto the emitted `CollectionChangeEvent` (the reactivity topic anchor
|
|
35
|
-
* `H(tailId ‖ "reactivity")`). Absent on bare per-block paths (e.g. churn replication), which never
|
|
36
|
-
* originate reactivity.
|
|
37
|
-
*/
|
|
38
|
-
tailId?: BlockId;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
1
|
+
import type { ActionBlocks, BlockContentDigests, CommitResult, GetBlockResults, PendResult, PendRequest, BlockGets, BlockId, ActionId } from "../index.js";
|
|
2
|
+
|
|
3
|
+
export type MessageOptions = {
|
|
4
|
+
expiration?: number;
|
|
5
|
+
signal?: AbortSignal;
|
|
6
|
+
/**
|
|
7
|
+
* Per-peer dial deadline in ms. Bounds only the dial portion of a call, so
|
|
8
|
+
* an unreachable peer fails fast and the caller's retry loop can re-pick
|
|
9
|
+
* a different coordinator. Independent of `expiration` (the overall budget):
|
|
10
|
+
* a 30s transaction with `dialTimeoutMs: 3000` can afford ten 3s dial
|
|
11
|
+
* attempts against different peers. Once a dial succeeds, the response wait
|
|
12
|
+
* is bound by the remaining `expiration` budget. Undefined means "do not
|
|
13
|
+
* impose a separate dial cap; the overall budget is the cap".
|
|
14
|
+
*/
|
|
15
|
+
dialTimeoutMs?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Blocks this coordinator is responsible for driving through consensus. Threaded
|
|
18
|
+
* from {@link NetworkTransactor.pend}'s batch (which consolidates several blocks
|
|
19
|
+
* onto one coordinating peer) into {@link CoordinatorRepo.pend}, which uses it to
|
|
20
|
+
* pick the cluster anchor. Absent on bare per-block paths, which fall back to the
|
|
21
|
+
* transforms' own block ids.
|
|
22
|
+
*/
|
|
23
|
+
coordinatingBlockIds?: BlockId[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type RepoCommitRequest = {
|
|
27
|
+
blockIds: BlockId[];
|
|
28
|
+
actionId: ActionId;
|
|
29
|
+
rev: number;
|
|
30
|
+
/**
|
|
31
|
+
* The collection's chain tail block id (the {@link CommitRequest.tailId}). Optional on the per-block
|
|
32
|
+
* repo operation: the transactor threads the committing collection's tail through every per-block
|
|
33
|
+
* commit so the coordinator carries it into the consensus commit op, letting the committing node's
|
|
34
|
+
* `StorageRepo.commit` stamp it onto the emitted `CollectionChangeEvent` (the reactivity topic anchor
|
|
35
|
+
* `H(tailId ‖ "reactivity")`). Absent on bare per-block paths (e.g. churn replication), which never
|
|
36
|
+
* originate reactivity.
|
|
37
|
+
*/
|
|
38
|
+
tailId?: BlockId;
|
|
39
|
+
/**
|
|
40
|
+
* Per-block content declarations for this batch (see {@link BlockContentDigests}).
|
|
41
|
+
* The transactor narrows its action-wide {@link CommitRequest.blockDigests} to this request's own
|
|
42
|
+
* `blockIds` before sending, so a cohort only ever declares for the blocks it is driving —
|
|
43
|
+
* `RepoClient.commit` wraps this whole request into the `RepoMessage`, and the coordinator places
|
|
44
|
+
* the received request into the consensus message, so the digests land inside every cohort
|
|
45
|
+
* signature's preimage. Absent when no block in this batch could be digested (each undeclared
|
|
46
|
+
* block falls back to corroboration).
|
|
47
|
+
*/
|
|
48
|
+
// NOTE: accepted tradeoff — optional by necessity, and NOT free: an undeclared block retains no
|
|
49
|
+
// durable commit proof and so cannot gain holders by push. Full rationale and the measured cost of
|
|
50
|
+
// making it required live at {@link CommitRequest.blockDigests} in `struct.ts`; keep the two in sync.
|
|
51
|
+
blockDigests?: BlockContentDigests;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type IRepo = {
|
|
55
|
+
get(blockGets: BlockGets, options?: MessageOptions): Promise<GetBlockResults>;
|
|
56
|
+
pend(request: PendRequest, options?: MessageOptions): Promise<PendResult>;
|
|
57
|
+
cancel(actionRef: ActionBlocks, options?: MessageOptions): Promise<void>;
|
|
58
|
+
commit(request: RepoCommitRequest, options?: MessageOptions): Promise<CommitResult>;
|
|
59
|
+
}
|
|
@@ -1,43 +1,67 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* `
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
1
|
+
import type { ActionId, ActionRev } from "../collection/action.js";
|
|
2
|
+
import type { StaleFailure } from "./struct.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The single rule for "is this non-success retryable after a re-read?" Both write paths and the
|
|
6
|
+
* transactor's aggregation call this — no consumer re-derives it.
|
|
7
|
+
*
|
|
8
|
+
* {@link StaleFailure.conflict} is authoritative when present. The `missing`/`pending` fallback
|
|
9
|
+
* covers producers that have not been taught the field, including a remote peer on an older build
|
|
10
|
+
* (the repo protocol is plain JSON, so an unset field simply arrives absent).
|
|
11
|
+
*/
|
|
12
|
+
export function isConflictFailure(failure: StaleFailure): boolean {
|
|
13
|
+
return failure.conflict ?? Boolean(failure.missing?.length || failure.pending?.length);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The single rule for picking one {@link StaleFailure.staleAt} out of several candidates.
|
|
18
|
+
*
|
|
19
|
+
* Highest `rev` wins: the losing writer's next request has to clear EVERY holder, so the largest
|
|
20
|
+
* confirmed revision is the binding constraint and any smaller one understates it. Ties keep the
|
|
21
|
+
* earlier candidate. Undefined entries (a block or batch with no confirmed number, or a peer that
|
|
22
|
+
* predates the field) contribute nothing, and an all-undefined input yields undefined so callers
|
|
23
|
+
* can omit the key rather than emit `staleAt: undefined`.
|
|
24
|
+
*
|
|
25
|
+
* Every site that has more than one candidate calls this — the producers scanning several blocks
|
|
26
|
+
* (`StorageRepo.pend`/`.commit`, `CoordinatorRepo.classifyStaleRejection`) as well as
|
|
27
|
+
* `NetworkTransactor` rebuilding one response from many per-batch ones. Uniformity is what makes
|
|
28
|
+
* the transactor's aggregate meaningful: if a producer reported an arbitrary block instead of its
|
|
29
|
+
* highest, taking the max across producers would still understate the constraint.
|
|
30
|
+
*
|
|
31
|
+
* NOTE: comparing revisions across blocks is only meaningful because one pend covers one
|
|
32
|
+
* collection, so every candidate comes from the same revision counter. If a pend is ever allowed
|
|
33
|
+
* to span collections, these numbers come from unrelated counters and selection must become
|
|
34
|
+
* per-collection.
|
|
35
|
+
*/
|
|
36
|
+
export function highestStaleAt(candidates: readonly StaleFailure['staleAt'][]): StaleFailure['staleAt'] {
|
|
37
|
+
let best: StaleFailure['staleAt'];
|
|
38
|
+
for (const candidate of candidates) {
|
|
39
|
+
if (candidate !== undefined && (best === undefined || candidate.rev > best.rev)) {
|
|
40
|
+
best = candidate;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return best;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The single rule for "is the action holding this revision OUR OWN?" — true only when `latest`
|
|
48
|
+
* names exactly the revision being requested AND the same action requesting it.
|
|
49
|
+
*
|
|
50
|
+
* A write touching several blocks is committed one group at a time, so it can end up with some
|
|
51
|
+
* blocks durable and the rest refused (a *torn action*). The retry reuses the same `actionId`, so
|
|
52
|
+
* every revision check meets the writer's own durable half and must treat it as a no-op rather
|
|
53
|
+
* than as a rival's win — otherwise the writer is refused by its own committed work, forever.
|
|
54
|
+
*
|
|
55
|
+
* Deliberately `===` only. At `latest.rev > rev` this returns false even for our own action: the
|
|
56
|
+
* follow-on commit is refused as stale anyway (`StorageRepo.commit`'s `missedCommits` branch), so
|
|
57
|
+
* approving would only defer the refusal by a round trip, and `latest` alone can no longer name
|
|
58
|
+
* who holds `rev` — that needs the revision index (see `IRevisionActionReader`).
|
|
59
|
+
*
|
|
60
|
+
* Every revision-vs-action check calls this: the pend tier (`StorageRepo.pend`,
|
|
61
|
+
* `ClusterMember.validatePendOperations`, `CoordinatorRepo.classifyStaleRejection`) and the commit
|
|
62
|
+
* tier (`StorageRepo.commit`'s `alreadyDone` partition, `ClusterMember.validateCommitRevisions`).
|
|
63
|
+
* Single-sourcing it is what makes "all the tiers agree" a fact rather than a comment.
|
|
64
|
+
*/
|
|
65
|
+
export function isOwnRevision(latest: ActionRev | undefined, rev: number | undefined, actionId: ActionId): boolean {
|
|
66
|
+
return latest !== undefined && rev !== undefined && latest.rev === rev && latest.actionId === actionId;
|
|
67
|
+
}
|