use std::time::Duration;
use crate::metrics::{QueryMetrics, SourceReadRuntimeMetrics};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SourceReadFact {
ChunkPlanned { row_groups: u64 },
ChunkAttempted,
ChunkCommitted { chunk_count: u64, row_groups: u64 },
ChunkRetried,
PrefetchStarted,
PrefetchCompleted,
PrefetchSkipped,
PrefetchAbandoned,
QueueWait(Duration),
InputBatch { rows: u64 },
ParquetSource { files: u64, known_bytes: u64, selected_row_groups: u64, read_columns: u64 },
MetadataLoadTime(Duration),
ParquetReadTime(Duration),
SourceReadTime(Duration),
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct SourceReadTotals {
pub(crate) input_batches: u64,
pub(crate) input_rows: u64,
pub parquet_files: u64,
pub parquet_bytes_known: u64,
pub row_groups_selected: u64,
pub(crate) read_columns: u64,
pub(crate) source_chunks_planned: u64,
pub(crate) source_chunks_attempted: u64,
pub(crate) source_chunks_committed: u64,
pub(crate) source_chunks_retried: u64,
pub(crate) row_groups_planned: u64,
pub(crate) row_groups_committed: u64,
pub(crate) source_read_prefetches_started: u64,
pub(crate) source_read_prefetches_completed: u64,
pub(crate) source_read_prefetches_skipped: u64,
pub(crate) source_read_prefetches_abandoned: u64,
pub(crate) source_metadata_load_time: Duration,
pub source_read_queue_wait_time: Duration,
pub(crate) parquet_read_time: Duration,
pub(crate) source_read_time: Duration,
}
impl SourceReadTotals {
pub(crate) fn apply(&mut self, fact: &SourceReadFact) -> bool {
match fact {
SourceReadFact::ChunkPlanned { row_groups } => {
add_u64(&mut self.source_chunks_planned, 1) & add_u64(&mut self.row_groups_planned, *row_groups)
},
SourceReadFact::ChunkAttempted => add_u64(&mut self.source_chunks_attempted, 1),
SourceReadFact::ChunkCommitted { chunk_count, row_groups } => {
add_u64(&mut self.source_chunks_committed, *chunk_count)
& add_u64(&mut self.row_groups_committed, *row_groups)
},
SourceReadFact::ChunkRetried => add_u64(&mut self.source_chunks_retried, 1),
SourceReadFact::PrefetchStarted => add_u64(&mut self.source_read_prefetches_started, 1),
SourceReadFact::PrefetchCompleted => add_u64(&mut self.source_read_prefetches_completed, 1),
SourceReadFact::PrefetchSkipped => add_u64(&mut self.source_read_prefetches_skipped, 1),
SourceReadFact::PrefetchAbandoned => add_u64(&mut self.source_read_prefetches_abandoned, 1),
SourceReadFact::InputBatch { rows } => {
add_u64(&mut self.input_batches, 1) & add_u64(&mut self.input_rows, *rows)
},
SourceReadFact::ParquetSource { files, known_bytes, selected_row_groups, read_columns } => {
add_u64(&mut self.parquet_files, *files)
& add_u64(&mut self.parquet_bytes_known, *known_bytes)
& add_u64(&mut self.row_groups_selected, *selected_row_groups)
& add_u64(&mut self.read_columns, *read_columns)
},
SourceReadFact::QueueWait(elapsed) => add_duration(&mut self.source_read_queue_wait_time, *elapsed),
SourceReadFact::MetadataLoadTime(elapsed) => add_duration(&mut self.source_metadata_load_time, *elapsed),
SourceReadFact::ParquetReadTime(elapsed) => add_duration(&mut self.parquet_read_time, *elapsed),
SourceReadFact::SourceReadTime(elapsed) => add_duration(&mut self.source_read_time, *elapsed),
}
}
}
fn add_u64(counter: &mut u64, value: u64) -> bool {
match counter.checked_add(value) {
Some(next) => {
*counter = next;
true
},
None => {
*counter = u64::MAX;
false
},
}
}
fn add_duration(total: &mut Duration, value: Duration) -> bool {
match total.checked_add(value) {
Some(next) => {
*total = next;
true
},
None => {
*total = Duration::MAX;
false
},
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct QueryMetricsSummary {
pub source_read: SourceReadTotals,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum MetricsCaptureMode {
Disabled,
Bounded,
}
impl MetricsCaptureMode {
pub const fn as_str(self) -> &'static str {
match self {
Self::Disabled => "disabled",
Self::Bounded => "bounded",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MetricsCompleteness {
pub(crate) capture_mode: MetricsCaptureMode,
pub(crate) detail_rows_dropped: u64,
pub truncated: bool,
pub(crate) totals_saturated: bool,
}
impl MetricsCompleteness {
#[cfg(test)]
pub(crate) const fn detail_is_complete(&self) -> bool {
matches!(self.capture_mode, MetricsCaptureMode::Bounded) && !self.truncated
}
pub(crate) const fn detail_status(&self) -> &'static str {
match (self.capture_mode, self.truncated) {
(MetricsCaptureMode::Disabled, _) => "not_captured",
(MetricsCaptureMode::Bounded, true) => "incomplete",
(MetricsCaptureMode::Bounded, false) => "complete",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QueryMetricsCheckpoint {
pub(crate) revision: u64,
pub(crate) sealed: bool,
pub summary: QueryMetricsSummary,
pub source_read_rows: Vec<SourceReadRuntimeMetrics>,
pub(crate) metrics: QueryMetrics,
pub(crate) completeness: MetricsCompleteness,
}
#[cfg(test)]
mod tests;