use super::DownloadJournalGuard;
pub use ic_metrics::{MeasurementHistogram, MeasurementSummary};
use std::{
sync::PoisonError,
time::{Duration, Instant},
};
const EMPTY_CHUNK_HISTOGRAM: MeasurementHistogram<4> =
match MeasurementHistogram::new([0, 32 * 1024, 256 * 1024, 1024 * 1024]) {
Ok(histogram) => histogram,
Err(_) => panic!("prepared chunk bounds must be strictly increasing"),
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct IcSnapshotLocalMetrics {
verification_success_ns: MeasurementSummary,
verification_failure_ns: MeasurementSummary,
upload_metadata_success_ns: MeasurementSummary,
upload_metadata_failure_ns: MeasurementSummary,
upload_data_success_ns: MeasurementSummary,
upload_data_failure_ns: MeasurementSummary,
prepared_chunk_bytes: MeasurementHistogram<4>,
}
impl Default for IcSnapshotLocalMetrics {
fn default() -> Self {
Self {
verification_success_ns: MeasurementSummary::EMPTY,
verification_failure_ns: MeasurementSummary::EMPTY,
upload_metadata_success_ns: MeasurementSummary::EMPTY,
upload_metadata_failure_ns: MeasurementSummary::EMPTY,
upload_data_success_ns: MeasurementSummary::EMPTY,
upload_data_failure_ns: MeasurementSummary::EMPTY,
prepared_chunk_bytes: EMPTY_CHUNK_HISTOGRAM,
}
}
}
impl IcSnapshotLocalMetrics {
#[must_use]
pub const fn verification_success_ns(self) -> MeasurementSummary {
self.verification_success_ns
}
#[must_use]
pub const fn verification_failure_ns(self) -> MeasurementSummary {
self.verification_failure_ns
}
#[must_use]
pub const fn upload_metadata_success_ns(self) -> MeasurementSummary {
self.upload_metadata_success_ns
}
#[must_use]
pub const fn upload_metadata_failure_ns(self) -> MeasurementSummary {
self.upload_metadata_failure_ns
}
#[must_use]
pub const fn upload_data_success_ns(self) -> MeasurementSummary {
self.upload_data_success_ns
}
#[must_use]
pub const fn upload_data_failure_ns(self) -> MeasurementSummary {
self.upload_data_failure_ns
}
#[must_use]
pub const fn prepared_chunk_bytes(self) -> MeasurementSummary {
self.prepared_chunk_bytes.summary()
}
#[must_use]
pub const fn prepared_chunk_bytes_histogram(self) -> MeasurementHistogram<4> {
self.prepared_chunk_bytes
}
fn record(
&mut self,
operation: LocalOperation,
elapsed: Duration,
succeeded: bool,
chunk_bytes: Option<usize>,
) {
let duration = u64::try_from(elapsed.as_nanos()).unwrap_or(u64::MAX);
let summary = match (operation, succeeded) {
(LocalOperation::Verification, true) => &mut self.verification_success_ns,
(LocalOperation::Verification, false) => &mut self.verification_failure_ns,
(LocalOperation::UploadMetadata, true) => &mut self.upload_metadata_success_ns,
(LocalOperation::UploadMetadata, false) => &mut self.upload_metadata_failure_ns,
(LocalOperation::UploadData, true) => &mut self.upload_data_success_ns,
(LocalOperation::UploadData, false) => &mut self.upload_data_failure_ns,
};
summary.record(duration);
if let (LocalOperation::UploadData, true, Some(bytes)) = (operation, succeeded, chunk_bytes)
{
self.prepared_chunk_bytes
.record(u64::try_from(bytes).unwrap_or(u64::MAX));
}
}
}
#[derive(Clone, Copy)]
pub(super) enum LocalOperation {
Verification,
UploadMetadata,
UploadData,
}
impl DownloadJournalGuard<'_> {
#[must_use]
pub fn ic_snapshot_metrics(&self) -> IcSnapshotLocalMetrics {
*self
.ic_snapshot_metrics
.lock()
.unwrap_or_else(PoisonError::into_inner)
}
pub(super) fn record_ic_snapshot_metrics(
&self,
operation: LocalOperation,
started: Instant,
succeeded: bool,
chunk_bytes: Option<usize>,
) {
let elapsed = started.elapsed();
self.ic_snapshot_metrics
.lock()
.unwrap_or_else(PoisonError::into_inner)
.record(operation, elapsed, succeeded, chunk_bytes);
}
}
#[cfg(test)]
mod tests;