github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/memstore/common/upsert_batch_header.go (about) 1 // Copyright (c) 2017-2018 Uber Technologies, 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package common 16 17 import ( 18 "github.com/uber/aresdb/utils" 19 ) 20 21 // ColumnHeaderSizeV0 22 // TODO: deprecated, remove after functional test updated 23 func ColumnHeaderSizeV0(numCols int) int { 24 // offset (4 bytes), data_type (4 bytes), column_id (2 bytes), column mode (1 byte) 25 return (numCols+1)*4 + numCols*4 + numCols*2 + numCols 26 } 27 28 // NewUpsertBatchHeaderV0 29 // TODO: deprecated, remove after functional test updated 30 func NewUpsertBatchHeaderV0(buffer []byte, numCols int) UpsertBatchHeader { 31 offset := 0 32 // Offset vector is of size numCols + 1. 33 offsetVector := buffer[0 : (numCols+1)*4] 34 offset += len(offsetVector) 35 typeVector := buffer[offset : offset+numCols*4] 36 offset += len(typeVector) 37 idVector := buffer[offset : offset+numCols*2] 38 offset += len(idVector) 39 modeVector := buffer[offset : offset+numCols] 40 41 return UpsertBatchHeader{ 42 offsetVector: offsetVector, 43 typeVector: typeVector, 44 idVector: idVector, 45 modeVector: modeVector, 46 } 47 } 48 49 // ColumnHeaderSize returns the total size of the column headers. 50 func ColumnHeaderSize(numCols int) int { 51 return (numCols+1)*4 + // offset (4 bytes) 52 numCols*4 + // enum dict length (4 bytes) 53 numCols*4 + // reserved (4 bytes) 54 numCols*4 + // data_type (4 bytes) 55 numCols*2 + // column_id (2 bytes) 56 numCols // column mode (1 byte) 57 } 58 59 // UpsertBatchHeader is a helper class used by upsert batch reader and writer to access the column 60 // header info. 61 type UpsertBatchHeader struct { 62 offsetVector []byte 63 enumDictLength []byte 64 typeVector []byte 65 idVector []byte 66 modeVector []byte 67 } 68 69 // NewUpsertBatchHeader create upsert batch header from buffer 70 func NewUpsertBatchHeader(buffer []byte, numCols int) UpsertBatchHeader { 71 offset := 0 72 // Offset vector is of size numCols + 1. 73 offsetVector := buffer[offset : offset+(numCols+1)*4] 74 offset += len(offsetVector) 75 76 enumDictLength := buffer[offset : offset+numCols*4] 77 offset += len(enumDictLength) + 78 numCols*4 // reserved extra space 79 80 typeVector := buffer[offset : offset+numCols*4] 81 offset += len(typeVector) 82 83 idVector := buffer[offset : offset+numCols*2] 84 offset += len(idVector) 85 86 modeVector := buffer[offset : offset+numCols] 87 88 return UpsertBatchHeader{ 89 offsetVector: offsetVector, 90 enumDictLength: enumDictLength, 91 typeVector: typeVector, 92 idVector: idVector, 93 modeVector: modeVector, 94 } 95 } 96 97 // WriteColumnOffset writes the offset of a column. It can take col index from 0 to numCols + 1. 98 func (u *UpsertBatchHeader) WriteColumnOffset(value int, col int) error { 99 writer := utils.NewBufferWriter(u.offsetVector) 100 err := writer.WriteUint32(uint32(value), col*4) 101 if err != nil { 102 return utils.StackError(err, "Failed to write start offset for column %d", col) 103 } 104 return nil 105 } 106 107 // WriteEnumDictLength writes the offset of a column. It can take col index from 0 to numCols - 1. 108 func (u *UpsertBatchHeader) WriteEnumDictLength(value int, col int) error { 109 writer := utils.NewBufferWriter(u.enumDictLength) 110 err := writer.WriteUint32(uint32(value), col*4) 111 if err != nil { 112 return utils.StackError(err, "Failed to write enum dict length for column %d", col) 113 } 114 return nil 115 } 116 117 // WriteColumnType writes the type of a column. 118 func (u *UpsertBatchHeader) WriteColumnType(value DataType, col int) error { 119 writer := utils.NewBufferWriter(u.typeVector) 120 err := writer.WriteUint32(uint32(value), col*4) 121 if err != nil { 122 return utils.StackError(err, "Failed to write type for column %d", col) 123 } 124 return nil 125 } 126 127 // WriteColumnID writes the id of a column. 128 func (u *UpsertBatchHeader) WriteColumnID(value int, col int) error { 129 writer := utils.NewBufferWriter(u.idVector) 130 err := writer.WriteUint16(uint16(value), col*2) 131 if err != nil { 132 return utils.StackError(err, "Failed to write id for column %d", col) 133 } 134 return nil 135 } 136 137 // WriteColumnFlag writes the mode of a column. 138 func (u *UpsertBatchHeader) WriteColumnFlag(columnMode ColumnMode, columnUpdateMode ColumnUpdateMode, col int) error { 139 value := uint8(columnMode&0x07) | uint8((columnUpdateMode&0x07)<<3) 140 writer := utils.NewBufferWriter(u.modeVector) 141 err := writer.WriteUint8(value, col) 142 if err != nil { 143 return utils.StackError(err, "Failed to write mode for column %d", col) 144 } 145 return nil 146 } 147 148 // ReadColumnOffset takes col index from 0 to numCols + 1 and returns the value stored. 149 func (u UpsertBatchHeader) ReadColumnOffset(col int) (int, error) { 150 result, err := utils.NewBufferReader(u.offsetVector).ReadUint32(col * 4) 151 if err != nil { 152 return 0, err 153 } 154 return int(result), err 155 } 156 157 // ReadEnumDictLength takes col index from 0 to numCols - 1 and returns the value stored. 158 func (u UpsertBatchHeader) ReadEnumDictLength(col int) (int, error) { 159 result, err := utils.NewBufferReader(u.enumDictLength).ReadUint32(col * 4) 160 if err != nil { 161 return 0, err 162 } 163 return int(result), err 164 } 165 166 // ReadColumnType returns the type for a column. 167 func (u UpsertBatchHeader) ReadColumnType(col int) (DataType, error) { 168 result, err := utils.NewBufferReader(u.typeVector).ReadUint32(col * 4) 169 if err != nil { 170 return Unknown, err 171 } 172 columnDataType, err := NewDataType(result) 173 if err != nil { 174 return Unknown, utils.StackError(err, "Unsupported data type %#x for col %d", result, col) 175 } 176 return columnDataType, nil 177 } 178 179 // ReadColumnID returns the logical ID for a column. 180 func (u UpsertBatchHeader) ReadColumnID(col int) (int, error) { 181 result, err := utils.NewBufferReader(u.idVector).ReadUint16(col * 2) 182 if err != nil { 183 return 0, err 184 } 185 return int(result), err 186 } 187 188 // ReadColumnFlag returns the mode for a column. 189 func (u UpsertBatchHeader) ReadColumnFlag(col int) (ColumnMode, ColumnUpdateMode, error) { 190 result, err := utils.NewBufferReader(u.modeVector).ReadUint8(col) 191 if err != nil { 192 return 0, 0, err 193 } 194 columnMode := ColumnMode(result & 0x0007) 195 columnUpdateMode := ColumnUpdateMode((result >> 3) & 0x0007) 196 if columnMode >= MaxColumnMode { 197 return columnMode, columnUpdateMode, utils.StackError(err, "Invalid column mode %d", columnMode) 198 } else if columnUpdateMode >= MaxColumnUpdateMode { 199 return columnMode, columnUpdateMode, utils.StackError(err, "Invalid column update mode %d", columnUpdateMode) 200 } 201 return columnMode, columnUpdateMode, nil 202 }