icydb_core/db/diagnostics/
execution_trace.rs1use crate::db::{
7 access::{AccessPath, AccessPlan},
8 direction::Direction,
9 query::plan::OrderDirection,
10};
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub enum ExecutionAccessPathVariant {
20 ByKey,
21 ByKeys,
22 KeyRange,
23 IndexPrefix,
24 IndexRange,
25 FullScan,
26 Union,
27 Intersection,
28}
29
30#[derive(Clone, Copy, Debug, Eq, PartialEq)]
37pub enum ExecutionOptimization {
38 PrimaryKey,
39 SecondaryOrderPushdown,
40 IndexRangeLimitPushdown,
41}
42
43#[derive(Clone, Copy, Debug, Eq, PartialEq)]
51pub struct ExecutionTrace {
52 pub access_path_variant: ExecutionAccessPathVariant,
53 pub direction: OrderDirection,
54 pub optimization: Option<ExecutionOptimization>,
55 pub keys_scanned: u64,
56 pub rows_returned: u64,
57 pub continuation_applied: bool,
58 pub index_predicate_applied: bool,
59 pub index_predicate_keys_rejected: u64,
60 pub distinct_keys_deduped: u64,
61}
62
63impl ExecutionTrace {
64 #[must_use]
66 pub(in crate::db) fn new<K>(
67 access: &AccessPlan<K>,
68 direction: Direction,
69 continuation_applied: bool,
70 ) -> Self {
71 Self {
72 access_path_variant: access_path_variant(access),
73 direction: execution_order_direction(direction),
74 optimization: None,
75 keys_scanned: 0,
76 rows_returned: 0,
77 continuation_applied,
78 index_predicate_applied: false,
79 index_predicate_keys_rejected: 0,
80 distinct_keys_deduped: 0,
81 }
82 }
83
84 pub(in crate::db) fn set_path_outcome(
86 &mut self,
87 optimization: Option<ExecutionOptimization>,
88 keys_scanned: usize,
89 rows_returned: usize,
90 index_predicate_applied: bool,
91 index_predicate_keys_rejected: u64,
92 distinct_keys_deduped: u64,
93 ) {
94 self.optimization = optimization;
95 self.keys_scanned = u64::try_from(keys_scanned).unwrap_or(u64::MAX);
96 self.rows_returned = u64::try_from(rows_returned).unwrap_or(u64::MAX);
97 self.index_predicate_applied = index_predicate_applied;
98 self.index_predicate_keys_rejected = index_predicate_keys_rejected;
99 self.distinct_keys_deduped = distinct_keys_deduped;
100 debug_assert_eq!(
101 self.keys_scanned,
102 u64::try_from(keys_scanned).unwrap_or(u64::MAX),
103 "execution trace keys_scanned must match rows_scanned metrics input",
104 );
105 }
106}
107
108fn access_path_variant<K>(access: &AccessPlan<K>) -> ExecutionAccessPathVariant {
109 match access {
110 AccessPlan::Path(path) => match path.as_ref() {
111 AccessPath::ByKey(_) => ExecutionAccessPathVariant::ByKey,
112 AccessPath::ByKeys(_) => ExecutionAccessPathVariant::ByKeys,
113 AccessPath::KeyRange { .. } => ExecutionAccessPathVariant::KeyRange,
114 AccessPath::IndexPrefix { .. } => ExecutionAccessPathVariant::IndexPrefix,
115 AccessPath::IndexRange { .. } => ExecutionAccessPathVariant::IndexRange,
116 AccessPath::FullScan => ExecutionAccessPathVariant::FullScan,
117 },
118 AccessPlan::Union(_) => ExecutionAccessPathVariant::Union,
119 AccessPlan::Intersection(_) => ExecutionAccessPathVariant::Intersection,
120 }
121}
122
123const fn execution_order_direction(direction: Direction) -> OrderDirection {
124 match direction {
125 Direction::Asc => OrderDirection::Asc,
126 Direction::Desc => OrderDirection::Desc,
127 }
128}