Skip to main content

canic_backup/restore/apply/journal/
counts.rs

1//! Module: restore::apply::journal::counts
2//!
3//! Responsibility: count restore apply operations by state and operation kind.
4//! Does not own: journal transitions, command rendering, or receipt validation.
5//! Boundary: validates reported journal counters against concrete operation rows.
6
7use super::{
8    RestoreApplyDryRunOperation, RestoreApplyJournalError, RestoreApplyJournalOperation,
9    RestoreApplyOperationKind, RestoreApplyOperationState, validate_apply_journal_count,
10};
11
12use serde::{Deserialize, Serialize};
13
14///
15/// RestoreApplyJournalStateCounts
16///
17/// Internal state counter projection for restore apply journal operations.
18/// Owned by restore apply journaling and used during journal validation.
19///
20
21#[derive(Clone, Debug, Default, Eq, PartialEq)]
22pub(super) struct RestoreApplyJournalStateCounts {
23    pub(super) pending: usize,
24    pub(super) ready: usize,
25    pub(super) blocked: usize,
26    pub(super) completed: usize,
27    pub(super) failed: usize,
28}
29
30impl RestoreApplyJournalStateCounts {
31    pub(super) fn from_operations(operations: &[RestoreApplyJournalOperation]) -> Self {
32        let mut counts = Self::default();
33        for operation in operations {
34            match operation.state {
35                RestoreApplyOperationState::Pending => counts.pending += 1,
36                RestoreApplyOperationState::Ready => counts.ready += 1,
37                RestoreApplyOperationState::Blocked => counts.blocked += 1,
38                RestoreApplyOperationState::Completed => counts.completed += 1,
39                RestoreApplyOperationState::Failed => counts.failed += 1,
40            }
41        }
42        counts
43    }
44}
45
46///
47/// RestoreApplyOperationKindCounts
48///
49/// Serializable operation-kind counter projection for restore apply journals.
50/// Owned by restore apply journaling and embedded in dry-run and journal outputs.
51///
52
53#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
54#[serde(deny_unknown_fields)]
55pub struct RestoreApplyOperationKindCounts {
56    #[serde(default)]
57    pub canister_stops: usize,
58    #[serde(default)]
59    pub canister_starts: usize,
60    pub snapshot_uploads: usize,
61    pub snapshot_loads: usize,
62    pub member_verifications: usize,
63    pub deployment_verifications: usize,
64    pub verification_operations: usize,
65}
66
67impl RestoreApplyOperationKindCounts {
68    /// Count restore apply journal operations by runner operation kind.
69    #[must_use]
70    pub fn from_operations(operations: &[RestoreApplyJournalOperation]) -> Self {
71        let mut counts = Self::default();
72        for operation in operations {
73            counts.record(&operation.operation);
74        }
75        counts
76    }
77
78    /// Validate this count object against concrete operations.
79    pub fn validate_matches(&self, expected: &Self) -> Result<(), RestoreApplyJournalError> {
80        validate_apply_journal_count(
81            "operation_counts.canister_stops",
82            self.canister_stops,
83            expected.canister_stops,
84        )?;
85        validate_apply_journal_count(
86            "operation_counts.canister_starts",
87            self.canister_starts,
88            expected.canister_starts,
89        )?;
90        validate_apply_journal_count(
91            "operation_counts.snapshot_uploads",
92            self.snapshot_uploads,
93            expected.snapshot_uploads,
94        )?;
95        validate_apply_journal_count(
96            "operation_counts.snapshot_loads",
97            self.snapshot_loads,
98            expected.snapshot_loads,
99        )?;
100        validate_apply_journal_count(
101            "operation_counts.member_verifications",
102            self.member_verifications,
103            expected.member_verifications,
104        )?;
105        validate_apply_journal_count(
106            "operation_counts.deployment_verifications",
107            self.deployment_verifications,
108            expected.deployment_verifications,
109        )?;
110        validate_apply_journal_count(
111            "operation_counts.verification_operations",
112            self.verification_operations,
113            expected.verification_operations,
114        )
115    }
116
117    /// Count restore apply dry-run operations by runner operation kind.
118    #[must_use]
119    pub fn from_dry_run_operations(operations: &[RestoreApplyDryRunOperation]) -> Self {
120        let mut counts = Self::default();
121        for operation in operations {
122            counts.record(&operation.operation);
123        }
124        counts
125    }
126
127    const fn record(&mut self, operation: &RestoreApplyOperationKind) {
128        match operation {
129            RestoreApplyOperationKind::StopCanister => self.canister_stops += 1,
130            RestoreApplyOperationKind::StartCanister => self.canister_starts += 1,
131            RestoreApplyOperationKind::UploadSnapshot => self.snapshot_uploads += 1,
132            RestoreApplyOperationKind::LoadSnapshot => self.snapshot_loads += 1,
133            RestoreApplyOperationKind::VerifyMember => {
134                self.member_verifications += 1;
135                self.verification_operations += 1;
136            }
137            RestoreApplyOperationKind::VerifyDeployment => {
138                self.deployment_verifications += 1;
139                self.verification_operations += 1;
140            }
141        }
142    }
143}