ic_backup/workflow/fence_acquisition/
mod.rs1use crate::{
4 model::{
5 fence_acquisition::{
6 FenceAcquisitionAcknowledgement, FenceAcquisitionError, FenceAcquisitionPayload,
7 FenceAcquisitionRequest, original_authority,
8 },
9 fence_obligation::FenceObligationRecord,
10 operation_plan::OperationPlanError,
11 },
12 ops::persistence::{
13 AttemptJournalError, AttemptJournalGuard, ExecutionProgressPersistenceError,
14 ExecutionStageGuard, ExecutionWorkflowPersistenceError, FenceObligationPersistenceError,
15 FenceObligationRequirement, read_fence_obligation,
16 },
17 policy::fence_acquisition::{FenceAcquisitionAcknowledgementError, validate_acknowledgement},
18 ports::fence_acquisition::{FenceAcquisitionProvider, FenceAcquisitionProviderError},
19};
20use thiserror::Error;
21
22pub async fn acquire_fence<E: std::error::Error + 'static>(
48 stage: &ExecutionStageGuard<'_>,
49 requirement: FenceObligationRequirement<'_>,
50 obligation: &FenceObligationRecord,
51 payload: &FenceAcquisitionPayload,
52 provider: &mut impl FenceAcquisitionProvider,
53 admit: impl AsyncFnOnce(&FenceAcquisitionRequest<'_>) -> Result<(), E>,
54) -> Result<FenceAcquisitionAcknowledgement, FenceAcquisitionExecutionError<E>> {
55 let plan = stage.plan();
56 let layout = stage.layout()?;
57 read_fence_obligation(layout, plan, requirement, &obligation.digest())?;
58 let authority = plan.attempt_authority(obligation.acquisition_operation())?;
59 let mut journal = AttemptJournalGuard::open(layout, &authority)?;
60 original_authority(plan, obligation, journal.record()?, payload)?;
61 journal.reserve_planned_mutation(&plan.digest())?;
62 let request = FenceAcquisitionRequest::new(plan, obligation, journal.record()?, payload)?;
63 admit(&request)
64 .await
65 .map_err(FenceAcquisitionExecutionError::Admission)?;
66 read_fence_obligation(stage.layout()?, plan, requirement, &obligation.digest())?;
67 let acknowledgement = provider.acquire_fence(&request, journal.record()?).await?;
68 let association = match journal.record() {
69 Ok(record) => record,
70 Err(source) => {
71 return Err(FenceAcquisitionExecutionError::AfterReplyJournal {
72 source,
73 acknowledgement: Box::new(acknowledgement),
74 });
75 }
76 };
77 if let Err(source) = validate_acknowledgement(&request, association, &acknowledgement) {
78 return Err(FenceAcquisitionExecutionError::Association {
79 source,
80 acknowledgement: Box::new(acknowledgement),
81 });
82 }
83 let layout = match stage.layout() {
84 Ok(layout) => layout,
85 Err(source) => {
86 return Err(FenceAcquisitionExecutionError::AfterReplyStage {
87 source,
88 acknowledgement: Box::new(acknowledgement),
89 });
90 }
91 };
92 if let Err(source) = read_fence_obligation(layout, plan, requirement, &obligation.digest()) {
93 return Err(FenceAcquisitionExecutionError::AfterReplyObligation {
94 source,
95 acknowledgement: Box::new(acknowledgement),
96 });
97 }
98 Ok(acknowledgement)
99}
100
101#[derive(Debug, Error)]
103pub enum FenceAcquisitionExecutionError<E: std::error::Error + 'static> {
104 #[error(transparent)]
106 Plan(#[from] OperationPlanError),
107 #[error(transparent)]
109 Stage(#[from] ExecutionWorkflowPersistenceError),
110 #[error(transparent)]
112 Obligation(#[from] FenceObligationPersistenceError),
113 #[error(transparent)]
115 Journal(#[from] AttemptJournalError),
116 #[error(transparent)]
118 Progress(#[from] ExecutionProgressPersistenceError),
119 #[error(transparent)]
121 Request(#[from] FenceAcquisitionError),
122 #[error("fresh fence acquisition admission failed: {0}")]
124 Admission(#[source] E),
125 #[error(transparent)]
127 Provider(#[from] FenceAcquisitionProviderError),
128 #[error("fence acquisition acknowledgement association failed: {source}")]
130 Association {
131 source: FenceAcquisitionAcknowledgementError,
133 acknowledgement: Box<FenceAcquisitionAcknowledgement>,
135 },
136 #[error("fence acquisition journal changed after reply: {source}")]
138 AfterReplyJournal {
139 source: AttemptJournalError,
141 acknowledgement: Box<FenceAcquisitionAcknowledgement>,
143 },
144 #[error("fence acquisition stage changed after reply: {source}")]
146 AfterReplyStage {
147 source: ExecutionWorkflowPersistenceError,
149 acknowledgement: Box<FenceAcquisitionAcknowledgement>,
151 },
152 #[error("fence acquisition obligation changed after reply: {source}")]
154 AfterReplyObligation {
155 source: FenceObligationPersistenceError,
157 acknowledgement: Box<FenceAcquisitionAcknowledgement>,
159 },
160}
161
162#[cfg(all(test, unix))]
163mod tests;