ic_backup/workflow/ic_snapshot_upload/
mod.rs1mod allocation;
4#[cfg(unix)]
5mod data;
6#[cfg(unix)]
7pub use data::{
8 IcSnapshotDataUploadExecutionError, IcSnapshotDataUploadReplyError, upload_snapshot_data,
9};
10
11pub use allocation::{
12 IcSnapshotAllocationExecutionError, IcSnapshotAllocationSettlementError, allocate_snapshot,
13};
14
15use crate::{
16 model::{
17 ic_mutation::IcMutationAcknowledgement,
18 ic_snapshot_upload::{
19 IcSnapshotUploadAttempt, IcSnapshotUploadAttemptError, IcSnapshotUploadRequest,
20 original_authority,
21 },
22 operation_plan::OperationPlanError,
23 },
24 ops::persistence::{
25 AttemptJournalError, AttemptJournalGuard, ExecutionProgressPersistenceError,
26 ExecutionStageGuard, ExecutionWorkflowPersistenceError,
27 },
28 policy::ic_snapshot_upload::{
29 IcSnapshotUploadAcknowledgementView, IcSnapshotUploadAssociationError,
30 validate_acknowledgement,
31 },
32 ports::{ic_mutation::IcMutationProviderError, ic_snapshot_upload::IcSnapshotUploadProvider},
33};
34use thiserror::Error;
35
36pub async fn upload_snapshot<E: std::error::Error + 'static>(
68 stage: &ExecutionStageGuard<'_>,
69 operation_sequence: u64,
70 payload: &IcSnapshotUploadRequest<'_>,
71 provider: &mut impl IcSnapshotUploadProvider,
72 admit: impl AsyncFnOnce(&IcSnapshotUploadAttempt<'_, '_>) -> Result<(), E>,
73) -> Result<IcMutationAcknowledgement, IcSnapshotUploadExecutionError<E>> {
74 let (acknowledgement, ()) = upload_snapshot_with(
75 stage,
76 operation_sequence,
77 payload,
78 provider,
79 admit,
80 async |_, _, _| (),
81 )
82 .await?;
83 Ok(acknowledgement)
84}
85
86async fn upload_snapshot_with<E: std::error::Error + 'static, T>(
89 stage: &ExecutionStageGuard<'_>,
90 operation_sequence: u64,
91 payload: &IcSnapshotUploadRequest<'_>,
92 provider: &mut impl IcSnapshotUploadProvider,
93 admit: impl AsyncFnOnce(&IcSnapshotUploadAttempt<'_, '_>) -> Result<(), E>,
94 complete: impl AsyncFnOnce(
95 &mut AttemptJournalGuard<'_>,
96 &IcSnapshotUploadAttempt<'_, '_>,
97 &IcSnapshotUploadAcknowledgementView<'_, '_>,
98 ) -> T,
99) -> Result<(IcMutationAcknowledgement, T), IcSnapshotUploadExecutionError<E>> {
100 let plan = stage.plan();
101 let authority = plan.attempt_authority(operation_sequence)?;
102 let mut journal = AttemptJournalGuard::open(stage.layout()?, &authority)?;
103 original_authority(plan, operation_sequence, journal.record()?, payload)?;
104 journal.reserve_planned_mutation(&plan.digest())?;
105 let request =
106 IcSnapshotUploadAttempt::new(plan, operation_sequence, journal.record()?, payload)?;
107 admit(&request)
108 .await
109 .map_err(IcSnapshotUploadExecutionError::Admission)?;
110 stage.layout()?;
111 let acknowledgement = provider.submit_upload(&request, journal.record()?).await?;
112 let record = match journal.record() {
113 Ok(record) => record,
114 Err(source) => {
115 return Err(IcSnapshotUploadExecutionError::AfterReplyJournal {
116 source,
117 acknowledgement: Box::new(acknowledgement),
118 });
119 }
120 };
121 let admitted = match validate_acknowledgement(&request, record, &acknowledgement) {
122 Ok(admitted) => admitted,
123 Err(source) => {
124 return Err(IcSnapshotUploadExecutionError::Association {
125 source,
126 acknowledgement: Box::new(acknowledgement),
127 });
128 }
129 };
130 if let Err(source) = stage.layout() {
131 return Err(IcSnapshotUploadExecutionError::AfterReplyStage {
132 source,
133 acknowledgement: Box::new(acknowledgement),
134 });
135 }
136 let result = complete(&mut journal, &request, &admitted).await;
137 Ok((acknowledgement, result))
138}
139
140#[derive(Debug, Error)]
142pub enum IcSnapshotUploadExecutionError<E: std::error::Error + 'static> {
143 #[error(transparent)]
145 Plan(#[from] OperationPlanError),
146 #[error(transparent)]
148 Stage(#[from] ExecutionWorkflowPersistenceError),
149 #[error(transparent)]
151 Journal(#[from] AttemptJournalError),
152 #[error(transparent)]
154 Progress(#[from] ExecutionProgressPersistenceError),
155 #[error(transparent)]
157 Request(#[from] IcSnapshotUploadAttemptError),
158 #[error("fresh snapshot upload admission failed: {0}")]
160 Admission(#[source] E),
161 #[error(transparent)]
163 Provider(#[from] IcMutationProviderError),
164 #[error("snapshot upload acknowledgement association failed: {source}")]
166 Association {
167 source: IcSnapshotUploadAssociationError,
169 acknowledgement: Box<IcMutationAcknowledgement>,
171 },
172 #[error("snapshot upload journal changed after reply: {source}")]
174 AfterReplyJournal {
175 source: AttemptJournalError,
177 acknowledgement: Box<IcMutationAcknowledgement>,
179 },
180 #[error("snapshot upload stage changed after reply: {source}")]
182 AfterReplyStage {
183 source: ExecutionWorkflowPersistenceError,
185 acknowledgement: Box<IcMutationAcknowledgement>,
187 },
188}
189
190#[cfg(all(test, unix))]
191mod tests;