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

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

commit 830507ac56aec7b4e9f9c843781744a6d91ab737
Author: Tian Jiang <[email protected]>
AuthorDate: Wed Sep 23 11:41:12 2026 +0800

    tmp
---
 .../apache/iotdb/db/i18n/DataNodeMiscMessages.java |   2 +
 .../apache/iotdb/db/i18n/DataNodeMiscMessages.java |   2 +
 .../compaction/repair/RepairDataFileScanUtil.java  |  12 +-
 .../memtable/AlignedWritableMemChunk.java          | 171 ++++++++++++---------
 .../dataregion/memtable/TsFileProcessor.java       |   5 +
 .../utils/datastructure/AlignedTVListFactory.java  |   7 +-
 .../datastructure/ColumnSortedAlignedTVList.java   |  90 +----------
 .../memtable/FlatDeviceMemTableDeletionTest.java   |  35 +++--
 .../memtable/FlatDeviceMemTableTest.java           |  31 ++--
 9 files changed, 154 insertions(+), 201 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
index e76211672ff..feca81a893f 100644
--- 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
@@ -1531,4 +1531,6 @@ public final class DataNodeMiscMessages {
   public static final String 
EXCEPTION_MISSING_VALUE_ARRAYS_FOR_ALIGNED_COLUMN_INDEX_ARG_DURING_MARK_NULL_VALUE_2893628E
 =
       "Missing value arrays for aligned column index %d during mark null 
value";
 
+  public static final String 
EXCEPTION_DELETING_TAG_COLUMN_ARG_IS_NOT_SUPPORTED_FOR_FLAT_DEVICE_TABLE_ARG_9B440C82
 =
+      "Deleting TAG column %d is not supported for flat device table %s.";
 }
