ic_backup/workflow/ic_snapshot_transfer_read/
mod.rs1use crate::{
4 model::{
5 ic_snapshot_transfer_read::{
6 IcSnapshotTransferReadError, IcSnapshotTransferReadPayload,
7 IcSnapshotTransferReadRequest, IcSnapshotTransferReadResponse,
8 },
9 operation_plan::OperationPlanError,
10 },
11 ops::persistence::{
12 AttemptJournalError, AttemptJournalGuard, ExecutionProgressPersistenceError,
13 ExecutionStageGuard, ExecutionWorkflowPersistenceError,
14 },
15 policy::ic_snapshot_transfer_read::{
16 IcSnapshotTransferReadAssociationError, IcSnapshotTransferReadView, validate_response,
17 },
18 ports::{
19 ic_observation::IcObservationProviderError,
20 ic_snapshot_transfer_read::IcSnapshotTransferReadProvider,
21 },
22};
23use thiserror::Error;
24
25pub(super) async fn read_snapshot_with<E: std::error::Error + 'static, T>(
29 stage: &ExecutionStageGuard<'_>,
30 operation_sequence: u64,
31 payload: IcSnapshotTransferReadPayload<'_, '_>,
32 provider: &mut impl IcSnapshotTransferReadProvider,
33 admit: impl AsyncFnOnce(&IcSnapshotTransferReadRequest<'_, '_>) -> Result<(), E>,
34 complete: impl AsyncFnOnce(
35 &mut AttemptJournalGuard<'_>,
36 &IcSnapshotTransferReadRequest<'_, '_>,
37 &IcSnapshotTransferReadView<'_, '_>,
38 ) -> T,
39) -> Result<(IcSnapshotTransferReadResponse, T), IcSnapshotTransferReadExecutionError<E>> {
40 let plan = stage.plan();
41 let authority = plan.attempt_authority(operation_sequence)?;
42 payload.validate_binding(&authority)?;
43 let mut journal = AttemptJournalGuard::open(stage.layout()?, &authority)?;
44 journal.reserve_planned_mutation(&plan.digest())?;
45 let request =
46 IcSnapshotTransferReadRequest::new(plan, operation_sequence, journal.record()?, payload)?;
47 admit(&request)
48 .await
49 .map_err(IcSnapshotTransferReadExecutionError::Admission)?;
50 stage.layout()?;
51 let response = provider.read_snapshot(&request, journal.record()?).await?;
52 let admit_reply = || {
53 let admitted = validate_response(&request, journal.record()?, &response)?;
54 stage.layout()?;
55 Ok::<_, IcSnapshotTransferReadReplyError>(admitted)
56 };
57 let admitted = match admit_reply() {
58 Ok(admitted) => admitted,
59 Err(source) => {
60 return Err(IcSnapshotTransferReadExecutionError::AfterReply {
61 source,
62 response: Box::new(response),
63 });
64 }
65 };
66 let result = complete(&mut journal, &request, &admitted).await;
67 Ok((response, result))
68}
69
70#[derive(Debug, Error)]
72pub enum IcSnapshotTransferReadExecutionError<E: std::error::Error + 'static> {
73 #[error(transparent)]
75 Plan(#[from] OperationPlanError),
76 #[error(transparent)]
78 Stage(#[from] ExecutionWorkflowPersistenceError),
79 #[error(transparent)]
81 Journal(#[from] AttemptJournalError),
82 #[error(transparent)]
84 Progress(#[from] ExecutionProgressPersistenceError),
85 #[error(transparent)]
87 Request(#[from] IcSnapshotTransferReadError),
88 #[error("fresh snapshot read admission failed: {0}")]
90 Admission(#[source] E),
91 #[error(transparent)]
93 Provider(#[from] IcObservationProviderError),
94 #[error("snapshot transfer read reply rejected: {source}")]
96 AfterReply {
97 source: IcSnapshotTransferReadReplyError,
99 response: Box<IcSnapshotTransferReadResponse>,
101 },
102}
103
104#[derive(Debug, Error)]
106pub enum IcSnapshotTransferReadReplyError {
107 #[error(transparent)]
109 Journal(#[from] AttemptJournalError),
110 #[error(transparent)]
112 Association(#[from] IcSnapshotTransferReadAssociationError),
113 #[error(transparent)]
115 Stage(#[from] ExecutionWorkflowPersistenceError),
116}
117
118#[cfg(all(test, unix))]
119mod tests;