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)]
54pub struct RestoreApplyOperationKindCounts {
55    #[serde(default)]
56    pub canister_stops: usize,
57    #[serde(default)]
58    pub canister_starts: usize,
59    pub snapshot_uploads: usize,
60    pub snapshot_loads: usize,
61    pub member_verifications: usize,
62    pub deployment_verifications: usize,
63    pub verification_operations: usize,
64}
65
66impl RestoreApplyOperationKindCounts {
67    /// Count restore apply journal operations by runner operation kind.
68    #[must_use]
69    pub fn from_operations(operations: &[RestoreApplyJournalOperation]) -> Self {
70        let mut counts = Self::default();
71        for operation in operations {
72            counts.record(&operation.operation);
73        }
74        counts
75    }
76
77    /// Validate this count object against concrete operations.
78    pub fn validate_matches(&self, expected: &Self) -> Result<(), RestoreApplyJournalError> {
79        validate_apply_journal_count(
80            "operation_counts.canister_stops",
81            self.canister_stops,
82            expected.canister_stops,
83        )?;
84        validate_apply_journal_count(
85            "operation_counts.canister_starts",
86            self.canister_starts,
87            expected.canister_starts,
88        )?;
89        validate_apply_journal_count(
90            "operation_counts.snapshot_uploads",
91            self.snapshot_uploads,
92            expected.snapshot_uploads,
93        )?;
94        validate_apply_journal_count(
95            "operation_counts.snapshot_loads",
96            self.snapshot_loads,
97            expected.snapshot_loads,
98        )?;
99        validate_apply_journal_count(
100            "operation_counts.member_verifications",
101            self.member_verifications,
102            expected.member_verifications,
103        )?;
104        validate_apply_journal_count(
105            "operation_counts.deployment_verifications",
106            self.deployment_verifications,
107            expected.deployment_verifications,
108        )?;
109        validate_apply_journal_count(
110            "operation_counts.verification_operations",
111            self.verification_operations,
112            expected.verification_operations,
113        )
114    }
115
116    /// Count restore apply dry-run operations by runner operation kind.
117    #[must_use]
118    pub fn from_dry_run_operations(operations: &[RestoreApplyDryRunOperation]) -> Self {
119        let mut counts = Self::default();
120        for operation in operations {
121            counts.record(&operation.operation);
122        }
123        counts
124    }
125
126    const fn record(&mut self, operation: &RestoreApplyOperationKind) {
127        match operation {
128            RestoreApplyOperationKind::StopCanister => self.canister_stops += 1,
129            RestoreApplyOperationKind::StartCanister => self.canister_starts += 1,
130            RestoreApplyOperationKind::UploadSnapshot => self.snapshot_uploads += 1,
131            RestoreApplyOperationKind::LoadSnapshot => self.snapshot_loads += 1,
132            RestoreApplyOperationKind::VerifyMember => {
133                self.member_verifications += 1;
134                self.verification_operations += 1;
135            }
136            RestoreApplyOperationKind::VerifyDeployment => {
137                self.deployment_verifications += 1;
138                self.verification_operations += 1;
139            }
140        }
141    }
142}