github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/property/physical_property.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 property 15 16 import ( 17 "fmt" 18 19 "github.com/whtcorpsinc/milevadb/memex" 20 "github.com/whtcorpsinc/milevadb/soliton/codec" 21 ) 22 23 // wholeTaskTypes records all possible HoTTs of task that a plan can return. For Agg, TopN and Limit, we will try to get 24 // these tasks one by one. 25 var wholeTaskTypes = []TaskType{CopSingleReadTaskType, CoFIDeloubleReadTaskType, RootTaskType} 26 27 // Item wraps the column and its order. 28 type Item struct { 29 DefCaus *memex.DeferredCauset 30 Desc bool 31 } 32 33 // PhysicalProperty stands for the required physical property by parents. 34 // It contains the orders and the task types. 35 type PhysicalProperty struct { 36 Items []Item 37 38 // TaskTp means the type of task that an operator requires. 39 // 40 // It needs to be specified because two different tasks can't be compared 41 // with cost directly. e.g. If a copTask takes less cost than a rootTask, 42 // we can't sure that we must choose the former one. Because the copTask 43 // must be finished and increase its cost in sometime, but we can't make 44 // sure the finishing time. So the best way to let the comparison fair is 45 // to add TaskType to required property. 46 TaskTp TaskType 47 48 // ExpectedCnt means this operator may be closed after fetching ExpectedCnt 49 // records. 50 ExpectedCnt float64 51 52 // hashcode stores the hash code of a PhysicalProperty, will be lazily 53 // calculated when function "HashCode()" being called. 54 hashcode []byte 55 56 // whether need to enforce property. 57 Enforced bool 58 } 59 60 // NewPhysicalProperty builds property from columns. 61 func NewPhysicalProperty(taskTp TaskType, defcaus []*memex.DeferredCauset, desc bool, expectCnt float64, enforced bool) *PhysicalProperty { 62 return &PhysicalProperty{ 63 Items: ItemsFromDefCauss(defcaus, desc), 64 TaskTp: taskTp, 65 ExpectedCnt: expectCnt, 66 Enforced: enforced, 67 } 68 } 69 70 // ItemsFromDefCauss builds property items from columns. 71 func ItemsFromDefCauss(defcaus []*memex.DeferredCauset, desc bool) []Item { 72 items := make([]Item, 0, len(defcaus)) 73 for _, col := range defcaus { 74 items = append(items, Item{DefCaus: col, Desc: desc}) 75 } 76 return items 77 } 78 79 // AllDefCaussFromSchema checks whether all the columns needed by this physical 80 // property can be found in the given schemaReplicant. 81 func (p *PhysicalProperty) AllDefCaussFromSchema(schemaReplicant *memex.Schema) bool { 82 for _, col := range p.Items { 83 if schemaReplicant.DeferredCausetIndex(col.DefCaus) == -1 { 84 return false 85 } 86 } 87 return true 88 } 89 90 // IsFlashOnlyProp return true if this physical property is only allowed to generate flash related task 91 func (p *PhysicalProperty) IsFlashOnlyProp() bool { 92 return p.TaskTp == CopTiFlashLocalReadTaskType || p.TaskTp == CopTiFlashGlobalReadTaskType 93 } 94 95 // GetAllPossibleChildTaskTypes enumrates the possible types of tasks for children. 96 func (p *PhysicalProperty) GetAllPossibleChildTaskTypes() []TaskType { 97 if p.TaskTp == RootTaskType { 98 return wholeTaskTypes 99 } 100 // TODO: For CopSingleReadTaskType and CoFIDeloubleReadTaskType, this function should never be called 101 return []TaskType{p.TaskTp} 102 } 103 104 // IsPrefix checks whether the order property is the prefix of another. 105 func (p *PhysicalProperty) IsPrefix(prop *PhysicalProperty) bool { 106 if len(p.Items) > len(prop.Items) { 107 return false 108 } 109 for i := range p.Items { 110 if !p.Items[i].DefCaus.Equal(nil, prop.Items[i].DefCaus) || p.Items[i].Desc != prop.Items[i].Desc { 111 return false 112 } 113 } 114 return true 115 } 116 117 // IsEmpty checks whether the order property is empty. 118 func (p *PhysicalProperty) IsEmpty() bool { 119 return len(p.Items) == 0 120 } 121 122 // HashCode calculates hash code for a PhysicalProperty object. 123 func (p *PhysicalProperty) HashCode() []byte { 124 if p.hashcode != nil { 125 return p.hashcode 126 } 127 hashcodeSize := 8 + 8 + 8 + (16+8)*len(p.Items) + 8 128 p.hashcode = make([]byte, 0, hashcodeSize) 129 if p.Enforced { 130 p.hashcode = codec.EncodeInt(p.hashcode, 1) 131 } else { 132 p.hashcode = codec.EncodeInt(p.hashcode, 0) 133 } 134 p.hashcode = codec.EncodeInt(p.hashcode, int64(p.TaskTp)) 135 p.hashcode = codec.EncodeFloat(p.hashcode, p.ExpectedCnt) 136 for _, item := range p.Items { 137 p.hashcode = append(p.hashcode, item.DefCaus.HashCode(nil)...) 138 if item.Desc { 139 p.hashcode = codec.EncodeInt(p.hashcode, 1) 140 } else { 141 p.hashcode = codec.EncodeInt(p.hashcode, 0) 142 } 143 } 144 return p.hashcode 145 } 146 147 // String implements fmt.Stringer interface. Just for test. 148 func (p *PhysicalProperty) String() string { 149 return fmt.Sprintf("Prop{defcaus: %v, TaskTp: %s, expectedCount: %v}", p.Items, p.TaskTp, p.ExpectedCnt) 150 } 151 152 // Clone returns a copy of PhysicalProperty. Currently, this function is only used to build new 153 // required property for children plan in `exhaustPhysicalCausets`, so we don't copy `Enforced` field 154 // because if `Enforced` is true, the `Items` must be empty now, this makes `Enforced` meaningless 155 // for children nodes. 156 func (p *PhysicalProperty) Clone() *PhysicalProperty { 157 prop := &PhysicalProperty{ 158 Items: p.Items, 159 TaskTp: p.TaskTp, 160 ExpectedCnt: p.ExpectedCnt, 161 } 162 return prop 163 } 164 165 // AllSameOrder checks if all the items have same order. 166 func (p *PhysicalProperty) AllSameOrder() (bool, bool) { 167 if len(p.Items) == 0 { 168 return true, false 169 } 170 for i := 1; i < len(p.Items); i++ { 171 if p.Items[i].Desc != p.Items[i-1].Desc { 172 return false, false 173 } 174 } 175 return true, p.Items[0].Desc 176 }