/** * Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.linkedin.pinot.core.io.reader.impl; import java.io.Closeable; import java.io.IOException; import java.nio.charset.Charset; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.linkedin.pinot.core.segment.memory.PinotDataBuffer; /** * * Generic utility class to read data from file. The data file consists of rows * and columns. The number of columns are fixed. Each column can have either * single value or multiple values. There are two basic types of methods to read * the data <br> * 1. <TYPE> getType(int row, int col) this is used for single value column <br> * 2. int getTYPEArray(int row, int col, TYPE[] array). The caller has to create * and initialize the array. The implementation will fill up the array. The * caller is responsible to ensure that the array is big enough to fit all the * values. The return value tells the number of values.<br> * * */ public class FixedByteSingleValueMultiColReader implements Closeable { private static final Logger LOGGER = LoggerFactory.getLogger(FixedByteSingleValueMultiColReader.class); private final int rows; private final int[] colOffSets; private int rowSize; private PinotDataBuffer indexDataBuffer; private final int[] columnSizes; /** * * @param pinotDataBuffer * @param rows * @param columnSizes * in bytes * @throws IOException */ public FixedByteSingleValueMultiColReader(PinotDataBuffer pinotDataBuffer, int rows, int[] columnSizes) { this.rows = rows; this.columnSizes = columnSizes; colOffSets = new int[columnSizes.length]; rowSize = 0; for (int i = 0; i < columnSizes.length; i++) { colOffSets[i] = rowSize; rowSize += columnSizes[i]; } this.indexDataBuffer = pinotDataBuffer; } /** * Computes the offset where the actual column data can be read * * @param row * @param col * @return */ private int computeOffset(int row, int col) { final int offset = row * rowSize + colOffSets[col]; return offset; } /** * * @param row * @param col * @return */ public char getChar(int row, int col) { final int offset = computeOffset(row, col); return indexDataBuffer.getChar(offset); } /** * * @param row * @param col * @return */ public short getShort(int row, int col) { final int offset = computeOffset(row, col); return indexDataBuffer.getShort(offset); } /** * * @param row * @param col * @return */ public int getInt(int row, int col) { assert getColumnSizes()[col] == 4; final int offset = computeOffset(row, col); return indexDataBuffer.getInt(offset); } /** * * @param row * @param col * @return */ public long getLong(int row, int col) { assert getColumnSizes()[col] == 8; final int offset = computeOffset(row, col); return indexDataBuffer.getLong(offset); } /** * * @param row * @param col * @return */ public float getFloat(int row, int col) { assert getColumnSizes()[col] == 4; final int offset = computeOffset(row, col); return indexDataBuffer.getFloat(offset); } /** * Reads the double at row,col * * @param row * @param col * @return */ public double getDouble(int row, int col) { assert getColumnSizes()[col] == 8; final int offset = computeOffset(row, col); return indexDataBuffer.getDouble(offset); } /** * Returns the string value, NOTE: It expects all String values in the file * to be of same length * * @param row * @param col * @return */ public String getString(int row, int col) { return new String(getBytes(row, col), Charset.forName("UTF-8")); } /** * Generic method to read the raw bytes * * @param row * @param col * @return */ public byte[] getBytes(int row, int col) { final int length = getColumnSizes()[col]; final byte[] dst = new byte[length]; final int offset = computeOffset(row, col); // copy starting from offset into dst index 0 and length elements indexDataBuffer.copyTo(offset, dst, 0, length); return dst; } public int getNumberOfRows() { return rows; } public int[] getColumnSizes() { return columnSizes; } @Override public void close() { indexDataBuffer.close(); indexDataBuffer = null; } public boolean open() { return false; } public void readIntValues(int[] rows, int col, int startPos, int limit, int[] values, int outStartPos) { int endPos = startPos + limit; for (int iter = startPos; iter < endPos; iter++) { values[outStartPos++] = getInt(rows[iter], col); } } public void readLongValues(int[] rows, int col, int startPos, int limit, long[] values, int outStartPos) { int endPos = startPos + limit; for (int iter = startPos; iter < endPos; iter++) { values[outStartPos++] = getLong(rows[iter], col); } } public void readFloatValues(int[] rows, int col, int startPos, int limit, float[] values, int outStartPos) { int endPos = startPos + limit; for (int iter = startPos; iter < endPos; iter++) { values[outStartPos++] = getFloat(rows[iter], col); } } public void readDoubleValues(int[] rows, int col, int startPos, int limit, double[] values, int outStartPos) { int endPos = startPos + limit; for (int iter = startPos; iter < endPos; iter++) { values[outStartPos++] = getDouble(rows[iter], col); } } public void readStringValues(int[] rows, int col, int startPos, int limit, String[] values, int outStartPos) { int endPos = startPos + limit; for (int iter = startPos; iter < endPos; iter++) { values[outStartPos++] = getString(rows[iter], col); } } }