github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/embedded/hashcode.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 embedded 15 16 import ( 17 "bytes" 18 "encoding/binary" 19 "sort" 20 21 "github.com/whtcorpsinc/milevadb/soliton/plancodec" 22 ) 23 24 func encodeIntAsUint32(result []byte, value int) []byte { 25 var buf [4]byte 26 binary.BigEndian.PutUint32(buf[:], uint32(value)) 27 return append(result, buf[:]...) 28 } 29 30 // HashCode implements LogicalCauset interface. 31 func (p *baseLogicalCauset) HashCode() []byte { 32 // We use CausetID for the default hash, so if two plans do not have 33 // the same id, the hash value will never be the same. 34 result := make([]byte, 0, 4) 35 result = encodeIntAsUint32(result, p.id) 36 return result 37 } 38 39 // HashCode implements LogicalCauset interface. 40 func (p *LogicalProjection) HashCode() []byte { 41 // CausetType + SelectOffset + ExprNum + [Exprs] 42 // Expressions are commonly `DeferredCauset`s, whose hashcode has the length 9, so 43 // we pre-alloc 10 bytes for each expr's hashcode. 44 result := make([]byte, 0, 12+len(p.Exprs)*10) 45 result = encodeIntAsUint32(result, plancodec.TypeStringToPhysicalID(p.tp)) 46 result = encodeIntAsUint32(result, p.SelectBlockOffset()) 47 result = encodeIntAsUint32(result, len(p.Exprs)) 48 for _, expr := range p.Exprs { 49 exprHashCode := expr.HashCode(p.ctx.GetStochastikVars().StmtCtx) 50 result = encodeIntAsUint32(result, len(exprHashCode)) 51 result = append(result, exprHashCode...) 52 } 53 return result 54 } 55 56 // HashCode implements LogicalCauset interface. 57 func (p *LogicalBlockDual) HashCode() []byte { 58 // CausetType + SelectOffset + RowCount 59 result := make([]byte, 0, 12) 60 result = encodeIntAsUint32(result, plancodec.TypeStringToPhysicalID(p.tp)) 61 result = encodeIntAsUint32(result, p.SelectBlockOffset()) 62 result = encodeIntAsUint32(result, p.RowCount) 63 return result 64 } 65 66 // HashCode implements LogicalCauset interface. 67 func (p *LogicalSelection) HashCode() []byte { 68 // CausetType + SelectOffset + ConditionNum + [Conditions] 69 // Conditions are commonly `ScalarFunction`s, whose hashcode usually has a 70 // length larger than 20, so we pre-alloc 25 bytes for each expr's hashcode. 71 result := make([]byte, 0, 12+len(p.Conditions)*25) 72 result = encodeIntAsUint32(result, plancodec.TypeStringToPhysicalID(p.tp)) 73 result = encodeIntAsUint32(result, p.SelectBlockOffset()) 74 result = encodeIntAsUint32(result, len(p.Conditions)) 75 76 condHashCodes := make([][]byte, len(p.Conditions)) 77 for i, expr := range p.Conditions { 78 condHashCodes[i] = expr.HashCode(p.ctx.GetStochastikVars().StmtCtx) 79 } 80 // Sort the conditions, so `a > 1 and a < 100` can equal to `a < 100 and a > 1`. 81 sort.Slice(condHashCodes, func(i, j int) bool { return bytes.Compare(condHashCodes[i], condHashCodes[j]) < 0 }) 82 83 for _, condHashCode := range condHashCodes { 84 result = encodeIntAsUint32(result, len(condHashCode)) 85 result = append(result, condHashCode...) 86 } 87 return result 88 } 89 90 // HashCode implements LogicalCauset interface. 91 func (p *LogicalLimit) HashCode() []byte { 92 // CausetType + SelectOffset + Offset + Count 93 result := make([]byte, 24) 94 binary.BigEndian.PutUint32(result, uint32(plancodec.TypeStringToPhysicalID(p.tp))) 95 binary.BigEndian.PutUint32(result[4:], uint32(p.SelectBlockOffset())) 96 binary.BigEndian.PutUint64(result[8:], p.Offset) 97 binary.BigEndian.PutUint64(result[16:], p.Count) 98 return result 99 }