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_less_reduce_in_eqprop: bool,
126    // See the feature flag of the same name.
127    enable_dequadratic_eqprop_map: bool,
128    // See the feature flag of the same name.
129    enable_fast_path_plan_insights: bool,
130    // See the feature flag of the same name.
131    enable_cast_elimination: bool,
132    // See the feature flag of the same name.
133    enable_case_literal_transform: bool,
134    // See the feature flag of the same name.
135    enable_simplify_quantified_comparisons: bool,
136    // See the feature flag of the same name.
137    enable_coalesce_case_transform: bool,
138    // See the feature flag of the same name.
139    enable_will_distinct_propagation: bool,
140});
141
142/// A trait used to implement layered config construction.
143pub trait OverrideFrom<T> {
144    /// Override the configuration represented by [`Self`] with values
145    /// from the given `layer`.
146    fn override_from(self, layer: &T) -> Self;
147}
148
149/// Overrides for `U` coming from an optional `T`.
150impl<T, U> OverrideFrom<Option<&T>> for U
151where
152    Self: OverrideFrom<T>,
153{
154    fn override_from(self, layer: &Option<&T>) -> Self {
155        match layer {
156            Some(layer) => self.override_from(layer),
157            None => self,
158        }
159    }
160}
161
162/// A trait that handles conversion of feature flags.
163trait OptimizerFeatureType {
164    fn encode(self) -> String;
165    fn decode(v: &str) -> Self;
166}
167
168/// A macro that implements [`OptimizerFeatureType`] for most common types.
169///
170/// WARNING: changing the definition of this macro might break catalog
171/// re-hydration for some catalog items (such as entries for `CREATE CLUSTER ...
172/// FEATURES(...)` statements).
173macro_rules! impl_optimizer_feature_type {
174    ($($type:ty),*) => {
175        $(
176            impl OptimizerFeatureType for $type {
177                fn encode(self) -> String {
178                    self.to_string()
179                }
180
181                fn decode(v: &str) -> Self {
182                    str::parse(&v).unwrap()
183                }
184            }
185        )*
186    };
187}
188
189// Implement `OptimizerFeatureType` for all types used in the
190// `optimizer_feature_flags!(...)`  call above.
191impl_optimizer_feature_type![usize];
192
193impl OptimizerFeatureType for bool {
194    fn encode(self) -> String {
195        self.to_string()
196    }
197
198    fn decode(v: &str) -> Self {
199        // Accept both the Rust spelling (`true`/`false`, what `encode` and
200        // `CREATE CLUSTER ... FEATURES` produce) and the canonical system-var /
201        // PostgreSQL spellings (`on`/`off`, ...). A cluster-coherent scoped
202        // override may arrive as the var's canonical `on`/`off`.
203        match v.trim().to_lowercase().as_str() {
204            "t" | "true" | "on" | "1" | "y" | "yes" => true,
205            "f" | "false" | "off" | "0" | "n" | "no" => false,
206            // The writer only stores values that passed `canonicalize`, so this
207            // arm is unreachable in practice. Log rather than panic anyway: a
208            // stored bad value reaching the plan path would otherwise crash the
209            // optimizer on every query for the affected cluster. Fall back to
210            // `false`.
211            other => {
212                mz_ore::soft_panic_or_log!("invalid boolean optimizer feature override: {other:?}");
213                false
214            }
215        }
216    }
217}
218
219#[cfg(test)]
220mod tests {
221    use std::collections::BTreeMap;
222
223    use super::OptimizerFeatureOverrides;
224
225    #[mz_ore::test]
226    fn bool_override_decodes_lenient_spellings() {
227        for (stored, want) in [
228            ("true", true),
229            ("false", false),
230            ("on", true),
231            ("off", false),
232        ] {
233            let map =
234                BTreeMap::from([("enable_eager_delta_joins".to_string(), stored.to_string())]);
235            assert_eq!(
236                OptimizerFeatureOverrides::from(map).enable_eager_delta_joins,
237                Some(want),
238            );
239        }
240    }
241}