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