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