You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by hy...@apache.org on 2020/06/24 16:10:28 UTC
[calcite] branch master updated: [CALCITE-3786] Make digestEquals
and digestHash available to be overridden
This is an automated email from the ASF dual-hosted git repository.
hyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push:
new af3bca3 [CALCITE-3786] Make digestEquals and digestHash available to be overridden
af3bca3 is described below
commit af3bca328a40d2d6515ea00e2094974cc725d4c3
Author: Haisheng Yuan <h....@alibaba-inc.com>
AuthorDate: Tue Jun 23 17:20:37 2020 -0500
[CALCITE-3786] Make digestEquals and digestHash available to be overridden
By default #digestEquals() and #digestHash() collect digest attributes from
compute hash code. This should work well for most cases. If the method is a
performance bottleneck for your project, or the default behavior can't handle
your scenario properly, you can choose to override #digestEquals() and
Only these operators are changed to override the default behavior, for
performance and demonstration purposes. All the other operators remain
unchanged.
Close #2044
---
.../java/org/apache/calcite/plan/RelOptNode.java | 15 +----------
.../org/apache/calcite/plan/hep/HepRelVertex.java | 11 +++++---
.../org/apache/calcite/rel/AbstractRelNode.java | 26 ++++++++++++------
.../main/java/org/apache/calcite/rel/RelNode.java | 24 ++++++++++++++---
.../java/org/apache/calcite/rel/core/Filter.java | 19 +++++++++++++
.../java/org/apache/calcite/rel/core/Join.java | 21 +++++++++++++++
.../java/org/apache/calcite/rel/core/Project.java | 20 ++++++++++++++
.../apache/calcite/rel/logical/LogicalFilter.java | 9 +++++++
.../apache/calcite/rel/logical/LogicalJoin.java | 13 +++++++++
.../apache/calcite/rel/logical/LogicalProject.java | 8 ++++++
.../org/apache/calcite/rel/type/RelDataType.java | 31 ++++++++++++++++++++++
11 files changed, 169 insertions(+), 28 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptNode.java b/core/src/main/java/org/apache/calcite/plan/RelOptNode.java
index 208a87c..c21f745 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptNode.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptNode.java
@@ -18,8 +18,6 @@ package org.apache.calcite.plan;
import org.apache.calcite.rel.type.RelDataType;
-import org.apiguardian.api.API;
-
import java.util.List;
/**
@@ -49,18 +47,7 @@ public interface RelOptNode {
*
* @return Digest string of this {@code RelNode}
*/
- default String getDigest() {
- return getRelDigest().toString();
- }
-
- /**
- * Digest of the {@code RelNode}, for planner internal use only.
- *
- * @return Digest of this {@code RelNode}
- * @see #getDigest()
- */
- @API(since = "1.24", status = API.Status.INTERNAL)
- RelDigest getRelDigest();
+ String getDigest();
/**
* Retrieves this RelNode's traits. Note that although the RelTraitSet
diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java b/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java
index 1061a61..4ad6d28 100644
--- a/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java
+++ b/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java
@@ -91,9 +91,14 @@ public class HepRelVertex extends AbstractRelNode {
return currentRel;
}
- @Override public RelWriter explainTerms(final RelWriter pw) {
- return super.explainTerms(pw)
- .item("currentRel", currentRel.getId());
+ @Override protected boolean digestEquals(Object obj) {
+ return this == obj
+ || (obj instanceof HepRelVertex
+ && currentRel == ((HepRelVertex) obj).currentRel);
+ }
+
+ @Override protected int digestHash() {
+ return currentRel.getId();
}
@Override public String getDigest() {
diff --git a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
index 4ab68a0..ec52c10 100644
--- a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
+++ b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
@@ -337,9 +337,8 @@ public abstract class AbstractRelNode implements RelNode {
return r;
}
- public RelDigest recomputeDigest() {
+ public void recomputeDigest() {
digest.clear();
- return digest;
}
public void replaceInput(
@@ -394,9 +393,19 @@ public abstract class AbstractRelNode implements RelNode {
}
/**
- * Equality check for RelNode digest
+ * Equality check for RelNode digest.
+ *
+ * <p>By default this method collects digest attributes from
+ * {@link #explainTerms(RelWriter)}, then compares each attribute pair.
+ * This should work well for most cases. If this method is a performance
+ * bottleneck for your project, or the default behavior can't handle
+ * your scenario properly, you can choose to override this method and
+ * {@link #digestHash()}. See {@code LogicalJoin} as an example.</p>
+ *
+ * @return Whether the 2 RelNodes are equivalent or have the same digest.
+ * @see #digestHash()
*/
- private boolean digestEquals(Object obj) {
+ protected boolean digestEquals(Object obj) {
if (this == obj) {
return true;
}
@@ -406,14 +415,15 @@ public abstract class AbstractRelNode implements RelNode {
AbstractRelNode that = (AbstractRelNode) obj;
return this.getTraitSet().equals(that.getTraitSet())
&& this.getDigestItems().equals(that.getDigestItems())
- && Pair.right(getRowType().getFieldList()).equals(
- Pair.right(that.getRowType().getFieldList()));
+ && this.getRowType().equalsSansFieldNames(that.getRowType());
}
/**
- * Compute hash code for RelNode digest
+ * Compute hash code for RelNode digest.
+ *
+ * @see #digestEquals(Object)
*/
- private int digestHash() {
+ protected int digestHash() {
return Objects.hash(getTraitSet(), getDigestItems());
}
diff --git a/core/src/main/java/org/apache/calcite/rel/RelNode.java b/core/src/main/java/org/apache/calcite/rel/RelNode.java
index 3d5a08e..21fbd7e 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelNode.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelNode.java
@@ -307,12 +307,30 @@ public interface RelNode extends RelOptNode, Cloneable {
RelNode onRegister(RelOptPlanner planner);
/**
- * Computes the digest, assigns it, and returns it. For planner use only.
+ * @return Digest string of this {@code RelNode}
+ */
+ default String getDigest() {
+ return getRelDigest().toString();
+ }
+
+ /**
+ * Digest of the {@code RelNode}, for planner internal use only.
+ *
+ * <p>INTERNAL USE ONLY.</p>
+ *
+ * @return Digest of this {@code RelNode}
+ * @see #getDigest()
+ */
+ @API(since = "1.24", status = API.Status.INTERNAL)
+ RelDigest getRelDigest();
+
+ /**
+ * Recomputes the digest. For planner internal use only.
*
- * @return Digest of this relational expression
+ * @see #getDigest()
*/
@API(since = "1.24", status = API.Status.INTERNAL)
- RelDigest recomputeDigest();
+ void recomputeDigest();
/**
* Replaces the <code>ordinalInParent</code><sup>th</sup> input. You must
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Filter.java b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
index dd13485..0efea06 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Filter.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
@@ -37,6 +37,7 @@ import org.apache.calcite.util.Litmus;
import com.google.common.collect.ImmutableList;
import java.util.List;
+import java.util.Objects;
/**
* Relational expression that iterates over its input
@@ -152,4 +153,22 @@ public abstract class Filter extends SingleRel {
return super.explainTerms(pw)
.item("condition", condition);
}
+
+ protected boolean digestEquals0(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ Filter o = (Filter) obj;
+ return traitSet.equals(o.traitSet)
+ && input.equals(o.input)
+ && condition.equals(o.condition)
+ && getRowType().equalsSansFieldNames(o.getRowType());
+ }
+
+ protected int digestHash0() {
+ return Objects.hash(traitSet, input, condition);
+ }
}
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Join.java b/core/src/main/java/org/apache/calcite/rel/core/Join.java
index 5d615a8..b8f6c13 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Join.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Join.java
@@ -233,6 +233,27 @@ public abstract class Join extends BiRel implements Hintable {
!getSystemFieldList().isEmpty());
}
+ protected boolean digestEquals0(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ Join o = (Join) obj;
+ return traitSet.equals(o.traitSet)
+ && getInputs().equals(o.getInputs())
+ && condition.equals(o.condition)
+ && joinType == o.joinType
+ && hints.equals(o.hints)
+ && getRowType().equalsSansFieldNames(o.getRowType());
+ }
+
+ protected int digestHash0() {
+ return Objects.hash(traitSet, left, right,
+ condition, joinType, hints);
+ }
+
@Override protected RelDataType deriveRowType() {
return SqlValidatorUtil.deriveJoinRowType(left.getRowType(),
right.getRowType(), joinType, getCluster().getTypeFactory(), null,
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Project.java b/core/src/main/java/org/apache/calcite/rel/core/Project.java
index e3c1412..99083c0 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Project.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Project.java
@@ -48,6 +48,7 @@ import com.google.common.collect.Lists;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -288,6 +289,25 @@ public abstract class Project extends SingleRel implements Hintable {
return pw;
}
+ protected boolean digestEquals0(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ Project o = (Project) obj;
+ return traitSet.equals(o.traitSet)
+ && input.equals(o.input)
+ && exps.equals(o.exps)
+ && hints.equals(o.hints)
+ && getRowType().equalsSansFieldNames(o.getRowType());
+ }
+
+ protected int digestHash0() {
+ return Objects.hash(traitSet, input, exps, hints);
+ }
+
/**
* Returns a mapping, or null if this projection is not a mapping.
*
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java
index 8995241..758d903 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java
@@ -135,4 +135,13 @@ public final class LogicalFilter extends Filter {
return super.explainTerms(pw)
.itemIf("variablesSet", variablesSet, !variablesSet.isEmpty());
}
+
+ @Override protected boolean digestEquals(Object obj) {
+ return digestEquals0(obj)
+ && variablesSet.equals(((LogicalFilter) obj).variablesSet);
+ }
+
+ @Override protected int digestHash() {
+ return Objects.hash(digestHash0(), variablesSet);
+ }
}
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java
index 4b55785..4a9620b 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java
@@ -191,6 +191,19 @@ public final class LogicalJoin extends Join {
.itemIf("semiJoinDone", semiJoinDone, semiJoinDone);
}
+ @Override protected boolean digestEquals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ return digestEquals0(obj)
+ && semiJoinDone == ((LogicalJoin) obj).semiJoinDone
+ && systemFieldList.equals(((LogicalJoin) obj).systemFieldList);
+ }
+
+ @Override protected int digestHash() {
+ return Objects.hash(digestHash0(), semiJoinDone, systemFieldList);
+ }
+
@Override public boolean isSemiJoinDone() {
return semiJoinDone;
}
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
index 2696dba..6829c9d 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
@@ -136,4 +136,12 @@ public final class LogicalProject extends Project {
return new LogicalProject(getCluster(), traitSet, hintList,
input, getProjects(), rowType);
}
+
+ @Override protected boolean digestEquals(Object obj) {
+ return digestEquals0(obj);
+ }
+
+ @Override protected int digestHash() {
+ return digestHash0();
+ }
}
diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
index 3e6f474..0e41c0d 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
@@ -21,6 +21,8 @@ import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.type.SqlTypeName;
+import org.apiguardian.api.API;
+
import java.nio.charset.Charset;
import java.util.List;
@@ -241,4 +243,33 @@ public interface RelDataType {
*/
boolean isDynamicStruct();
+ /**
+ * @return whether the field types are equal with each other by ignoring
+ * the field names. If it is not a struct, just return the result of
+ * {@code #equals(Object)}.
+ */
+ @API(since = "1.24", status = API.Status.INTERNAL)
+ default boolean equalsSansFieldNames(RelDataType that) {
+ if (this == that) {
+ return true;
+ }
+ if (that == null || getClass() != that.getClass()) {
+ return false;
+ }
+ if (isStruct()) {
+ List<RelDataTypeField> l1 = this.getFieldList();
+ List<RelDataTypeField> l2 = that.getFieldList();
+ if (l1.size() != l2.size()) {
+ return false;
+ }
+ for (int i = 0; i < l1.size(); i++) {
+ if (!l1.get(i).getType().equals(l2.get(i).getType())) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return equals(that);
+ }
+ }
}