Skip to main content

mz_repr/
optimize.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Facilities for defining optimizer feature flags.
11
12use std::collections::BTreeMap;
13
14#[cfg(any(test, feature = "proptest"))]
15use proptest_derive::Arbitrary;
16use serde::{Deserialize, Serialize};
17
18/// A macro for feature flags managed by the optimizer.
19macro_rules! optimizer_feature_flags {
20    ({ $($feature:ident: $type:ty,)* }) => {
21        #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
22        #[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
23        pub struct OptimizerFeatures {
24            $(pub $feature: $type),*
25        }
26
27        #[derive(Clone, Debug, Deserialize, Serialize, PartialOrd, PartialEq, Eq, Ord)]
28        pub struct OptimizerFeatureOverrides {
29            $(pub $feature: Option<$type>),*
30        }
31
32        impl Default for OptimizerFeatureOverrides {
33            fn default() -> Self {
34                Self {
35                    $($feature: None),*
36                }
37            }
38        }
39
40        /// An [`OverrideFrom`] implementation that updates
41        /// [`OptimizerFeatures`] using [`OptimizerFeatureOverrides`] values.
42        impl OverrideFrom<OptimizerFeatureOverrides> for OptimizerFeatures {
43            fn override_from(mut self, overrides: &OptimizerFeatureOverrides) -> Self {
44                $(if let Some(feature_value) = overrides.$feature {
45                    self.$feature = feature_value;
46                })*
47                self
48            }
49        }
50
51        /// An `OptimizerFeatureOverrides ⇒ BTreeMap<String, String>`
52        /// conversion.
53        ///
54        /// WARNING: changing the definition of item might break catalog
55        /// re-hydration for some catalog items (such as entries for `CREATE
56        /// CLUSTER ... FEATURES(...)` statements).
57        impl From<BTreeMap<String, String>> for OptimizerFeatureOverrides {
58            fn from(value: BTreeMap<String, String>) -> Self {
59                let mut overrides = OptimizerFeatureOverrides::default();
60
61                for (name, value) in value.into_iter() {
62                    match name.as_str() {
63                        $(stringify!($feature) => {
64                            let value = Some(<$type>::decode(&value));
65                            overrides.$feature = value;
66                        }),*
67                        _ => (), // Ignore
68                    }
69                }
70
71                overrides
72            }
73        }
74
75        /// A `BTreeMap<String, String> ⇒ OptimizerFeatureOverrides` conversion.
76        ///
77        /// WARNING: changing the definition of item might break catalog
78        /// re-hydration for some catalog items (such as entries for `CREATE
79        /// CLUSTER ... FEATURES(...)` statements).
80        impl From<OptimizerFeatureOverrides> for BTreeMap<String, String> {
81            fn from(overrides: OptimizerFeatureOverrides) -> Self {
82                let mut map = BTreeMap::<String, String>::default();
83
84                $(if let Some(value) = overrides.$feature {
85                    let k = stringify!($feature).into();
86                    let v = value.encode();
87                    map.insert(k, v);
88                };)*
89
90                map
91            }
92        }
93    };
94}
95
96optimizer_feature_flags!({
97    // Use `EquivalenceClassesWithholdingErrors` instead of raw
98    // `EquivalenceClasses` during eq prop for joins.
99    enable_eq_classes_withholding_errors: bool,
100    // Bound from `SystemVars::enable_eager_delta_joins`.
101    enable_eager_delta_joins: bool,
102    // Enable Lattice-based fixpoint iteration on LetRec nodes in the
103    // Analysis framework.
104    enable_letrec_fixpoint_analysis: bool,
105    // Bound from `SystemVars::enable_new_outer_join_lowering`.
106    enable_new_outer_join_lowering: bool,
107    // Bound from `SystemVars::enable_reduce_mfp_fusion`.
108    enable_reduce_mfp_fusion: bool,
109    // Enable joint HIR ⇒ MIR lowering of stacks of left joins.
110    enable_variadic_left_join_lowering: bool,
111    // Enable cardinality estimation
112    enable_cardinality_estimates: bool,
113    // An exclusive upper bound on the number of results we may return from a
114    // Persist fast-path peek. Required by the `create_fast_path_plan` call in
115    // `peek::Optimizer`.
116    persist_fast_path_limit: usize,
117    // Reoptimize imported views when building and optimizing a
118    // `DataflowDescription` in the global MIR optimization phase.
119    reoptimize_imported_views: bool,
120    // See the feature flag of the same name.
121    enable_join_prioritize_arranged: bool,
122    // See the feature flag of the same name.
123    enable_projection_pushdown_after_relation_cse: bool,
124    // See the feature flag of the same name.
125    enable_union_cancellation_after_relation_cse: bool,
126    // See the feature flag of the same name.
127    enable_less_reduce_in_eqprop: bool,
128    // See the feature flag of the same name.
129    enable_dequadratic_eqprop_map: bool,
130    // See the feature flag of the same name.
131    enable_fast_path_plan_insights: bool,
132    // See the feature flag of the same name.
133    enable_cast_elimination: bool,
134    // See the feature flag of the same name.
135    enable_case_literal_transform: bool,
136    // See the feature flag of the same name.
137    enable_simplify_quantified_comparisons: bool,
138    // See the feature flag of the same name.
139    enable_simplify_from_less_existence: bool,
140    // See the feature flag of the same name.
141    enable_coalesce_case_transform: bool,
142    // See the feature flag of the same name.
143    enable_will_distinct_propagation: bool,
144    // See the feature flag of the same name.
145    enable_fixed_correlated_cte_lowering: bool,
146});
147
148/// A trait used to implement layered config construction.
149pub trait OverrideFrom<T> {
150    /// Override the configuration represented by [`Self`] with values
151    /// from the given `layer`.
152    fn override_from(self, layer: &T) -> Self;
153}
154
155/// Overrides for `U` coming from an optional `T`.
156impl<T, U> OverrideFrom<Option<&T>> for U
157where
158    Self: OverrideFrom<T>,
159{
160    fn override_from(self, layer: &Option<&T>) -> Self {
161        match layer {
162            Some(layer) => self.override_from(layer),
163            None => self,
164        }
165    }
166}
167
168/// A trait that handles conversion of feature flags.
169trait OptimizerFeatureType {
170    fn encode(self) -> String;
171    fn decode(v: &str) -> Self;
172}
173
174/// A macro that implements [`OptimizerFeatureType`] for most common types.
175///
176/// WARNING: changing the definition of this macro might break catalog
177/// re-hydration for some catalog items (such as entries for `CREATE CLUSTER ...
178/// FEATURES(...)` statements).
179macro_rules! impl_optimizer_feature_type {
180    ($($type:ty),*) => {
181        $(
182            impl OptimizerFeatureType for $type {
183                fn encode(self) -> String {
184                    self.to_string()
185                }
186
187                fn decode(v: &str) -> Self {
188                    str::parse(&v).unwrap()
189                }
190            }
191        )*
192    };
193}
194
195// Implement `OptimizerFeatureType` for all types used in the
196// `optimizer_feature_flags!(...)`  call above.
197impl_optimizer_feature_type![usize];
198
199impl OptimizerFeatureType for bool {
200    fn encode(self) -> String {
201        self.to_string()
202    }
203
204    fn decode(v: &str) -> Self {
205        // Accept both the Rust spelling (`true`/`false`, what `encode` and
206        // `CREATE CLUSTER ... FEATURES` produce) and the canonical system-var /
207        // PostgreSQL spellings (`on`/`off`, ...). A cluster-coherent scoped
208        // override may arrive as the var's canonical `on`/`off`.
209        match v.trim().to_lowercase().as_str() {
210            "t" | "true" | "on" | "1" | "y" | "yes" => true,
211            "f" | "false" | "off" | "0" | "n" | "no" => false,
212            // The writer only stores values that passed `canonicalize`, so this
213            // arm is unreachable in practice. Log rather than panic anyway: a
214            // stored bad value reaching the plan path would otherwise crash the
215            // optimizer on every query for the affected cluster. Fall back to
216            // `false`.
217            other => {
218                mz_ore::soft_panic_or_log!("invalid boolean optimizer feature override: {other:?}");
219                false
220            }
221        }
222    }
223}
224
225#[cfg(test)]
226mod tests {
227    use std::collections::BTreeMap;
228
229    use super::OptimizerFeatureOverrides;
230
231    #[mz_ore::test]
232    fn bool_override_decodes_lenient_spellings() {
233        for (stored, want) in [
234            ("true", true),
235            ("false", false),
236            ("on", true),
237            ("off", false),
238        ] {
239            let map =
240                BTreeMap::from([("enable_eager_delta_joins".to_string(), stored.to_string())]);
241            assert_eq!(
242                OptimizerFeatureOverrides::from(map).enable_eager_delta_joins,
243                Some(want),
244            );
245        }
246    }
247}