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(super) fn open_original<'a, E>(
24 stage: &'a ExecutionStageGuard<'_>,
25 requirement: FenceObligationRequirement<'_>,
26 obligation: &FenceObligationRecord,
27 payload: &FenceAcquisitionPayload,
28) -> Result<AttemptJournalGuard<'a>, E>
29where
30 E: From<ExecutionWorkflowPersistenceError>
31 + From<FenceObligationPersistenceError>
32 + From<OperationPlanError>
33 + From<AttemptJournalError>
34 + From<FenceAcquisitionError>,
35{
36 let plan = stage.plan();
37 let layout = stage.layout()?;
38 read_fence_obligation(layout, plan, requirement, &obligation.digest())?;
39 let authority = plan.attempt_authority(obligation.acquisition_operation())?;
40 let journal = AttemptJournalGuard::open(layout, &authority)?;
41 original_authority(plan, obligation, journal.record()?, payload)?;
42 Ok(journal)
43}
44
45pub async fn acquire_fence<E: std::error::Error + 'static>(
71 stage: &ExecutionStageGuard<'_>,
72 requirement: FenceObligationRequirement<'_>,
73 obligation: &FenceObligationRecord,
74 payload: &FenceAcquisitionPayload,
75 provider: &mut impl FenceAcquisitionProvider,
76 admit: impl AsyncFnOnce(&FenceAcquisitionRequest<'_>) -> Result<(), E>,
77) -> Result<FenceAcquisitionAcknowledgement, FenceAcquisitionExecutionError<E>> {
78 let plan = stage.plan();
79 let mut journal = super::fence_acquisition::open_original::<FenceAcquisitionExecutionError<E>>(
80 stage,
81 requirement,
82 obligation,
83 payload,
84 )?;
85 journal.reserve_planned_mutation(&plan.digest())?;
86 let request = FenceAcquisitionRequest::new(plan, obligation, journal.record()?, payload)?;
87 admit(&request)
88 .await
89 .map_err(FenceAcquisitionExecutionError::Admission)?;
90 read_fence_obligation(stage.layout()?, plan, requirement, &obligation.digest())?;
91 let acknowledgement = provider.acquire_fence(&request, journal.record()?).await?;
92 let admit_reply = || -> Result<(), FenceAcquisitionReplyError> {
93 validate_acknowledgement(&request, journal.record()?, &acknowledgement)?;
94 read_fence_obligation(stage.layout()?, plan, requirement, &obligation.digest())?;
95 Ok(())
96 };
97 match admit_reply() {
98 Ok(()) => Ok(acknowledgement),
99 Err(source) => Err(FenceAcquisitionExecutionError::AfterReply {
100 source,
101 acknowledgement: Box::new(acknowledgement),
102 }),
103 }
104}
105
106#[derive(Debug, Error)]
108pub enum FenceAcquisitionExecutionError<E: std::error::Error + 'static> {
109 #[error(transparent)]
111 Plan(#[from] OperationPlanError),
112 #[error(transparent)]
114 Stage(#[from] ExecutionWorkflowPersistenceError),
115 #[error(transparent)]
117 Obligation(#[from] FenceObligationPersistenceError),
118 #[error(transparent)]
120 Journal(#[from] AttemptJournalError),
121 #[error(transparent)]
123 Progress(#[from] ExecutionProgressPersistenceError),
124 #[error(transparent)]
126 Request(#[from] FenceAcquisitionError),
127 #[error("fresh fence acquisition admission failed: {0}")]
129 Admission(#[source] E),
130 #[error(transparent)]
132 Provider(#[from] FenceAcquisitionProviderError),
133 #[error("fence acquisition reply rejected: {source}")]
135 AfterReply {
136 source: FenceAcquisitionReplyError,
138 acknowledgement: Box<FenceAcquisitionAcknowledgement>,
140 },
141}
142
143#[derive(Debug, Error)]
145pub enum FenceAcquisitionReplyError {
146 #[error(transparent)]
148 Journal(#[from] AttemptJournalError),
149 #[error(transparent)]
151 Association(#[from] FenceAcquisitionAcknowledgementError),
152 #[error(transparent)]
154 Stage(#[from] ExecutionWorkflowPersistenceError),
155 #[error(transparent)]
157 Obligation(#[from] FenceObligationPersistenceError),
158}
159
160#[cfg(all(test, unix))]
161mod tests;