in iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java [997:1140]
public TsBlock buildTsBlock(
int floatPrecision,
List<TSEncoding> encodingList,
List<TimeRange> timeColumnDeletion,
List<List<TimeRange>> deletionList,
boolean ignoreAllNullRows) {
TsBlockBuilder builder = new TsBlockBuilder(dataTypes);
// Time column
TimeColumnBuilder timeBuilder = builder.getTimeColumnBuilder();
int validRowCount = 0;
// duplicated time or deleted time are all invalid, true if we don't need this row
boolean[] timeInvalidInfo = null;
int[] deleteCursor = {0};
// time column
for (int sortedRowIndex = 0; sortedRowIndex < rowCount; sortedRowIndex++) {
// skip empty row
if (allValueColDeletedMap != null
&& allValueColDeletedMap.isMarked(getValueIndex(sortedRowIndex))) {
continue;
}
if (isTimeDeleted(sortedRowIndex)) {
continue;
}
int nextRowIndex = sortedRowIndex + 1;
while (nextRowIndex < rowCount
&& ((allValueColDeletedMap != null
&& allValueColDeletedMap.isMarked(getValueIndex(nextRowIndex)))
|| (isTimeDeleted(nextRowIndex)))) {
nextRowIndex++;
}
long timestamp = getTime(sortedRowIndex);
if ((nextRowIndex == rowCount || timestamp != getTime(nextRowIndex))
&& !isPointDeleted(timestamp, timeColumnDeletion, deleteCursor)) {
timeBuilder.writeLong(getTime(sortedRowIndex));
validRowCount++;
} else {
if (Objects.isNull(timeInvalidInfo)) {
timeInvalidInfo = new boolean[rowCount];
}
timeInvalidInfo[sortedRowIndex] = true;
}
sortedRowIndex = nextRowIndex - 1;
}
boolean[] hasAnyNonNullValue = new boolean[validRowCount];
int columnCount = dataTypes.size();
int currentWriteRowIndex;
// value columns
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
deleteCursor = new int[] {0};
// Pair of Time and Index
Pair<Long, Integer> lastValidPointIndexForTimeDupCheck = null;
if (Objects.nonNull(timeInvalidInfo)) {
lastValidPointIndexForTimeDupCheck = new Pair<>(Long.MIN_VALUE, null);
}
ColumnBuilder valueBuilder = builder.getColumnBuilder(columnIndex);
currentWriteRowIndex = 0;
for (int sortedRowIndex = 0; sortedRowIndex < rowCount; sortedRowIndex++) {
// skip empty row
if ((allValueColDeletedMap != null
&& allValueColDeletedMap.isMarked(getValueIndex(sortedRowIndex)))
|| (isTimeDeleted(sortedRowIndex))) {
continue;
}
// skip time duplicated or totally deleted rows
if (Objects.nonNull(timeInvalidInfo)) {
if (!isNullValue(getValueIndex(sortedRowIndex), columnIndex)) {
lastValidPointIndexForTimeDupCheck.left = getTime(sortedRowIndex);
lastValidPointIndexForTimeDupCheck.right = getValueIndex(sortedRowIndex);
}
if (timeInvalidInfo[sortedRowIndex]) {
continue;
}
}
// The part of code solves the following problem:
// Time: 1,2,2,3
// Value: 1,2,null,null
// When rowIndex:1, pair(min,null), timeDuplicateInfo:false, write(T:1,V:1)
// When rowIndex:2, pair(2,2), timeDuplicateInfo:true, skip writing value
// When rowIndex:3, pair(2,2), timeDuplicateInfo:false, T:2==pair.left:2, write(T:2,V:2)
// When rowIndex:4, pair(2,2), timeDuplicateInfo:false, T:3!=pair.left:2, write(T:3,V:null)
int originRowIndex;
if (Objects.nonNull(lastValidPointIndexForTimeDupCheck)
&& (getTime(sortedRowIndex) == lastValidPointIndexForTimeDupCheck.left)) {
originRowIndex = lastValidPointIndexForTimeDupCheck.right;
} else {
originRowIndex = getValueIndex(sortedRowIndex);
}
if (isNullValue(originRowIndex, columnIndex)
|| isPointDeleted(
getTime(sortedRowIndex),
Objects.isNull(deletionList) ? null : deletionList.get(columnIndex),
deleteCursor)) {
valueBuilder.appendNull();
currentWriteRowIndex++;
continue;
}
hasAnyNonNullValue[currentWriteRowIndex++] = true;
switch (dataTypes.get(columnIndex)) {
case BOOLEAN:
valueBuilder.writeBoolean(getBooleanByValueIndex(originRowIndex, columnIndex));
break;
case INT32:
case DATE:
valueBuilder.writeInt(getIntByValueIndex(originRowIndex, columnIndex));
break;
case INT64:
case TIMESTAMP:
valueBuilder.writeLong(getLongByValueIndex(originRowIndex, columnIndex));
break;
case FLOAT:
valueBuilder.writeFloat(
roundValueWithGivenPrecision(
getFloatByValueIndex(originRowIndex, columnIndex),
floatPrecision,
encodingList.get(columnIndex)));
break;
case DOUBLE:
valueBuilder.writeDouble(
roundValueWithGivenPrecision(
getDoubleByValueIndex(originRowIndex, columnIndex),
floatPrecision,
encodingList.get(columnIndex)));
break;
case TEXT:
case BLOB:
case STRING:
valueBuilder.writeBinary(getBinaryByValueIndex(originRowIndex, columnIndex));
break;
default:
break;
}
}
}
builder.declarePositions(validRowCount);
TsBlock tsBlock = builder.build();
if (!ignoreAllNullRows || !needRebuildTsBlock(hasAnyNonNullValue)) {
return tsBlock;
} else {
// if exist all null rows, at most have validRowCount - 1 valid rows
return reBuildTsBlock(hasAnyNonNullValue, validRowCount, columnCount, tsBlock);
}
}