Skip to main content

laminar_core/cluster/control/topology/
restore.rs

1//! Current-authority input for a private, effect-free target state image.
2
3use super::{
4    ClusterTopologyValidation, TopologyAdmissionPlan, TopologyAdmissionStatus,
5    TopologyMigrationRoot,
6};
7use crate::checkpoint::{CheckpointAssignmentFence, CommittedCheckpointIndex, LeaderProof};
8use crate::checkpoint_decision::CheckpointOutcome;
9use crate::cluster::control::{CatalogManifest, LocalProcessAuthorityIdentity};
10
11/// A live read of the exact prepared operation, cut and local ownership.
12/// Only the configured controller/authority can construct this input. It permits private restore
13/// preparation, never graph installation, source start, output or intake release. A retained input
14/// can become stale; installation must revalidate authority and require a target Commit/Release.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct TopologyRestoreInput {
17    pub(crate) operation: TopologyAdmissionStatus,
18    pub(crate) plan: TopologyAdmissionPlan,
19    pub(crate) parent: CatalogManifest,
20    pub(crate) target: CatalogManifest,
21    pub(crate) descriptor: ClusterTopologyValidation,
22    pub(crate) root: TopologyMigrationRoot,
23    pub(crate) outcome: CheckpointOutcome,
24    pub(crate) checkpoint: CommittedCheckpointIndex,
25    pub(crate) owned_vnodes: Vec<u32>,
26    pub(crate) process: LocalProcessAuthorityIdentity,
27    pub(crate) restore_assignment: CheckpointAssignmentFence,
28    pub(crate) restore_processes: Vec<LocalProcessAuthorityIdentity>,
29    pub(crate) committed_leader: Option<LeaderProof>,
30}
31
32impl TopologyRestoreInput {
33    /// Exact current owner/evidence roster revalidated for committed reconstruction.
34    #[must_use]
35    pub fn processes(&self) -> &[LocalProcessAuthorityIdentity] {
36        &self.restore_processes
37    }
38
39    /// Current committed reconstruction leader, absent for pre-Commit private preparation.
40    #[must_use]
41    pub fn current_leader(&self) -> Option<LeaderProof> {
42        self.committed_leader.clone()
43    }
44    /// Compare all restore requirements, allowing only monotonic receipt/status progress.
45    /// Both inputs must come from current controller authorization; this comparison never
46    /// replaces a fresh read or the authority's receipt, leader, process and assignment audits.
47    #[must_use]
48    pub fn same_restore_requirements(&self, other: &Self) -> bool {
49        self.same_installed_generation(other) && self.committed_leader == other.committed_leader
50    }
51
52    /// Immutable installed generation, excluding the current leader read. A leader change after
53    /// Commit never changes the restored state; current installation/Release must be audited anew.
54    #[must_use]
55    pub fn same_installed_generation(&self, other: &Self) -> bool {
56        self.operation.same_restore_binding(&other.operation)
57            && self.plan == other.plan
58            && self.parent == other.parent
59            && self.target == other.target
60            && self.descriptor == other.descriptor
61            && self.root == other.root
62            && self.outcome == other.outcome
63            && self.checkpoint == other.checkpoint
64            && self.owned_vnodes == other.owned_vnodes
65            && self.process == other.process
66            && self.restore_assignment == other.restore_assignment
67            && self.restore_processes == other.restore_processes
68    }
69
70    /// Whether a fresh committed authorization retains the prepared image's exact historical
71    /// requirements and local process. This compares images only, never grants output or Release.
72    #[must_use]
73    pub fn is_committed_successor_of(&self, prepared: &Self) -> bool {
74        self.operation.has_target_commit()
75            && self.committed_leader.is_some()
76            && prepared.operation.phase == super::TopologyAdmissionPhase::CutPrepared
77            && prepared.operation.commit.is_none()
78            && self.operation.same_migration_binding(&prepared.operation)
79            && self.plan == prepared.plan
80            && self.parent == prepared.parent
81            && self.target == prepared.target
82            && self.descriptor == prepared.descriptor
83            && self.root == prepared.root
84            && self.outcome == prepared.outcome
85            && self.checkpoint == prepared.checkpoint
86            && self.owned_vnodes == prepared.owned_vnodes
87            && self.process == prepared.process
88            && self.restore_assignment == prepared.restore_assignment
89    }
90
91    /// Exact current assignment authorizing this private reconstruction. Historical state and
92    /// source attempts retain `plan().assignment`; recovery may replace boots with the same owners.
93    #[must_use]
94    pub const fn assignment(&self) -> &CheckpointAssignmentFence {
95        &self.restore_assignment
96    }
97
98    /// Whether this is explicit committed-root reconstruction, still without installation/Release.
99    #[must_use]
100    pub const fn is_committed(&self) -> bool {
101        self.committed_leader.is_some()
102    }
103    /// Exact prepared or committed operation, including its root authority anchor.
104    #[must_use]
105    pub const fn operation(&self) -> &TopologyAdmissionStatus {
106        &self.operation
107    }
108    /// Immutable admitted plan and assignment.
109    #[must_use]
110    pub const fn plan(&self) -> &TopologyAdmissionPlan {
111        &self.plan
112    }
113    /// Complete exact predecessor inventory. Removals cannot be inferred from a target prefix.
114    #[must_use]
115    pub const fn parent(&self) -> &CatalogManifest {
116        &self.parent
117    }
118    /// Complete sealed target inventory, committed only when this authorization records Commit.
119    #[must_use]
120    pub const fn target(&self) -> &CatalogManifest {
121        &self.target
122    }
123    /// Independently certified parent/target and per-object contracts.
124    #[must_use]
125    pub const fn descriptor(&self) -> &ClusterTopologyValidation {
126        &self.descriptor
127    }
128    /// Immutable requirements, including sealed source positions and subscription mappings.
129    #[must_use]
130    pub const fn root(&self) -> &TopologyMigrationRoot {
131        &self.root
132    }
133    /// Definitive old-topology checkpoint Commit; never a target Commit.
134    #[must_use]
135    pub const fn outcome(&self) -> &CheckpointOutcome {
136        &self.outcome
137    }
138    /// Exact historical index, retaining the parent pipeline identity.
139    #[must_use]
140    pub const fn checkpoint(&self) -> &CommittedCheckpointIndex {
141        &self.checkpoint
142    }
143    /// Canonical local vnode roster from the unchanged current assignment.
144    #[must_use]
145    pub fn owned_vnodes(&self) -> &[u32] {
146        &self.owned_vnodes
147    }
148    /// Exact process incarnation and term for this preparation.
149    #[must_use]
150    pub const fn process(&self) -> LocalProcessAuthorityIdentity {
151        self.process
152    }
153}