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  }