canic_backup/journal/
report.rs1use crate::journal::{ArtifactState, DownloadJournal, DownloadOperationMetrics, ResumeAction};
8
9use serde::{Deserialize, Serialize};
10
11impl DownloadJournal {
12 #[must_use]
14 pub fn resume_report(&self) -> JournalResumeReport {
15 let mut counts = JournalStateCounts::default();
16 let mut artifacts = Vec::with_capacity(self.artifacts.len());
17
18 for artifact in &self.artifacts {
19 counts.record(artifact.state, artifact.resume_action());
20 artifacts.push(ArtifactResumeReport {
21 canister_id: artifact.canister_id.clone(),
22 snapshot_id: artifact.snapshot_id.clone(),
23 state: artifact.state,
24 resume_action: artifact.resume_action(),
25 artifact_path: artifact.artifact_path.clone(),
26 temp_path: artifact.temp_path.clone(),
27 updated_at: artifact.updated_at.clone(),
28 });
29 }
30
31 JournalResumeReport {
32 backup_id: self.backup_id.clone(),
33 discovery_topology_hash: self.discovery_topology_hash.clone(),
34 pre_snapshot_topology_hash: self.pre_snapshot_topology_hash.clone(),
35 total_artifacts: self.artifacts.len(),
36 is_complete: counts.skip == self.artifacts.len(),
37 pending_artifacts: self.artifacts.len() - counts.skip,
38 counts,
39 operation_metrics: self.operation_metrics.clone(),
40 artifacts,
41 }
42 }
43}
44
45#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
53#[serde(deny_unknown_fields)]
54pub struct JournalResumeReport {
55 pub backup_id: String,
56 pub discovery_topology_hash: Option<String>,
57 pub pre_snapshot_topology_hash: Option<String>,
58 pub total_artifacts: usize,
59 pub is_complete: bool,
60 pub pending_artifacts: usize,
61 pub counts: JournalStateCounts,
62 pub operation_metrics: DownloadOperationMetrics,
63 pub artifacts: Vec<ArtifactResumeReport>,
64}
65
66#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
74#[serde(deny_unknown_fields)]
75pub struct JournalStateCounts {
76 pub created: usize,
77 pub downloaded: usize,
78 pub checksum_verified: usize,
79 pub durable: usize,
80 pub download: usize,
81 pub verify_checksum: usize,
82 pub finalize: usize,
83 pub skip: usize,
84}
85
86impl JournalStateCounts {
87 const fn record(&mut self, state: ArtifactState, action: ResumeAction) {
88 match state {
89 ArtifactState::Created => self.created += 1,
90 ArtifactState::Downloaded => self.downloaded += 1,
91 ArtifactState::ChecksumVerified => self.checksum_verified += 1,
92 ArtifactState::Durable => self.durable += 1,
93 }
94
95 match action {
96 ResumeAction::Download => self.download += 1,
97 ResumeAction::VerifyChecksum => self.verify_checksum += 1,
98 ResumeAction::Finalize => self.finalize += 1,
99 ResumeAction::Skip => self.skip += 1,
100 }
101 }
102}
103
104#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
112#[serde(deny_unknown_fields)]
113pub struct ArtifactResumeReport {
114 pub canister_id: String,
115 pub snapshot_id: String,
116 pub state: ArtifactState,
117 pub resume_action: ResumeAction,
118 pub artifact_path: String,
119 pub temp_path: Option<String>,
120 pub updated_at: String,
121}