canic_core/ops/orchestration/cascade/
mod.rs

1//! Cascade propagation.
2//!
3//! Pushes environment/topology/state changes from root to child canisters.
4//! This is orchestration logic (fanout), not storage and not placement strategy.
5
6pub mod state;
7pub mod topology;
8
9use crate::{Error, ThisError, log, log::Topic, ops::orchestration::OrchestrationOpsError};
10use candid::Principal;
11
12const SYNC_CALL_WARN_THRESHOLD: usize = 10;
13
14///
15/// CascadeOpsError
16/// Errors raised during synchronization
17///
18
19#[derive(Debug, ThisError)]
20pub enum CascadeOpsError {
21    #[error("canister not found")]
22    CanisterNotFound(Principal),
23
24    #[error("invalid parent chain: empty")]
25    InvalidParentChain,
26
27    #[error("parent chain does not start with self ({0})")]
28    ParentChainMissingSelf(Principal),
29
30    #[error("cycle detected in parent chain at {0}")]
31    ParentChainCycle(Principal),
32
33    #[error("parent chain length {0} exceeds registry size")]
34    ParentChainTooLong(usize),
35
36    #[error("parent chain did not terminate at root (stopped at {0})")]
37    ParentChainNotRootTerminated(Principal),
38
39    #[error("next hop {0} not found in parent chain")]
40    NextHopNotFound(Principal),
41}
42
43impl From<CascadeOpsError> for Error {
44    fn from(err: CascadeOpsError) -> Self {
45        OrchestrationOpsError::from(err).into()
46    }
47}
48
49///
50/// Helpers
51///
52
53fn warn_if_large(label: &str, count: usize) {
54    if count > SYNC_CALL_WARN_THRESHOLD {
55        log!(
56            Topic::Sync,
57            Warn,
58            "sync: large {}: {} entries",
59            label,
60            count
61        );
62    }
63}