Skip to main content

ic_backup/ops/persistence/
mod.rs

1//! Durable publication, journal/layout exclusion and retained local dependencies.
2
3mod artifact_commit;
4mod command_lifetime_lock;
5mod file_lock;
6mod journal_lock;
7mod json;
8mod layout_lifetime;
9
10pub use artifact_commit::{ArtifactCommitOutcome, commit_artifact_directory};
11pub use command_lifetime_lock::{
12    COMMAND_CUSTODY_DESCRIPTOR_ENV, CommandLifetimeLock, CommandLifetimeLockError,
13    CommandQuiescenceGuard,
14};
15pub use journal_lock::{JournalLock, JournalLockError};
16pub use json::{create_json_durable, read_json, write_json_durable};
17pub use layout_lifetime::{BackupLayoutGuard, MAX_RESTORE_REFERENCE_BYTES};
18
19use crate::{model::artifacts::ChecksumError, ops::artifacts::ArtifactError};
20use std::io;
21use thiserror::Error;
22
23/// Typed local persistence failure.
24#[derive(Debug, Error)]
25pub enum PersistenceError {
26    /// An existing layout path no longer denotes the held directory.
27    #[error("backup layout changed while held: {path:?}")]
28    LayoutChanged {
29        /// Resolved layout location.
30        path: std::path::PathBuf,
31    },
32    /// A retained dependency document or journal location has an unsafe entry type.
33    #[error("unsafe restore reference entry: {path:?}")]
34    InvalidRestoreReferences {
35        /// Rejected local path.
36        path: std::path::PathBuf,
37    },
38    /// Restore dependency validation or an immutable retention transition failed.
39    #[error(transparent)]
40    RestoreReference(#[from] crate::model::restore_references::RestoreReferenceError),
41    /// Filesystem IO failed; publication may require local reconciliation.
42    #[error(transparent)]
43    Io(#[from] io::Error),
44    /// JSON encoding or decoding failed.
45    #[error(transparent)]
46    Json(#[from] serde_json::Error),
47    /// A machine record exceeds its caller-selected byte bound.
48    #[error("record exceeds byte limit {limit}")]
49    RecordTooLarge {
50        /// Maximum accepted bytes.
51        limit: u64,
52    },
53    /// Artifact traversal or streaming failed.
54    #[error(transparent)]
55    Artifact(#[from] ArtifactError),
56    /// Verified bytes do not match the expected checksum.
57    #[error(transparent)]
58    Checksum(#[from] ChecksumError),
59    /// Publication requires distinct siblings in one directory.
60    #[error("artifact commit paths must be distinct siblings: {temporary}, {canonical}")]
61    ArtifactCommitPathMismatch {
62        /// Retained staging path.
63        temporary: String,
64        /// Canonical destination.
65        canonical: String,
66    },
67    /// Both staging and canonical trees exist; neither is overwritten.
68    #[error("artifact commit has conflicting paths: {temporary}, {canonical}")]
69    ArtifactCommitPathConflict {
70        /// Retained staging path.
71        temporary: String,
72        /// Existing canonical destination.
73        canonical: String,
74    },
75    /// Neither expected tree exists.
76    #[error("artifact commit is missing both paths: {temporary}, {canonical}")]
77    ArtifactCommitPathMissing {
78        /// Missing staging path.
79        temporary: String,
80        /// Missing canonical destination.
81        canonical: String,
82    },
83    /// Atomic no-replace directory publication is unsupported.
84    #[error("durable artifact publication is unsupported on {platform}")]
85    ArtifactCommitUnsupportedPlatform {
86        /// Host platform name.
87        platform: &'static str,
88    },
89    /// Publication found an unsafe tree entry.
90    #[error("unsupported artifact entry at {path}: {kind}")]
91    UnsupportedArtifactEntry {
92        /// Entry path.
93        path: String,
94        /// Observed entry kind.
95        kind: String,
96    },
97}