-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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: support the Group and GroupExpr for the cascades planner #7917
Changes from 1 commit
0980447
86729af
c0fcf75
e426174
62ff87f
b196d8b
faa6b7a
9d6cd50
ea29e03
d3a917f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Copyright 2018 PingCAP, Inc. | ||
// | ||
// 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, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package cascades | ||
|
||
import ( | ||
"container/list" | ||
"fmt" | ||
) | ||
|
||
// Group is short for expression group, which is used to store all the | ||
// logically equivalent expressions. It's a set of GroupExpr. | ||
type Group struct { | ||
equivalents *list.List | ||
fingerprints map[string]*list.Element | ||
|
||
explored bool | ||
selfFingerprint string | ||
} | ||
|
||
// NewGroup creates a new Group. | ||
func NewGroup(e *GroupExpr) *Group { | ||
g := &Group{ | ||
equivalents: list.New(), | ||
fingerprints: make(map[string]*list.Element), | ||
} | ||
g.Insert(e) | ||
return g | ||
} | ||
|
||
// FingerPrint returns the unique fingerprint of the group. | ||
func (g *Group) FingerPrint() string { | ||
if g.selfFingerprint == "" { | ||
g.selfFingerprint = fmt.Sprintf("%p", g) | ||
} | ||
return g.selfFingerprint | ||
} | ||
|
||
// Insert a nonexistent group exxpression. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
func (g *Group) Insert(e *GroupExpr) bool { | ||
if g.Exists(e) { | ||
return false | ||
} | ||
newEquiv := g.equivalents.PushBack(e) | ||
g.fingerprints[e.FingerPrint()] = newEquiv | ||
return true | ||
} | ||
|
||
// Delete an existing group expression. | ||
func (g *Group) Delete(e *GroupExpr) { | ||
fingerprint := e.FingerPrint() | ||
if equiv, ok := g.fingerprints[fingerprint]; ok { | ||
g.equivalents.Remove(equiv) | ||
delete(g.fingerprints, fingerprint) | ||
} | ||
} | ||
|
||
// Exists checks whether a group expression existed in a Group. | ||
func (g *Group) Exists(e *GroupExpr) bool { | ||
_, ok := g.fingerprints[e.FingerPrint()] | ||
return ok | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright 2018 PingCAP, Inc. | ||
// | ||
// 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, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package cascades | ||
|
||
import ( | ||
"fmt" | ||
|
||
plannercore "github.com/pingcap/tidb/planner/core" | ||
) | ||
|
||
// GroupExpr is used to store all the logically equivalent expressions which | ||
// have the same root operator. Different from a normal expression, the | ||
// children of a group expression are expression Groups, not expressions. | ||
// Another property of group expression is that the child group references will | ||
// never be changed once the group expression is created. | ||
type GroupExpr struct { | ||
exprNode plannercore.LogicalPlan | ||
children []*Group | ||
explored bool | ||
|
||
selfFingerprint string | ||
} | ||
|
||
// NewGroupExpr creates a GroupExpr based on a logical plan node. | ||
func NewGroupExpr(node plannercore.LogicalPlan) *GroupExpr { | ||
return &GroupExpr{ | ||
exprNode: node, | ||
children: nil, | ||
explored: false, | ||
} | ||
} | ||
|
||
// FingerPrint get the unique fingerprint of the group expression. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/ get /gets |
||
func (e *GroupExpr) FingerPrint() string { | ||
if e.selfFingerprint == "" { | ||
e.selfFingerprint = fmt.Sprintf("%v", e.exprNode.ID()) | ||
for i := range e.children { | ||
e.selfFingerprint += e.children[i].FingerPrint() | ||
} | ||
} | ||
return e.selfFingerprint | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Copyright 2018 PingCAP, Inc. | ||
// | ||
// 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, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package cascades | ||
|
||
import ( | ||
. "github.com/pingcap/check" | ||
plannercore "github.com/pingcap/tidb/planner/core" | ||
) | ||
|
||
func (s *testCascadesSuite) TestNewGroupExpr(c *C) { | ||
p := &plannercore.LogicalLimit{} | ||
expr := NewGroupExpr(p) | ||
c.Assert(expr.exprNode, Equals, p) | ||
c.Assert(expr.children, IsNil) | ||
c.Assert(expr.explored, IsFalse) | ||
} | ||
|
||
func (s *testCascadesSuite) TestGroupExprFingerprint(c *C) { | ||
p := &plannercore.LogicalLimit{} | ||
expr := NewGroupExpr(p) | ||
|
||
// we haven't set the id of the created LogicalLimit, so the result is 0. | ||
c.Assert(expr.FingerPrint(), Equals, "0") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// Copyright 2018 PingCAP, Inc. | ||
// | ||
// 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, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package cascades | ||
|
||
import ( | ||
// "container/list" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove these two lines? |
||
//"fmt" | ||
"testing" | ||
|
||
. "github.com/pingcap/check" | ||
plannercore "github.com/pingcap/tidb/planner/core" | ||
"github.com/pingcap/tidb/sessionctx" | ||
"github.com/pingcap/tidb/util/mock" | ||
"github.com/pingcap/tidb/util/testleak" | ||
) | ||
|
||
func TestT(t *testing.T) { | ||
CustomVerboseFlag = true | ||
TestingT(t) | ||
} | ||
|
||
var _ = Suite(&testCascadesSuite{}) | ||
|
||
type testCascadesSuite struct { | ||
sctx sessionctx.Context | ||
} | ||
|
||
func (s *testCascadesSuite) SetUpSuite(c *C) { | ||
testleak.BeforeTest() | ||
s.sctx = mock.NewContext() | ||
} | ||
|
||
func (s *testCascadesSuite) TearDownSuite(c *C) { | ||
testleak.AfterTest(c)() | ||
} | ||
|
||
func (s *testCascadesSuite) TestNewGroup(c *C) { | ||
p := &plannercore.LogicalLimit{} | ||
expr := NewGroupExpr(p) | ||
g := NewGroup(expr) | ||
|
||
c.Assert(g.equivalents.Len(), Equals, 1) | ||
c.Assert(g.equivalents.Front().Value.(*GroupExpr), Equals, expr) | ||
c.Assert(len(g.fingerprints), Equals, 1) | ||
c.Assert(g.explored, IsFalse) | ||
} | ||
|
||
func (s *testCascadesSuite) TestGroupInsert(c *C) { | ||
p := &plannercore.LogicalLimit{} | ||
expr := NewGroupExpr(p) | ||
g := NewGroup(expr) | ||
c.Assert(g.Insert(expr), IsFalse) | ||
expr.selfFingerprint = "1" | ||
c.Assert(g.Insert(expr), IsTrue) | ||
} | ||
|
||
func (s *testCascadesSuite) TestGroupDelete(c *C) { | ||
p := &plannercore.LogicalLimit{} | ||
expr := NewGroupExpr(p) | ||
g := NewGroup(expr) | ||
c.Assert(g.equivalents.Len(), Equals, 1) | ||
|
||
g.Delete(expr) | ||
c.Assert(g.equivalents.Len(), Equals, 0) | ||
|
||
g.Delete(expr) | ||
c.Assert(g.equivalents.Len(), Equals, 0) | ||
} | ||
|
||
func (s *testCascadesSuite) TestGroupExists(c *C) { | ||
p := &plannercore.LogicalLimit{} | ||
expr := NewGroupExpr(p) | ||
g := NewGroup(expr) | ||
c.Assert(g.Exists(expr), IsTrue) | ||
|
||
g.Delete(expr) | ||
c.Assert(g.Exists(expr), IsFalse) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/ exx../expression