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, validate_response,
17 },
18 ports::{
19 ic_observation::IcObservationProviderError,
20 ic_snapshot_transfer_read::IcSnapshotTransferReadProvider,
21 },
22};
23use thiserror::Error;
24
25pub async fn read_snapshot<E: std::error::Error + 'static>(
50 stage: &ExecutionStageGuard<'_>,
51 operation_sequence: u64,
52 payload: IcSnapshotTransferReadPayload<'_, '_>,
53 provider: &mut impl IcSnapshotTransferReadProvider,
54 admit: impl AsyncFnOnce(&IcSnapshotTransferReadRequest<'_, '_>) -> Result<(), E>,
55) -> Result<IcSnapshotTransferReadResponse, IcSnapshotTransferReadExecutionError<E>> {
56 let plan = stage.plan();
57 let authority = plan.attempt_authority(operation_sequence)?;
58 payload.validate_binding(&authority)?;
59 let mut journal = AttemptJournalGuard::open(stage.layout()?, &authority)?;
60 journal.reserve_planned_mutation(&plan.digest())?;
61 let request =
62 IcSnapshotTransferReadRequest::new(plan, operation_sequence, journal.record()?, payload)?;
63 let response = super::reserved_effect::submit_once(
64 &journal,
65 &request,
66 async |request| {
67 admit(request)
68 .await
69 .map_err(IcSnapshotTransferReadExecutionError::Admission)
70 },
71 || {
72 stage
73 .layout()
74 .map(|_| ())
75 .map_err(IcSnapshotTransferReadExecutionError::Stage)
76 },
77 async |request, record| {
78 provider
79 .read_snapshot(request, record)
80 .await
81 .map_err(IcSnapshotTransferReadExecutionError::Provider)
82 },
83 IcSnapshotTransferReadExecutionError::Journal,
84 )
85 .await?;
86 if let Err(error) = super::reserved_effect::check_returned(
87 stage,
88 &journal,
89 &request,
90 &response,
91 |request, record, reply| validate_response(request, record, reply).map(|_| ()),
92 ) {
93 return Err(match error {
94 super::reserved_effect::ReturnedError::Journal(source) => {
95 IcSnapshotTransferReadExecutionError::AfterReplyJournal {
96 source,
97 response: Box::new(response),
98 }
99 }
100 super::reserved_effect::ReturnedError::Association(source) => {
101 IcSnapshotTransferReadExecutionError::Association {
102 source,
103 response: Box::new(response),
104 }
105 }
106 super::reserved_effect::ReturnedError::Stage(source) => {
107 IcSnapshotTransferReadExecutionError::AfterReplyStage {
108 source,
109 response: Box::new(response),
110 }
111 }
112 });
113 }
114 Ok(response)
115}
116
117#[derive(Debug, Error)]
119pub enum IcSnapshotTransferReadExecutionError<E: std::error::Error + 'static> {
120 #[error(transparent)]
122 Plan(#[from] OperationPlanError),
123 #[error(transparent)]
125 Stage(#[from] ExecutionWorkflowPersistenceError),
126 #[error(transparent)]
128 Journal(#[from] AttemptJournalError),
129 #[error(transparent)]
131 Progress(#[from] ExecutionProgressPersistenceError),
132 #[error(transparent)]
134 Request(#[from] IcSnapshotTransferReadError),
135 #[error("fresh snapshot read admission failed: {0}")]
137 Admission(#[source] E),
138 #[error(transparent)]
140 Provider(#[from] IcObservationProviderError),
141 #[error("snapshot read response association failed: {source}")]
143 Association {
144 source: IcSnapshotTransferReadAssociationError,
146 response: Box<IcSnapshotTransferReadResponse>,
148 },
149 #[error("snapshot read journal changed after reply: {source}")]
151 AfterReplyJournal {
152 source: AttemptJournalError,
154 response: Box<IcSnapshotTransferReadResponse>,
156 },
157 #[error("snapshot read stage changed after reply: {source}")]
159 AfterReplyStage {
160 source: ExecutionWorkflowPersistenceError,
162 response: Box<IcSnapshotTransferReadResponse>,
164 },
165}
166
167#[cfg(all(test, unix))]
168mod tests;