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  }