laminar_db/db/topology/
commit.rs1use laminar_core::cluster::control::{TopologyAdmissionStatus, TopologyError};
4
5use super::{DbError, LaminarDB, PreparedTopologyRestore};
6
7impl LaminarDB {
8 pub async fn commit_cluster_topology_target(
21 &self,
22 image: &mut PreparedTopologyRestore,
23 ) -> Result<TopologyAdmissionStatus, DbError> {
24 if !image.belongs_to(self) {
25 return Err(TopologyError::Conflict(
26 "target image belongs to a different database runtime".into(),
27 )
28 .into());
29 }
30 tokio::time::timeout(std::time::Duration::from_secs(45), async {
31 let controller = self.cluster_controller.lock().clone().ok_or_else(|| {
32 TopologyError::Protocol("Commit requires the configured controller".into())
33 })?;
34 let status = self
35 .cluster_topology_operation_status(image.input.operation().operation_id)
36 .await?
37 .ok_or_else(|| TopologyError::Conflict("unknown topology operation".into()))?;
38 if status.commit.is_none() {
39 self.certify_cluster_topology_target_preparation(image)
40 .await?;
41 drop(
44 super::restore::prepare_source_positions(&image.candidate, &image.input)
45 .await?,
46 );
47 self.validate_topology_retirement_input(&image.input)
48 .await?;
49 controller.commit_topology_target(&image.input).await?;
50 }
51 self.ensure_topology_restore_available(true)?;
52 if !image.parent_retirement_observed {
53 return Err(TopologyError::Fenced.into());
54 }
55 self.stop_pipeline_for_topology_retirement().await?;
57 let fresh = controller
58 .committed_topology_restore_input(image.input.operation().operation_id)
59 .await?;
60 if !fresh.same_restore_requirements(&image.input)
61 && !fresh.is_committed_successor_of(&image.input)
62 {
63 return Err(TopologyError::Fenced.into());
64 }
65 self.ensure_topology_restore_available(true)?;
66 let result = fresh.operation().clone();
67 image.input = fresh;
68 Ok(result)
69 })
70 .await
71 .map_err(|_| TopologyError::Contended)?
72 }
73}