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, MeasurementHistogram, 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    /// Parent preparation, record reads or other local filesystem IO failed.
81    /// Shared JSON publication failures retain their separate structured boundary.
82    #[error(transparent)]
83    Io(#[from] io::Error),
84    /// Shared file publication failed, retaining producer/cleanup causes and visibility.
85    /// An after-publication failure leaves output visible and requires reconciliation.
86    #[error(transparent)]
87    Publication(#[from] ic_host_fs::durable::NamedWriteError<io::Error>),
88    /// JSON encoding or decoding failed.
89    #[error(transparent)]
90    Json(#[from] serde_json::Error),
91    /// A machine record exceeds its caller-selected byte bound.
92    #[error("record exceeds byte limit {limit}")]
93    RecordTooLarge {
94        /// Maximum accepted bytes.
95        limit: u64,
96    },
97    /// Artifact traversal or streaming failed.
98    #[error(transparent)]
99    Artifact(#[from] ArtifactError),
100    /// Verified bytes do not match the expected checksum.
101    #[error(transparent)]
102    Checksum(#[from] ChecksumError),
103    /// Publication requires distinct siblings in one directory.
104    #[error("artifact commit paths must be distinct siblings: {temporary}, {canonical}")]
105    ArtifactCommitPathMismatch {
106        /// Retained staging path.
107        temporary: String,
108        /// Canonical destination.
109        canonical: String,
110    },
111    /// Both staging and canonical trees exist; neither is overwritten.
112    #[error("artifact commit has conflicting paths: {temporary}, {canonical}")]
113    ArtifactCommitPathConflict {
114        /// Retained staging path.
115        temporary: String,
116        /// Existing canonical destination.
117        canonical: String,
118    },
119    /// Neither expected tree exists.
120    #[error("artifact commit is missing both paths: {temporary}, {canonical}")]
121    ArtifactCommitPathMissing {
122        /// Missing staging path.
123        temporary: String,
124        /// Missing canonical destination.
125        canonical: String,
126    },
127    /// Atomic no-replace directory publication is unsupported.
128    #[error("durable artifact publication is unsupported on {platform}")]
129    ArtifactCommitUnsupportedPlatform {
130        /// Host platform name.
131        platform: &'static str,
132    },
133    /// Publication found an unsafe tree entry.
134    #[error("unsupported artifact entry at {path}: {kind}")]
135    UnsupportedArtifactEntry {
136        /// Entry path.
137        path: String,
138        /// Observed entry kind.
139        kind: String,
140    },
141}