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 attempt_journal;
5mod command_lifetime_lock;
6mod consistency;
7mod download_journal;
8mod effect_graph;
9mod execution_settlement;
10mod fence_obligation;
11mod file_lock;
12mod inventory;
13mod journal_lock;
14mod json;
15mod layout_lifetime;
16mod operation_plan;
17mod restore_safety;
18
19pub use artifact_commit::{ArtifactCommitOutcome, commit_artifact_directory};
20pub use attempt_journal::{AttemptJournalError, AttemptJournalGuard};
21pub use command_lifetime_lock::{
22    COMMAND_CUSTODY_DESCRIPTOR_ENV, CommandLifetimeLock, CommandLifetimeLockError,
23    CommandQuiescenceGuard,
24};
25pub use consistency::{
26    ConsistencyPersistenceError, create_consistency_requirement, read_consistency_requirement,
27};
28pub use download_journal::{
29    DownloadIntegrityError, DownloadJournalError, DownloadJournalGuard, DownloadManifestError,
30    LocalRestoreArtifactError, LocalRestoreArtifactPublicationError, LocalRestoreArtifactView,
31    LocalRestoreSourceError, read_download_manifest,
32};
33pub use effect_graph::{EffectGraphPersistenceError, create_effect_graph, read_effect_graph};
34pub use execution_settlement::{
35    ExecutionSettlementPersistenceError, create_execution_settlement, read_execution_settlement,
36};
37pub use fence_obligation::{
38    FenceObligationPersistenceError, FenceObligationRequirement, create_fence_obligation,
39    read_fence_obligation,
40};
41pub use inventory::{InventoryError, create_inventory, read_inventory};
42pub use journal_lock::{JournalLock, JournalLockError};
43pub use json::{create_json_durable, read_json, write_json_durable};
44pub use layout_lifetime::{BackupLayoutGuard, MAX_RESTORE_REFERENCE_BYTES};
45pub use operation_plan::{
46    OperationPlanPersistenceError, create_operation_plan, read_operation_plan,
47};
48pub use restore_safety::{
49    RestoreSafetyPersistenceError, create_restore_safety_requirement,
50    read_restore_safety_requirement,
51};
52
53use crate::{model::artifacts::ChecksumError, ops::artifacts::ArtifactError};
54use std::io;
55use thiserror::Error;
56
57/// Typed local persistence failure.
58#[derive(Debug, Error)]
59pub enum PersistenceError {
60    /// An existing layout path no longer denotes the held directory.
61    #[error("backup layout changed while held: {path:?}")]
62    LayoutChanged {
63        /// Resolved layout location.
64        path: std::path::PathBuf,
65    },
66    /// A retained dependency document or journal location has an unsafe entry type.
67    #[error("unsafe restore reference entry: {path:?}")]
68    InvalidRestoreReferences {
69        /// Rejected local path.
70        path: std::path::PathBuf,
71    },
72    /// Restore dependency validation or an immutable retention transition failed.
73    #[error(transparent)]
74    RestoreReference(#[from] crate::model::restore_references::RestoreReferenceError),
75    /// Filesystem IO failed; publication may require local reconciliation.
76    #[error(transparent)]
77    Io(#[from] io::Error),
78    /// JSON encoding or decoding failed.
79    #[error(transparent)]
80    Json(#[from] serde_json::Error),
81    /// A machine record exceeds its caller-selected byte bound.
82    #[error("record exceeds byte limit {limit}")]
83    RecordTooLarge {
84        /// Maximum accepted bytes.
85        limit: u64,
86    },
87    /// Artifact traversal or streaming failed.
88    #[error(transparent)]
89    Artifact(#[from] ArtifactError),
90    /// Verified bytes do not match the expected checksum.
91    #[error(transparent)]
92    Checksum(#[from] ChecksumError),
93    /// Publication requires distinct siblings in one directory.
94    #[error("artifact commit paths must be distinct siblings: {temporary}, {canonical}")]
95    ArtifactCommitPathMismatch {
96        /// Retained staging path.
97        temporary: String,
98        /// Canonical destination.
99        canonical: String,
100    },
101    /// Both staging and canonical trees exist; neither is overwritten.
102    #[error("artifact commit has conflicting paths: {temporary}, {canonical}")]
103    ArtifactCommitPathConflict {
104        /// Retained staging path.
105        temporary: String,
106        /// Existing canonical destination.
107        canonical: String,
108    },
109    /// Neither expected tree exists.
110    #[error("artifact commit is missing both paths: {temporary}, {canonical}")]
111    ArtifactCommitPathMissing {
112        /// Missing staging path.
113        temporary: String,
114        /// Missing canonical destination.
115        canonical: String,
116    },
117    /// Atomic no-replace directory publication is unsupported.
118    #[error("durable artifact publication is unsupported on {platform}")]
119    ArtifactCommitUnsupportedPlatform {
120        /// Host platform name.
121        platform: &'static str,
122    },
123    /// Publication found an unsafe tree entry.
124    #[error("unsupported artifact entry at {path}: {kind}")]
125    UnsupportedArtifactEntry {
126        /// Entry path.
127        path: String,
128        /// Observed entry kind.
129        kind: String,
130    },
131}