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