Skip to main content

ic_backup/ops/persistence/effect_graph/
mod.rs

1//! Immutable bounded graph publication and exact original local graph admission.
2
3use super::json::check_json_size;
4use super::{
5    BackupLayoutGuard, JournalLock, JournalLockError, PersistenceError, create_json_durable,
6    read_json,
7};
8use crate::model::{
9    artifacts::ArtifactChecksumRecord,
10    effect_graph::{EffectGraphRecord, MAX_EFFECT_GRAPH_BYTES},
11};
12use thiserror::Error;
13
14/// Durably create `effect-graph.json` under layout exclusion without replacing evidence.
15///
16/// # Errors
17/// Rejects excessive canonical bytes, existing/unsafe entries, replaced roots and IO/locks.
18pub fn create_effect_graph(
19    layout: &BackupLayoutGuard,
20    record: &EffectGraphRecord,
21) -> Result<(), EffectGraphPersistenceError> {
22    layout.check_root()?;
23    let path = layout.root().join("effect-graph.json");
24    let _lock = JournalLock::acquire(&path)?;
25    check_json_size(record, MAX_EFFECT_GRAPH_BYTES)?;
26    create_json_durable(&path, record)?;
27    Ok(())
28}
29
30/// Admit retained bounded graph under its original exact expected digest, using local IO only.
31///
32/// Lost creation replies reconcile by reading the exact graph. This neither checks
33/// remote completion nor grants effects, fresh authority or plan acceptance.
34///
35/// # Errors
36/// Rejects unsafe/missing/oversized/invalid graphs, digest mismatch, replaced roots and locks.
37pub fn read_effect_graph(
38    layout: &BackupLayoutGuard,
39    expected: &ArtifactChecksumRecord,
40) -> Result<EffectGraphRecord, EffectGraphPersistenceError> {
41    layout.check_root()?;
42    let path = layout.root().join("effect-graph.json");
43    let _lock = JournalLock::acquire(&path)?;
44    let record: EffectGraphRecord = read_json(&path, MAX_EFFECT_GRAPH_BYTES)?;
45    check_json_size(&record, MAX_EFFECT_GRAPH_BYTES)?;
46    if &record.digest() != expected {
47        return Err(EffectGraphPersistenceError::DigestMismatch);
48    }
49    Ok(record)
50}
51
52/// Typed declared graph identity or immutable local persistence rejection.
53#[derive(Debug, Error)]
54pub enum EffectGraphPersistenceError {
55    /// Retained graph differs from the original exact declared digest.
56    #[error("effect graph digest mismatch")]
57    DigestMismatch,
58    /// Cooperating layout/journal ownership failed.
59    #[error(transparent)]
60    Lock(#[from] JournalLockError),
61    /// Bounded JSON, graph admission or durable filesystem access failed.
62    #[error(transparent)]
63    Persistence(#[from] PersistenceError),
64}
65
66#[cfg(all(test, unix))]
67mod tests;