1use std::sync::atomic::{AtomicU64, Ordering};
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41#[doc(hidden)]
42pub enum FilteredReadTable {
43 Edge,
45 Node,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51#[doc(hidden)]
52pub enum FilteredReadStrategy {
53 DenseRowSelection,
55 RowGroupPredicate,
57 FullFallback,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63#[doc(hidden)]
64pub struct FilteredReadPruning {
65 pub strategy: FilteredReadStrategy,
67 pub row_groups_considered: u64,
69 pub row_groups_selected: u64,
71 pub pages_considered: u64,
73 pub pages_selected: u64,
75 pub exact_rows_selected: u64,
77 pub metadata_fallbacks: u64,
79 pub validation_fallbacks: u64,
81}
82
83#[doc(hidden)]
89pub trait FilteredReadObserver: Send + Sync {
90 fn read_started(&self, table: FilteredReadTable);
92
93 fn rows_scanned(&self, table: FilteredReadTable, rows: u64);
95
96 fn read_completed(&self, table: FilteredReadTable, rows: u64, full: bool);
99
100 fn read_failed(&self, table: FilteredReadTable);
102
103 fn pruning(&self, _table: FilteredReadTable, _pruning: FilteredReadPruning) {}
105}
106
107static EDGE_FULL_READS: AtomicU64 = AtomicU64::new(0);
108static EDGE_FULL_ROWS: AtomicU64 = AtomicU64::new(0);
109static EDGE_FILTERED_READS: AtomicU64 = AtomicU64::new(0);
110static EDGE_FILTERED_ROWS: AtomicU64 = AtomicU64::new(0);
111static NODE_FULL_READS: AtomicU64 = AtomicU64::new(0);
112static NODE_FULL_ROWS: AtomicU64 = AtomicU64::new(0);
113static NODE_FILTERED_READS: AtomicU64 = AtomicU64::new(0);
114static NODE_FILTERED_ROWS: AtomicU64 = AtomicU64::new(0);
115static EDGE_SCANNED_ROWS: AtomicU64 = AtomicU64::new(0);
116static NODE_SCANNED_ROWS: AtomicU64 = AtomicU64::new(0);
117static NODE_DENSE_ROW_SELECTION_READS: AtomicU64 = AtomicU64::new(0);
118static NODE_ROW_GROUP_PREDICATE_READS: AtomicU64 = AtomicU64::new(0);
119static NODE_ROW_GROUPS_CONSIDERED: AtomicU64 = AtomicU64::new(0);
120static NODE_ROW_GROUPS_SELECTED: AtomicU64 = AtomicU64::new(0);
121static NODE_PAGES_CONSIDERED: AtomicU64 = AtomicU64::new(0);
122static NODE_PAGES_SELECTED: AtomicU64 = AtomicU64::new(0);
123static NODE_EXACT_ROWS_SELECTED: AtomicU64 = AtomicU64::new(0);
124static NODE_METADATA_FALLBACKS: AtomicU64 = AtomicU64::new(0);
125static NODE_VALIDATION_FALLBACKS: AtomicU64 = AtomicU64::new(0);
126static REWRITE_COMMITS: AtomicU64 = AtomicU64::new(0);
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
131pub struct IoSnapshot {
132 pub edge_full_reads: u64,
134 pub edge_full_rows: u64,
136 pub edge_filtered_reads: u64,
138 pub edge_filtered_rows: u64,
140 pub node_full_reads: u64,
142 pub node_full_rows: u64,
144 pub node_filtered_reads: u64,
147 pub node_filtered_rows: u64,
149 pub edge_scanned_rows: u64,
154 pub node_scanned_rows: u64,
156 pub node_dense_row_selection_reads: u64,
158 pub node_row_group_predicate_reads: u64,
160 pub node_row_groups_considered: u64,
162 pub node_row_groups_selected: u64,
164 pub node_pages_considered: u64,
166 pub node_pages_selected: u64,
168 pub node_exact_rows_selected: u64,
170 pub node_metadata_fallbacks: u64,
172 pub node_validation_fallbacks: u64,
174 pub rewrite_commits: u64,
177}
178
179#[must_use]
181pub fn snapshot() -> IoSnapshot {
182 IoSnapshot {
183 edge_full_reads: EDGE_FULL_READS.load(Ordering::Relaxed),
184 edge_full_rows: EDGE_FULL_ROWS.load(Ordering::Relaxed),
185 edge_filtered_reads: EDGE_FILTERED_READS.load(Ordering::Relaxed),
186 edge_filtered_rows: EDGE_FILTERED_ROWS.load(Ordering::Relaxed),
187 node_full_reads: NODE_FULL_READS.load(Ordering::Relaxed),
188 node_full_rows: NODE_FULL_ROWS.load(Ordering::Relaxed),
189 node_filtered_reads: NODE_FILTERED_READS.load(Ordering::Relaxed),
190 node_filtered_rows: NODE_FILTERED_ROWS.load(Ordering::Relaxed),
191 edge_scanned_rows: EDGE_SCANNED_ROWS.load(Ordering::Relaxed),
192 node_scanned_rows: NODE_SCANNED_ROWS.load(Ordering::Relaxed),
193 node_dense_row_selection_reads: NODE_DENSE_ROW_SELECTION_READS.load(Ordering::Relaxed),
194 node_row_group_predicate_reads: NODE_ROW_GROUP_PREDICATE_READS.load(Ordering::Relaxed),
195 node_row_groups_considered: NODE_ROW_GROUPS_CONSIDERED.load(Ordering::Relaxed),
196 node_row_groups_selected: NODE_ROW_GROUPS_SELECTED.load(Ordering::Relaxed),
197 node_pages_considered: NODE_PAGES_CONSIDERED.load(Ordering::Relaxed),
198 node_pages_selected: NODE_PAGES_SELECTED.load(Ordering::Relaxed),
199 node_exact_rows_selected: NODE_EXACT_ROWS_SELECTED.load(Ordering::Relaxed),
200 node_metadata_fallbacks: NODE_METADATA_FALLBACKS.load(Ordering::Relaxed),
201 node_validation_fallbacks: NODE_VALIDATION_FALLBACKS.load(Ordering::Relaxed),
202 rewrite_commits: REWRITE_COMMITS.load(Ordering::Relaxed),
203 }
204}
205
206pub fn reset() {
208 for c in [
209 &EDGE_FULL_READS,
210 &EDGE_FULL_ROWS,
211 &EDGE_FILTERED_READS,
212 &EDGE_FILTERED_ROWS,
213 &NODE_FULL_READS,
214 &NODE_FULL_ROWS,
215 &NODE_FILTERED_READS,
216 &NODE_FILTERED_ROWS,
217 &EDGE_SCANNED_ROWS,
218 &NODE_SCANNED_ROWS,
219 &NODE_DENSE_ROW_SELECTION_READS,
220 &NODE_ROW_GROUP_PREDICATE_READS,
221 &NODE_ROW_GROUPS_CONSIDERED,
222 &NODE_ROW_GROUPS_SELECTED,
223 &NODE_PAGES_CONSIDERED,
224 &NODE_PAGES_SELECTED,
225 &NODE_EXACT_ROWS_SELECTED,
226 &NODE_METADATA_FALLBACKS,
227 &NODE_VALIDATION_FALLBACKS,
228 &REWRITE_COMMITS,
229 ] {
230 c.store(0, Ordering::Relaxed);
231 }
232}
233
234pub(crate) fn record_edge_full_read(rows: u64) {
235 EDGE_FULL_READS.fetch_add(1, Ordering::Relaxed);
236 EDGE_FULL_ROWS.fetch_add(rows, Ordering::Relaxed);
237}
238
239pub(crate) fn record_edge_filtered_read(rows: u64) {
240 EDGE_FILTERED_READS.fetch_add(1, Ordering::Relaxed);
241 EDGE_FILTERED_ROWS.fetch_add(rows, Ordering::Relaxed);
242}
243
244pub(crate) fn record_node_full_read(rows: u64) {
245 NODE_FULL_READS.fetch_add(1, Ordering::Relaxed);
246 NODE_FULL_ROWS.fetch_add(rows, Ordering::Relaxed);
247}
248
249pub(crate) fn record_node_filtered_read(rows: u64) {
250 NODE_FILTERED_READS.fetch_add(1, Ordering::Relaxed);
251 NODE_FILTERED_ROWS.fetch_add(rows, Ordering::Relaxed);
252}
253
254pub(crate) fn record_edge_scanned(rows: u64) {
255 EDGE_SCANNED_ROWS.fetch_add(rows, Ordering::Relaxed);
256}
257
258pub(crate) fn record_node_scanned(rows: u64) {
259 NODE_SCANNED_ROWS.fetch_add(rows, Ordering::Relaxed);
260}
261
262pub(crate) fn record_node_pruning(pruning: FilteredReadPruning) {
263 match pruning.strategy {
264 FilteredReadStrategy::DenseRowSelection => {
265 NODE_DENSE_ROW_SELECTION_READS.fetch_add(1, Ordering::Relaxed);
266 }
267 FilteredReadStrategy::RowGroupPredicate => {
268 NODE_ROW_GROUP_PREDICATE_READS.fetch_add(1, Ordering::Relaxed);
269 }
270 FilteredReadStrategy::FullFallback => {}
271 }
272 NODE_ROW_GROUPS_CONSIDERED.fetch_add(pruning.row_groups_considered, Ordering::Relaxed);
273 NODE_ROW_GROUPS_SELECTED.fetch_add(pruning.row_groups_selected, Ordering::Relaxed);
274 NODE_PAGES_CONSIDERED.fetch_add(pruning.pages_considered, Ordering::Relaxed);
275 NODE_PAGES_SELECTED.fetch_add(pruning.pages_selected, Ordering::Relaxed);
276 NODE_EXACT_ROWS_SELECTED.fetch_add(pruning.exact_rows_selected, Ordering::Relaxed);
277 NODE_METADATA_FALLBACKS.fetch_add(pruning.metadata_fallbacks, Ordering::Relaxed);
278 NODE_VALIDATION_FALLBACKS.fetch_add(pruning.validation_fallbacks, Ordering::Relaxed);
279}
280
281pub(crate) fn record_rewrite_commit() {
282 REWRITE_COMMITS.fetch_add(1, Ordering::Relaxed);
283}