canic_backup/restore/persistence/
mod.rs1use super::{RestoreApplyJournal, RestoreApplyJournalError, RestorePlan, RestorePlanError};
8use crate::persistence::{PersistenceError, create_json_durable, read_json, write_json_durable};
9
10use std::{io, path::Path};
11
12use thiserror::Error as ThisError;
13
14#[derive(Debug, ThisError)]
22pub enum RestorePersistenceError {
23 #[error("restore apply journal conflicts with the existing recovery document: {path}")]
24 ApplyJournalConflict { path: String },
25
26 #[error(transparent)]
27 InvalidPlan(#[from] RestorePlanError),
28
29 #[error(transparent)]
30 InvalidJournal(#[from] RestoreApplyJournalError),
31
32 #[error(transparent)]
33 Persistence(#[from] PersistenceError),
34
35 #[error("restore plan conflicts with the existing recovery document: {path}")]
36 PlanConflict { path: String },
37}
38
39pub fn create_or_adopt_restore_plan(
41 path: &Path,
42 plan: &RestorePlan,
43) -> Result<(), RestorePersistenceError> {
44 plan.validate()?;
45 match read_json::<RestorePlan>(path) {
46 Ok(existing) => {
47 existing.validate()?;
48 if existing == *plan {
49 Ok(())
50 } else {
51 Err(RestorePersistenceError::PlanConflict {
52 path: path.display().to_string(),
53 })
54 }
55 }
56 Err(PersistenceError::Io(error)) if error.kind() == io::ErrorKind::NotFound => {
57 create_json_durable(path, plan).map_err(RestorePersistenceError::from)
58 }
59 Err(error) => Err(error.into()),
60 }
61}
62
63pub fn create_or_adopt_restore_apply_journal(
65 path: &Path,
66 journal: &RestoreApplyJournal,
67) -> Result<(), RestorePersistenceError> {
68 journal.validate()?;
69 match read_json::<RestoreApplyJournal>(path) {
70 Ok(existing) => {
71 existing.validate()?;
72 if existing == *journal {
73 Ok(())
74 } else {
75 Err(RestorePersistenceError::ApplyJournalConflict {
76 path: path.display().to_string(),
77 })
78 }
79 }
80 Err(PersistenceError::Io(error)) if error.kind() == io::ErrorKind::NotFound => {
81 create_json_durable(path, journal).map_err(RestorePersistenceError::from)
82 }
83 Err(error) => Err(error.into()),
84 }
85}
86
87pub fn write_restore_plan(path: &Path, plan: &RestorePlan) -> Result<(), RestorePersistenceError> {
89 plan.validate()?;
90 write_json_durable(path, plan)?;
91 Ok(())
92}
93
94pub fn write_restore_apply_journal(
96 path: &Path,
97 journal: &RestoreApplyJournal,
98) -> Result<(), RestorePersistenceError> {
99 journal.validate()?;
100 write_json_durable(path, journal)?;
101 Ok(())
102}