Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* 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.db.it.performance;

import org.apache.iotdb.isession.ISession;
import org.apache.iotdb.it.env.EnvFactory;
import org.apache.iotdb.it.framework.IoTDBTestRunner;
import org.apache.iotdb.itbase.category.LocalStandaloneIT;

import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.utils.BitMap;
import org.apache.tsfile.write.record.Tablet;
import org.apache.tsfile.write.schema.IMeasurementSchema;
import org.apache.tsfile.write.schema.MeasurementSchema;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@RunWith(IoTDBTestRunner.class)
@Category({LocalStandaloneIT.class})
public class IoTDBAlignedTVListBitMapPerformanceIT {

private static final Logger LOGGER =
LoggerFactory.getLogger(IoTDBAlignedTVListBitMapPerformanceIT.class);

private static final String ENABLED_PROPERTY = "iotdb.aligned.bitmap.perf.enabled";
private static final String MEASUREMENT_COUNT_PROPERTY =
"iotdb.aligned.bitmap.perf.measurement.count";
private static final String WARMUP_BATCH_COUNT_PROPERTY =
"iotdb.aligned.bitmap.perf.warmup.batch.count";
private static final String BATCH_COUNT_PROPERTY = "iotdb.aligned.bitmap.perf.batch.count";
private static final String ROUND_COUNT_PROPERTY = "iotdb.aligned.bitmap.perf.round.count";

private static final int ROWS_PER_BATCH = 64;
private static final int MEASUREMENT_COUNT = Integer.getInteger(MEASUREMENT_COUNT_PROPERTY, 256);
private static final int WARMUP_BATCH_COUNT = Integer.getInteger(WARMUP_BATCH_COUNT_PROPERTY, 50);
private static final int BATCH_COUNT = Integer.getInteger(BATCH_COUNT_PROPERTY, 100);
private static final int ROUND_COUNT = Integer.getInteger(ROUND_COUNT_PROPERTY, 5);
private static final String DEVICE = "root.aligned_bitmap_performance.d1";

@BeforeClass
public static void setUp() throws Exception {
Assume.assumeTrue(Boolean.getBoolean(ENABLED_PROPERTY));
EnvFactory.getEnv()
.getConfig()
.getCommonConfig()
.setAutoCreateSchemaEnabled(true)
.setPrimitiveArraySize(ROWS_PER_BATCH)
.setMemtableSizeThreshold(512L * 1024 * 1024);
EnvFactory.getEnv().initClusterEnvironment();
}

@AfterClass
public static void tearDown() throws Exception {
EnvFactory.getEnv().cleanClusterEnvironment();
}

@Test
public void testNullHeavyAlignedTabletWritePerformance() throws Exception {
Assert.assertTrue(MEASUREMENT_COUNT > 0);
Assert.assertTrue(WARMUP_BATCH_COUNT >= 0);
Assert.assertTrue(BATCH_COUNT > 0);
Assert.assertTrue(ROUND_COUNT > 0);

Tablet tablet = createTablet();
long nextTimestamp = 0;
try (ISession session = EnvFactory.getEnv().getSessionConnection()) {
nextTimestamp = insertBatches(session, tablet, nextTimestamp, WARMUP_BATCH_COUNT);

long[] elapsedNanos = new long[ROUND_COUNT];
for (int round = 0; round < ROUND_COUNT; round++) {
long startTime = System.nanoTime();
nextTimestamp = insertBatches(session, tablet, nextTimestamp, BATCH_COUNT);
elapsedNanos[round] = System.nanoTime() - startTime;
}

long expectedBatchCount = WARMUP_BATCH_COUNT + (long) BATCH_COUNT * ROUND_COUNT;
assertFirstMeasurementCount(session, expectedBatchCount * (ROWS_PER_BATCH - 1L));
Arrays.sort(elapsedNanos);
double medianNanos = elapsedNanos[elapsedNanos.length / 2];
double pointsPerSecond =
(double) BATCH_COUNT * ROWS_PER_BATCH * MEASUREMENT_COUNT * 1_000_000_000L / medianNanos;
LOGGER.info(
"AlignedTVList bitmap write benchmark: measurements={}, rows/batch={}, warmup batches={}, "
+ "batches/round={}, rounds={}, median={} ms/round, throughput={} points/s",
MEASUREMENT_COUNT,
ROWS_PER_BATCH,
WARMUP_BATCH_COUNT,
BATCH_COUNT,
ROUND_COUNT,
String.format("%.3f", medianNanos / 1_000_000.0),
String.format("%.0f", pointsPerSecond));
}
}

private static Tablet createTablet() {
List<IMeasurementSchema> schemas = new ArrayList<>(MEASUREMENT_COUNT);
for (int i = 0; i < MEASUREMENT_COUNT; i++) {
schemas.add(new MeasurementSchema("s" + i, TSDataType.INT64));
}
Tablet tablet = new Tablet(DEVICE, schemas, ROWS_PER_BATCH);
tablet.initBitMaps();
Object[] values = tablet.getValues();
BitMap[] bitMaps = tablet.getBitMaps();
for (int column = 0; column < MEASUREMENT_COUNT; column++) {
long[] columnValues = (long[]) values[column];
Arrays.fill(columnValues, column);
bitMaps[column] = new BitMap(ROWS_PER_BATCH);
bitMaps[column].mark(column % ROWS_PER_BATCH);
}
tablet.setRowSize(ROWS_PER_BATCH);
return tablet;
}

private static long insertBatches(
ISession session, Tablet tablet, long nextTimestamp, int batchCount) throws Exception {
long[] timestamps = tablet.getTimestamps();
for (int batch = 0; batch < batchCount; batch++) {
for (int row = 0; row < ROWS_PER_BATCH; row++) {
timestamps[row] = nextTimestamp++;
}
session.insertAlignedTablet(tablet);
}
return nextTimestamp;
}

private static void assertFirstMeasurementCount(ISession session, long expectedCount)
throws Exception {
try (org.apache.iotdb.isession.SessionDataSet dataSet =
session.executeQueryStatement("SELECT COUNT(s0) FROM " + DEVICE)) {
Assert.assertTrue(dataSet.hasNext());
Assert.assertEquals(expectedCount, dataSet.next().getFields().get(0).getLongV());
Assert.assertFalse(dataSet.hasNext());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
import org.apache.tsfile.utils.Binary;
import org.apache.tsfile.utils.BitMap;
import org.apache.tsfile.utils.Pair;
import org.apache.tsfile.utils.RamUsageEstimator;
import org.apache.tsfile.utils.ReadWriteForEncodingUtils;
import org.apache.tsfile.utils.ReadWriteIOUtils;
import org.apache.tsfile.utils.TsPrimitiveType;
Expand Down Expand Up @@ -74,9 +73,7 @@
public abstract class AlignedTVList extends TVList {

private static final long BITMAP_RAM_COST_PER_BLOCK =
RamUsageEstimator.shallowSizeOfInstance(BitMap.class)
+ RamUsageEstimator.sizeOfByteArray(BitMap.getSizeOfBytes(ARRAY_SIZE))
+ NUM_BYTES_OBJECT_REF;
BitMap.createBitMapDynamically(ARRAY_SIZE).ramBytesUsed() + NUM_BYTES_OBJECT_REF;

// Data types of this aligned tvList
protected List<TSDataType> dataTypes;
Expand Down Expand Up @@ -426,7 +423,7 @@ public void extendColumn(TSDataType dataType) {
default:
break;
}
BitMap bitMap = new BitMap(ARRAY_SIZE);
BitMap bitMap = BitMap.createBitMapDynamically(ARRAY_SIZE);
// The following code is for these 2 kinds of scenarios.

// Eg1: If rowCount=5 and ARRAY_SIZE=2, we need to supply 3 bitmaps for the extending column.
Expand Down Expand Up @@ -734,13 +731,13 @@ public void deleteColumn(int columnIndex) {
if (bitMaps.get(columnIndex) == null) {
List<BitMap> columnBitMaps = new ArrayList<>(values.get(columnIndex).size());
for (int i = 0; i < values.get(columnIndex).size(); i++) {
columnBitMaps.add(new BitMap(ARRAY_SIZE));
columnBitMaps.add(BitMap.createBitMapDynamically(ARRAY_SIZE));
}
bitMaps.set(columnIndex, columnBitMaps);
}
for (int i = 0; i < bitMaps.get(columnIndex).size(); i++) {
if (bitMaps.get(columnIndex).get(i) == null) {
bitMaps.get(columnIndex).set(i, new BitMap(ARRAY_SIZE));
bitMaps.get(columnIndex).set(i, BitMap.createBitMapDynamically(ARRAY_SIZE));
}
bitMaps.get(columnIndex).get(i).markAll();
}
Expand Down Expand Up @@ -832,12 +829,9 @@ protected void expandValues() {
*/
private boolean markRowNull(int i) {
if (timeColDeletedMap == null) {
timeColDeletedMap = new BitMap(rowCount);
timeColDeletedMap = BitMap.createBitMapDynamically(rowCount);
} else if (timeColDeletedMap.getSize() < rowCount) {
byte[] prevBytes = timeColDeletedMap.getByteArray();
byte[] newBytes = new byte[rowCount / 8 + 1];
System.arraycopy(prevBytes, 0, newBytes, 0, prevBytes.length);
timeColDeletedMap = new BitMap(rowCount, newBytes);
timeColDeletedMap.extend(rowCount);
}
// use value index so that sorts will not change the nullability
if (timeColDeletedMap.isMarked(getValueIndex(i))) {
Expand Down Expand Up @@ -930,9 +924,9 @@ private void markNullBitmapRange(
int arrayIndex) {

/* 1. Build result-level bitmap (1 = failure row) */
byte[] resultBitMap =
BitMap resultBitMap =
results != null && containsFailedStatus(results, idx, len)
? buildResultBitMapBytes(results, idx, elementIdx, len)
? buildResultBitMap(results, idx, elementIdx, len)
: null;

for (int j = 0; j < values.length; j++) {
Expand All @@ -949,7 +943,7 @@ private void markNullBitmapRange(

/* 3. Overlay result bitmap (failure rows) */
if (resultBitMap != null) {
markNullValue(j, arrayIndex, elementIdx, resultBitMap);
getBitMap(j, arrayIndex).merge(resultBitMap, elementIdx & 7, elementIdx, len);
}
}
}
Expand Down Expand Up @@ -990,13 +984,18 @@ private static boolean containsMarkedBit(BitMap bitMap, int start, int length) {

public static byte[] buildResultBitMapBytes(
TSStatus[] results, int idx, int elementIdx, int length) {
int totalBits = (elementIdx & 7) + length;
return Arrays.copyOf(
buildResultBitMap(results, idx, elementIdx, length).getByteArray(), (totalBits + 7) >> 3);
}

private static BitMap buildResultBitMap(TSStatus[] results, int idx, int elementIdx, int length) {
int start = elementIdx & 7;
int totalBits = start + length;
int size = (totalBits + 7) >> 3;
BitMap bitmap = new BitMap(totalBits, new byte[size]);
BitMap bitmap = BitMap.createBitMapDynamically(totalBits);

if (results == null) {
return bitmap.getByteArray();
return bitmap;
}

for (int i = 0; i < length; i++) {
Expand All @@ -1005,7 +1004,7 @@ public static byte[] buildResultBitMapBytes(
bitmap.mark(start + i);
}
}
return bitmap.getByteArray();
return bitmap;
}

private void arrayCopy(Object[] value, int idx, int arrayIndex, int elementIndex, int remaining) {
Expand Down Expand Up @@ -1077,21 +1076,12 @@ private BitMap getBitMap(int columnIndex, int arrayIndex) {

// if the bitmap in arrayIndex is null, init the bitmap
if (bitMaps.get(columnIndex).get(arrayIndex) == null) {
bitMaps.get(columnIndex).set(arrayIndex, new BitMap(ARRAY_SIZE));
bitMaps.get(columnIndex).set(arrayIndex, BitMap.createBitMapDynamically(ARRAY_SIZE));
}

return bitMaps.get(columnIndex).get(arrayIndex);
}

private void markNullValue(
int columnIndex, int arrayIndex, int elementIndex, byte[] resultBitMap) {
byte[] bitMap = getBitMap(columnIndex, arrayIndex).getByteArray();
int start = elementIndex >>> 3;
for (byte b : resultBitMap) {
bitMap[start++] |= b;
}
}

private boolean markNullValue(int columnIndex, int arrayIndex, int elementIndex) {
// mark the null value in the current bitmap
BitMap bitMap = getBitMap(columnIndex, arrayIndex);
Expand Down Expand Up @@ -1548,7 +1538,7 @@ public static AlignedTVList deserialize(DataInputStream stream) throws IOExcepti
Object[] values = new Object[dataTypeNum];
BitMap[] bitMaps = new BitMap[dataTypeNum];
for (int columnIndex = 0; columnIndex < dataTypeNum; ++columnIndex) {
BitMap bitMap = new BitMap(rowCount);
BitMap bitMap = BitMap.createBitMapDynamically(rowCount);
Object valuesOfOneColumn;
switch (dataTypes.get(columnIndex)) {
case TEXT:
Expand Down Expand Up @@ -1702,8 +1692,9 @@ public BitMap getAllValueColDeletedMap(int rowCount) {
}

byte bits = (byte) 0X00;
byte[] bitMapBytes = bitMap.getByteArray();
for (int j = 0; j < size; j++) {
rowBitsArr[index] &= bitMap.getByteArray()[j];
rowBitsArr[index] &= bitMapBytes[j];
bits |= rowBitsArr[index++];
isEnd = false;
}
Expand Down Expand Up @@ -1946,7 +1937,8 @@ && isPointDeleted(
valueColumnsDeletionList.get(columnIndex),
valueColumnDeleteCursor.get(columnIndex),
scanOrder))) {
bitMap = bitMap == null ? new BitMap(dataTypeList.size()) : bitMap;
bitMap =
bitMap == null ? BitMap.createBitMapDynamically(dataTypeList.size()) : bitMap;
bitMap.mark(columnIndex);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void mark(int index) {
ensureCapacity(blockIndex);
BitMap block = blocks.get(blockIndex);
if (block == null) {
block = new BitMap(blockSize);
block = BitMap.createBitMapDynamically(blockSize);
blocks.set(blockIndex, block);
}
block.mark(getInnerIndex(index));
Expand Down
Loading
Loading