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 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 (response, ()) = read_snapshot_with(
57 stage,
58 operation_sequence,
59 payload,
60 provider,
61 admit,
62 async |_, _, _| (),
63 )
64 .await?;
65 Ok(response)
66}
67
68pub(super) async fn read_snapshot_with<E: std::error::Error + 'static, T>(
72 stage: &ExecutionStageGuard<'_>,
73 operation_sequence: u64,
74 payload: IcSnapshotTransferReadPayload<'_, '_>,
75 provider: &mut impl IcSnapshotTransferReadProvider,
76 admit: impl AsyncFnOnce(&IcSnapshotTransferReadRequest<'_, '_>) -> Result<(), E>,
77 complete: impl AsyncFnOnce(
78 &mut AttemptJournalGuard<'_>,
79 &IcSnapshotTransferReadRequest<'_, '_>,
80 &IcSnapshotTransferReadView<'_, '_>,
81 ) -> T,
82) -> Result<(IcSnapshotTransferReadResponse, T), IcSnapshotTransferReadExecutionError<E>> {
83 let plan = stage.plan();
84 let authority = plan.attempt_authority(operation_sequence)?;
85 payload.validate_binding(&authority)?;
86 let mut journal = AttemptJournalGuard::open(stage.layout()?, &authority)?;
87 journal.reserve_planned_mutation(&plan.digest())?;
88 let request =
89 IcSnapshotTransferReadRequest::new(plan, operation_sequence, journal.record()?, payload)?;
90 let response = super::reserved_effect::submit_once(
91 &journal,
92 &request,
93 async |request| {
94 admit(request)
95 .await
96 .map_err(IcSnapshotTransferReadExecutionError::Admission)
97 },
98 || {
99 stage
100 .layout()
101 .map(|_| ())
102 .map_err(IcSnapshotTransferReadExecutionError::Stage)
103 },
104 async |request, record| {
105 provider
106 .read_snapshot(request, record)
107 .await
108 .map_err(IcSnapshotTransferReadExecutionError::Provider)
109 },
110 IcSnapshotTransferReadExecutionError::Journal,
111 )
112 .await?;
113 let admitted = match super::reserved_effect::check_returned(
114 stage,
115 &journal,
116 &request,
117 &response,
118 validate_response,
119 ) {
120 Ok((_, admitted)) => admitted,
121 Err(error) => {
122 return Err(match error {
123 super::reserved_effect::ReturnedError::Journal(source) => {
124 IcSnapshotTransferReadExecutionError::AfterReplyJournal {
125 source,
126 response: Box::new(response),
127 }
128 }
129 super::reserved_effect::ReturnedError::Association(source) => {
130 IcSnapshotTransferReadExecutionError::Association {
131 source,
132 response: Box::new(response),
133 }
134 }
135 super::reserved_effect::ReturnedError::Stage(source) => {
136 IcSnapshotTransferReadExecutionError::AfterReplyStage {
137 source,
138 response: Box::new(response),
139 }
140 }
141 });
142 }
143 };
144 let result = complete(&mut journal, &request, &admitted).await;
145 Ok((response, result))
146}
147
148#[derive(Debug, Error)]
150pub enum IcSnapshotTransferReadExecutionError<E: std::error::Error + 'static> {
151 #[error(transparent)]
153 Plan(#[from] OperationPlanError),
154 #[error(transparent)]
156 Stage(#[from] ExecutionWorkflowPersistenceError),
157 #[error(transparent)]
159 Journal(#[from] AttemptJournalError),
160 #[error(transparent)]
162 Progress(#[from] ExecutionProgressPersistenceError),
163 #[error(transparent)]
165 Request(#[from] IcSnapshotTransferReadError),
166 #[error("fresh snapshot read admission failed: {0}")]
168 Admission(#[source] E),
169 #[error(transparent)]
171 Provider(#[from] IcObservationProviderError),
172 #[error("snapshot read response association failed: {source}")]
174 Association {
175 source: IcSnapshotTransferReadAssociationError,
177 response: Box<IcSnapshotTransferReadResponse>,
179 },
180 #[error("snapshot read journal changed after reply: {source}")]
182 AfterReplyJournal {
183 source: AttemptJournalError,
185 response: Box<IcSnapshotTransferReadResponse>,
187 },
188 #[error("snapshot read stage changed after reply: {source}")]
190 AfterReplyStage {
191 source: ExecutionWorkflowPersistenceError,
193 response: Box<IcSnapshotTransferReadResponse>,
195 },
196}
197
198#[cfg(all(test, unix))]
199mod tests;