github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/rowcodec/row.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 rowcodec 15 16 import ( 17 "encoding/binary" 18 ) 19 20 // event is the struct type used to access the a event. 21 type event struct { 22 // small: defCausID []byte, offsets []uint16, optimized for most cases. 23 // large: defCausID []uint32, offsets []uint32. 24 large bool 25 numNotNullDefCauss uint16 26 numNullDefCauss uint16 27 defCausIDs []byte 28 29 offsets []uint16 30 data []byte 31 32 // for large event 33 defCausIDs32 []uint32 34 offsets32 []uint32 35 } 36 37 func (r *event) getData(i int) []byte { 38 var start, end uint32 39 if r.large { 40 if i > 0 { 41 start = r.offsets32[i-1] 42 } 43 end = r.offsets32[i] 44 } else { 45 if i > 0 { 46 start = uint32(r.offsets[i-1]) 47 } 48 end = uint32(r.offsets[i]) 49 } 50 return r.data[start:end] 51 } 52 53 func (r *event) fromBytes(rowData []byte) error { 54 if rowData[0] != CodecVer { 55 return errInvalidCodecVer 56 } 57 r.large = rowData[1]&1 > 0 58 r.numNotNullDefCauss = binary.LittleEndian.Uint16(rowData[2:]) 59 r.numNullDefCauss = binary.LittleEndian.Uint16(rowData[4:]) 60 cursor := 6 61 if r.large { 62 defCausIDsLen := int(r.numNotNullDefCauss+r.numNullDefCauss) * 4 63 r.defCausIDs32 = bytesToU32Slice(rowData[cursor : cursor+defCausIDsLen]) 64 cursor += defCausIDsLen 65 offsetsLen := int(r.numNotNullDefCauss) * 4 66 r.offsets32 = bytesToU32Slice(rowData[cursor : cursor+offsetsLen]) 67 cursor += offsetsLen 68 } else { 69 defCausIDsLen := int(r.numNotNullDefCauss + r.numNullDefCauss) 70 r.defCausIDs = rowData[cursor : cursor+defCausIDsLen] 71 cursor += defCausIDsLen 72 offsetsLen := int(r.numNotNullDefCauss) * 2 73 r.offsets = bytes2U16Slice(rowData[cursor : cursor+offsetsLen]) 74 cursor += offsetsLen 75 } 76 r.data = rowData[cursor:] 77 return nil 78 } 79 80 func (r *event) toBytes(buf []byte) []byte { 81 buf = append(buf, CodecVer) 82 flag := byte(0) 83 if r.large { 84 flag = 1 85 } 86 buf = append(buf, flag) 87 buf = append(buf, byte(r.numNotNullDefCauss), byte(r.numNotNullDefCauss>>8)) 88 buf = append(buf, byte(r.numNullDefCauss), byte(r.numNullDefCauss>>8)) 89 if r.large { 90 buf = append(buf, u32SliceToBytes(r.defCausIDs32)...) 91 buf = append(buf, u32SliceToBytes(r.offsets32)...) 92 } else { 93 buf = append(buf, r.defCausIDs...) 94 buf = append(buf, u16SliceToBytes(r.offsets)...) 95 } 96 buf = append(buf, r.data...) 97 return buf 98 } 99 100 func (r *event) findDefCausID(defCausID int64) (idx int, isNil, notFound bool) { 101 // Search the defCausumn in not-null defCausumns array. 102 i, j := 0, int(r.numNotNullDefCauss) 103 for i < j { 104 h := int(uint(i+j) >> 1) // avoid overflow when computing h 105 // i ≤ h < j 106 var v int64 107 if r.large { 108 v = int64(r.defCausIDs32[h]) 109 } else { 110 v = int64(r.defCausIDs[h]) 111 } 112 if v < defCausID { 113 i = h + 1 114 } else if v > defCausID { 115 j = h 116 } else { 117 idx = h 118 return 119 } 120 } 121 122 // Search the defCausumn in null defCausumns array. 123 i, j = int(r.numNotNullDefCauss), int(r.numNotNullDefCauss+r.numNullDefCauss) 124 for i < j { 125 h := int(uint(i+j) >> 1) // avoid overflow when computing h 126 // i ≤ h < j 127 var v int64 128 if r.large { 129 v = int64(r.defCausIDs32[h]) 130 } else { 131 v = int64(r.defCausIDs[h]) 132 } 133 if v < defCausID { 134 i = h + 1 135 } else if v > defCausID { 136 j = h 137 } else { 138 isNil = true 139 return 140 } 141 } 142 notFound = true 143 return 144 } 145 146 // DeferredCausetIsNull returns if the defCausumn value is null. Mainly used for count defCausumn aggregation. 147 // this method will used in entangledstore. 148 func (r *event) DeferredCausetIsNull(rowData []byte, defCausID int64, defaultVal []byte) (bool, error) { 149 err := r.fromBytes(rowData) 150 if err != nil { 151 return false, err 152 } 153 _, isNil, notFound := r.findDefCausID(defCausID) 154 if notFound { 155 return defaultVal == nil, nil 156 } 157 return isNil, nil 158 } 159 160 func (r *event) initDefCausIDs() { 161 numDefCauss := int(r.numNotNullDefCauss + r.numNullDefCauss) 162 if cap(r.defCausIDs) >= numDefCauss { 163 r.defCausIDs = r.defCausIDs[:numDefCauss] 164 } else { 165 r.defCausIDs = make([]byte, numDefCauss) 166 } 167 } 168 169 func (r *event) initDefCausIDs32() { 170 numDefCauss := int(r.numNotNullDefCauss + r.numNullDefCauss) 171 if cap(r.defCausIDs32) >= numDefCauss { 172 r.defCausIDs32 = r.defCausIDs32[:numDefCauss] 173 } else { 174 r.defCausIDs32 = make([]uint32, numDefCauss) 175 } 176 } 177 178 func (r *event) initOffsets() { 179 if cap(r.offsets) >= int(r.numNotNullDefCauss) { 180 r.offsets = r.offsets[:r.numNotNullDefCauss] 181 } else { 182 r.offsets = make([]uint16, r.numNotNullDefCauss) 183 } 184 } 185 186 func (r *event) initOffsets32() { 187 if cap(r.offsets32) >= int(r.numNotNullDefCauss) { 188 r.offsets32 = r.offsets32[:r.numNotNullDefCauss] 189 } else { 190 r.offsets32 = make([]uint32, r.numNotNullDefCauss) 191 } 192 }