query_runtime/observability/
metrics_summary.rs1use std::time::Duration;
12
13use crate::metrics::{QueryMetrics, SourceReadRuntimeMetrics};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum SourceReadFact {
23 ChunkPlanned { row_groups: u64 },
25 ChunkAttempted,
27 ChunkCommitted { chunk_count: u64, row_groups: u64 },
29 ChunkRetried,
31 PrefetchStarted,
33 PrefetchCompleted,
35 PrefetchSkipped,
37 PrefetchAbandoned,
39 QueueWait(Duration),
41 InputBatch { rows: u64 },
43 ParquetSource { files: u64, known_bytes: u64, selected_row_groups: u64, read_columns: u64 },
47 MetadataLoadTime(Duration),
49 ParquetReadTime(Duration),
51 SourceReadTime(Duration),
53}
54
55#[derive(Debug, Clone, Default, PartialEq, Eq)]
57pub struct SourceReadTotals {
58 pub(crate) input_batches: u64,
59 pub(crate) input_rows: u64,
60 pub parquet_files: u64,
62 pub parquet_bytes_known: u64,
64 pub row_groups_selected: u64,
66 pub(crate) read_columns: u64,
67 pub(crate) source_chunks_planned: u64,
68 pub(crate) source_chunks_attempted: u64,
69 pub(crate) source_chunks_committed: u64,
70 pub(crate) source_chunks_retried: u64,
71 pub(crate) row_groups_planned: u64,
72 pub(crate) row_groups_committed: u64,
73 pub(crate) source_read_prefetches_started: u64,
74 pub(crate) source_read_prefetches_completed: u64,
75 pub(crate) source_read_prefetches_skipped: u64,
76 pub(crate) source_read_prefetches_abandoned: u64,
77 pub(crate) source_metadata_load_time: Duration,
78 pub source_read_queue_wait_time: Duration,
80 pub(crate) parquet_read_time: Duration,
81 pub(crate) source_read_time: Duration,
82}
83
84impl SourceReadTotals {
85 pub(crate) fn apply(&mut self, fact: &SourceReadFact) -> bool {
88 match fact {
89 SourceReadFact::ChunkPlanned { row_groups } => {
90 add_u64(&mut self.source_chunks_planned, 1) & add_u64(&mut self.row_groups_planned, *row_groups)
91 },
92 SourceReadFact::ChunkAttempted => add_u64(&mut self.source_chunks_attempted, 1),
93 SourceReadFact::ChunkCommitted { chunk_count, row_groups } => {
94 add_u64(&mut self.source_chunks_committed, *chunk_count)
95 & add_u64(&mut self.row_groups_committed, *row_groups)
96 },
97 SourceReadFact::ChunkRetried => add_u64(&mut self.source_chunks_retried, 1),
98 SourceReadFact::PrefetchStarted => add_u64(&mut self.source_read_prefetches_started, 1),
99 SourceReadFact::PrefetchCompleted => add_u64(&mut self.source_read_prefetches_completed, 1),
100 SourceReadFact::PrefetchSkipped => add_u64(&mut self.source_read_prefetches_skipped, 1),
101 SourceReadFact::PrefetchAbandoned => add_u64(&mut self.source_read_prefetches_abandoned, 1),
102 SourceReadFact::InputBatch { rows } => {
103 add_u64(&mut self.input_batches, 1) & add_u64(&mut self.input_rows, *rows)
104 },
105 SourceReadFact::ParquetSource { files, known_bytes, selected_row_groups, read_columns } => {
106 add_u64(&mut self.parquet_files, *files)
107 & add_u64(&mut self.parquet_bytes_known, *known_bytes)
108 & add_u64(&mut self.row_groups_selected, *selected_row_groups)
109 & add_u64(&mut self.read_columns, *read_columns)
110 },
111 SourceReadFact::QueueWait(elapsed) => add_duration(&mut self.source_read_queue_wait_time, *elapsed),
112 SourceReadFact::MetadataLoadTime(elapsed) => add_duration(&mut self.source_metadata_load_time, *elapsed),
113 SourceReadFact::ParquetReadTime(elapsed) => add_duration(&mut self.parquet_read_time, *elapsed),
114 SourceReadFact::SourceReadTime(elapsed) => add_duration(&mut self.source_read_time, *elapsed),
115 }
116 }
117}
118
119fn add_u64(counter: &mut u64, value: u64) -> bool {
122 match counter.checked_add(value) {
123 Some(next) => {
124 *counter = next;
125 true
126 },
127 None => {
128 *counter = u64::MAX;
129 false
130 },
131 }
132}
133
134fn add_duration(total: &mut Duration, value: Duration) -> bool {
135 match total.checked_add(value) {
136 Some(next) => {
137 *total = next;
138 true
139 },
140 None => {
141 *total = Duration::MAX;
142 false
143 },
144 }
145}
146
147#[derive(Debug, Clone, Default, PartialEq, Eq)]
149pub struct QueryMetricsSummary {
150 pub source_read: SourceReadTotals,
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub(crate) enum MetricsCaptureMode {
161 Disabled,
163 Bounded,
165}
166
167impl MetricsCaptureMode {
168 pub const fn as_str(self) -> &'static str {
170 match self {
171 Self::Disabled => "disabled",
172 Self::Bounded => "bounded",
173 }
174 }
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq)]
179pub struct MetricsCompleteness {
180 pub(crate) capture_mode: MetricsCaptureMode,
181 pub(crate) detail_rows_dropped: u64,
183 pub truncated: bool,
185 pub(crate) totals_saturated: bool,
187}
188
189impl MetricsCompleteness {
190 #[cfg(test)]
192 pub(crate) const fn detail_is_complete(&self) -> bool {
193 matches!(self.capture_mode, MetricsCaptureMode::Bounded) && !self.truncated
194 }
195
196 pub(crate) const fn detail_status(&self) -> &'static str {
199 match (self.capture_mode, self.truncated) {
200 (MetricsCaptureMode::Disabled, _) => "not_captured",
201 (MetricsCaptureMode::Bounded, true) => "incomplete",
202 (MetricsCaptureMode::Bounded, false) => "complete",
203 }
204 }
205}
206
207#[derive(Debug, Clone, PartialEq, Eq)]
214pub struct QueryMetricsCheckpoint {
215 pub(crate) revision: u64,
216 pub(crate) sealed: bool,
218 pub summary: QueryMetricsSummary,
220 pub source_read_rows: Vec<SourceReadRuntimeMetrics>,
222 pub(crate) metrics: QueryMetrics,
225 pub(crate) completeness: MetricsCompleteness,
226}
227
228#[cfg(test)]
229mod tests;