diff --git 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
index c9a3f49710f..da8a836c83b 100644
--- 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
@@ -1508,4 +1508,6 @@ public final class DataNodeMiscMessages {
   public static final String 
EXCEPTION_MISSING_VALUE_ARRAYS_FOR_ALIGNED_COLUMN_INDEX_ARG_DURING_MARK_NULL_VALUE_2893628E
 =
       "标记空值过程中缺少对齐列索引 %d 的值数组";
 
+  public static final String 
EXCEPTION_DELETING_TAG_COLUMN_ARG_IS_NOT_SUPPORTED_FOR_FLAT_DEVICE_TABLE_ARG_9B440C82
 =
+      "不支持删除索引为 %d 的 TAG 列(flat device 表:%s)。";
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/RepairDataFileScanUtil.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/RepairDataFileScanUtil.java
index fabb79cd615..309aed2ca27 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/RepairDataFileScanUtil.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/RepairDataFileScanUtil.java
@@ -19,7 +19,6 @@
 
 package org.apache.iotdb.db.storageengine.dataregion.compaction.repair;
 
-import java.util.Objects;
 import org.apache.iotdb.commons.schema.table.TsFileTableSchemaUtil;
 import org.apache.iotdb.db.i18n.StorageEngineMessages;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.execute.exception.CompactionLastTimeCheckFailedException;
@@ -70,12 +69,12 @@ import java.io.File;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 import static 
org.apache.tsfile.read.reader.chunk.ChunkReader.decryptAndUncompressPageData;
@@ -290,9 +289,7 @@ public class RepairDataFileScanUtil {
         IPointReader rows = chunkReader.nextPageData().getBatchDataIterator();
         while (rows.hasNextTimeValuePair()) {
           TimeValuePair row = rows.nextTimeValuePair();
-          if (previous != null
-              && compareAlignedRowKey(previous, row)
-              >= 0) {
+          if (previous != null && compareAlignedRowKey(previous, row) >= 0) {
             throw new CompactionLastTimeCheckFailedException(
                 device.toString(), row.getTimestamp(), 
previous.getTimestamp());
           }
@@ -306,8 +303,9 @@ public class RepairDataFileScanUtil {
     TsPrimitiveType[] previousValues = previous.getValue().getVector();
     TsPrimitiveType[] currentValues = current.getValue().getVector();
     for (int i = 0; i < previousValues.length; i++) {
-      int compare = Objects.compare(previousValues[i].getBinary(), 
currentValues[i].getBinary(),
-          Binary::compareTo);
+      int compare =
+          Objects.compare(
+              previousValues[i].getBinary(), currentValues[i].getBinary(), 
Binary::compareTo);
       if (compare != 0) {
         return compare;
       }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunk.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunk.java
index e1eb0944600..0eee722067d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunk.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunk.java
@@ -35,7 +35,6 @@ import 
org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALWriteUtils;
 import org.apache.iotdb.db.utils.datastructure.AlignedTVList;
 import org.apache.iotdb.db.utils.datastructure.AlignedTVListFactory;
 import org.apache.iotdb.db.utils.datastructure.BatchEncodeInfo;
-import org.apache.iotdb.db.utils.datastructure.ColumnSortedAlignedTVList;
 import org.apache.iotdb.db.utils.datastructure.FlatDeviceAlignedTVList;
 import org.apache.iotdb.db.utils.datastructure.MemPointIterator;
 import org.apache.iotdb.db.utils.datastructure.MemPointIteratorFactory;
@@ -60,6 +59,7 @@ import org.apache.tsfile.write.schema.MeasurementSchema;
 import java.io.DataInputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -69,7 +69,6 @@ import java.util.TreeMap;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import static 
org.apache.iotdb.db.storageengine.rescon.memory.PrimitiveArrayManager.ARRAY_SIZE;
 import static org.apache.iotdb.db.utils.ModificationUtils.isPointDeleted;
 
 public class AlignedWritableMemChunk extends AbstractWritableMemChunk {
@@ -238,14 +237,14 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
     this.measurementIndexMap = new LinkedHashMap<>();
     this.measurementCategoryMap = new LinkedHashMap<>();
     this.schemaList = new ArrayList<>(schemaList);
-    this.useColumnSortedList = list instanceof ColumnSortedAlignedTVList;
+    this.useColumnSortedList = list instanceof FlatDeviceAlignedTVList;
     if (list instanceof FlatDeviceAlignedTVList) {
       Objects.requireNonNull(physicalDeviceId);
     }
     this.physicalDeviceId = physicalDeviceId;
     this.sortColumnIndices =
-        this.useColumnSortedList
-            ? new ArrayList<>(((ColumnSortedAlignedTVList) 
list).getSortColumnIndices())
+        list instanceof FlatDeviceAlignedTVList flat
+            ? flat.getTagColumnIndices()
             : new ArrayList<>();
     for (int i = 0; i < schemaList.size(); i++) {
       measurementIndexMap.put(schemaList.get(i).getMeasurementName(), i);
@@ -458,10 +457,9 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
           boolean isTagColumn =
               useColumnSortedList && measurementCategory == 
TsTableColumnCategory.TAG;
           index = this.list.getTsDataTypes().size();
-          insertColumn(index, measurementSchema);
+          insertColumn(index, measurementSchema, isTagColumn);
           if (isTagColumn) {
             sortColumnIndices.add(index);
-            ((ColumnSortedAlignedTVList) this.list).addSortColumn(index);
           }
         }
         if (index != i) {
@@ -494,14 +492,17 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
   }
 
   /**
-   * Appends a newly discovered measurement to the working list and updates 
the physical index map.
+   * Appends a newly discovered measurement and updates the logical 
column-index map.
    *
-   * <p>Flat-device TAG columns are appended physically and their indices are 
recorded separately in
-   * {@code sortColumnIndices}. Historical TVLists remain unchanged because 
queries may still hold
-   * their original column-index mapping.
+   * <p>Flat-device TAGs extend only device metadata, without allocating FIELD 
storage. Historical
+   * TVLists remain unchanged because queries may still hold their original 
column-index mapping.
    */
-  private void insertColumn(int columnIndex, IMeasurementSchema 
measurementSchema) {
-    this.list.insertColumn(columnIndex, measurementSchema.getType());
+  private void insertColumn(int columnIndex, IMeasurementSchema 
measurementSchema, boolean isTag) {
+    if (isTag && list instanceof FlatDeviceAlignedTVList flat) {
+      flat.addTagColumn(columnIndex, measurementSchema.getType());
+    } else {
+      this.list.insertColumn(columnIndex, measurementSchema.getType());
+    }
     this.schemaList.add(measurementSchema);
     this.measurementIndexMap.put(measurementSchema.getMeasurementName(), 
columnIndex);
   }
@@ -582,76 +583,69 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
     // timestamp: 1 bitmap: 011
     // timestamp: 2 bitmap: 101
     // timestamp: 4 bitmap: 110
-    List<long[]> timestampsList = alignedTVList.getTimestamps();
-    List<int[]> indicesList = alignedTVList.getIndices();
-    int row = -1;
-    for (int i = 0; i < timestampsList.size(); i++) {
-      long[] timestamps = timestampsList.get(i);
-      int[] indices = indicesList == null ? null : indicesList.get(i);
-      int limit = (i == timestampsList.size() - 1) ? rowCount - i * ARRAY_SIZE 
: ARRAY_SIZE;
-      for (int j = 0; j < limit; j++) {
-        row++;
-        // the row is deleted
-        if (allValueColDeletedMap != null && 
allValueColDeletedMap.isMarked(row)) {
-          continue;
-        }
-        long timestamp = timestamps[j];
-        if (globalTimeFilter != null && !globalTimeFilter.satisfy(timestamp, 
null)) {
+    for (int row = 0; row < rowCount; row++) {
+      int valueIndex = alignedTVList.getValueIndex(row);
+      // the row is deleted
+      if (alignedTVList.isTimeDeleted(row)
+          || (allValueColDeletedMap != null && 
allValueColDeletedMap.isMarked(valueIndex))) {
+        continue;
+      }
+      long timestamp = alignedTVList.getTime(row);
+      if (globalTimeFilter != null && !globalTimeFilter.satisfy(timestamp, 
null)) {
+        continue;
+      }
+
+      // Note that this method will only perform bitmap unmarking on the first 
occurrence of a
+      // non-null value in multiple timestamps for the same column.
+      BitMap currentRowNullValueBitmap = null;
+      for (int column = 0; column < schemaList.size(); column++) {
+        // Late-added columns do not exist in historical lists and are 
therefore null there.
+        if (column >= alignedTVList.getTsDataTypes().size()
+            || alignedTVList.isNullValue(valueIndex, column)) {
           continue;
         }
 
-        // Note that this method will only perform bitmap unmarking on the 
first occurrence of a
-        // non-null value in multiple timestamps for the same column.
-        BitMap currentRowNullValueBitmap = null;
-        for (int column = 0; column < schemaList.size(); column++) {
-          // Late-added columns do not exist in historical lists and are 
therefore null there.
-          if (column >= alignedTVList.getTsDataTypes().size()
-              || alignedTVList.isNullValue(indices == null ? row : indices[j], 
column)) {
-            continue;
-          }
-
-          // skip deleted row
-          if (valueColumnsDeletionList != null && 
!valueColumnsDeletionList.isEmpty()) {
-            List<TimeRange> columnDeletionList = 
valueColumnsDeletionList.get(column);
-            int[] deleteCursor = valueColumnDeleteCursor.get(column);
-            if (columnDeletionList != null && !columnDeletionList.isEmpty()) {
-              if (!alignedTVList.isSorted() || !alignedTVList.isTimeOrdered()) 
{
-                deleteCursor[0] = 0;
-              }
-              if (isPointDeleted(timestamp, columnDeletionList, deleteCursor)) 
{
-                continue;
-              }
+        // skip deleted row
+        if (valueColumnsDeletionList != null && 
!valueColumnsDeletionList.isEmpty()) {
+          List<TimeRange> columnDeletionList = 
valueColumnsDeletionList.get(column);
+          int[] deleteCursor = valueColumnDeleteCursor.get(column);
+          if (columnDeletionList != null && !columnDeletionList.isEmpty()) {
+            if (!alignedTVList.isSorted() || !alignedTVList.isTimeOrdered()) {
+              deleteCursor[0] = 0;
+            }
+            if (isPointDeleted(timestamp, columnDeletionList, deleteCursor)) {
+              continue;
             }
-          }
-          if (!columnHasNonNullValue.isMarked(column)) {
-            hasNonNullValueColumnCount.incrementAndGet();
-            columnHasNonNullValue.mark(column);
-            currentRowNullValueBitmap =
-                currentRowNullValueBitmap != null
-                    ? currentRowNullValueBitmap
-                    : timestampWithBitmap.computeIfAbsent(
-                        timestamp, k -> getAllMarkedBitmap(schemaList.size()));
-            currentRowNullValueBitmap.unmark(column);
           }
         }
-
-        if (!ignoreAllNullRows) {
-          timestampWithBitmap.put(
-              timestamp,
+        if (!columnHasNonNullValue.isMarked(column)) {
+          hasNonNullValueColumnCount.incrementAndGet();
+          columnHasNonNullValue.mark(column);
+          currentRowNullValueBitmap =
               currentRowNullValueBitmap != null
                   ? currentRowNullValueBitmap
-                  : getAllMarkedBitmap(schemaList.size()));
-          return;
-        }
-        if (currentRowNullValueBitmap == null) {
-          continue;
+                  : timestampWithBitmap.computeIfAbsent(
+                      timestamp, k -> getAllMarkedBitmap(schemaList.size()));
+          currentRowNullValueBitmap.unmark(column);
         }
-        // found new column with non-null value
-        timestampWithBitmap.put(timestamp, currentRowNullValueBitmap);
+      }
 
-        if (hasNonNullValueColumnCount.get() == schemaList.size()) {
-          return;
-        }
+      if (!ignoreAllNullRows) {
+        timestampWithBitmap.put(
+            timestamp,
+            currentRowNullValueBitmap != null
+                ? currentRowNullValueBitmap
+                : getAllMarkedBitmap(schemaList.size()));
+        return;
+      }
+      if (currentRowNullValueBitmap == null) {
+        continue;
+      }
+      // found new column with non-null value
+      timestampWithBitmap.put(timestamp, currentRowNullValueBitmap);
+
+      if (hasNonNullValueColumnCount.get() == schemaList.size()) {
+        return;
       }
     }
   }
@@ -868,6 +862,18 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
     BitMap allValueColDeletedMap;
     AlignedTVList alignedWorkingListForFlush = (AlignedTVList) 
workingListForFlush;
 
+    if (alignedWorkingListForFlush instanceof FlatDeviceAlignedTVList flat) {
+      FlatDeviceAlignedTVList.encode(
+          Collections.singletonList(flat),
+          activeSchemaList,
+          buildColumnIndexList(activeSchemaList),
+          encryptParameter,
+          ioTaskQueue,
+          maxNumberOfPointsInChunk,
+          maxNumberOfPointsInPage);
+      return;
+    }
+
     allValueColDeletedMap =
         ignoreAllNullRows ? 
alignedWorkingListForFlush.getAllValueColDeletedMap() : null;
 
@@ -1301,6 +1307,25 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
             encodeInfo.maxNumberOfPointsInChunk,
             (encodeInfo.targetChunkSize / getAvgPointSizeOfLargestColumn()));
 
+    if (useColumnSortedList) {
+      List<FlatDeviceAlignedTVList> lists = new ArrayList<>(sortedList.size() 
+ 1);
+      for (AlignedTVList historical : sortedList) {
+        lists.add((FlatDeviceAlignedTVList) historical);
+      }
+      lists.add((FlatDeviceAlignedTVList) workingListForFlush);
+      List<IMeasurementSchema> activeSchemas = getActiveSchemaList();
+      FlatDeviceAlignedTVList.encode(
+          lists,
+          activeSchemas,
+          buildColumnIndexList(activeSchemas),
+          encryptParameter,
+          ioTaskQueue,
+          encodeInfo.maxNumberOfPointsInChunk,
+          encodeInfo.maxNumberOfPointsInPage);
+      encodeInfo.reset();
+      return;
+    }
+
     if (TVLIST_SORT_THRESHOLD == 0) {
       encodeWorkingAlignedTVList(
           ioTaskQueue, encodeInfo.maxNumberOfPointsInChunk, 
encodeInfo.maxNumberOfPointsInPage);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java
index 7541f2fa468..8570124ac3b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java
@@ -81,6 +81,7 @@ import org.apache.iotdb.db.utils.EncryptDBUtils;
 import org.apache.iotdb.db.utils.MemUtils;
 import org.apache.iotdb.db.utils.ModificationUtils;
 import org.apache.iotdb.db.utils.datastructure.AlignedTVList;
+import org.apache.iotdb.db.utils.datastructure.FlatDeviceAlignedTVList;
 import org.apache.iotdb.db.utils.datastructure.TVList;
 import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
@@ -1354,6 +1355,10 @@ public class TsFileProcessor {
     if (alignedMemChunk == null || 
!alignedMemChunk.containsMeasurement(measurement)) {
       return false;
     }
+    if (alignedMemChunk.getWorkingTVList() instanceof FlatDeviceAlignedTVList 
flat) {
+      return flat.isValueArrayMaterialized(
+          alignedMemChunk.getMeasurementIndex(measurement), arrayIndex);
+    }
     List<Object> valueArrays =
         alignedMemChunk
             .getWorkingTVList()
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVListFactory.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVListFactory.java
index 4fc8f3662ac..e635b465a65 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVListFactory.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVListFactory.java
@@ -75,8 +75,11 @@ public final class AlignedTVListFactory {
     int dataTypeCount = stream.readInt();
     if (encodedDataType == FlatDeviceAlignedTVList.WAL_DATA_TYPE_MARKER) {
       Objects.requireNonNull(physicalDeviceId);
-      return ColumnSortedAlignedTVList.deserialize(
-          stream, dataTypeCount, true, physicalDeviceId.getTableName());
+      return FlatDeviceAlignedTVList.deserialize(
+          stream, dataTypeCount, physicalDeviceId.getTableName());
+    }
+    if (encodedDataType == ColumnSortedAlignedTVList.WAL_DATA_TYPE_MARKER) {
+      return ColumnSortedAlignedTVList.deserialize(stream, dataTypeCount);
     }
 
     return AlignedTVList.deserialize(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/ColumnSortedAlignedTVList.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/ColumnSortedAlignedTVList.java
index 242fd968eb6..afc2524e0fe 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/ColumnSortedAlignedTVList.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/ColumnSortedAlignedTVList.java
@@ -24,7 +24,6 @@ import org.apache.iotdb.db.i18n.DataNodeMiscMessages;
 import 
org.apache.iotdb.db.storageengine.dataregion.wal.buffer.IWALByteBufferView;
 
 import org.apache.tsfile.enums.TSDataType;
-import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.BitMap;
 import org.apache.tsfile.utils.Pair;
 import org.apache.tsfile.utils.ReadWriteIOUtils;
@@ -253,8 +252,7 @@ public class ColumnSortedAlignedTVList extends 
AlignedTVList {
     serializeWALRows(buffer);
   }
 
-  static ColumnSortedAlignedTVList deserialize(
-      DataInputStream stream, int dataTypeCount, boolean flatDevice, String 
tableName)
+  static ColumnSortedAlignedTVList deserialize(DataInputStream stream, int 
dataTypeCount)
       throws IOException {
     List<TSDataType> dataTypes = new ArrayList<>(dataTypeCount);
     for (int columnIndex = 0; columnIndex < dataTypeCount; columnIndex++) {
@@ -266,91 +264,9 @@ public class ColumnSortedAlignedTVList extends 
AlignedTVList {
       sortColumnIndices.add(stream.readInt());
     }
     ColumnSortedAlignedTVList tvList =
-        flatDevice
-            ? new FlatDeviceAlignedTVList(dataTypes, sortColumnIndices, true, 
tableName)
-            : new ColumnSortedAlignedTVList(dataTypes, sortColumnIndices, 
true);
-
-    int rowCount = stream.readInt();
-    long[] times = new long[rowCount];
-    for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
-      times[rowIndex] = stream.readLong();
-    }
-
-    Object[] values = new Object[dataTypeCount];
-    BitMap[] bitMaps = new BitMap[dataTypeCount];
-    for (int columnIndex = 0; columnIndex < dataTypeCount; columnIndex++) {
-      BitMap bitMap = BitMap.createBitMapDynamically(rowCount);
-      Object valuesOfOneColumn =
-          switch (dataTypes.get(columnIndex)) {
-            case TEXT, BLOB, STRING, OBJECT -> {
-              Binary[] binaryValues = new Binary[rowCount];
-              for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
-                binaryValues[rowIndex] = ReadWriteIOUtils.readBinary(stream);
-                if (ReadWriteIOUtils.readBool(stream)) {
-                  bitMap.mark(rowIndex);
-                }
-              }
-              yield binaryValues;
-            }
-            case FLOAT -> {
-              float[] floatValues = new float[rowCount];
-              for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
-                floatValues[rowIndex] = stream.readFloat();
-                if (ReadWriteIOUtils.readBool(stream)) {
-                  bitMap.mark(rowIndex);
-                }
-              }
-              yield floatValues;
-            }
-            case INT32, DATE -> {
-              int[] intValues = new int[rowCount];
-              for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
-                intValues[rowIndex] = stream.readInt();
-                if (ReadWriteIOUtils.readBool(stream)) {
-                  bitMap.mark(rowIndex);
-                }
-              }
-              yield intValues;
-            }
-            case INT64, TIMESTAMP -> {
-              long[] longValues = new long[rowCount];
-              for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
-                longValues[rowIndex] = stream.readLong();
-                if (ReadWriteIOUtils.readBool(stream)) {
-                  bitMap.mark(rowIndex);
-                }
-              }
-              yield longValues;
-            }
-            case DOUBLE -> {
-              double[] doubleValues = new double[rowCount];
-              for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
-                doubleValues[rowIndex] = stream.readDouble();
-                if (ReadWriteIOUtils.readBool(stream)) {
-                  bitMap.mark(rowIndex);
-                }
-              }
-              yield doubleValues;
-            }
-            case BOOLEAN -> {
-              boolean[] booleanValues = new boolean[rowCount];
-              for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
-                booleanValues[rowIndex] = ReadWriteIOUtils.readBool(stream);
-                if (ReadWriteIOUtils.readBool(stream)) {
-                  bitMap.mark(rowIndex);
-                }
-              }
-              yield booleanValues;
-            }
-            case VECTOR, UNKNOWN ->
-                throw new 
UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
-          };
-      values[columnIndex] = valuesOfOneColumn;
-      bitMaps[columnIndex] = bitMap;
-    }
+        new ColumnSortedAlignedTVList(dataTypes, sortColumnIndices, true);
 
-    tvList.putAlignedValues(times, values, bitMaps, 0, rowCount, null);
-    tvList.deserializeTimeDeletion(stream);
+    AlignedTVList.deserializeRows(stream, tvList, dataTypes);
     return tvList;
   }
 
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/FlatDeviceMemTableDeletionTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/FlatDeviceMemTableDeletionTest.java
index 3d60d0754a7..d8ac7c3b37e 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/FlatDeviceMemTableDeletionTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/FlatDeviceMemTableDeletionTest.java
@@ -56,6 +56,7 @@ import java.util.concurrent.LinkedBlockingQueue;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
 public class FlatDeviceMemTableDeletionTest {
@@ -276,30 +277,32 @@ public class FlatDeviceMemTableDeletionTest {
     }
   }
 
-  // A selective TAG-column deletion changes the compound key, unlike a 
whole-row deletion.
-  // The next sort must restore TAG order without clearing the other row's TAG 
or FIELD.
+  // Reject TAG deletion before changing the logical device identity or the 
sorted rows.
   @Test
-  public void testSelectiveTagColumnDeletionInvalidatesSort() {
+  public void testSelectiveTagColumnDeletionIsRejected() {
     PrimitiveMemTable memTable = newMemTable();
     insert(memTable, 1, "a", "x", 10);
     insert(memTable, 1, "b", "x", 20);
     AlignedTVList list = chunk(memTable).getWorkingTVList();
     list.sort();
-    assertEquals(
-        1,
-        memTable.delete(
-            flatDeletion(
-                new DeletionPredicate(
-                    TABLE, new TagPredicate.SegmentExactMatch("b", 1), 
List.of("tag1")),
-                new TimeRange(1, 1))));
-    assertFalse(list.isSorted());
-    list.sort();
-    assertTrue(list.isNullValue(list.getValueIndex(0), 0));
-    assertEquals(List.of(20L, 10L), remainingValues(list, 2));
+    assertThrows(
+        UnsupportedOperationException.class,
+        () ->
+            memTable.delete(
+                flatDeletion(
+                    new DeletionPredicate(
+                        TABLE, new TagPredicate.SegmentExactMatch("b", 1), 
List.of("tag1")),
+                    new TimeRange(1, 1))));
+    assertThrows(UnsupportedOperationException.class, () -> 
chunk(memTable).removeColumn("tag1"));
+    assertTrue(chunk(memTable).containsMeasurement("tag1"));
+    assertTrue(list.isSorted());
+    assertEquals(binary("a"), 
list.getBinaryByValueIndex(list.getValueIndex(0), 0));
+    assertEquals(binary("b"), 
list.getBinaryByValueIndex(list.getValueIndex(1), 0));
+    assertEquals(List.of(10L, 20L), remainingValues(list, 2));
   }
 
   // Deletions at the first, middle and last sorted positions must not 
contribute to page sizes
-  // or value chunks. Exercise both flush encoders, including a physically 
dropped TAG column.
+  // or value chunks. Cover active-column projection after dropping a FIELD; 
TAGs remain intact.
   @Test
   public void testFlushSkipsDeletedRowsInEveryColumn() {
     for (boolean dropColumn : new boolean[] {false, true}) {
@@ -313,7 +316,7 @@ public class FlatDeviceMemTableDeletionTest {
       }
       AlignedWritableMemChunk chunk = chunk(memTable);
       if (dropColumn) {
-        chunk.removeColumn("tag2");
+        chunk.removeColumn("field1");
       }
       chunk.sortTvListForFlush();
       BlockingQueue<Object> queue = new LinkedBlockingQueue<>();
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/FlatDeviceMemTableTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/FlatDeviceMemTableTest.java
index 03d3188ffdb..f4161c890b1 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/FlatDeviceMemTableTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/FlatDeviceMemTableTest.java
@@ -28,7 +28,6 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.RelationalIn
 import 
org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALByteBufferForTest;
 import org.apache.iotdb.db.utils.datastructure.AlignedTVList;
 import org.apache.iotdb.db.utils.datastructure.BatchEncodeInfo;
-import org.apache.iotdb.db.utils.datastructure.ColumnSortedAlignedTVList;
 import org.apache.iotdb.db.utils.datastructure.FlatDeviceAlignedTVList;
 
 import org.apache.tsfile.common.conf.TSFileConfig;
@@ -117,16 +116,16 @@ public class FlatDeviceMemTableTest {
     Assert.assertEquals(TSEncoding.DICTIONARY, 
chunk.getSchemaList().get(1).getEncodingType());
     Assert.assertNotEquals(TSEncoding.DICTIONARY, 
chunk.getSchemaList().get(2).getEncodingType());
     AlignedTVList tvList = chunk.getWorkingTVList();
-    Assert.assertTrue(tvList instanceof ColumnSortedAlignedTVList);
-    Assert.assertEquals(2, ((ColumnSortedAlignedTVList) 
tvList).getSortColumnCount());
+    Assert.assertTrue(tvList instanceof FlatDeviceAlignedTVList);
+    Assert.assertEquals(2, ((FlatDeviceAlignedTVList) 
tvList).getSortColumnCount());
 
     tvList.sort();
     Assert.assertArrayEquals(new long[] {10, 15, 20, 30}, payloads(tvList));
     Assert.assertTrue(tvList.isNullValue(tvList.getValueIndex(0), 0));
 
     chunk.handoverAlignedTvList();
-    Assert.assertTrue(chunk.getSortedList().get(0) instanceof 
ColumnSortedAlignedTVList);
-    Assert.assertTrue(chunk.getWorkingTVList() instanceof 
ColumnSortedAlignedTVList);
+    Assert.assertTrue(chunk.getSortedList().get(0) instanceof 
FlatDeviceAlignedTVList);
+    Assert.assertTrue(chunk.getWorkingTVList() instanceof 
FlatDeviceAlignedTVList);
   }
 
   // The tablet keeps its complete logical device IDs for partition routing, 
while the MemTable
@@ -160,7 +159,7 @@ public class FlatDeviceMemTableTest {
         TSEncoding.DICTIONARY, 
group.getAlignedMemChunk().getSchemaList().get(2).getEncodingType());
 
     AlignedTVList tvList = group.getAlignedMemChunk().getWorkingTVList();
-    Assert.assertTrue(tvList instanceof ColumnSortedAlignedTVList);
+    Assert.assertTrue(tvList instanceof FlatDeviceAlignedTVList);
     tvList.sort();
     Assert.assertArrayEquals(new long[] {10, 11, 20}, payloads(tvList));
   }
@@ -221,7 +220,7 @@ public class FlatDeviceMemTableTest {
         });
     Assert.assertEquals(2, chunk.rowCount());
     Assert.assertEquals(3, chunk.getSortColumnCount());
-    Assert.assertTrue(chunk.getWorkingTVList() instanceof 
ColumnSortedAlignedTVList);
+    Assert.assertTrue(chunk.getWorkingTVList() instanceof 
FlatDeviceAlignedTVList);
     Assert.assertEquals(
         List.of("tag1", "field1", "tag2", "tag3"),
         chunk.getSchemaList().stream()
@@ -276,11 +275,11 @@ public class FlatDeviceMemTableTest {
     Assert.assertEquals(2, historicalList.getTsDataTypes().size());
     Assert.assertEquals(binary("a"), historicalList.getBinaryByValueIndex(0, 
0));
     Assert.assertEquals(10L, historicalList.getLongByValueIndex(0, 1));
-    Assert.assertEquals(1, ((ColumnSortedAlignedTVList) 
historicalList).getSortColumnCount());
+    Assert.assertEquals(1, ((FlatDeviceAlignedTVList) 
historicalList).getSortColumnCount());
 
     Assert.assertEquals(4, currentList.getTsDataTypes().size());
     Assert.assertEquals(
-        List.of(0, 2, 3), ((ColumnSortedAlignedTVList) 
currentList).getSortColumnIndices());
+        List.of(0, 2, 3), ((FlatDeviceAlignedTVList) 
currentList).getSortColumnIndices());
     Assert.assertEquals(binary("b"), currentList.getBinaryByValueIndex(0, 2));
     Assert.assertEquals(binary("c"), currentList.getBinaryByValueIndex(0, 3));
     Assert.assertEquals(20L, currentList.getLongByValueIndex(0, 1));
@@ -333,7 +332,7 @@ public class FlatDeviceMemTableTest {
             .getAlignedMemChunk();
     Assert.assertEquals(2, chunk.getSortColumnCount());
     AlignedTVList tvList = chunk.getWorkingTVList();
-    Assert.assertEquals(List.of(0, 2), ((ColumnSortedAlignedTVList) 
tvList).getSortColumnIndices());
+    Assert.assertEquals(List.of(0, 2), ((FlatDeviceAlignedTVList) 
tvList).getSortColumnIndices());
     Assert.assertEquals(
         List.of("tag1", "field1", "tag3"),
         chunk.getSchemaList().stream()
@@ -362,7 +361,7 @@ public class FlatDeviceMemTableTest {
             .map(IMeasurementSchema::getMeasurementName)
             .collect(Collectors.toList()));
     Assert.assertEquals(
-        List.of(0), ((ColumnSortedAlignedTVList) 
chunk.getWorkingTVList()).getSortColumnIndices());
+        List.of(0), ((FlatDeviceAlignedTVList) 
chunk.getWorkingTVList()).getSortColumnIndices());
     chunk.getWorkingTVList().sort();
     Assert.assertEquals(
         binary("a"),
@@ -397,7 +396,7 @@ public class FlatDeviceMemTableTest {
             .map(IMeasurementSchema::getMeasurementName)
             .collect(Collectors.toList()));
     Assert.assertEquals(
-        List.of(0), ((ColumnSortedAlignedTVList) 
chunk.getWorkingTVList()).getSortColumnIndices());
+        List.of(0), ((FlatDeviceAlignedTVList) 
chunk.getWorkingTVList()).getSortColumnIndices());
     chunk.getWorkingTVList().sort();
     Assert.assertEquals(
         binary("x"),
@@ -437,12 +436,12 @@ public class FlatDeviceMemTableTest {
     AlignedWritableMemChunk recovered =
         AlignedWritableMemChunk.deserialize(
             new DataInputStream(new ByteArrayInputStream(buffer.array())), 
true, PHYSICAL_DEVICE);
-    Assert.assertTrue(recovered.getWorkingTVList() instanceof 
ColumnSortedAlignedTVList);
+    Assert.assertTrue(recovered.getWorkingTVList() instanceof 
FlatDeviceAlignedTVList);
     Assert.assertEquals(
-        2, ((ColumnSortedAlignedTVList) 
recovered.getWorkingTVList()).getSortColumnCount());
+        2, ((FlatDeviceAlignedTVList) 
recovered.getWorkingTVList()).getSortColumnCount());
 
     recovered.handoverAlignedTvList();
-    Assert.assertTrue(recovered.getWorkingTVList() instanceof 
ColumnSortedAlignedTVList);
+    Assert.assertTrue(recovered.getWorkingTVList() instanceof 
FlatDeviceAlignedTVList);
   }
 
   // Covers the direct MemChunk flush path used when TVList handover is 
disabled. Equal timestamps
@@ -601,7 +600,7 @@ public class FlatDeviceMemTableTest {
   private static void assertNoSortColumns(AlignedWritableMemChunkGroup group) {
     AlignedWritableMemChunk chunk = group.getAlignedMemChunk();
     Assert.assertEquals(0, chunk.getSortColumnCount());
-    Assert.assertFalse(chunk.getWorkingTVList() instanceof 
ColumnSortedAlignedTVList);
+    Assert.assertFalse(chunk.getWorkingTVList() instanceof 
FlatDeviceAlignedTVList);
   }
 
   private static Binary binary(String value) {

Reply via email to