This is an automated email from the ASF dual-hosted git repository.

jiangtian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 51fe585dfcd perf: Optimize the mark bitmap operation of AlignedTVList 
InsertTablet (#16199)
51fe585dfcd is described below

commit 51fe585dfcd2e1b6a42b4f164c1fa8ebb999c0fe
Author: Zhenyu Luo <[email protected]>
AuthorDate: Wed Aug 27 10:10:51 2025 +0800

    perf: Optimize the mark bitmap operation of AlignedTVList InsertTablet 
(#16199)
    
    * perf: Optimize the mark bitmap operation of AlignedTVList InsertTablet
    
    * add UT
    
    * update
    
    * fix
    
    * fix
    
    * update tsfile version
    
    * fix
---
 .../resource/memory/InsertNodeMemoryEstimator.java |  10 +-
 .../db/utils/datastructure/AlignedTVList.java      | 156 +++++++++++++++------
 pom.xml                                            |   2 +-
 3 files changed, 118 insertions(+), 50 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimator.java
index ed34f0de310..476ec83b787 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimator.java
@@ -650,10 +650,12 @@ public class InsertNodeMemoryEstimator {
       return 0L;
     }
 
-    return RamUsageEstimator.shallowSizeOf(binaries)
-        + Arrays.stream(binaries)
-            .mapToLong(InsertNodeMemoryEstimator::sizeOfBinary)
-            .reduce(0L, Long::sum);
+    long size = 0L;
+    for (Binary binary : binaries) {
+      size += InsertNodeMemoryEstimator.sizeOfBinary(binary);
+    }
+
+    return size + RamUsageEstimator.shallowSizeOf(binaries);
   }
 
   public static long sizeOfValues(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
index 80649eb182d..62b20e3e6ba 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
@@ -786,17 +786,9 @@ public abstract class AlignedTVList extends TVList {
           if (indices != null) {
             indices.get(arrayIdx)[elementIdx + i] = rowCount;
           }
-          for (int j = 0; j < values.size(); j++) {
-            if (value[j] == null
-                || bitMaps != null && bitMaps[j] != null && 
bitMaps[j].isMarked(idx + i)
-                || results != null
-                    && results[idx + i] != null
-                    && results[idx + i].code != 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-              markNullValue(j, arrayIdx, elementIdx + i);
-            }
-          }
           rowCount++;
         }
+        markNullBitmapRange(value, bitMaps, results, idx, elementIdx, 
inputRemaining, arrayIdx);
         break;
       } else {
         // the remaining inputs cannot fit the last array, fill the last array 
and create a new
@@ -807,23 +799,67 @@ public abstract class AlignedTVList extends TVList {
           if (indices != null) {
             indices.get(arrayIdx)[elementIdx + i] = rowCount;
           }
-          for (int j = 0; j < values.size(); j++) {
-            if (value[j] == null
-                || bitMaps != null && bitMaps[j] != null && 
bitMaps[j].isMarked(idx + i)
-                || results != null
-                    && results[idx + i] != null
-                    && results[idx + i].code != 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-              markNullValue(j, arrayIdx, elementIdx + i);
-            }
-          }
           rowCount++;
         }
+        markNullBitmapRange(value, bitMaps, results, idx, elementIdx, 
internalRemaining, arrayIdx);
         idx += internalRemaining;
         checkExpansion();
       }
     }
   }
 
