github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/memo/group.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package memo 15 16 import ( 17 "container/list" 18 "fmt" 19 20 causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded" 21 "github.com/whtcorpsinc/milevadb/causet/property" 22 "github.com/whtcorpsinc/milevadb/memex" 23 ) 24 25 // EngineType is determined by whether it's above or below `Gather`s. 26 // Causet will choose the different engine to be implemented/executed on according to its EngineType. 27 // Different engine may support different operators with different cost, so we should design 28 // different transformation and implementation rules for each engine. 29 type EngineType uint 30 31 const ( 32 // EngineMilevaDB stands for groups which is above `Gather`s and will be executed in MilevaDB layer. 33 EngineMilevaDB EngineType = 1 << iota 34 // EngineEinsteinDB stands for groups which is below `Gather`s and will be executed in EinsteinDB layer. 35 EngineEinsteinDB 36 // EngineTiFlash stands for groups which is below `Gather`s and will be executed in TiFlash layer. 37 EngineTiFlash 38 ) 39 40 // EngineTypeSet is the bit set of EngineTypes. 41 type EngineTypeSet uint 42 43 const ( 44 // EngineMilevaDBOnly is the EngineTypeSet for EngineMilevaDB only. 45 EngineMilevaDBOnly = EngineTypeSet(EngineMilevaDB) 46 // EngineEinsteinDBOnly is the EngineTypeSet for EngineEinsteinDB only. 47 EngineEinsteinDBOnly = EngineTypeSet(EngineEinsteinDB) 48 // EngineTiFlashOnly is the EngineTypeSet for EngineTiFlash only. 49 EngineTiFlashOnly = EngineTypeSet(EngineTiFlash) 50 // EngineEinsteinDBOrTiFlash is the EngineTypeSet for (EngineEinsteinDB | EngineTiFlash). 51 EngineEinsteinDBOrTiFlash = EngineTypeSet(EngineEinsteinDB | EngineTiFlash) 52 // EngineAll is the EngineTypeSet for all of the EngineTypes. 53 EngineAll = EngineTypeSet(EngineMilevaDB | EngineEinsteinDB | EngineTiFlash) 54 ) 55 56 // Contains checks whether the EngineTypeSet contains the EngineType. 57 func (e EngineTypeSet) Contains(tp EngineType) bool { 58 return uint(e)&uint(tp) != 0 59 } 60 61 // String implements fmt.Stringer interface. 62 func (e EngineType) String() string { 63 switch e { 64 case EngineMilevaDB: 65 return "EngineMilevaDB" 66 case EngineEinsteinDB: 67 return "EngineEinsteinDB" 68 case EngineTiFlash: 69 return "EngineTiFlash" 70 } 71 return "UnknownEngineType" 72 } 73 74 // ExploreMark is uses to mark whether a Group or GroupExpr has 75 // been fully explored by a transformation rule batch. 76 type ExploreMark int 77 78 // SetExplored sets the roundth bit. 79 func (m *ExploreMark) SetExplored(round int) { 80 *m |= 1 << round 81 } 82 83 // SetUnexplored unsets the roundth bit. 84 func (m *ExploreMark) SetUnexplored(round int) { 85 *m &= ^(1 << round) 86 } 87 88 // Explored returns whether the roundth bit has been set. 89 func (m *ExploreMark) Explored(round int) bool { 90 return *m&(1<<round) != 0 91 } 92 93 // Group is short for memex Group, which is used to causetstore all the 94 // logically equivalent memexs. It's a set of GroupExpr. 95 type Group struct { 96 Equivalents *list.List 97 98 FirstExpr map[Operand]*list.Element 99 Fingerprints map[string]*list.Element 100 101 ImplMap map[string]Implementation 102 Prop *property.LogicalProperty 103 104 EngineType EngineType 105 106 SelfFingerprint string 107 108 // ExploreMark is uses to mark whether this Group has been explored 109 // by a transformation rule batch in a certain round. 110 ExploreMark 111 112 //hasBuiltKeyInfo indicates whether this group has called `BuildKeyInfo`. 113 // BuildKeyInfo is lazily called when a rule needs information of 114 // unique key or maxOneRow (in LogicalProp). For each Group, we only need 115 // to collect these information once. 116 hasBuiltKeyInfo bool 117 } 118 119 // NewGroupWithSchema creates a new Group with given schemaReplicant. 120 func NewGroupWithSchema(e *GroupExpr, s *memex.Schema) *Group { 121 prop := &property.LogicalProperty{Schema: memex.NewSchema(s.DeferredCausets...)} 122 g := &Group{ 123 Equivalents: list.New(), 124 Fingerprints: make(map[string]*list.Element), 125 FirstExpr: make(map[Operand]*list.Element), 126 ImplMap: make(map[string]Implementation), 127 Prop: prop, 128 EngineType: EngineMilevaDB, 129 } 130 g.Insert(e) 131 return g 132 } 133 134 // SetEngineType sets the engine type of the group. 135 func (g *Group) SetEngineType(e EngineType) *Group { 136 g.EngineType = e 137 return g 138 } 139 140 // FingerPrint returns the unique fingerprint of the Group. 141 func (g *Group) FingerPrint() string { 142 if g.SelfFingerprint == "" { 143 g.SelfFingerprint = fmt.Sprintf("%p", g) 144 } 145 return g.SelfFingerprint 146 } 147 148 // Insert a nonexistent Group memex. 149 func (g *Group) Insert(e *GroupExpr) bool { 150 if e == nil || g.Exists(e) { 151 return false 152 } 153 154 operand := GetOperand(e.ExprNode) 155 var newEquiv *list.Element 156 mark, hasMark := g.FirstExpr[operand] 157 if hasMark { 158 newEquiv = g.Equivalents.InsertAfter(e, mark) 159 } else { 160 newEquiv = g.Equivalents.PushBack(e) 161 g.FirstExpr[operand] = newEquiv 162 } 163 g.Fingerprints[e.FingerPrint()] = newEquiv 164 e.Group = g 165 return true 166 } 167 168 // Delete an existing Group memex. 169 func (g *Group) Delete(e *GroupExpr) { 170 fingerprint := e.FingerPrint() 171 equiv, ok := g.Fingerprints[fingerprint] 172 if !ok { 173 return // Can not find the target GroupExpr. 174 } 175 176 operand := GetOperand(equiv.Value.(*GroupExpr).ExprNode) 177 if g.FirstExpr[operand] == equiv { 178 // The target GroupExpr is the first Element of the same Operand. 179 // We need to change the FirstExpr to the next Expr, or delete the FirstExpr. 180 nextElem := equiv.Next() 181 if nextElem != nil && GetOperand(nextElem.Value.(*GroupExpr).ExprNode) == operand { 182 g.FirstExpr[operand] = nextElem 183 } else { 184 // There is no more GroupExpr of the Operand, so we should 185 // delete the FirstExpr of this Operand. 186 delete(g.FirstExpr, operand) 187 } 188 } 189 190 g.Equivalents.Remove(equiv) 191 delete(g.Fingerprints, fingerprint) 192 e.Group = nil 193 } 194 195 // DeleteAll deletes all of the GroupExprs in the Group. 196 func (g *Group) DeleteAll() { 197 g.Equivalents = list.New() 198 g.Fingerprints = make(map[string]*list.Element) 199 g.FirstExpr = make(map[Operand]*list.Element) 200 g.SelfFingerprint = "" 201 } 202 203 // Exists checks whether a Group memex existed in a Group. 204 func (g *Group) Exists(e *GroupExpr) bool { 205 _, ok := g.Fingerprints[e.FingerPrint()] 206 return ok 207 } 208 209 // GetFirstElem returns the first Group memex which matches the Operand. 210 // Return a nil pointer if there isn't. 211 func (g *Group) GetFirstElem(operand Operand) *list.Element { 212 if operand == OperandAny { 213 return g.Equivalents.Front() 214 } 215 return g.FirstExpr[operand] 216 } 217 218 // GetImpl returns the best Implementation satisfy the physical property. 219 func (g *Group) GetImpl(prop *property.PhysicalProperty) Implementation { 220 key := prop.HashCode() 221 return g.ImplMap[string(key)] 222 } 223 224 // InsertImpl inserts the best Implementation satisfy the physical property. 225 func (g *Group) InsertImpl(prop *property.PhysicalProperty, impl Implementation) { 226 key := prop.HashCode() 227 g.ImplMap[string(key)] = impl 228 } 229 230 // Convert2GroupExpr converts a logical plan to a GroupExpr. 231 func Convert2GroupExpr(node causetembedded.LogicalCauset) *GroupExpr { 232 e := NewGroupExpr(node) 233 e.Children = make([]*Group, 0, len(node.Children())) 234 for _, child := range node.Children() { 235 childGroup := Convert2Group(child) 236 e.Children = append(e.Children, childGroup) 237 } 238 return e 239 } 240 241 // Convert2Group converts a logical plan to a Group. 242 func Convert2Group(node causetembedded.LogicalCauset) *Group { 243 e := Convert2GroupExpr(node) 244 g := NewGroupWithSchema(e, node.Schema()) 245 // Stats property for `Group` would be computed after exploration phase. 246 return g 247 } 248 249 // BuildKeyInfo recursively builds UniqueKey and MaxOneRow info in the LogicalProperty. 250 func (g *Group) BuildKeyInfo() { 251 if g.hasBuiltKeyInfo { 252 return 253 } 254 g.hasBuiltKeyInfo = true 255 256 e := g.Equivalents.Front().Value.(*GroupExpr) 257 childSchema := make([]*memex.Schema, len(e.Children)) 258 childMaxOneRow := make([]bool, len(e.Children)) 259 for i := range e.Children { 260 e.Children[i].BuildKeyInfo() 261 childSchema[i] = e.Children[i].Prop.Schema 262 childMaxOneRow[i] = e.Children[i].Prop.MaxOneRow 263 } 264 if len(childSchema) == 1 { 265 // For UnaryCauset(such as Selection, Limit ...), we can set the child's unique key as its unique key. 266 // If the GroupExpr is a schemaProducer, schemaReplicant.Keys will be reset below in `BuildKeyInfo()`. 267 g.Prop.Schema.Keys = childSchema[0].Keys 268 } 269 e.ExprNode.BuildKeyInfo(g.Prop.Schema, childSchema) 270 g.Prop.MaxOneRow = e.ExprNode.MaxOneRow() || causetembedded.HasMaxOneRow(e.ExprNode, childMaxOneRow) 271 }