| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.iotdb.tsfile.write.record; |
| |
| import org.apache.iotdb.tsfile.common.conf.TSFileConfig; |
| import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException; |
| import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; |
| import org.apache.iotdb.tsfile.utils.Binary; |
| import org.apache.iotdb.tsfile.utils.BitMap; |
| import org.apache.iotdb.tsfile.utils.BytesUtils; |
| import org.apache.iotdb.tsfile.utils.PublicBAOS; |
| import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils; |
| import org.apache.iotdb.tsfile.write.schema.MeasurementSchema; |
| |
| import java.io.DataOutputStream; |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| /** |
| * A tablet data of one device, the tablet contains multiple measurements of this device that share |
| * the same time column. |
| * |
| * <p>for example: device root.sg1.d1 |
| * |
| * <p>time, m1, m2, m3 1, 1, 2, 3 2, 1, 2, 3 3, 1, 2, 3 |
| * |
| * <p>Notice: The tablet should not have empty cell, please use BitMap to denote null value |
| */ |
| public class Tablet { |
| |
| private static final int DEFAULT_SIZE = 1024; |
| private static final String NOT_SUPPORT_DATATYPE = "Data type %s is not supported."; |
| |
| /** DeviceId of this {@link Tablet} */ |
| public String deviceId; |
| |
| /** The list of {@link MeasurementSchema}s for creating the {@link Tablet} */ |
| private List<MeasurementSchema> schemas; |
| |
| /** MeasurementId->indexOf({@link MeasurementSchema}) */ |
| private final Map<String, Integer> measurementIndex; |
| |
| /** Timestamps in this {@link Tablet} */ |
| public long[] timestamps; |
| /** Each object is a primitive type array, which represents values of one measurement */ |
| public Object[] values; |
| /** Each {@link BitMap} represents the existence of each value in the current column. */ |
| public BitMap[] bitMaps; |
| /** The number of rows to include in this {@link Tablet} */ |
| public int rowSize; |
| /** The maximum number of rows for this {@link Tablet} */ |
| private final int maxRowNumber; |
| |
| /** |
| * Return a {@link Tablet} with default specified row number. This is the standard constructor |
| * (all Tablet should be the same size). |
| * |
| * @param deviceId the name of the device specified to be written in |
| * @param schemas the list of {@link MeasurementSchema}s for creating the tablet, only |
| * measurementId and type take effects |
| */ |
| public Tablet(String deviceId, List<MeasurementSchema> schemas) { |
| this(deviceId, schemas, DEFAULT_SIZE); |
| } |
| |
| /** |
| * Return a {@link Tablet} with the specified number of rows (maxBatchSize). Only call this |
| * constructor directly for testing purposes. {@link Tablet} should normally always be default |
| * size. |
| * |
| * @param deviceId the name of the device specified to be written in |
| * @param schemas the list of {@link MeasurementSchema}s for creating the row batch, only |
| * measurementId and type take effects |
| * @param maxRowNumber the maximum number of rows for this tablet |
| */ |
| public Tablet(String deviceId, List<MeasurementSchema> schemas, int maxRowNumber) { |
| this.deviceId = deviceId; |
| this.schemas = new ArrayList<>(schemas); |
| this.maxRowNumber = maxRowNumber; |
| measurementIndex = new HashMap<>(); |
| constructMeasurementIndexMap(); |
| |
| createColumns(); |
| |
| reset(); |
| } |
| |
| /** |
| * Return a {@link Tablet} with specified timestamps and values. Only call this constructor |
| * directly for Trigger. |
| * |
| * @param deviceId the name of the device specified to be written in |
| * @param schemas the list of {@link MeasurementSchema}s for creating the row batch, only |
| * measurementId and type take effects |
| * @param timestamps given timestamps |
| * @param values given values |
| * @param bitMaps given {@link BitMap}s |
| * @param maxRowNumber the maximum number of rows for this {@link Tablet} |
| */ |
| public Tablet( |
| String deviceId, |
| List<MeasurementSchema> schemas, |
| long[] timestamps, |
| Object[] values, |
| BitMap[] bitMaps, |
| int maxRowNumber) { |
| this.deviceId = deviceId; |
| this.schemas = schemas; |
| this.timestamps = timestamps; |
| this.values = values; |
| this.bitMaps = bitMaps; |
| this.maxRowNumber = maxRowNumber; |
| // rowSize == maxRowNumber in this case |
| this.rowSize = maxRowNumber; |
| measurementIndex = new HashMap<>(); |
| constructMeasurementIndexMap(); |
| } |
| |
| private void constructMeasurementIndexMap() { |
| int indexInSchema = 0; |
| for (MeasurementSchema schema : schemas) { |
| measurementIndex.put(schema.getMeasurementId(), indexInSchema); |
| indexInSchema++; |
| } |
| } |
| |
| public void setDeviceId(String deviceId) { |
| this.deviceId = deviceId; |
| } |
| |
| public void setSchemas(List<MeasurementSchema> schemas) { |
| this.schemas = schemas; |
| } |
| |
| public void initBitMaps() { |
| this.bitMaps = new BitMap[schemas.size()]; |
| for (int column = 0; column < schemas.size(); column++) { |
| this.bitMaps[column] = new BitMap(getMaxRowNumber()); |
| } |
| } |
| |
| public void addTimestamp(int rowIndex, long timestamp) { |
| timestamps[rowIndex] = timestamp; |
| } |
| |
| public void addValue(String measurementId, int rowIndex, Object value) { |
| int indexOfSchema = measurementIndex.get(measurementId); |
| MeasurementSchema measurementSchema = schemas.get(indexOfSchema); |
| addValueOfDataType(measurementSchema.getType(), rowIndex, indexOfSchema, value); |
| } |
| |
| private void addValueOfDataType( |
| TSDataType dataType, int rowIndex, int indexOfSchema, Object value) { |
| |
| if (value == null) { |
| // Init the bitMap to mark null value |
| if (bitMaps == null) { |
| bitMaps = new BitMap[values.length]; |
| } |
| if (bitMaps[indexOfSchema] == null) { |
| bitMaps[indexOfSchema] = new BitMap(maxRowNumber); |
| } |
| // Mark the null value position |
| bitMaps[indexOfSchema].mark(rowIndex); |
| } |
| switch (dataType) { |
| case TEXT: |
| { |
| Binary[] sensor = (Binary[]) values[indexOfSchema]; |
| if (value instanceof Binary) { |
| sensor[rowIndex] = (Binary) value; |
| } else { |
| sensor[rowIndex] = |
| value != null |
| ? new Binary((String) value, TSFileConfig.STRING_CHARSET) |
| : Binary.EMPTY_VALUE; |
| } |
| break; |
| } |
| case FLOAT: |
| { |
| float[] sensor = (float[]) values[indexOfSchema]; |
| sensor[rowIndex] = value != null ? (float) value : Float.MIN_VALUE; |
| break; |
| } |
| case INT32: |
| { |
| int[] sensor = (int[]) values[indexOfSchema]; |
| sensor[rowIndex] = value != null ? (int) value : Integer.MIN_VALUE; |
| break; |
| } |
| case INT64: |
| { |
| long[] sensor = (long[]) values[indexOfSchema]; |
| sensor[rowIndex] = value != null ? (long) value : Long.MIN_VALUE; |
| break; |
| } |
| case DOUBLE: |
| { |
| double[] sensor = (double[]) values[indexOfSchema]; |
| sensor[rowIndex] = value != null ? (double) value : Double.MIN_VALUE; |
| break; |
| } |
| case BOOLEAN: |
| { |
| boolean[] sensor = (boolean[]) values[indexOfSchema]; |
| sensor[rowIndex] = value != null && (boolean) value; |
| break; |
| } |
| default: |
| throw new UnSupportedDataTypeException(String.format(NOT_SUPPORT_DATATYPE, dataType)); |
| } |
| } |
| |
| public List<MeasurementSchema> getSchemas() { |
| return schemas; |
| } |
| |
| /** Return the maximum number of rows for this tablet */ |
| public int getMaxRowNumber() { |
| return maxRowNumber; |
| } |
| |
| /** Reset Tablet to the default state - set the rowSize to 0 and reset bitMaps */ |
| public void reset() { |
| rowSize = 0; |
| if (bitMaps != null) { |
| for (BitMap bitMap : bitMaps) { |
| if (bitMap != null) { |
| bitMap.reset(); |
| } |
| } |
| } |
| } |
| |
| private void createColumns() { |
| // create timestamp column |
| timestamps = new long[maxRowNumber]; |
| |
| // calculate total value column size |
| int valueColumnsSize = schemas.size(); |
| |
| // value column |
| values = new Object[valueColumnsSize]; |
| int columnIndex = 0; |
| for (MeasurementSchema schema : schemas) { |
| TSDataType dataType = schema.getType(); |
| values[columnIndex] = createValueColumnOfDataType(dataType); |
| columnIndex++; |
| } |
| } |
| |
| private Object createValueColumnOfDataType(TSDataType dataType) { |
| |
| Object valueColumn; |
| switch (dataType) { |
| case INT32: |
| valueColumn = new int[maxRowNumber]; |
| break; |
| case INT64: |
| valueColumn = new long[maxRowNumber]; |
| break; |
| case FLOAT: |
| valueColumn = new float[maxRowNumber]; |
| break; |
| case DOUBLE: |
| valueColumn = new double[maxRowNumber]; |
| break; |
| case BOOLEAN: |
| valueColumn = new boolean[maxRowNumber]; |
| break; |
| case TEXT: |
| valueColumn = new Binary[maxRowNumber]; |
| break; |
| default: |
| throw new UnSupportedDataTypeException(String.format(NOT_SUPPORT_DATATYPE, dataType)); |
| } |
| return valueColumn; |
| } |
| |
| public int getTimeBytesSize() { |
| return rowSize * 8; |
| } |
| |
| /** @return Total bytes of values */ |
| public int getTotalValueOccupation() { |
| int valueOccupation = 0; |
| int columnIndex = 0; |
| for (MeasurementSchema schema : schemas) { |
| valueOccupation += calOccupationOfOneColumn(schema.getType(), columnIndex); |
| columnIndex++; |
| } |
| // Add bitmap size if the tablet has bitMaps |
| if (bitMaps != null) { |
| for (BitMap bitMap : bitMaps) { |
| // Marker byte |
| valueOccupation++; |
| if (bitMap != null && !bitMap.isAllUnmarked()) { |
| valueOccupation += rowSize / Byte.SIZE + 1; |
| } |
| } |
| } |
| return valueOccupation; |
| } |
| |
| private int calOccupationOfOneColumn(TSDataType dataType, int columnIndex) { |
| int valueOccupation = 0; |
| switch (dataType) { |
| case BOOLEAN: |
| valueOccupation += rowSize; |
| break; |
| case INT32: |
| case FLOAT: |
| valueOccupation += rowSize * 4; |
| break; |
| case INT64: |
| case DOUBLE: |
| valueOccupation += rowSize * 8; |
| break; |
| case TEXT: |
| valueOccupation += rowSize * 4; |
| Binary[] binaries = (Binary[]) values[columnIndex]; |
| for (int rowIndex = 0; rowIndex < rowSize; rowIndex++) { |
| valueOccupation += binaries[rowIndex].getLength(); |
| } |
| break; |
| default: |
| throw new UnSupportedDataTypeException(String.format(NOT_SUPPORT_DATATYPE, dataType)); |
| } |
| return valueOccupation; |
| } |
| |
| /** Serialize {@link Tablet} */ |
| public ByteBuffer serialize() throws IOException { |
| try (PublicBAOS byteArrayOutputStream = new PublicBAOS(); |
| DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream)) { |
| serialize(outputStream); |
| return ByteBuffer.wrap(byteArrayOutputStream.getBuf(), 0, byteArrayOutputStream.size()); |
| } |
| } |
| |
| public void serialize(DataOutputStream stream) throws IOException { |
| ReadWriteIOUtils.write(deviceId, stream); |
| ReadWriteIOUtils.write(rowSize, stream); |
| writeMeasurementSchemas(stream); |
| writeTimes(stream); |
| writeBitMaps(stream); |
| writeValues(stream); |
| } |
| |
| /** Serialize {@link MeasurementSchema}s */ |
| private void writeMeasurementSchemas(DataOutputStream stream) throws IOException { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(schemas != null), stream); |
| if (schemas != null) { |
| ReadWriteIOUtils.write(schemas.size(), stream); |
| for (MeasurementSchema schema : schemas) { |
| if (schema == null) { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(false), stream); |
| } else { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(true), stream); |
| schema.serializeTo(stream); |
| } |
| } |
| } |
| } |
| |
| private void writeTimes(DataOutputStream stream) throws IOException { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(timestamps != null), stream); |
| if (timestamps != null) { |
| for (int i = 0; i < rowSize; i++) { |
| ReadWriteIOUtils.write(timestamps[i], stream); |
| } |
| } |
| } |
| |
| /** Serialize {@link BitMap}s */ |
| private void writeBitMaps(DataOutputStream stream) throws IOException { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(bitMaps != null), stream); |
| if (bitMaps != null) { |
| int size = (schemas == null ? 0 : schemas.size()); |
| for (int i = 0; i < size; i++) { |
| if (bitMaps[i] == null) { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(false), stream); |
| } else { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(true), stream); |
| ReadWriteIOUtils.write(bitMaps[i].getSize(), stream); |
| ReadWriteIOUtils.write(new Binary(bitMaps[i].getByteArray()), stream); |
| } |
| } |
| } |
| } |
| |
| /** Serialize values */ |
| private void writeValues(DataOutputStream stream) throws IOException { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(values != null), stream); |
| if (values != null) { |
| int size = (schemas == null ? 0 : schemas.size()); |
| for (int i = 0; i < size; i++) { |
| serializeColumn(schemas.get(i).getType(), values[i], stream); |
| } |
| } |
| } |
| |
| private void serializeColumn(TSDataType dataType, Object column, DataOutputStream stream) |
| throws IOException { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(column != null), stream); |
| |
| if (column != null) { |
| switch (dataType) { |
| case INT32: |
| int[] intValues = (int[]) column; |
| for (int j = 0; j < rowSize; j++) { |
| ReadWriteIOUtils.write(intValues[j], stream); |
| } |
| break; |
| case INT64: |
| long[] longValues = (long[]) column; |
| for (int j = 0; j < rowSize; j++) { |
| ReadWriteIOUtils.write(longValues[j], stream); |
| } |
| break; |
| case FLOAT: |
| float[] floatValues = (float[]) column; |
| for (int j = 0; j < rowSize; j++) { |
| ReadWriteIOUtils.write(floatValues[j], stream); |
| } |
| break; |
| case DOUBLE: |
| double[] doubleValues = (double[]) column; |
| for (int j = 0; j < rowSize; j++) { |
| ReadWriteIOUtils.write(doubleValues[j], stream); |
| } |
| break; |
| case BOOLEAN: |
| boolean[] boolValues = (boolean[]) column; |
| for (int j = 0; j < rowSize; j++) { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(boolValues[j]), stream); |
| } |
| break; |
| case TEXT: |
| Binary[] binaryValues = (Binary[]) column; |
| for (int j = 0; j < rowSize; j++) { |
| ReadWriteIOUtils.write(BytesUtils.boolToByte(binaryValues[j] != null), stream); |
| if (binaryValues[j] != null) { |
| ReadWriteIOUtils.write(binaryValues[j], stream); |
| } |
| } |
| break; |
| default: |
| throw new UnSupportedDataTypeException( |
| String.format("Data type %s is not supported.", dataType)); |
| } |
| } |
| } |
| |
| /** Deserialize Tablet */ |
| public static Tablet deserialize(ByteBuffer byteBuffer) { |
| String deviceId = ReadWriteIOUtils.readString(byteBuffer); |
| int rowSize = ReadWriteIOUtils.readInt(byteBuffer); |
| |
| // deserialize schemas |
| int schemaSize = 0; |
| List<MeasurementSchema> schemas = new ArrayList<>(); |
| boolean isSchemasNotNull = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(byteBuffer)); |
| if (isSchemasNotNull) { |
| schemaSize = ReadWriteIOUtils.readInt(byteBuffer); |
| for (int i = 0; i < schemaSize; i++) { |
| boolean hasSchema = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(byteBuffer)); |
| if (hasSchema) { |
| schemas.add(MeasurementSchema.deserializeFrom(byteBuffer)); |
| } |
| } |
| } |
| |
| // deserialize times |
| long[] times = new long[rowSize]; |
| boolean isTimesNotNull = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(byteBuffer)); |
| if (isTimesNotNull) { |
| for (int i = 0; i < rowSize; i++) { |
| times[i] = ReadWriteIOUtils.readLong(byteBuffer); |
| } |
| } |
| |
| // deserialize bitmaps |
| BitMap[] bitMaps = new BitMap[schemaSize]; |
| boolean isBitMapsNotNull = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(byteBuffer)); |
| if (isBitMapsNotNull) { |
| bitMaps = readBitMapsFromBuffer(byteBuffer, schemaSize); |
| } |
| |
| // deserialize values |
| TSDataType[] dataTypes = |
| schemas.stream().map(MeasurementSchema::getType).toArray(TSDataType[]::new); |
| Object[] values = new Object[schemaSize]; |
| boolean isValuesNotNull = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(byteBuffer)); |
| if (isValuesNotNull) { |
| values = readTabletValuesFromBuffer(byteBuffer, dataTypes, schemaSize, rowSize); |
| } |
| |
| Tablet tablet = new Tablet(deviceId, schemas, times, values, bitMaps, rowSize); |
| tablet.constructMeasurementIndexMap(); |
| return tablet; |
| } |
| |
| /** deserialize bitmaps */ |
| public static BitMap[] readBitMapsFromBuffer(ByteBuffer byteBuffer, int columns) { |
| BitMap[] bitMaps = new BitMap[columns]; |
| for (int i = 0; i < columns; i++) { |
| boolean hasBitMap = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(byteBuffer)); |
| if (hasBitMap) { |
| final int size = ReadWriteIOUtils.readInt(byteBuffer); |
| final Binary valueBinary = ReadWriteIOUtils.readBinary(byteBuffer); |
| bitMaps[i] = new BitMap(size, valueBinary.getValues()); |
| } |
| } |
| return bitMaps; |
| } |
| |
| /** |
| * @param byteBuffer data values |
| * @param columns column number |
| */ |
| @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning |
| public static Object[] readTabletValuesFromBuffer( |
| ByteBuffer byteBuffer, TSDataType[] types, int columns, int rowSize) { |
| Object[] values = new Object[columns]; |
| for (int i = 0; i < columns; i++) { |
| boolean isValueColumnsNotNull = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(byteBuffer)); |
| |
| if (isValueColumnsNotNull) { |
| switch (types[i]) { |
| case BOOLEAN: |
| boolean[] boolValues = new boolean[rowSize]; |
| for (int index = 0; index < rowSize; index++) { |
| boolValues[index] = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(byteBuffer)); |
| } |
| values[i] = boolValues; |
| break; |
| case INT32: |
| int[] intValues = new int[rowSize]; |
| for (int index = 0; index < rowSize; index++) { |
| intValues[index] = ReadWriteIOUtils.readInt(byteBuffer); |
| } |
| values[i] = intValues; |
| break; |
| case INT64: |
| long[] longValues = new long[rowSize]; |
| for (int index = 0; index < rowSize; index++) { |
| longValues[index] = ReadWriteIOUtils.readLong(byteBuffer); |
| } |
| values[i] = longValues; |
| break; |
| case FLOAT: |
| float[] floatValues = new float[rowSize]; |
| for (int index = 0; index < rowSize; index++) { |
| floatValues[index] = ReadWriteIOUtils.readFloat(byteBuffer); |
| } |
| values[i] = floatValues; |
| break; |
| case DOUBLE: |
| double[] doubleValues = new double[rowSize]; |
| for (int index = 0; index < rowSize; index++) { |
| doubleValues[index] = ReadWriteIOUtils.readDouble(byteBuffer); |
| } |
| values[i] = doubleValues; |
| break; |
| case TEXT: |
| Binary[] binaryValues = new Binary[rowSize]; |
| for (int index = 0; index < rowSize; index++) { |
| boolean isNotNull = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(byteBuffer)); |
| if (isNotNull) { |
| binaryValues[index] = ReadWriteIOUtils.readBinary(byteBuffer); |
| } else { |
| binaryValues[index] = Binary.EMPTY_VALUE; |
| } |
| } |
| values[i] = binaryValues; |
| break; |
| default: |
| throw new UnSupportedDataTypeException( |
| String.format( |
| "data type %s is not supported when convert data at client", types[i])); |
| } |
| } |
| } |
| return values; |
| } |
| |
| /** |
| * Note that the function will judge 2 {@link Tablet}s to be equal when their contents are logically the |
| * same. Namely, a {@link Tablet} with {@link BitMap} "null" may be equal to another {@link Tablet} with 3 columns and |
| * {@link BitMap "[null, null, null]", and a {@link Tablet} with rowSize 2 is judged identical to other {@link Tablet}s |
| * regardless of any timeStamps with indexes larger than or equal to 2. |
| * |
| * @param o the tablet to compare |
| * @return {@code true} if the tablets are logically equal |
| */ |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) { |
| return true; |
| } |
| if (o == null || !getClass().equals(o.getClass())) { |
| return false; |
| } |
| Tablet that = (Tablet) o; |
| |
| boolean flag = |
| that.rowSize == rowSize |
| && Objects.equals(that.deviceId, deviceId) |
| && Objects.equals(that.schemas, schemas) |
| && Objects.equals(that.measurementIndex, measurementIndex); |
| if (!flag) { |
| return false; |
| } |
| |
| // assert timestamps and bitmaps |
| int columns = (schemas == null ? 0 : schemas.size()); |
| if (!isTimestampsEqual(this.timestamps, that.timestamps, rowSize) |
| || !isBitMapsEqual(this.bitMaps, that.bitMaps, columns)) { |
| return false; |
| } |
| |
| // assert values |
| Object[] thatValues = that.values; |
| if (thatValues == values) { |
| return true; |
| } |
| if (thatValues == null || values == null) { |
| return false; |
| } |
| if (thatValues.length != values.length) { |
| return false; |
| } |
| for (int i = 0, n = values.length; i < n; i++) { |
| if (thatValues[i] == values[i]) { |
| continue; |
| } |
| if (thatValues[i] == null || values[i] == null) { |
| return false; |
| } |
| if (!thatValues[i].getClass().equals(values[i].getClass())) { |
| return false; |
| } |
| |
| switch (schemas.get(i).getType()) { |
| case INT32: |
| int[] thisIntValues = (int[]) values[i]; |
| int[] thatIntValues = (int[]) thatValues[i]; |
| if (thisIntValues.length < rowSize || thatIntValues.length < rowSize) { |
| return false; |
| } |
| for (int j = 0; j < rowSize; j++) { |
| if (thisIntValues[j] != thatIntValues[j]) { |
| return false; |
| } |
| } |
| break; |
| case INT64: |
| long[] thisLongValues = (long[]) values[i]; |
| long[] thatLongValues = (long[]) thatValues[i]; |
| if (thisLongValues.length < rowSize || thatLongValues.length < rowSize) { |
| return false; |
| } |
| for (int j = 0; j < rowSize; j++) { |
| if (thisLongValues[j] != thatLongValues[j]) { |
| return false; |
| } |
| } |
| break; |
| case FLOAT: |
| float[] thisFloatValues = (float[]) values[i]; |
| float[] thatFloatValues = (float[]) thatValues[i]; |
| if (thisFloatValues.length < rowSize || thatFloatValues.length < rowSize) { |
| return false; |
| } |
| for (int j = 0; j < rowSize; j++) { |
| if (thisFloatValues[j] != thatFloatValues[j]) { |
| return false; |
| } |
| } |
| break; |
| case DOUBLE: |
| double[] thisDoubleValues = (double[]) values[i]; |
| double[] thatDoubleValues = (double[]) thatValues[i]; |
| if (thisDoubleValues.length < rowSize || thatDoubleValues.length < rowSize) { |
| return false; |
| } |
| for (int j = 0; j < rowSize; j++) { |
| if (thisDoubleValues[j] != thatDoubleValues[j]) { |
| return false; |
| } |
| } |
| break; |
| case BOOLEAN: |
| boolean[] thisBooleanValues = (boolean[]) values[i]; |
| boolean[] thatBooleanValues = (boolean[]) thatValues[i]; |
| if (thisBooleanValues.length < rowSize || thatBooleanValues.length < rowSize) { |
| return false; |
| } |
| for (int j = 0; j < rowSize; j++) { |
| if (thisBooleanValues[j] != thatBooleanValues[j]) { |
| return false; |
| } |
| } |
| break; |
| case TEXT: |
| Binary[] thisBinaryValues = (Binary[]) values[i]; |
| Binary[] thatBinaryValues = (Binary[]) thatValues[i]; |
| if (thisBinaryValues.length < rowSize || thatBinaryValues.length < rowSize) { |
| return false; |
| } |
| for (int j = 0; j < rowSize; j++) { |
| if (!thisBinaryValues[j].equals(thatBinaryValues[j])) { |
| return false; |
| } |
| } |
| break; |
| default: |
| throw new UnSupportedDataTypeException( |
| String.format("Data type %s is not supported.", schemas.get(i).getType())); |
| } |
| } |
| |
| return true; |
| } |
| |
| private boolean isTimestampsEqual(long[] thisTimestamps, long[] thatTimestamps, int rowSize) { |
| if (thisTimestamps == thatTimestamps) { |
| return true; |
| } |
| if (thisTimestamps == null || thatTimestamps == null) { |
| return false; |
| } |
| |
| for (int i = 0; i < rowSize; i++) { |
| if (thisTimestamps[i] != thatTimestamps[i]) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private boolean isBitMapsEqual(BitMap[] thisBitMaps, BitMap[] thatBitMaps, int columns) { |
| if (thisBitMaps == thatBitMaps) { |
| return true; |
| } |
| if (thisBitMaps == null) { |
| for (int i = 0; i < columns; i++) { |
| if (thatBitMaps[i] != null && !thatBitMaps[i].isAllMarked()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| if (thatBitMaps == null) { |
| for (int i = 0; i < columns; i++) { |
| if (thisBitMaps[i] != null && !thisBitMaps[i].isAllMarked()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| for (int i = 0; i < columns; i++) { |
| if (!thisBitMaps[i].equals(thatBitMaps[i])) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |