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