+  private void markNullBitmapRange(
+      Object[] values,
+      BitMap[] bitMaps,
+      TSStatus[] results,
+      int idx,
+      int elementIdx,
+      int len,
+      int arrayIndex) {
+
+    /* 1. Build result-level bitmap (1 = failure row) */
+    byte[] resultBitMap =
+        (results != null) ? buildResultBitMapBytes(results, idx, elementIdx, 
len) : null;
+
+    for (int j = 0; j < values.length; j++) {
+      /* Fast-path: column is entirely null */
+      if (values[j] == null) {
+        getBitMap(j, arrayIndex).markRange(elementIdx, len);
+        continue;
+      }
+
+      /* 2.mask the column bitmap */
+      if (bitMaps != null && bitMaps[j] != null) {
+        getBitMap(j, arrayIndex).merge(bitMaps[j], idx, elementIdx, len);
+      }
+
+      /* 3. Overlay result bitmap (failure rows) */
+      if (resultBitMap != null) {
+        markNullValue(j, arrayIndex, elementIdx, resultBitMap);
+      }
+    }
+  }
+
+  public static byte[] buildResultBitMapBytes(
+      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(size, new byte[size]);
+
+    if (results == null) {
+      return bitmap.getByteArray();
+    }
+
+    for (int i = 0; i < length; i++) {
+      if (results[idx + i] != null
+          && results[idx + i].code != 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        bitmap.mark(start + i);
+      }
+    }
+    return bitmap.getByteArray();
+  }
+
   private void arrayCopy(Object[] value, int idx, int arrayIndex, int 
elementIndex, int remaining) {
     for (int i = 0; i < values.size(); i++) {
       if (value[i] == null) {
@@ -871,7 +907,7 @@ public abstract class AlignedTVList extends TVList {
     }
   }
 
-  private void markNullValue(int columnIndex, int arrayIndex, int 
elementIndex) {
+  private BitMap getBitMap(int columnIndex, int arrayIndex) {
     // init BitMaps if doesn't have
     if (bitMaps == null) {
       List<List<BitMap>> localBitMaps = new ArrayList<>(dataTypes.size());
@@ -885,18 +921,31 @@ public abstract class AlignedTVList extends TVList {
     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(new BitMap(ARRAY_SIZE, new byte[ARRAY_SIZE]));
       }
       bitMaps.set(columnIndex, columnBitMaps);
     }
 
     // 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, new BitMap(ARRAY_SIZE, new 
byte[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 void markNullValue(int columnIndex, int arrayIndex, int 
elementIndex) {
     // mark the null value in the current bitmap
-    bitMaps.get(columnIndex).get(arrayIndex).mark(elementIndex);
+    getBitMap(columnIndex, arrayIndex).mark(elementIndex);
   }
 
   @Override
@@ -1451,33 +1500,50 @@ public abstract class AlignedTVList extends TVList {
     }
 
     byte[] rowBitsArr = new byte[rowCount / Byte.SIZE + 1];
-    for (int row = 0; row < rowCount; row += Byte.SIZE) {
-      boolean isFirstColumn = true;
-      byte rowBits = 0x00;
-      for (int columnIndex = 0; columnIndex < values.size(); columnIndex++) {
-        List<BitMap> columnBitMaps = bitMaps.get(columnIndex);
-        byte columnBits;
-        if (values.get(columnIndex) == null) {
-          columnBits = (byte) 0xFF;
-        } else if (columnBitMaps == null || columnBitMaps.get(row / 
ARRAY_SIZE) == null) {
-          // row exists when any column value exists
-          rowBits = 0x00;
-          break;
-        } else {
-          columnBits =
-              columnBitMaps.get(row / ARRAY_SIZE).getByteArray()[(row % 
ARRAY_SIZE) / Byte.SIZE];
+    int bitsMapSize =
+        rowCount % ARRAY_SIZE == 0 ? rowCount / ARRAY_SIZE : rowCount / 
ARRAY_SIZE + 1;
+    boolean[] allNotNullArray = new boolean[bitsMapSize];
+    Arrays.fill(rowBitsArr, (byte) 0xFF);
+    for (int columnIndex = 0; columnIndex < values.size(); columnIndex++) {
+      List<BitMap> columnBitMaps = bitMaps.get(columnIndex);
+      if (columnBitMaps == null) {
+        Arrays.fill(rowBitsArr, (byte) 0x00);
+        break;
+      } else if (values.get(columnIndex) != null) {
+        int row = 0;
+        boolean isEnd = true;
+        for (int i = 0; i < bitsMapSize; i++) {
+          if (allNotNullArray[i]) {
+            row += ARRAY_SIZE;
+            continue;
+          }
+
+          BitMap bitMap = columnBitMaps.get(i);
+          int index = row / Byte.SIZE;
+          int size = ((Math.min((rowCount - row), ARRAY_SIZE)) + 7) >>> 3;
+          row += ARRAY_SIZE;
+
+          if (bitMap == null) {
+            Arrays.fill(rowBitsArr, index, index + size, (byte) 0x00);
+            allNotNullArray[i] = true;
+            continue;
+          }
+
+          byte bits = (byte) 0X00;
+          for (int j = 0; j < size; j++) {
+            rowBitsArr[index] &= bitMap.getByteArray()[j];
+            bits |= rowBitsArr[index++];
+            isEnd = false;
+          }
+
+          allNotNullArray[i] = bits == (byte) 0;
         }
-        // set row to null when all column values are null
-        if (isFirstColumn) {
-          rowBits = columnBits;
-          isFirstColumn = false;
-        } else {
-          rowBits &= columnBits;
+
+        if (isEnd) {
+          break;
         }
       }
-      rowBitsArr[row / Byte.SIZE] = rowBits;
     }
-
     return new BitMap(rowCount, rowBitsArr);
   }
 
diff --git a/pom.xml b/pom.xml
index cbe309852db..cf0f8017745 100644
--- a/pom.xml
+++ b/pom.xml
@@ -176,7 +176,7 @@
         <thrift.version>0.14.1</thrift.version>
         <xz.version>1.9</xz.version>
         <zstd-jni.version>1.5.6-3</zstd-jni.version>
-        <tsfile.version>2.2.0-250813-SNAPSHOT</tsfile.version>
+        <tsfile.version>2.2.0-250825-SNAPSHOT</tsfile.version>
     </properties>
     <!--
     if we claim dependencies in dependencyManagement, then we do not claim

Reply via email to