-
Notifications
You must be signed in to change notification settings - Fork 104
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
516 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
144 changes: 144 additions & 0 deletions
144
...va/com/apple/foundationdb/record/query/plan/cascades/expressions/RecursiveExpression.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/* | ||
* RecursiveExpression.java | ||
* | ||
* This source file is part of the FoundationDB open source project | ||
* | ||
* Copyright 2015-2020 Apple Inc. and the FoundationDB project authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.apple.foundationdb.record.query.plan.cascades.expressions; | ||
|
||
import com.apple.foundationdb.annotation.API; | ||
import com.apple.foundationdb.record.query.plan.cascades.AliasMap; | ||
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; | ||
import com.apple.foundationdb.record.query.plan.cascades.Quantifier; | ||
import com.apple.foundationdb.record.query.plan.cascades.explain.InternalPlannerGraphRewritable; | ||
import com.apple.foundationdb.record.query.plan.cascades.explain.PlannerGraph; | ||
import com.apple.foundationdb.record.query.plan.cascades.values.Value; | ||
import com.apple.foundationdb.record.query.plan.cascades.values.Values; | ||
import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; | ||
import com.google.common.collect.ImmutableList; | ||
import com.google.common.collect.ImmutableMap; | ||
|
||
import javax.annotation.Nonnull; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
/** | ||
* A recursive expression. | ||
*/ | ||
@API(API.Status.EXPERIMENTAL) | ||
public class RecursiveExpression implements RelationalExpressionWithChildren, InternalPlannerGraphRewritable { | ||
@Nonnull | ||
private final Value resultValue; | ||
@Nonnull | ||
private final Quantifier rootQuantifier; | ||
@Nonnull | ||
private final Quantifier childQuantifier; | ||
|
||
public RecursiveExpression(@Nonnull Value resultValue, | ||
@Nonnull Quantifier rootQuantifier, | ||
@Nonnull Quantifier childQuantifier) { | ||
this.resultValue = resultValue; | ||
this.rootQuantifier = rootQuantifier; | ||
this.childQuantifier = childQuantifier; | ||
} | ||
|
||
@Nonnull | ||
@Override | ||
public Value getResultValue() { | ||
return resultValue; | ||
} | ||
|
||
@Nonnull | ||
public List<? extends Value> getResultValues() { | ||
return Values.deconstructRecord(getResultValue()); | ||
} | ||
|
||
@Nonnull | ||
@Override | ||
public List<? extends Quantifier> getQuantifiers() { | ||
return List.of(rootQuantifier, childQuantifier); | ||
} | ||
|
||
@Override | ||
public int getRelationalChildCount() { | ||
return 2; | ||
} | ||
|
||
@Override | ||
public boolean canCorrelate() { | ||
return true; | ||
} | ||
|
||
@Nonnull | ||
@Override | ||
public Set<CorrelationIdentifier> getCorrelatedToWithoutChildren() { | ||
return resultValue.getCorrelatedTo(); | ||
} | ||
|
||
@Nonnull | ||
@Override | ||
public RecursiveExpression translateCorrelations(@Nonnull final TranslationMap translationMap, @Nonnull final List<? extends Quantifier> translatedQuantifiers) { | ||
final Value translatedResultValue = resultValue.translateCorrelations(translationMap); | ||
return new RecursiveExpression(translatedResultValue, translatedQuantifiers.get(0), translatedQuantifiers.get(1)); | ||
} | ||
|
||
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass") | ||
@Override | ||
public boolean equals(final Object other) { | ||
return semanticEquals(other); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return semanticHashCode(); | ||
} | ||
|
||
@Override | ||
@SuppressWarnings({"UnstableApiUsage", "PMD.CompareObjectsWithEquals"}) | ||
public boolean equalsWithoutChildren(@Nonnull RelationalExpression otherExpression, | ||
@Nonnull final AliasMap aliasMap) { | ||
if (this == otherExpression) { | ||
return true; | ||
} | ||
if (getClass() != otherExpression.getClass()) { | ||
return false; | ||
} | ||
|
||
return semanticEqualsForResults(otherExpression, aliasMap); | ||
} | ||
|
||
@Override | ||
public int hashCodeWithoutChildren() { | ||
return getResultValue().hashCode(); | ||
} | ||
|
||
@Nonnull | ||
@Override | ||
public PlannerGraph rewriteInternalPlannerGraph(@Nonnull final List<? extends PlannerGraph> childGraphs) { | ||
return PlannerGraph.fromNodeAndChildGraphs( | ||
new PlannerGraph.LogicalOperatorNode(this, | ||
"RECURSIVE " + resultValue, | ||
ImmutableList.of(), | ||
ImmutableMap.of()), | ||
childGraphs); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "RECURSIVE " + resultValue; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
.../java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementRecursiveRule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/* | ||
* ImplementRecursiveRule.java | ||
* | ||
* This source file is part of the FoundationDB open source project | ||
* | ||
* Copyright 2015-2019 Apple Inc. and the FoundationDB project authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.apple.foundationdb.record.query.plan.cascades.rules; | ||
|
||
import com.apple.foundationdb.annotation.API; | ||
import com.apple.foundationdb.record.logging.KeyValueLogMessage; | ||
import com.apple.foundationdb.record.query.plan.cascades.CascadesRule; | ||
import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; | ||
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition; | ||
import com.apple.foundationdb.record.query.plan.cascades.Quantifier; | ||
import com.apple.foundationdb.record.query.plan.cascades.Reference; | ||
import com.apple.foundationdb.record.query.plan.cascades.debug.Debugger; | ||
import com.apple.foundationdb.record.query.plan.cascades.expressions.RecursiveExpression; | ||
import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; | ||
import com.apple.foundationdb.record.query.plan.plans.RecordQueryRecursivePlan; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import javax.annotation.Nonnull; | ||
|
||
import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.ListMatcher.exactly; | ||
import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MultiMatcher.all; | ||
import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.QuantifierMatchers.anyQuantifierOverRef; | ||
import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.ReferenceMatchers.anyPlanPartition; | ||
import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.ReferenceMatchers.planPartitions; | ||
import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.ReferenceMatchers.rollUp; | ||
import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.RelationalExpressionMatchers.canBeImplemented; | ||
import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.RelationalExpressionMatchers.recursiveExpression; | ||
|
||
/** | ||
* A rule that implements an existential nested loop join of its (already implemented) children. | ||
*/ | ||
@API(API.Status.EXPERIMENTAL) | ||
public class ImplementRecursiveRule extends CascadesRule<RecursiveExpression> { | ||
@Nonnull | ||
private static final Logger logger = LoggerFactory.getLogger(ImplementRecursiveRule.class); | ||
|
||
@Nonnull | ||
private static final BindingMatcher<PlanPartition> rootPlanPartitionsMatcher = anyPlanPartition(); | ||
|
||
@Nonnull | ||
private static final BindingMatcher<Reference> rootReferenceMatcher = planPartitions(rollUp(all(rootPlanPartitionsMatcher))); | ||
@Nonnull | ||
private static final BindingMatcher<Quantifier> rootQuantifierMatcher = anyQuantifierOverRef(rootReferenceMatcher); | ||
@Nonnull | ||
private static final BindingMatcher<PlanPartition> childPlanPartitionsMatcher = anyPlanPartition(); | ||
|
||
@Nonnull | ||
private static final BindingMatcher<Reference> childReferenceMatcher = planPartitions(rollUp(all(childPlanPartitionsMatcher))); | ||
@Nonnull | ||
private static final BindingMatcher<Quantifier> childQuantifierMatcher = anyQuantifierOverRef(childReferenceMatcher); | ||
@Nonnull | ||
private static final BindingMatcher<RecursiveExpression> root = | ||
recursiveExpression(exactly(rootQuantifierMatcher, childQuantifierMatcher)).where(canBeImplemented()); | ||
|
||
public ImplementRecursiveRule() { | ||
super(root); | ||
} | ||
|
||
@Override | ||
public void onMatch(@Nonnull final CascadesRuleCall call) { | ||
final var bindings = call.getBindings(); | ||
final var recursiveExpression = bindings.get(root); | ||
Debugger.withDebugger(debugger -> logger.debug(KeyValueLogMessage.of("matched RecursiveExpression", "legs", recursiveExpression.getQuantifiers().size()))); | ||
|
||
final var rootQuantifier = bindings.get(rootQuantifierMatcher); | ||
final var childQuantifier = bindings.get(childQuantifierMatcher); | ||
|
||
final var rootReference = bindings.get(rootReferenceMatcher); | ||
final var childReference = bindings.get(childReferenceMatcher); | ||
|
||
final var rootPartition = bindings.get(rootPlanPartitionsMatcher); | ||
final var childPartition = bindings.get(childPlanPartitionsMatcher); | ||
|
||
final var rootAlias = rootQuantifier.getAlias(); | ||
final var childAlias = childQuantifier.getAlias(); | ||
|
||
var rootRef = call.memoizeMemberPlans(rootReference, rootPartition.getPlans()); | ||
final var newRootQuantifier = Quantifier.physicalBuilder().withAlias(rootAlias).build(rootRef); | ||
|
||
var childRef = call.memoizeMemberPlans(childReference, childPartition.getPlans()); | ||
final var newChildQuantifier = Quantifier.physicalBuilder().withAlias(childAlias).build(childRef); | ||
|
||
call.yieldExpression(new RecordQueryRecursivePlan(newRootQuantifier, newChildQuantifier, recursiveExpression.getResultValue(), true)); | ||
} | ||
} |
Oops, something went wrong.