From b4e74e5b336d8ac3795b47a3a729c7dc20d3a748 Mon Sep 17 00:00:00 2001 From: Robert Brunel Date: Thu, 4 Jun 2026 19:16:29 +0100 Subject: [PATCH] Leverage rule indexing for `CollapseNullStrictValueOverNullValueRule` Remove `CollapseNullStrictValueOverNullValueRule` from the always-rules bucket of `DefaultValueSimplificationRuleSet` and instead create multiple instances of the rule, one instance per strictly null-propagating subclass `Value` subclass (such as `CastValue`, et cetera). To this end, introduce a `V` type parameter and build a `typedMatcherWithPredicate` directly for `V.class`. This reduces the overhead in trying to match this rule. --- ...lapseNullStrictValueOverNullValueRule.java | 52 +++++++------------ .../DefaultValueSimplificationRuleSet.java | 25 ++++++++- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/simplification/CollapseNullStrictValueOverNullValueRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/simplification/CollapseNullStrictValueOverNullValueRule.java index da343a050a..22bd6eeb26 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/simplification/CollapseNullStrictValueOverNullValueRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/simplification/CollapseNullStrictValueOverNullValueRule.java @@ -23,18 +23,10 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; import com.apple.foundationdb.record.query.plan.cascades.values.ArithmeticValue; -import com.apple.foundationdb.record.query.plan.cascades.values.CastValue; -import com.apple.foundationdb.record.query.plan.cascades.values.FieldValue; -import com.apple.foundationdb.record.query.plan.cascades.values.NotValue; import com.apple.foundationdb.record.query.plan.cascades.values.NullValue; -import com.apple.foundationdb.record.query.plan.cascades.values.PromoteValue; -import com.apple.foundationdb.record.query.plan.cascades.values.SubscriptValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Streams; import javax.annotation.Nonnull; -import java.util.Optional; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.TypedMatcherWithPredicate.typedMatcherWithPredicate; @@ -42,45 +34,41 @@ * A rule that collapses a {@link Value} into a {@link NullValue} if it is strictly null-propagating and has at least * one child that is a {@link NullValue}. A {@code Value} class is strictly null-propagating if it produces a * null result when any child evaluates to null. For example, arithmetic operators ({@link ArithmeticValue}) yield null - * when either operand is null. For the particular classes that are considered by this rule, see {@link #VALUE_CLASSES}. + * when either operand is null. + * + *

The rule is parameterized over the concrete, strictly null-propagating {@link Value} subclass. This way it can use + * a typed matcher for the specific class and benefit from the rule index in the rule set. + * + * @param the {@link Value} subclass that this rule instance matches */ @API(API.Status.EXPERIMENTAL) -public class CollapseNullStrictValueOverNullValueRule extends ValueSimplificationRule { - - /** - * {@link Value} subclasses that are considered to be strictly null-propagating by this rule. - */ - @Nonnull - private static final ImmutableSet> VALUE_CLASSES = ImmutableSet.of( - ArithmeticValue.class, - CastValue.class, - FieldValue.class, - NotValue.class, - PromoteValue.class, - SubscriptValue.class); +public final class CollapseNullStrictValueOverNullValueRule extends ValueSimplificationRule { @Nonnull - private static final BindingMatcher rootMatcher = typedMatcherWithPredicate(Value.class, - v -> VALUE_CLASSES.contains(v.getClass()) && hasNullValueChild(v)); + private final BindingMatcher rootMatcher; - public CollapseNullStrictValueOverNullValueRule() { - super(rootMatcher); + public CollapseNullStrictValueOverNullValueRule(@Nonnull final Class valueClass) { + this(typedMatcherWithPredicate(valueClass, CollapseNullStrictValueOverNullValueRule::hasNullValueChild)); } - @Nonnull - @Override - public Optional> getRootOperator() { - return Optional.empty(); + private CollapseNullStrictValueOverNullValueRule(@Nonnull final BindingMatcher rootMatcher) { + super(rootMatcher); + this.rootMatcher = rootMatcher; } @Override public void onMatch(@Nonnull final ValueSimplificationRuleCall call) { - final Value value = call.getBindings().get(rootMatcher); + final V value = call.getBindings().get(rootMatcher); // Note that the `NullValue` will always have a nullable result type even if the value’s result type is not. call.yieldResult(new NullValue(value.getResultType())); } private static boolean hasNullValueChild(@Nonnull final Value value) { - return Streams.stream(value.getChildren()).anyMatch(NullValue.class::isInstance); + for (final Value child : value.getChildren()) { + if (child instanceof NullValue) { + return true; + } + } + return false; } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/simplification/DefaultValueSimplificationRuleSet.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/simplification/DefaultValueSimplificationRuleSet.java index de8a0db738..9ee6c99cea 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/simplification/DefaultValueSimplificationRuleSet.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/simplification/DefaultValueSimplificationRuleSet.java @@ -21,6 +21,12 @@ package com.apple.foundationdb.record.query.plan.cascades.values.simplification; import com.apple.foundationdb.annotation.API; +import com.apple.foundationdb.record.query.plan.cascades.values.ArithmeticValue; +import com.apple.foundationdb.record.query.plan.cascades.values.CastValue; +import com.apple.foundationdb.record.query.plan.cascades.values.FieldValue; +import com.apple.foundationdb.record.query.plan.cascades.values.NotValue; +import com.apple.foundationdb.record.query.plan.cascades.values.PromoteValue; +import com.apple.foundationdb.record.query.plan.cascades.values.SubscriptValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; @@ -36,7 +42,17 @@ @SuppressWarnings("java:S1452") public class DefaultValueSimplificationRuleSet extends AbstractValueRuleSet { @Nonnull - protected static final ValueSimplificationRule collapseNullStrictValueOverNullValueRule = new CollapseNullStrictValueOverNullValueRule(); + protected static final ValueSimplificationRule collapseNullStrictArithmeticValueOverNullValueRule = new CollapseNullStrictValueOverNullValueRule<>(ArithmeticValue.class); + @Nonnull + protected static final ValueSimplificationRule collapseNullStrictCastValueOverNullValueRule = new CollapseNullStrictValueOverNullValueRule<>(CastValue.class); + @Nonnull + protected static final ValueSimplificationRule collapseNullStrictFieldValueOverNullValueRule = new CollapseNullStrictValueOverNullValueRule<>(FieldValue.class); + @Nonnull + protected static final ValueSimplificationRule collapseNullStrictNotValueOverNullValueRule = new CollapseNullStrictValueOverNullValueRule<>(NotValue.class); + @Nonnull + protected static final ValueSimplificationRule collapseNullStrictPromoteValueOverNullValueRule = new CollapseNullStrictValueOverNullValueRule<>(PromoteValue.class); + @Nonnull + protected static final ValueSimplificationRule collapseNullStrictSubscriptValueOverNullValueRule = new CollapseNullStrictValueOverNullValueRule<>(SubscriptValue.class); @Nonnull protected static final ValueSimplificationRule composeFieldValueOverRecordConstructorRule = new ComposeFieldValueOverRecordConstructorRule(); @Nonnull @@ -48,7 +64,12 @@ public class DefaultValueSimplificationRuleSet extends AbstractValueRuleSet> SIMPLIFICATION_RULES = ImmutableSet.of( - collapseNullStrictValueOverNullValueRule, + collapseNullStrictArithmeticValueOverNullValueRule, + collapseNullStrictCastValueOverNullValueRule, + collapseNullStrictFieldValueOverNullValueRule, + collapseNullStrictNotValueOverNullValueRule, + collapseNullStrictPromoteValueOverNullValueRule, + collapseNullStrictSubscriptValueOverNullValueRule, composeFieldValueOverRecordConstructorRule, composeFieldValueOverFieldValueRule, collapseRecordConstructorOverFieldsToStarRule);