ic_backup/ops/persistence/fence_obligation/
mod.rs1use super::{
4 BackupLayoutGuard, ConsistencyPersistenceError, JournalLockError, PersistenceError,
5 RestoreSafetyPersistenceError, immutable_record, read_consistency_requirement,
6 read_restore_safety_requirement,
7};
8use crate::model::{
9 artifacts::ArtifactChecksumRecord,
10 consistency::{ApplicationFenceBinding, ConsistencyRequirementRecord},
11 fence_obligation::{FenceObligationError, FenceObligationRecord, MAX_FENCE_OBLIGATION_BYTES},
12 operation_plan::OperationPlanRecord,
13 restore_safety::RestoreSafetyRequirementRecord,
14};
15use thiserror::Error;
16
17#[derive(Clone, Copy, Debug)]
21pub enum FenceObligationRequirement<'a> {
22 Capture {
24 requirement: &'a ConsistencyRequirementRecord,
26 fence: &'a ApplicationFenceBinding,
28 },
29 Restore {
31 source_layout: &'a BackupLayoutGuard,
33 source: &'a OperationPlanRecord,
35 requirement: &'a RestoreSafetyRequirementRecord,
37 },
38}
39impl FenceObligationRequirement<'_> {
40 fn validate(
41 self,
42 layout: &BackupLayoutGuard,
43 plan: &OperationPlanRecord,
44 record: &FenceObligationRecord,
45 ) -> Result<(), FenceObligationPersistenceError> {
46 match self {
47 Self::Capture { requirement, fence } => {
48 record.validate_capture(plan, requirement, fence)?;
49 read_consistency_requirement(layout, plan, &requirement.digest())?;
50 }
51 Self::Restore {
52 source_layout,
53 source,
54 requirement,
55 } => {
56 record.validate_restore(plan, source, requirement)?;
57 read_restore_safety_requirement(
58 layout,
59 source_layout,
60 plan,
61 source,
62 &requirement.digest(),
63 )?;
64 }
65 }
66 Ok(())
67 }
68}
69pub fn create_fence_obligation(
77 layout: &BackupLayoutGuard,
78 plan: &OperationPlanRecord,
79 requirement: FenceObligationRequirement<'_>,
80 record: &FenceObligationRecord,
81) -> Result<(), FenceObligationPersistenceError> {
82 requirement.validate(layout, plan, record)?;
83 immutable_record::create(
84 layout,
85 "fence-obligation.json",
86 MAX_FENCE_OBLIGATION_BYTES,
87 record,
88 )
89}
90pub fn read_fence_obligation(
98 layout: &BackupLayoutGuard,
99 plan: &OperationPlanRecord,
100 requirement: FenceObligationRequirement<'_>,
101 expected: &ArtifactChecksumRecord,
102) -> Result<FenceObligationRecord, FenceObligationPersistenceError> {
103 super::read_operation_plan(layout, &plan.digest())?;
105 immutable_record::read_with(
106 layout,
107 "fence-obligation.json",
108 MAX_FENCE_OBLIGATION_BYTES,
109 |record: &FenceObligationRecord| {
110 requirement.validate(layout, plan, record)?;
111 if &record.digest() != expected {
112 return Err(FenceObligationPersistenceError::DigestMismatch);
113 }
114 Ok(())
115 },
116 )
117}
118#[derive(Debug, Error)]
120pub enum FenceObligationPersistenceError {
121 #[error("fence obligation digest mismatch")]
123 DigestMismatch,
124 #[error(transparent)]
126 Obligation(#[from] FenceObligationError),
127 #[error(transparent)]
129 Plan(#[from] super::OperationPlanPersistenceError),
130 #[error(transparent)]
132 Consistency(#[from] ConsistencyPersistenceError),
133 #[error(transparent)]
135 Restore(#[from] RestoreSafetyPersistenceError),
136 #[error(transparent)]
138 Lock(#[from] JournalLockError),
139 #[error(transparent)]
141 Persistence(#[from] PersistenceError),
142}
143
144#[cfg(all(test, unix))]
145mod tests;