Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner: generate the hash64 and equals for logical aggregation. #57074

Merged
merged 1 commit into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
// If a field is tagged with `hash64-equals`, then it will be computed in hash64 and equals func.
// If a field is not tagged, then it will be skipped.
func GenHash64Equals4LogicalOps() ([]byte, error) {
var structures = []any{logicalop.LogicalJoin{}}
var structures = []any{logicalop.LogicalJoin{}, logicalop.LogicalAggregation{}}
c := new(cc)
c.write(codeGenHash64EqualsPrefix)
for _, s := range structures {
Expand Down Expand Up @@ -86,7 +86,7 @@ func genHash64EqualsForLogicalOps(x any) ([]byte, error) {
}
leftCallName := "op." + vType.Field(i).Name
rightCallName := "op2." + vType.Field(i).Name
c.EqualsElement(f.Type, leftCallName, rightCallName)
c.EqualsElement(f.Type, leftCallName, rightCallName, "i")
}
c.write("return true")
c.write("}")
Expand All @@ -97,6 +97,8 @@ func logicalOpName2PlanCodecString(name string) string {
switch name {
case "LogicalJoin":
return "plancodec.TypeJoin"
case "LogicalAggregation":
return "plancodec.TypeAgg"
default:
return ""
}
Expand All @@ -107,13 +109,22 @@ func isHash64EqualsField(fType reflect.StructField) bool {
}

// EqualsElement EqualsElements generate the equals function for every field inside logical op.
func (c *cc) EqualsElement(fType reflect.Type, lhs, rhs string) {
func (c *cc) EqualsElement(fType reflect.Type, lhs, rhs string, i string) {
switch fType.Kind() {
case reflect.Slice:
c.write("if len(%v) != len(%v) { return false }", lhs, rhs)
c.write("for i, one := range %v {", lhs)
c.write("for %v, one := range %v {", i, lhs)
// one more round
c.EqualsElement(fType.Elem(), "one", rhs+"[i]")
rhs = rhs + "[" + i + "]"
// for ?, one := range [][][][]...
// for use i for out-most ref, for each level deeper, appending another i for simple.
// and you will see:
// for i, one range := [][][]
// for ii, one range := [][]
// for iii, one := range []
// and so on...
newi := i + "i"
c.EqualsElement(fType.Elem(), "one", rhs, newi)
c.write("}")
case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
Expand Down
76 changes: 76 additions & 0 deletions pkg/planner/core/operator/logicalop/hash64_equals_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 4 additions & 61 deletions pkg/planner/core/operator/logicalop/logical_aggregation.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/pingcap/tidb/pkg/kv"
"github.com/pingcap/tidb/pkg/parser/ast"
"github.com/pingcap/tidb/pkg/planner/cardinality"
base2 "github.com/pingcap/tidb/pkg/planner/cascades/base"
"github.com/pingcap/tidb/pkg/planner/core/base"
ruleutil "github.com/pingcap/tidb/pkg/planner/core/rule/util"
fd "github.com/pingcap/tidb/pkg/planner/funcdep"
Expand All @@ -41,15 +40,15 @@ import (
type LogicalAggregation struct {
LogicalSchemaProducer

AggFuncs []*aggregation.AggFuncDesc
GroupByItems []expression.Expression
AggFuncs []*aggregation.AggFuncDesc `hash64-equals:"true"`
GroupByItems []expression.Expression `hash64-equals:"true"`

// PreferAggType And PreferAggToCop stores aggregation hint information.
PreferAggType uint
PreferAggToCop bool

PossibleProperties [][]*expression.Column
InputCount float64 // InputCount is the input count of this plan.
PossibleProperties [][]*expression.Column `hash64-equals:"true"`
InputCount float64 // InputCount is the input count of this plan.

// NoCopPushDown indicates if planner must not push this agg down to coprocessor.
// It is true when the agg is in the outer child tree of apply.
Expand All @@ -62,62 +61,6 @@ func (la LogicalAggregation) Init(ctx base.PlanContext, offset int) *LogicalAggr
return &la
}

// *************************** start implementation of HashEquals interface ****************************

// Hash64 implements the base.Hash64.<0th> interface.
func (la *LogicalAggregation) Hash64(h base2.Hasher) {
h.HashInt(len(la.AggFuncs))
for _, one := range la.AggFuncs {
one.Hash64(h)
}
h.HashInt(len(la.GroupByItems))
for _, one := range la.GroupByItems {
one.Hash64(h)
}
h.HashInt(len(la.PossibleProperties))
for _, one := range la.PossibleProperties {
h.HashInt(len(one))
for _, col := range one {
col.Hash64(h)
}
}
}

// Equals implements the base.HashEquals.<1st> interface.
func (la *LogicalAggregation) Equals(other any) bool {
if other == nil {
return false
}
la2, ok := other.(*LogicalAggregation)
if !ok {
return false
}
if len(la.AggFuncs) != len(la2.AggFuncs) || len(la.GroupByItems) != len(la2.GroupByItems) || len(la.PossibleProperties) != len(la2.PossibleProperties) {
return false
}
for i := range la.AggFuncs {
if !la.AggFuncs[i].Equals(la2.AggFuncs[i]) {
return false
}
}
for i := range la.GroupByItems {
if !la.GroupByItems[i].Equals(la2.GroupByItems[i]) {
return false
}
}
for i := range la.PossibleProperties {
if len(la.PossibleProperties[i]) != len(la2.PossibleProperties[i]) {
return false
}
for j := range la.PossibleProperties[i] {
if !la.PossibleProperties[i][j].Equals(la2.PossibleProperties[i][j]) {
return false
}
}
}
return true
}

// *************************** start implementation of Plan interface ***************************

// ExplainInfo implements base.Plan.<4th> interface.
Expand Down