laminar_db/db/topology/
installation.rs1use std::sync::atomic::Ordering;
4use std::sync::Arc;
5
6use laminar_core::cluster::control::{TopologyError, TopologyRestoreInput};
7use laminar_core::shuffle::ShuffleTopologyFence;
8
9use super::{DbError, DbState, LaminarDB, PreparedTopologyRestore};
10
11impl LaminarDB {
12 pub async fn install_committed_cluster_topology(
22 self: &Arc<Self>,
23 mut image: PreparedTopologyRestore,
24 ) -> Result<(), DbError> {
25 let deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(45);
26 tokio::time::timeout_at(
27 deadline,
28 self.prepare_cluster_topology_transport(&mut image),
29 )
30 .await
31 .map_err(|_| TopologyError::Contended)??;
32 self.start_with_topology_image(image, deadline).await
33 }
34
35 pub(crate) async fn validate_topology_installation(
36 &self,
37 input: &TopologyRestoreInput,
38 ) -> Result<(), DbError> {
39 self.ensure_topology_runtime_held()?;
40 let controller = self
41 .cluster_controller
42 .lock()
43 .clone()
44 .ok_or(TopologyError::Fenced)?;
45 let fresh = controller
46 .committed_topology_restore_input(input.operation().operation_id)
47 .await?;
48 if if DbState::load(&self.state) == DbState::Starting {
49 !fresh.same_restore_requirements(input)
50 } else {
51 !fresh.same_installed_generation(input)
52 } {
53 return Err(TopologyError::Fenced.into());
54 }
55 if controller.is_recovering() {
56 return Err(TopologyError::Fenced.into());
57 }
58 self.validate_topology_transport_identity(input)?;
59 self.ensure_topology_runtime_held()
60 }
61
62 pub(crate) fn validate_topology_transport_identity(
63 &self,
64 input: &TopologyRestoreInput,
65 ) -> Result<(), DbError> {
66 let controller = self
67 .cluster_controller
68 .lock()
69 .clone()
70 .ok_or(TopologyError::Fenced)?;
71 let target = ShuffleTopologyFence::from_manifest(
72 input.descriptor().target_version,
73 &input.plan().target_manifest,
74 )
75 .map_err(|error| TopologyError::Invalid(error.to_string()))?;
76 let sender = self
77 .shuffle_sender
78 .lock()
79 .clone()
80 .ok_or(TopologyError::Fenced)?;
81 let receiver = self
82 .shuffle_receiver
83 .lock()
84 .clone()
85 .ok_or(TopologyError::Fenced)?;
86 let registry = self
87 .vnode_registry
88 .lock()
89 .clone()
90 .ok_or(TopologyError::Fenced)?;
91 let assignment = registry.versioned_snapshot();
92 let owners = assignment
93 .owners()
94 .iter()
95 .map(|owner| owner.0)
96 .collect::<Vec<_>>();
97 if assignment.version() != input.assignment().assignment_version
98 || !input.assignment().matches_owner_map(&owners)
99 || sender.topology_fence() != Some(target)
100 || receiver.topology_fence() != Some(target)
101 || sender.active_assignment_digest() != Some(input.assignment().digest())
102 || receiver.active_assignment_digest() != Some(input.assignment().digest())
103 || controller.try_live_local_process_authority_identity().ok() != Some(input.process())
104 || controller.is_draining()
105 {
106 return Err(TopologyError::Fenced.into());
107 }
108 Ok(())
109 }
110
111 pub(crate) fn ensure_topology_installation_held(&self) -> Result<(), DbError> {
112 if DbState::load(&self.state) != DbState::Starting {
113 return Err(TopologyError::Fenced.into());
114 }
115 self.ensure_topology_runtime_held()
116 }
117
118 pub(crate) fn ensure_topology_runtime_held(&self) -> Result<(), DbError> {
119 if self.is_closed() {
120 return Err(DbError::Shutdown);
121 }
122 if !self.is_cluster_runtime()
123 || !matches!(
124 DbState::load(&self.state),
125 DbState::Starting | DbState::Running
126 )
127 || !self.source_gate.load(Ordering::Acquire)
128 || !self.topology_cut_hold.load(Ordering::Acquire)
129 || self.cluster_authority_revoked.load(Ordering::Acquire)
130 || self.durable_terminal_recovery_fence.load(Ordering::Acquire)
131 || self.terminal_pipeline_halt.load(Ordering::Acquire)
132 || self.coordinated_recovery_in_progress()
133 || self.pending_recovery_fault.load(Ordering::Acquire) != 0
134 || self.last_fault.lock().is_some()
135 {
136 return Err(TopologyError::Fenced.into());
137 }
138 self.ensure_catalog_cleanup_unfenced("committed topology installation")
139 }
140}