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