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

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

commit e1a540722a65ba7ee973a5f40f17c8f12fc3ba1d
Author: shuwenwei <[email protected]>
AuthorDate: Fri Oct 9 18:24:50 2026 +0800

    [Storage] Pass table model explicitly in memtable, flush and WAL replay
---
 .../apache/iotdb/db/i18n/ImportWALMessages.java    |  6 ++-
 .../apache/iotdb/db/i18n/ImportWALMessages.java    |  6 ++-
 .../builder/PipeTableModelTsFileBuilderV2.java     |  3 +-
 .../util/builder/PipeTreeModelTsFileBuilderV2.java |  3 +-
 .../schemaregion/utils/ResourceByPathUtils.java    |  5 +-
 .../dataregion/flush/MemTableFlushTask.java        | 22 ++++++--
 .../dataregion/memtable/AbstractMemTable.java      | 54 +++++++++++--------
 .../memtable/AbstractWritableMemChunk.java         |  9 ++--
 .../memtable/AlignedWritableMemChunk.java          | 52 +++++++++---------
 .../memtable/AlignedWritableMemChunkGroup.java     | 37 +++++++------
 .../dataregion/memtable/IMemTable.java             |  8 +--
 .../dataregion/memtable/IWritableMemChunk.java     | 14 +++--
 .../memtable/IWritableMemChunkGroup.java           | 12 ++---
 .../dataregion/memtable/TsFileProcessor.java       | 12 +++--
 .../dataregion/memtable/WritableMemChunk.java      | 27 ++++++----
 .../dataregion/memtable/WritableMemChunkGroup.java | 26 ++++-----
 .../wal/recover/file/TsFilePlanRedoer.java         |  9 +++-
 .../file/UnsealedTsFileRecoverPerformer.java       | 13 +++--
 .../java/org/apache/iotdb/db/tools/ImportWAL.java  | 61 ++++++++++++++++------
 .../fragment/FragmentInstanceExecutionTest.java    | 10 ++--
 ...ignedBitmapMemoryAccountingPerformanceTest.java |  6 +--
 .../memtable/MemChunkDeserializeTest.java          | 12 ++---
 .../dataregion/memtable/MemTableFlushTaskTest.java | 28 +++++-----
 .../dataregion/memtable/PrimitiveMemTableTest.java | 27 ++++++----
 .../memtable/WritableMemChunkRegionScanTest.java   |  8 +--
 .../org/apache/iotdb/db/tools/ImportWALTest.java   | 54 +++++++++++++++++--
 26 files changed, 338 insertions(+), 186 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/ImportWALMessages.java
 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/ImportWALMessages.java
index d28ca7dbcfa..fefbfffe869 100644
--- 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/ImportWALMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/ImportWALMessages.java
@@ -136,14 +136,16 @@ public final class ImportWALMessages {
   public static final String 
MESSAGE_SKIPPED_ARG_CORRUPTED_WAL_FILES_SOURCE_FILES_RETAINED_A889CCE2 =
       "Skipped %d corrupted WAL files; source files retained.";
 
-  public static final String 
MESSAGE_TARGET_DATABASE_FOR_TABLE_MODEL_WAL_ENTRIES_IF_OMITTED_INFER_FROM_THE_WAL_PARENT_DIRECTORY_AND_ASK_FOR_CONFIRMATION_4B1E409D
 =
-      "Target database for table-model WAL entries. If omitted, infer from the 
WAL parent directory and ask for confirmation.";
+  public static final String 
MESSAGE_TARGET_DATABASE_FOR_WAL_REPLAY_IF_OMITTED_INFER_FROM_THE_WAL_PARENT_DIRECTORY_IF_INFERENCE_FAILS_DB_DATABASE_IS_REQUIRED_6EEBC019
 =
+      "Target database for WAL replay. If omitted, infer from the WAL parent 
directory; if inference fails, -db/--database is required.";
   public static final String 
MESSAGE_INFERRED_TABLE_DATABASE_ARG_FROM_WAL_DIRECTORY_ARG_REPLAY_INTO_THIS_DATABASE_Y_YES_A_ACCEPT_ALL_INFERRED_DATABASES_N_QUIT_5B59D833
 =
       "Inferred table database %s from WAL directory %s. Replay into this 
database? [y] yes, [a] accept all inferred databases, [N] quit: ";
   public static final String 
EXCEPTION_DATABASE_CONFIRMATION_REQUIRED_FOR_WAL_DIRECTORY_ARG_INFERRED_DATABASE_ARG_SPECIFY_DB_DATABASE_OR_SKIP_DB_CONFIRMATION_WHEN_INTERACTIVE_INPUT_IS_UNAVAILABLE_14DF6D36
 =
       "Database confirmation required for WAL directory %s (inferred database: 
%s). Specify -db/--database or --skip_db_confirmation when interactive input is 
unavailable.";
   public static final String 
EXCEPTION_REPLAY_INTO_INFERRED_DATABASE_ARG_WAS_NOT_CONFIRMED_SPECIFY_DB_DATABASE_TO_SELECT_THE_TARGET_EXPLICITLY_86F81190
 =
       "Replay into inferred database %s was not confirmed. Specify 
-db/--database to select the target explicitly.";
+  public static final String 
EXCEPTION_CANNOT_DETERMINE_THE_TARGET_DATABASE_OF_WAL_DIRECTORIES_ARG_SPECIFY_DB_DATABASE_WHICH_APPLIES_TO_ALL_IMPORTED_DIRECTORIES_55B174E4
 =
+      "Cannot determine the target database of WAL directories %s. Specify 
-db/--database, which applies to all imported directories.";
 
   public static final String 
MESSAGE_ACCEPT_ALL_INFERRED_DATABASE_NAMES_WITHOUT_CONFIRMATION_DB_DATABASE_STILL_TAKES_PRECEDENCE_FA49A73C
 =
       "Accept all inferred database names without confirmation; -db/--database 
still takes precedence.";
diff --git 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/ImportWALMessages.java
 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/ImportWALMessages.java
index 5f9b6e18b02..fc65b1bec5b 100644
--- 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/ImportWALMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/ImportWALMessages.java
@@ -135,14 +135,16 @@ public final class ImportWALMessages {
   public static final String 
MESSAGE_SKIPPED_ARG_CORRUPTED_WAL_FILES_SOURCE_FILES_RETAINED_A889CCE2 =
       "已跳过 %d 个损坏的 WAL 文件;源文件已保留。";
 
-  public static final String 
MESSAGE_TARGET_DATABASE_FOR_TABLE_MODEL_WAL_ENTRIES_IF_OMITTED_INFER_FROM_THE_WAL_PARENT_DIRECTORY_AND_ASK_FOR_CONFIRMATION_4B1E409D
 =
-      "表模型 WAL 条目的目标数据库。省略时尝试从 WAL 文件的父目录名推断,并请求确认。";
+  public static final String 
MESSAGE_TARGET_DATABASE_FOR_WAL_REPLAY_IF_OMITTED_INFER_FROM_THE_WAL_PARENT_DIRECTORY_IF_INFERENCE_FAILS_DB_DATABASE_IS_REQUIRED_6EEBC019
 =
+      "WAL 重放的目标数据库。省略时尝试从 WAL 文件的父目录名推断;无法推断时必须指定 -db/--database。";
   public static final String 
MESSAGE_INFERRED_TABLE_DATABASE_ARG_FROM_WAL_DIRECTORY_ARG_REPLAY_INTO_THIS_DATABASE_Y_YES_A_ACCEPT_ALL_INFERRED_DATABASES_N_QUIT_5B59D833
 =
       "推断目标表模型数据库为 %s,来源 WAL 目录为 %s。是否向此数据库重放?[y] 同意,[a] 全部同意推断的数据库,[N] 退出:";
   public static final String 
EXCEPTION_DATABASE_CONFIRMATION_REQUIRED_FOR_WAL_DIRECTORY_ARG_INFERRED_DATABASE_ARG_SPECIFY_DB_DATABASE_OR_SKIP_DB_CONFIRMATION_WHEN_INTERACTIVE_INPUT_IS_UNAVAILABLE_14DF6D36
 =
       "需要确认 WAL 目录 %s 的目标数据库(推断结果:%s)。无交互终端时请指定 -db/--database 或 
--skip_db_confirmation。";
   public static final String 
EXCEPTION_REPLAY_INTO_INFERRED_DATABASE_ARG_WAS_NOT_CONFIRMED_SPECIFY_DB_DATABASE_TO_SELECT_THE_TARGET_EXPLICITLY_86F81190
 =
       "未确认向推断出的数据库 %s 重放。请使用 -db/--database 显式选择目标。";
+  public static final String 
EXCEPTION_CANNOT_DETERMINE_THE_TARGET_DATABASE_OF_WAL_DIRECTORIES_ARG_SPECIFY_DB_DATABASE_WHICH_APPLIES_TO_ALL_IMPORTED_DIRECTORIES_55B174E4
 =
+      "无法推断 WAL 目录 %s 的目标数据库,请使用 -db/--database 显式指定(-db 会作用于本次导入的所有目录)。";
 
   public static final String 
MESSAGE_ACCEPT_ALL_INFERRED_DATABASE_NAMES_WITHOUT_CONFIRMATION_DB_DATABASE_STILL_TAKES_PRECEDENCE_FA49A73C
 =
       "自动接受所有推断出的数据库名,不再询问确认;-db/--database 仍优先。";
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/util/builder/PipeTableModelTsFileBuilderV2.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/util/builder/PipeTableModelTsFileBuilderV2.java
index ca4efdadb98..dc1a58ff012 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/util/builder/PipeTableModelTsFileBuilderV2.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/util/builder/PipeTableModelTsFileBuilderV2.java
@@ -329,7 +329,8 @@ public class PipeTableModelTsFileBuilderV2 extends 
PipeTsFileBuilder {
       }
     }
 
-    final MemTableFlushTask memTableFlushTask = new 
MemTableFlushTask(memTable, writer, null, null);
+    final MemTableFlushTask memTableFlushTask =
+        new MemTableFlushTask(memTable, writer, null, null, true);
     memTableFlushTask.syncFlushMemTable();
 
     writer.endFile();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/util/builder/PipeTreeModelTsFileBuilderV2.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/util/builder/PipeTreeModelTsFileBuilderV2.java
index 9d9d8b0fb0a..21dd3bb9cb0 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/util/builder/PipeTreeModelTsFileBuilderV2.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/util/builder/PipeTreeModelTsFileBuilderV2.java
@@ -257,7 +257,8 @@ public class PipeTreeModelTsFileBuilderV2 extends 
PipeTsFileBuilder {
       }
     }
 
-    final MemTableFlushTask memTableFlushTask = new 
MemTableFlushTask(memTable, writer, null, null);
+    final MemTableFlushTask memTableFlushTask =
+        new MemTableFlushTask(memTable, writer, null, null, false);
     memTableFlushTask.syncFlushMemTable();
 
     writer.endFile();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/ResourceByPathUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/ResourceByPathUtils.java
index f95fcfda473..f7271138724 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/ResourceByPathUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/ResourceByPathUtils.java
@@ -816,7 +816,10 @@ class MeasurementResourceByPathUtils extends 
ResourceByPathUtils {
       return null;
     }
     IWritableMemChunk memChunk =
-        
memTableMap.get(deviceID).getMemChunkMap().get(fullPath.getMeasurement());
+        memTableMap
+            .get(deviceID)
+            .getMemChunkMap(context.isIgnoreAllNullRows())
+            .get(fullPath.getMeasurement());
     // check If data type matches
     if (memChunk.getSchema().getType() != 
fullPath.getMeasurementSchema().getType()
         && !fullPath
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/flush/MemTableFlushTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/flush/MemTableFlushTask.java
index 68727f03aa7..4a2dfd88cd6 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/flush/MemTableFlushTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/flush/MemTableFlushTask.java
@@ -85,6 +85,12 @@ public class MemTableFlushTask {
   private String storageGroup;
   private String dataRegionId;
 
+  /**
+   * Whether rows whose values are all null should be ignored when flushing. 
All-null rows are only
+   * meaningful for table model databases, so it is the negation of {@code 
isTableModel}.
+   */
+  private final boolean ignoreAllNullRows;
+
   private IMemTable memTable;
 
   private volatile long memSerializeTime = 0L;
@@ -97,16 +103,21 @@ public class MemTableFlushTask {
    * @param memTable the memTable to flush
    * @param writer the writer where memTable will be flushed to (current 
tsfile writer or vm writer)
    * @param storageGroup current database
+   * @param dataRegionId current data region id
+   * @param isTableModel whether the memTable belongs to a table model 
database, it cannot be
+   *     inferred when the caller does not know the database, e.g. the pipe 
tsfile builders
    */
   public MemTableFlushTask(
       IMemTable memTable,
       RestorableTsFileIOWriter writer,
       String storageGroup,
-      String dataRegionId) {
+      String dataRegionId,
+      boolean isTableModel) {
     this.memTable = memTable;
     this.writer = writer;
     this.storageGroup = storageGroup;
     this.dataRegionId = dataRegionId;
+    this.ignoreAllNullRows = !isTableModel;
     this.encodingTaskFuture = SUB_TASK_POOL_MANAGER.submit(encodingTask);
     this.ioTaskFuture = SUB_TASK_POOL_MANAGER.submit(ioTask);
 
@@ -160,9 +171,10 @@ public class MemTableFlushTask {
     // sort the IDeviceID in lexicographical order
     Collections.sort(deviceIDList);
     for (IDeviceID deviceID : deviceIDList) {
-      final Map<String, IWritableMemChunk> value = 
memTableMap.get(deviceID).getMemChunkMap();
+      final Map<String, IWritableMemChunk> value =
+          memTableMap.get(deviceID).getMemChunkMap(ignoreAllNullRows);
       // skip the empty device/chunk group
-      if (memTableMap.get(deviceID).isEmpty() || value.isEmpty()) {
+      if (memTableMap.get(deviceID).isEmpty(ignoreAllNullRows) || 
value.isEmpty()) {
         continue;
       }
       encodingTaskQueue.put(new StartFlushGroupIOTask(deviceID));
@@ -171,7 +183,7 @@ public class MemTableFlushTask {
       for (String seriesId : seriesInOrder) {
         long startTime = System.currentTimeMillis();
         IWritableMemChunk series = value.get(seriesId);
-        if (series.count() == 0) {
+        if (series.count(ignoreAllNullRows) == 0) {
           continue;
         }
         /*
@@ -278,7 +290,7 @@ public class MemTableFlushTask {
               if (writableMemChunk instanceof AlignedWritableMemChunk && times 
== null) {
                 times = new long[MAX_NUMBER_OF_POINTS_IN_PAGE];
               }
-              writableMemChunk.encode(ioTaskQueue, encodeInfo, times);
+              writableMemChunk.encode(ioTaskQueue, encodeInfo, times, 
ignoreAllNullRows);
               long subTaskTime = System.currentTimeMillis() - starTime;
               
WRITING_METRICS.recordFlushSubTaskCost(WritingMetrics.ENCODING_TASK, 
subTaskTime);
               memSerializeTime += subTaskTime;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractMemTable.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractMemTable.java
index 35a3696630e..2bdc6c29035 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractMemTable.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractMemTable.java
@@ -187,7 +187,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
             deviceId,
             k -> {
               seriesNumber += filteredSchemaList.size();
-              return new AlignedWritableMemChunkGroup(filteredSchemaList, 
k.isTableModel());
+              return new AlignedWritableMemChunkGroup(filteredSchemaList);
             });
     for (IMeasurementSchema schema : schemaList) {
       if (schema != null && 
!memChunkGroup.contains(schema.getMeasurementName())) {
@@ -562,10 +562,10 @@ public abstract class AbstractMemTable implements 
IMemTable {
   }
 
   @Override
-  public long size() {
+  public long size(boolean ignoreAllNullRows) {
     long sum = 0;
     for (IWritableMemChunkGroup writableMemChunkGroup : memTableMap.values()) {
-      sum += writableMemChunkGroup.count();
+      sum += writableMemChunkGroup.count(ignoreAllNullRows);
     }
     return sum;
   }
@@ -617,6 +617,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
       Filter globalTimeFilter) {
 
     IDeviceID deviceID = fullPath.getDeviceId();
+    // Rows whose values are all null can never satisfy this read path, so 
they are always ignored.
     if (fullPath instanceof NonAlignedFullPath) {
       String measurementId = ((NonAlignedFullPath) fullPath).getMeasurement();
 
@@ -637,6 +638,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
           chunkMetaDataMap,
           memChunkHandleMap,
           deletionList,
+          true,
           globalTimeFilter);
     } else {
       // check If MemTable Contains this path
@@ -660,6 +662,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
           chunkMetaDataMap,
           memChunkHandleMap,
           deletionList,
+          true,
           globalTimeFilter);
     }
   }
@@ -682,6 +685,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
     }
 
     IWritableMemChunkGroup writableMemChunkGroup = memTableMap.get(deviceID);
+    // Rows whose values are all null can never satisfy this read path, so 
they are always ignored.
     if (isAligned) {
       getMemAlignedChunkHandleFromMemTable(
           deviceID,
@@ -690,6 +694,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
           memChunkHandleMap,
           ttlLowerBound,
           modsToMemTabled,
+          true,
           globalTimeFilter);
     } else {
       getMemChunkHandleFromMemTable(
@@ -699,6 +704,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
           memChunkHandleMap,
           ttlLowerBound,
           modsToMemTabled,
+          true,
           globalTimeFilter);
     }
   }
@@ -709,10 +715,12 @@ public abstract class AbstractMemTable implements 
IMemTable {
       Map<String, List<IChunkMetadata>> chunkMetadataMap,
       Map<String, List<IChunkHandle>> memChunkHandleMap,
       List<TimeRange> deletionList,
+      boolean ignoreAllNullRows,
       Filter globalTimeFilter) {
 
     WritableMemChunk memChunk =
-        (WritableMemChunk) 
memTableMap.get(deviceID).getMemChunkMap().get(measurementId);
+        (WritableMemChunk)
+            
memTableMap.get(deviceID).getMemChunkMap(ignoreAllNullRows).get(measurementId);
 
     if (memChunk == null) {
       return;
@@ -740,6 +748,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
       Map<String, List<IChunkMetadata>> chunkMetadataList,
       Map<String, List<IChunkHandle>> memChunkHandleMap,
       List<List<TimeRange>> deletionList,
+      boolean ignoreAllNullRows,
       Filter globalTimeFilter) {
 
     AlignedWritableMemChunk alignedMemChunk =
@@ -758,7 +767,8 @@ public abstract class AbstractMemTable implements IMemTable 
{
 
     List<BitMap> bitMaps = new ArrayList<>();
     long[] timestamps =
-        alignedMemChunk.getAnySatisfiedTimestamp(deletionList, bitMaps, true, 
globalTimeFilter);
+        alignedMemChunk.getAnySatisfiedTimestamp(
+            deletionList, bitMaps, ignoreAllNullRows, globalTimeFilter);
     if (timestamps.length == 0) {
       return;
     }
@@ -780,6 +790,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
       Map<String, List<IChunkHandle>> memChunkHandleMap,
       long ttlLowerBound,
       List<Pair<ModEntry, IMemTable>> modsToMemTabled,
+      boolean ignoreAllNullRows,
       Filter globalTimeFilter) {
 
     AlignedWritableMemChunk memChunk = 
writableMemChunkGroup.getAlignedMemChunk();
@@ -796,7 +807,8 @@ public abstract class AbstractMemTable implements IMemTable 
{
 
     List<BitMap> bitMaps = new ArrayList<>();
     long[] timestamps =
-        memChunk.getAnySatisfiedTimestamp(deletionList, bitMaps, true, 
globalTimeFilter);
+        memChunk.getAnySatisfiedTimestamp(
+            deletionList, bitMaps, ignoreAllNullRows, globalTimeFilter);
     if (timestamps.length == 0) {
       return;
     }
@@ -817,10 +829,11 @@ public abstract class AbstractMemTable implements 
IMemTable {
       Map<String, List<IChunkHandle>> memChunkHandleMap,
       long ttlLowerBound,
       List<Pair<ModEntry, IMemTable>> modsToMemTabled,
+      boolean ignoreAllNullRows,
       Filter globalTimeFilter) {
 
     for (Entry<String, IWritableMemChunk> entry :
-        writableMemChunkGroup.getMemChunkMap().entrySet()) {
+        writableMemChunkGroup.getMemChunkMap(ignoreAllNullRows).entrySet()) {
 
       String measurementId = entry.getKey();
       WritableMemChunk writableMemChunk = (WritableMemChunk) entry.getValue();
@@ -921,7 +934,7 @@ public abstract class AbstractMemTable implements IMemTable 
{
   }
 
   @Override
-  public long delete(ModEntry modEntry) {
+  public long delete(ModEntry modEntry, boolean ignoreAllNullRows) {
     List<Pair<IDeviceID, IWritableMemChunkGroup>> targetDeviceList = new 
ArrayList<>();
     for (Entry<IDeviceID, IWritableMemChunkGroup> entry : 
memTableMap.entrySet()) {
       if (modEntry.affects(entry.getKey())) {
@@ -932,11 +945,11 @@ public abstract class AbstractMemTable implements 
IMemTable {
     long pointDeleted = 0;
     for (Pair<IDeviceID, IWritableMemChunkGroup> pair : targetDeviceList) {
       if (modEntry.affectsAll(pair.left)) {
-        pointDeleted += pair.right.deleteTime(modEntry);
+        pointDeleted += pair.right.deleteTime(modEntry, ignoreAllNullRows);
       } else {
-        pointDeleted += pair.right.delete(modEntry);
+        pointDeleted += pair.right.delete(modEntry, ignoreAllNullRows);
       }
-      if (pair.right.isEmpty()) {
+      if (pair.right.isEmpty(ignoreAllNullRows)) {
         memTableMap.remove(pair.left).release();
       }
     }
@@ -1087,15 +1100,13 @@ public abstract class AbstractMemTable implements 
IMemTable {
       IWritableMemChunkGroup memChunkGroup;
       if (multiTvListInMemChunk) {
         if (isAligned) {
-          memChunkGroup = AlignedWritableMemChunkGroup.deserialize(stream, 
deviceID.isTableModel());
+          memChunkGroup = AlignedWritableMemChunkGroup.deserialize(stream);
         } else {
           memChunkGroup = WritableMemChunkGroup.deserialize(stream);
         }
       } else {
         if (isAligned) {
-          memChunkGroup =
-              AlignedWritableMemChunkGroup.deserializeSingleTVListMemChunks(
-                  stream, deviceID.isTableModel());
+          memChunkGroup = 
AlignedWritableMemChunkGroup.deserializeSingleTVListMemChunks(stream);
         } else {
           memChunkGroup = 
WritableMemChunkGroup.deserializeSingleTVListMemChunks(stream);
         }
@@ -1130,15 +1141,13 @@ public abstract class AbstractMemTable implements 
IMemTable {
       IWritableMemChunkGroup memChunkGroup;
       if (multiTvListInMemChunk) {
         if (isAligned) {
-          memChunkGroup = AlignedWritableMemChunkGroup.deserialize(stream, 
deviceID.isTableModel());
+          memChunkGroup = AlignedWritableMemChunkGroup.deserialize(stream);
         } else {
           memChunkGroup = WritableMemChunkGroup.deserialize(stream);
         }
       } else {
         if (isAligned) {
-          memChunkGroup =
-              AlignedWritableMemChunkGroup.deserializeSingleTVListMemChunks(
-                  stream, deviceID.isTableModel());
+          memChunkGroup = 
AlignedWritableMemChunkGroup.deserializeSingleTVListMemChunks(stream);
         } else {
           memChunkGroup = 
WritableMemChunkGroup.deserializeSingleTVListMemChunks(stream);
         }
@@ -1148,11 +1157,12 @@ public abstract class AbstractMemTable implements 
IMemTable {
   }
 
   @Override
-  public Map<IDeviceID, Long> getMaxTime() {
+  public Map<IDeviceID, Long> getMaxTime(boolean ignoreAllNullRows) {
     Map<IDeviceID, Long> latestTimeForEachDevice = new HashMap<>();
     for (Entry<IDeviceID, IWritableMemChunkGroup> entry : 
memTableMap.entrySet()) {
-      if (entry.getValue().count() > 0 && !entry.getValue().isEmpty()) {
-        latestTimeForEachDevice.put(entry.getKey(), 
entry.getValue().getMaxTime());
+      if (entry.getValue().count(ignoreAllNullRows) > 0
+          && !entry.getValue().isEmpty(ignoreAllNullRows)) {
+        latestTimeForEachDevice.put(entry.getKey(), 
entry.getValue().getMaxTime(ignoreAllNullRows));
       }
     }
     return latestTimeForEachDevice;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractWritableMemChunk.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractWritableMemChunk.java
index 4f2bb0abd11..327944c2975 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractWritableMemChunk.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractWritableMemChunk.java
@@ -222,7 +222,7 @@ public abstract class AbstractWritableMemChunk implements 
IWritableMemChunk {
       TSStatus[] results);
 
   @Override
-  public abstract long count();
+  public abstract long count(boolean ignoreAllNullRows);
 
   @Override
   public abstract long rowCount();
@@ -284,13 +284,16 @@ public abstract class AbstractWritableMemChunk implements 
IWritableMemChunk {
 
   @Override
   public abstract void encode(
-      BlockingQueue<Object> ioTaskQueue, BatchEncodeInfo encodeInfo, long[] 
times);
+      BlockingQueue<Object> ioTaskQueue,
+      BatchEncodeInfo encodeInfo,
+      long[] times,
+      boolean ignoreAllNullRows);
 
   @Override
   public abstract void release();
 
   @Override
-  public abstract boolean isEmpty();
+  public abstract boolean isEmpty(boolean ignoreAllNullRows);
 
   @Override
   public abstract List<? extends TVList> getSortedList();
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 ebdc024aac8..54b481de66a 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
@@ -75,7 +75,6 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
   private AlignedTVList list;
   private List<AlignedTVList> sortedList;
   private long sortedRowCount = 0;
-  private final boolean ignoreAllNullRows;
 
   private static final IoTDBConfig CONFIG = 
IoTDBDescriptor.getInstance().getConfig();
   private final int TVLIST_SORT_THRESHOLD = CONFIG.getTvListSortThreshold();
@@ -84,14 +83,12 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
 
   private EncryptParameter encryptParameter;
 
-  public AlignedWritableMemChunk(List<IMeasurementSchema> schemaList, boolean 
isTableModel) {
-    this(schemaList, isTableModel, EncryptUtils.getEncryptParameter());
+  public AlignedWritableMemChunk(List<IMeasurementSchema> schemaList) {
+    this(schemaList, EncryptUtils.getEncryptParameter());
   }
 
   public AlignedWritableMemChunk(
-      List<IMeasurementSchema> schemaList,
-      boolean isTableModel,
-      EncryptParameter encryptParameter) {
+      List<IMeasurementSchema> schemaList, EncryptParameter encryptParameter) {
     this.measurementIndexMap = new LinkedHashMap<>();
     this.dataTypes = new ArrayList<>();
     this.schemaList = schemaList;
@@ -101,19 +98,16 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
     }
     this.list = AlignedTVList.newAlignedList(dataTypes);
     this.sortedList = new ArrayList<>();
-    this.ignoreAllNullRows = !isTableModel;
     this.encryptParameter = encryptParameter;
   }
 
-  private AlignedWritableMemChunk(
-      List<IMeasurementSchema> schemaList, AlignedTVList list, boolean 
isTableModel) {
-    this(schemaList, list, isTableModel, EncryptUtils.getEncryptParameter());
+  private AlignedWritableMemChunk(List<IMeasurementSchema> schemaList, 
AlignedTVList list) {
+    this(schemaList, list, EncryptUtils.getEncryptParameter());
   }
 
   private AlignedWritableMemChunk(
       List<IMeasurementSchema> schemaList,
       AlignedTVList list,
-      boolean isTableModel,
       EncryptParameter encryptParameter) {
     this.measurementIndexMap = new LinkedHashMap<>();
     this.schemaList = schemaList;
@@ -123,7 +117,6 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
     this.list = list;
     this.dataTypes = list.getTsDataTypes();
     this.sortedList = new ArrayList<>();
-    this.ignoreAllNullRows = !isTableModel;
     this.encryptParameter = encryptParameter;
   }
 
@@ -465,7 +458,7 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
   }
 
   @Override
-  public long count() {
+  public long count(boolean ignoreAllNullRows) {
     if (!ignoreAllNullRows && measurementIndexMap.isEmpty()) {
       return rowCount();
     }
@@ -487,8 +480,8 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
   }
 
   @Override
-  public long getMaxTime() {
-    if (isEmpty()) {
+  public long getMaxTime(boolean ignoreAllNullRows) {
+    if (isEmpty(ignoreAllNullRows)) {
       return Long.MIN_VALUE;
     }
     long maxTime = list.getMaxTime();
@@ -582,7 +575,8 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
   public void encodeWorkingAlignedTVList(
       BlockingQueue<Object> ioTaskQueue,
       long maxNumberOfPointsInChunk,
-      int maxNumberOfPointsInPage) {
+      int maxNumberOfPointsInPage,
+      boolean ignoreAllNullRows) {
     List<IMeasurementSchema> activeSchemaList = getActiveSchemaList();
     if (activeSchemaList.isEmpty() && ignoreAllNullRows) {
       return;
@@ -1065,7 +1059,11 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
   }
 
   @Override
-  public void encode(BlockingQueue<Object> ioTaskQueue, BatchEncodeInfo 
encodeInfo, long[] times) {
+  public void encode(
+      BlockingQueue<Object> ioTaskQueue,
+      BatchEncodeInfo encodeInfo,
+      long[] times,
+      boolean ignoreAllNullRows) {
     encodeInfo.maxNumberOfPointsInChunk =
         Math.min(
             encodeInfo.maxNumberOfPointsInChunk,
@@ -1073,7 +1071,10 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
 
     if (TVLIST_SORT_THRESHOLD == 0) {
       encodeWorkingAlignedTVList(
-          ioTaskQueue, encodeInfo.maxNumberOfPointsInChunk, 
encodeInfo.maxNumberOfPointsInPage);
+          ioTaskQueue,
+          encodeInfo.maxNumberOfPointsInChunk,
+          encodeInfo.maxNumberOfPointsInPage,
+          ignoreAllNullRows);
       return;
     }
 
@@ -1151,15 +1152,15 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
   }
 
   @Override
-  public long getLastPoint() {
+  public long getLastPoint(boolean ignoreAllNullRows) {
     if (rowCount() == 0) {
       return Long.MIN_VALUE;
     }
-    return getMaxTime();
+    return getMaxTime(ignoreAllNullRows);
   }
 
   @Override
-  public boolean isEmpty() {
+  public boolean isEmpty(boolean ignoreAllNullRows) {
     if (rowCount() == 0) {
       return true;
     }
@@ -1215,8 +1216,7 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
     list.serializeToWAL(buffer);
   }
 
-  public static AlignedWritableMemChunk deserialize(DataInputStream stream, 
boolean isTableModel)
-      throws IOException {
+  public static AlignedWritableMemChunk deserialize(DataInputStream stream) 
throws IOException {
     int schemaListSize = stream.readInt();
     List<IMeasurementSchema> schemaList = new ArrayList<>(schemaListSize);
     for (int i = 0; i < schemaListSize; i++) {
@@ -1230,13 +1230,13 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
       sortedList.add(tvList);
     }
     AlignedTVList list = AlignedTVList.deserialize(stream);
-    AlignedWritableMemChunk chunk = new AlignedWritableMemChunk(schemaList, 
list, isTableModel);
+    AlignedWritableMemChunk chunk = new AlignedWritableMemChunk(schemaList, 
list);
     chunk.sortedList = sortedList;
     return chunk;
   }
 
   public static AlignedWritableMemChunk deserializeSingleTVListMemChunks(
-      DataInputStream stream, boolean isTableModel) throws IOException {
+      DataInputStream stream) throws IOException {
     int schemaListSize = stream.readInt();
     List<IMeasurementSchema> schemaList = new ArrayList<>(schemaListSize);
     for (int i = 0; i < schemaListSize; i++) {
@@ -1245,7 +1245,7 @@ public class AlignedWritableMemChunk extends 
AbstractWritableMemChunk {
     }
 
     AlignedTVList list = AlignedTVList.deserialize(stream);
-    return new AlignedWritableMemChunk(schemaList, list, isTableModel);
+    return new AlignedWritableMemChunk(schemaList, list);
   }
 
   public List<IMeasurementSchema> getSchemaList() {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunkGroup.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunkGroup.java
index a27973acdb1..e1235ca935b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunkGroup.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunkGroup.java
@@ -46,13 +46,13 @@ public class AlignedWritableMemChunkGroup implements 
IWritableMemChunkGroup {
 
   private EncryptParameter encryptParameter;
 
-  public AlignedWritableMemChunkGroup(List<IMeasurementSchema> schemaList, 
boolean isTableModel) {
-    memChunk = new AlignedWritableMemChunk(schemaList, isTableModel);
+  public AlignedWritableMemChunkGroup(List<IMeasurementSchema> schemaList) {
+    memChunk = new AlignedWritableMemChunk(schemaList);
   }
 
   @TestOnly
   public AlignedWritableMemChunkGroup(
-      AlignedWritableMemChunk memChunk, List<IMeasurementSchema> schemaList, 
boolean isTableModel) {
+      AlignedWritableMemChunk memChunk, List<IMeasurementSchema> schemaList) {
     this.memChunk = memChunk;
   }
 
@@ -78,8 +78,8 @@ public class AlignedWritableMemChunkGroup implements 
IWritableMemChunkGroup {
   }
 
   @Override
-  public long count() {
-    return memChunk.count();
+  public long count(boolean ignoreAllNullRows) {
+    return memChunk.count(ignoreAllNullRows);
   }
 
   /**
@@ -101,20 +101,20 @@ public class AlignedWritableMemChunkGroup implements 
IWritableMemChunkGroup {
   }
 
   @Override
-  public Map<String, IWritableMemChunk> getMemChunkMap() {
-    if (memChunk.count() == 0) {
+  public Map<String, IWritableMemChunk> getMemChunkMap(boolean 
ignoreAllNullRows) {
+    if (memChunk.count(ignoreAllNullRows) == 0) {
       return Collections.emptyMap();
     }
     return Collections.singletonMap("", memChunk);
   }
 
   @Override
-  public boolean isEmpty() {
-    return memChunk.isEmpty() || memChunk.isAllDeleted();
+  public boolean isEmpty(boolean ignoreAllNullRows) {
+    return memChunk.isEmpty(ignoreAllNullRows) || memChunk.isAllDeleted();
   }
 
   @Override
-  public long delete(ModEntry modEntry) {
+  public long delete(ModEntry modEntry, boolean ignoreAllNullRows) {
     int deletedPointsNumber = 0;
     Set<String> measurements = memChunk.getAllMeasurements();
     List<String> columnsToBeRemoved = new ArrayList<>();
@@ -138,7 +138,7 @@ public class AlignedWritableMemChunkGroup implements 
IWritableMemChunkGroup {
     return deletedPointsNumber;
   }
 
-  public long deleteTime(ModEntry modEntry) {
+  public long deleteTime(ModEntry modEntry, boolean ignoreAllNullRows) {
     return memChunk.deleteTime(modEntry.getStartTime(), modEntry.getEndTime());
   }
 
@@ -148,8 +148,8 @@ public class AlignedWritableMemChunkGroup implements 
IWritableMemChunkGroup {
   }
 
   @Override
-  public long getMaxTime() {
-    return memChunk.getMaxTime();
+  public long getMaxTime(boolean ignoreAllNullRows) {
+    return memChunk.getMaxTime(ignoreAllNullRows);
   }
 
   public AlignedWritableMemChunk getAlignedMemChunk() {
@@ -172,10 +172,10 @@ public class AlignedWritableMemChunkGroup implements 
IWritableMemChunkGroup {
     memChunk.setEncryptParameter(encryptParameter);
   }
 
-  protected static AlignedWritableMemChunkGroup deserialize(
-      DataInputStream stream, boolean isTableModel) throws IOException {
+  protected static AlignedWritableMemChunkGroup deserialize(DataInputStream 
stream)
+      throws IOException {
     AlignedWritableMemChunkGroup memChunkGroup = new 
AlignedWritableMemChunkGroup();
-    memChunkGroup.memChunk = AlignedWritableMemChunk.deserialize(stream, 
isTableModel);
+    memChunkGroup.memChunk = AlignedWritableMemChunk.deserialize(stream);
     return memChunkGroup;
   }
 
@@ -185,10 +185,9 @@ public class AlignedWritableMemChunkGroup implements 
IWritableMemChunkGroup {
   }
 
   protected static AlignedWritableMemChunkGroup 
deserializeSingleTVListMemChunks(
-      DataInputStream stream, boolean isTableModel) throws IOException {
+      DataInputStream stream) throws IOException {
     AlignedWritableMemChunkGroup memChunkGroup = new 
AlignedWritableMemChunkGroup();
-    memChunkGroup.memChunk =
-        AlignedWritableMemChunk.deserializeSingleTVListMemChunks(stream, 
isTableModel);
+    memChunkGroup.memChunk = 
AlignedWritableMemChunk.deserializeSingleTVListMemChunks(stream);
     return memChunkGroup;
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IMemTable.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IMemTable.java
index afa24083ff6..48d43644c8d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IMemTable.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IMemTable.java
@@ -68,9 +68,11 @@ public interface IMemTable extends WALEntryValue {
       Object[] objectValue);
 
   /**
+   * @param ignoreAllNullRows whether rows whose values are all null should be 
ignored, it is
+   *     determined by the data model of the database the memtable belongs to
    * @return the number of points
    */
-  long size();
+  long size(boolean ignoreAllNullRows);
 
   /**
    * @return memory usage
@@ -170,7 +172,7 @@ public interface IMemTable extends WALEntryValue {
    *
    * @return
    */
-  long delete(ModEntry modEntry);
+  long delete(ModEntry modEntry, boolean ignoreAllNullRows);
 
   /**
    * Make a copy of this MemTable.
@@ -214,7 +216,7 @@ public interface IMemTable extends WALEntryValue {
 
   void setFlushStatus(FlushStatus flushStatus);
 
-  Map<IDeviceID, Long> getMaxTime();
+  Map<IDeviceID, Long> getMaxTime(boolean ignoreAllNullRows);
 
   String getDatabase();
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunk.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunk.java
index e57f30680f9..71f205ef601 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunk.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunk.java
@@ -84,7 +84,7 @@ public interface IWritableMemChunk extends WALEntryValue {
       int end,
       TSStatus[] results);
 
-  long count();
+  long count(boolean ignoreAllNullRows);
 
   long rowCount();
 
@@ -100,7 +100,7 @@ public interface IWritableMemChunk extends WALEntryValue {
 
   void releaseTemporaryTvListForFlush();
 
-  default long getMaxTime() {
+  default long getMaxTime(boolean ignoreAllNullRows) {
     return Long.MAX_VALUE;
   }
 
@@ -115,15 +115,19 @@ public interface IWritableMemChunk extends WALEntryValue {
 
   IChunkWriter createIChunkWriter();
 
-  void encode(BlockingQueue<Object> ioTaskQueue, BatchEncodeInfo encodeInfo, 
long[] times);
+  void encode(
+      BlockingQueue<Object> ioTaskQueue,
+      BatchEncodeInfo encodeInfo,
+      long[] times,
+      boolean ignoreAllNullRows);
 
   void release();
 
   long getFirstPoint();
 
-  long getLastPoint();
+  long getLastPoint(boolean ignoreAllNullRows);
 
-  boolean isEmpty();
+  boolean isEmpty(boolean ignoreAllNullRows);
 
   List<? extends TVList> getSortedList();
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunkGroup.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunkGroup.java
index 46a21f05840..0cafd436329 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunkGroup.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunkGroup.java
@@ -47,21 +47,21 @@ public interface IWritableMemChunkGroup extends 
WALEntryValue {
 
   void release();
 
-  long count();
+  long count(boolean ignoreAllNullRows);
 
   boolean contains(String measurement);
 
-  Map<String, IWritableMemChunk> getMemChunkMap();
+  Map<String, IWritableMemChunk> getMemChunkMap(boolean ignoreAllNullRows);
 
-  boolean isEmpty();
+  boolean isEmpty(boolean ignoreAllNullRows);
 
-  long delete(ModEntry modEntry);
+  long delete(ModEntry modEntry, boolean ignoreAllNullRows);
 
-  long deleteTime(ModEntry modEntry);
+  long deleteTime(ModEntry modEntry, boolean ignoreAllNullRows);
 
   IWritableMemChunk getWritableMemChunk(String measurement);
 
-  long getMaxTime();
+  long getMaxTime(boolean ignoreAllNullRows);
 
   void setEncryptParameter(EncryptParameter encryptParameter);
 
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 78c48a2702b..7a89a07a9af 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
@@ -1584,6 +1584,11 @@ public class TsFileProcessor {
     }
   }
 
+  /** Whether the data region of this processor belongs to a table model 
database. */
+  private boolean isTableModel() {
+    return dataRegionInfo.getDataRegion().isTableModel();
+  }
+
   /**
    * Delete data which belongs to the timeseries `deviceId.measurementId` and 
the timestamp of which
    * <= 'timestamp' in the deletion. <br>
@@ -1599,7 +1604,7 @@ public class TsFileProcessor {
     try {
       boolean deleted = false;
       if (workMemTable != null) {
-        long pointDeleted = workMemTable.delete(deletion);
+        long pointDeleted = workMemTable.delete(deletion, !isTableModel());
         logger.info(
             StorageEngineMessages
                 
.STORAGE_LOG_DELETION_DELETION_WITH_IN_WORKMEMTABLE_POINTS_DELETED_00EA995A,
@@ -1767,7 +1772,7 @@ public class TsFileProcessor {
    * flushManager again.
    */
   private Future<?> addAMemtableIntoFlushingList(IMemTable tobeFlushed) throws 
IOException {
-    final Map<IDeviceID, Long> lastTimeForEachDevice = 
tobeFlushed.getMaxTime();
+    final Map<IDeviceID, Long> lastTimeForEachDevice = 
tobeFlushed.getMaxTime(!isTableModel());
 
     // If some devices have been removed in MemTable, the number of device in 
MemTable and
     // tsFileResource will not be the same. And the endTime of these devices 
in resource will be
@@ -1911,7 +1916,8 @@ public class TsFileProcessor {
                   memTableToFlush,
                   writer,
                   dataRegionName,
-                  dataRegionInfo.getDataRegion().getDataRegionIdString());
+                  dataRegionInfo.getDataRegion().getDataRegionIdString(),
+                  isTableModel());
           flushTask.syncFlushMemTable();
           memTableFlushPointCount = memTableToFlush.getTotalPointsNum();
         } catch (Throwable e) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunk.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunk.java
index 7e54296c6a8..929108e9246 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunk.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunk.java
@@ -222,7 +222,12 @@ public class WritableMemChunk extends 
AbstractWritableMemChunk {
   }
 
   @Override
-  public long count() {
+  public long count(boolean ignoreAllNullRows) {
+    // a non-aligned chunk never stores all-null rows, so ignoreAllNullRows 
makes no difference
+    return pointCount();
+  }
+
+  private long pointCount() {
     long count = list.count();
     for (TVList tvList : sortedList) {
       count += tvList.count();
@@ -241,7 +246,7 @@ public class WritableMemChunk extends 
AbstractWritableMemChunk {
   }
 
   @Override
-  public long getMaxTime() {
+  public long getMaxTime(boolean ignoreAllNullRows) {
     long maxTime = list.getMaxTime();
     for (TVList tvList : sortedList) {
       maxTime = Math.max(maxTime, tvList.getMaxTime());
@@ -260,23 +265,23 @@ public class WritableMemChunk extends 
AbstractWritableMemChunk {
 
   @Override
   public long getFirstPoint() {
-    if (count() == 0) {
+    if (pointCount() == 0) {
       return Long.MAX_VALUE;
     }
     return getMinTime();
   }
 
   @Override
-  public long getLastPoint() {
-    if (count() == 0) {
+  public long getLastPoint(boolean ignoreAllNullRows) {
+    if (pointCount() == 0) {
       return Long.MIN_VALUE;
     }
-    return getMaxTime();
+    return getMaxTime(ignoreAllNullRows);
   }
 
   @Override
-  public boolean isEmpty() {
-    return count() == 0;
+  public boolean isEmpty(boolean ignoreAllNullRows) {
+    return pointCount() == 0;
   }
 
   @Override
@@ -389,7 +394,11 @@ public class WritableMemChunk extends 
AbstractWritableMemChunk {
   }
 
   @Override
-  public void encode(BlockingQueue<Object> ioTaskQueue, BatchEncodeInfo 
encodeInfo, long[] times) {
+  public void encode(
+      BlockingQueue<Object> ioTaskQueue,
+      BatchEncodeInfo encodeInfo,
+      long[] times,
+      boolean ignoreAllNullRows) {
     if (TVLIST_SORT_THRESHOLD == 0) {
       encodeWorkingTVList(
           ioTaskQueue, encodeInfo.maxNumberOfPointsInChunk, 
encodeInfo.targetChunkSize);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkGroup.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkGroup.java
index 6f5c63824c4..9f27648b0ae 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkGroup.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkGroup.java
@@ -93,10 +93,10 @@ public class WritableMemChunkGroup implements 
IWritableMemChunkGroup {
   }
 
   @Override
-  public long count() {
+  public long count(boolean ignoreAllNullRows) {
     long count = 0;
     for (IWritableMemChunk memChunk : memChunkMap.values()) {
-      count += memChunk.count();
+      count += memChunk.count(ignoreAllNullRows);
     }
     return count;
   }
@@ -118,17 +118,19 @@ public class WritableMemChunkGroup implements 
IWritableMemChunkGroup {
   }
 
   @Override
-  public Map<String, IWritableMemChunk> getMemChunkMap() {
+  public Map<String, IWritableMemChunk> getMemChunkMap(boolean 
ignoreAllNullRows) {
+    // a group of non-aligned chunks never stores all-null rows, so 
ignoreAllNullRows makes no
+    // difference
     return memChunkMap;
   }
 
   @Override
-  public boolean isEmpty() {
-    return memChunkMap.isEmpty() || count() == 0;
+  public boolean isEmpty(boolean ignoreAllNullRows) {
+    return memChunkMap.isEmpty() || count(ignoreAllNullRows) == 0;
   }
 
   @Override
-  public long delete(ModEntry modEntry) {
+  public long delete(ModEntry modEntry, boolean ignoreAllNullRows) {
     Iterator<Entry<String, IWritableMemChunk>> iter = 
memChunkMap.entrySet().iterator();
     long deletedPointsNumber = 0;
     while (iter.hasNext()) {
@@ -140,11 +142,11 @@ public class WritableMemChunkGroup implements 
IWritableMemChunkGroup {
       IWritableMemChunk chunk = entry.getValue();
       if (modEntry.getStartTime() == Long.MIN_VALUE && modEntry.getEndTime() 
== Long.MAX_VALUE) {
         iter.remove();
-        deletedPointsNumber += chunk.count();
+        deletedPointsNumber += chunk.count(ignoreAllNullRows);
         chunk.release();
       } else {
         deletedPointsNumber += chunk.delete(modEntry.getStartTime(), 
modEntry.getEndTime());
-        if (chunk.count() == 0) {
+        if (chunk.count(ignoreAllNullRows) == 0) {
           iter.remove();
         }
       }
@@ -153,8 +155,8 @@ public class WritableMemChunkGroup implements 
IWritableMemChunkGroup {
   }
 
   @Override
-  public long deleteTime(ModEntry modEntry) {
-    return delete(modEntry);
+  public long deleteTime(ModEntry modEntry, boolean ignoreAllNullRows) {
+    return delete(modEntry, ignoreAllNullRows);
   }
 
   @Override
@@ -166,10 +168,10 @@ public class WritableMemChunkGroup implements 
IWritableMemChunkGroup {
   }
 
   @Override
-  public long getMaxTime() {
+  public long getMaxTime(boolean ignoreAllNullRows) {
     long maxTime = Long.MIN_VALUE;
     for (IWritableMemChunk memChunk : memChunkMap.values()) {
-      maxTime = Math.max(maxTime, memChunk.getMaxTime());
+      maxTime = Math.max(maxTime, memChunk.getMaxTime(ignoreAllNullRows));
     }
     return maxTime;
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/TsFilePlanRedoer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/TsFilePlanRedoer.java
index 221d39cdfcc..8e191d475ba 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/TsFilePlanRedoer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/TsFilePlanRedoer.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.commons.path.MeasurementPath;
 import org.apache.iotdb.commons.service.metric.MetricService;
 import org.apache.iotdb.commons.service.metric.enums.Metric;
 import org.apache.iotdb.commons.service.metric.enums.Tag;
+import org.apache.iotdb.commons.utils.PathUtils;
 import org.apache.iotdb.db.exception.WriteProcessException;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.DeleteDataNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertNode;
@@ -55,11 +56,15 @@ import java.util.Optional;
  */
 public class TsFilePlanRedoer {
   private final TsFileResource tsFileResource;
+  // whether rows whose values are all null should be ignored, which depends 
on the data model of
+  // the database this tsfile belongs to
+  private final boolean ignoreAllNullRows;
   // store data when redoing logs
   private IMemTable recoveryMemTable;
 
   public TsFilePlanRedoer(TsFileResource tsFileResource) {
     this.tsFileResource = tsFileResource;
+    this.ignoreAllNullRows = 
!PathUtils.isTableModelDatabase(tsFileResource.getDatabaseName());
     this.recoveryMemTable =
         new PrimitiveMemTable(tsFileResource.getDatabaseName(), 
tsFileResource.getDataRegionId());
     
WritingMetrics.getInstance().recordActiveMemTableCount(tsFileResource.getDataRegionId(),
 1);
@@ -73,7 +78,7 @@ public class TsFilePlanRedoer {
       TreeDeletionEntry deletionEntry =
           new TreeDeletionEntry(
               path, deleteDataNode.getDeleteStartTime(), 
deleteDataNode.getDeleteEndTime());
-      recoveryMemTable.delete(deletionEntry);
+      recoveryMemTable.delete(deletionEntry, ignoreAllNullRows);
       deletionEntries.add(deletionEntry);
     }
     tsFileResource.getModFileForWrite().write(deletionEntries);
@@ -81,7 +86,7 @@ public class TsFilePlanRedoer {
 
   void redoDelete(RelationalDeleteDataNode node) throws IOException {
     for (TableDeletionEntry modEntry : node.getModEntries()) {
-      recoveryMemTable.delete(modEntry);
+      recoveryMemTable.delete(modEntry, ignoreAllNullRows);
     }
     tsFileResource.getModFileForWrite().write(node.getModEntries());
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/UnsealedTsFileRecoverPerformer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/UnsealedTsFileRecoverPerformer.java
index abce4d0ec03..d8369e2c406 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/UnsealedTsFileRecoverPerformer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/UnsealedTsFileRecoverPerformer.java
@@ -192,13 +192,15 @@ public class UnsealedTsFileRecoverPerformer extends 
AbstractTsFileRecoverPerform
                           new DeletionPredicate(device.getTableName(), new 
FullExactMatch(device)),
                           new TimeRange(
                               tsFileResource.getStartTime(device).get(),
-                              tsFileResource.getEndTime(device).get())));
+                              tsFileResource.getEndTime(device).get())),
+                      !isTableModel);
                 } else {
                   memTable.delete(
                       new TreeDeletionEntry(
                           new MeasurementPath(device, "*"),
                           tsFileResource.getStartTime(device).get(),
-                          tsFileResource.getEndTime(device).get()));
+                          tsFileResource.getEndTime(device).get()),
+                      !isTableModel);
                 }
               }
             }
@@ -269,10 +271,10 @@ public class UnsealedTsFileRecoverPerformer extends 
AbstractTsFileRecoverPerform
       for (Map.Entry<IDeviceID, IWritableMemChunkGroup> deviceEntry : 
memTableMap.entrySet()) {
         IDeviceID deviceId = deviceEntry.getKey();
         for (Map.Entry<String, IWritableMemChunk> measurementEntry :
-            deviceEntry.getValue().getMemChunkMap().entrySet()) {
+            deviceEntry.getValue().getMemChunkMap(!isTableModel).entrySet()) {
           IWritableMemChunk memChunk = measurementEntry.getValue();
           tsFileResource.updateStartTime(deviceId, memChunk.getFirstPoint());
-          tsFileResource.updateEndTime(deviceId, memChunk.getLastPoint());
+          tsFileResource.updateEndTime(deviceId, 
memChunk.getLastPoint(!isTableModel));
         }
       }
       // flush memTable
@@ -283,7 +285,8 @@ public class UnsealedTsFileRecoverPerformer extends 
AbstractTsFileRecoverPerform
                   recoveryMemTable,
                   writer,
                   databaseName + FILE_NAME_SEPARATOR + dataRegionId,
-                  dataRegionId);
+                  dataRegionId,
+                  isTableModel);
           tableFlushTask.syncFlushMemTable();
           tsFileResource.updatePlanIndexes(recoveryMemTable.getMinPlanIndex());
           tsFileResource.updatePlanIndexes(recoveryMemTable.getMaxPlanIndex());
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/ImportWAL.java 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/ImportWAL.java
index 265c027e8ac..005b78c5a0c 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/ImportWAL.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/ImportWAL.java
@@ -163,6 +163,7 @@ public class ImportWAL {
                               
.MESSAGE_INFERRED_TABLE_DATABASE_ARG_FROM_WAL_DIRECTORY_ARG_REPLAY_INTO_THIS_DATABASE_Y_YES_A_ACCEPT_ALL_INFERRED_DATABASES_N_QUIT_5B59D833,
                           inferredDatabase,
                           directory));
+      requireResolvedDatabases(directoryDatabases);
       final ReplayStatistics statistics =
           replayWALDirectories(
               walFiles,
@@ -255,7 +256,7 @@ public class ImportWAL {
             .hasArg()
             .desc(
                 ImportWALMessages
-                    
.MESSAGE_TARGET_DATABASE_FOR_TABLE_MODEL_WAL_ENTRIES_IF_OMITTED_INFER_FROM_THE_WAL_PARENT_DIRECTORY_AND_ASK_FOR_CONFIRMATION_4B1E409D)
+                    
.MESSAGE_TARGET_DATABASE_FOR_WAL_REPLAY_IF_OMITTED_INFER_FROM_THE_WAL_PARENT_DIRECTORY_IF_INFERENCE_FAILS_DB_DATABASE_IS_REQUIRED_6EEBC019)
             .build());
     options.addOption(
         Option.builder()
@@ -444,8 +445,9 @@ public class ImportWAL {
       final WALReplayer.ReplayDecisionController replayDecisionController)
       throws IOException {
     final Session treeSession = createSession(host, port, username, password, 
null);
+    final boolean isTableModel = database != null && 
PathUtils.isTableModelDatabase(database);
     final Session tableSession =
-        database == null ? null : createSession(host, port, username, 
password, database);
+        isTableModel ? createSession(host, port, username, password, database) 
: null;
     try {
       treeSession.open(false);
       if (tableSession != null) {
@@ -576,6 +578,26 @@ public class ImportWAL {
     return databases;
   }
 
+  /**
+   * The data model of every directory must be known before any replay starts, 
otherwise a WAL
+   * snapshot could only be replayed with a guessed model.
+   */
+  static void requireResolvedDatabases(final Map<Path, String> 
directoryDatabases) {
+    final List<String> unresolvedDirectories = new ArrayList<>();
+    for (final Map.Entry<Path, String> entry : directoryDatabases.entrySet()) {
+      if (entry.getValue() == null) {
+        unresolvedDirectories.add(entry.getKey().toString());
+      }
+    }
+    if (!unresolvedDirectories.isEmpty()) {
+      throw new IllegalArgumentException(
+          String.format(
+              ImportWALMessages
+                  
.EXCEPTION_CANNOT_DETERMINE_THE_TARGET_DATABASE_OF_WAL_DIRECTORIES_ARG_SPECIFY_DB_DATABASE_WHICH_APPLIES_TO_ALL_IMPORTED_DIRECTORIES_55B174E4,
+              String.join(", ", unresolvedDirectories)));
+    }
+  }
+
   private static final Comparator<Path> WAL_FILE_COMPARATOR =
       Comparator.comparing((Path path) -> Objects.toString(path.getParent(), 
""))
           .thenComparingLong(ImportWAL::getWALVersion)
@@ -936,6 +958,7 @@ public class ImportWAL {
 
     private final Session treeSession;
     private final Session tableSession;
+    private final boolean isTableModel;
     private final ConsensusLogToTabletConverter converter;
     private final ReplayDecisionPrompt replayDecisionPrompt;
     private final Map<String, TableSchema> tableSchemas = new HashMap<>();
@@ -949,6 +972,15 @@ public class ImportWAL {
           new ReplayDecisionController(System.console()));
     }
 
+    /**
+     * @param treeSession the session which replays tree model entries, it 
carries no database
+     * @param tableSession the session which replays table model entries, null 
when no table
+     *     database is declared
+     * @param tableDatabaseName the target database resolved before replay; 
null means no table
+     *     database is declared, so the entries are replayed with the tree 
model only
+     * @param replayDecisionPrompt the prompt which decides how to handle 
entries that cannot be
+     *     replayed automatically
+     */
     WALReplayer(
         final Session treeSession,
         final Session tableSession,
@@ -956,10 +988,12 @@ public class ImportWAL {
         final ReplayDecisionPrompt replayDecisionPrompt) {
       this.treeSession = treeSession;
       this.tableSession = tableSession;
+      this.isTableModel =
+          tableDatabaseName != null && 
PathUtils.isTableModelDatabase(tableDatabaseName);
       this.replayDecisionPrompt = replayDecisionPrompt;
       converter =
           new ConsensusLogToTabletConverter(
-              null, null, ColumnFilterMatcher.matchAll(), tableDatabaseName);
+              null, null, ColumnFilterMatcher.matchAll(), isTableModel ? 
tableDatabaseName : null);
     }
 
     @Override
@@ -972,9 +1006,8 @@ public class ImportWAL {
         throws IoTDBConnectionException, StatementExecutionException {
       if (entry.getType() == WALEntryType.MEMORY_TABLE_SNAPSHOT
           || entry.getType() == WALEntryType.OLD_MEMORY_TABLE_SNAPSHOT) {
-        return replayMemTableSnapshot((IMemTable) entry.getValue())
-            ? ReplayResult.REPLAYED
-            : ReplayResult.IGNORED;
+        final IMemTable memTable = (IMemTable) entry.getValue();
+        return replayMemTableSnapshot(memTable) ? ReplayResult.REPLAYED : 
ReplayResult.IGNORED;
       }
       if (entry.getValue() instanceof InsertNode insertNode) {
         replayInsert(insertNode);
@@ -1318,8 +1351,8 @@ public class ImportWAL {
           memTable.getMemTableMap().entrySet()) {
         final IDeviceID deviceId = deviceEntry.getKey();
         final IWritableMemChunkGroup group = deviceEntry.getValue();
-        for (IWritableMemChunk chunk : group.getMemChunkMap().values()) {
-          if (chunk == null || chunk.isEmpty()) {
+        for (IWritableMemChunk chunk : 
group.getMemChunkMap(!isTableModel).values()) {
+          if (chunk == null || chunk.isEmpty(!isTableModel)) {
             continue;
           }
           if (chunk instanceof AlignedWritableMemChunk) {
@@ -1336,8 +1369,7 @@ public class ImportWAL {
         final IDeviceID deviceId, final IWritableMemChunk chunk)
         throws IoTDBConnectionException, StatementExecutionException {
       final List<IMeasurementSchema> schemas = 
Collections.singletonList(chunk.getSchema());
-      final boolean tableModel = deviceId.isTableModel();
-      requireTableSessionIfNeeded(tableModel);
+      requireTableSessionIfNeeded(isTableModel);
       final TableTabletSchema tabletSchema = createTableTabletSchema(deviceId, 
schemas);
       final List<TVList> lists = new ArrayList<>();
       lists.addAll(chunk.getSortedList());
@@ -1354,7 +1386,7 @@ public class ImportWAL {
           final int end = Math.min(start + SNAPSHOT_TABLET_ROW_LIMIT, 
list.rowCount());
           final Tablet tablet =
               buildNonAlignedTablet(deviceId, tabletSchema, schemas, list, 
start, end);
-          sendTablet(tablet, tableModel, false);
+          sendTablet(tablet, isTableModel, false);
           replayed = true;
         }
       }
@@ -1364,8 +1396,7 @@ public class ImportWAL {
     private boolean replayAlignedMemChunk(
         final IDeviceID deviceId, final AlignedWritableMemChunk chunk)
         throws IoTDBConnectionException, StatementExecutionException {
-      final boolean tableModel = deviceId.isTableModel();
-      requireTableSessionIfNeeded(tableModel);
+      requireTableSessionIfNeeded(isTableModel);
       final List<IMeasurementSchema> schemas = chunk.getSchemaList();
       final TableTabletSchema tabletSchema = createTableTabletSchema(deviceId, 
schemas);
       final List<AlignedTVList> lists = new ArrayList<>();
@@ -1384,7 +1415,7 @@ public class ImportWAL {
           final int end = Math.min(start + SNAPSHOT_TABLET_ROW_LIMIT, 
replayableRows.size());
           final Tablet tablet =
               buildAlignedTablet(deviceId, tabletSchema, schemas, list, 
replayableRows, start, end);
-          sendTablet(tablet, tableModel, true);
+          sendTablet(tablet, isTableModel, true);
           replayed = true;
         }
       }
@@ -1412,7 +1443,7 @@ public class ImportWAL {
     private TableTabletSchema createTableTabletSchema(
         final IDeviceID deviceId, final List<IMeasurementSchema> fieldSchemas)
         throws IoTDBConnectionException, StatementExecutionException {
-      if (!deviceId.isTableModel()) {
+      if (!isTableModel) {
         return new TableTabletSchema(fieldSchemas, null, 0);
       }
       final List<IMeasurementSchema> tagSchemas =
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceExecutionTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceExecutionTest.java
index 79e66f92d9e..0caf1692f63 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceExecutionTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceExecutionTest.java
@@ -209,7 +209,7 @@ public class FragmentInstanceExecutionTest {
                   new MeasurementSchema("s0", TSDataType.INT64, 
TSEncoding.PLAIN),
                   new MeasurementSchema("s1", TSDataType.INT64, 
TSEncoding.PLAIN),
                   new MeasurementSchema("s2", TSDataType.INT64, 
TSEncoding.PLAIN)));
-      AlignedWritableMemChunk memChunk = new AlignedWritableMemChunk(schemas, 
true);
+      AlignedWritableMemChunk memChunk = new AlignedWritableMemChunk(schemas);
       for (int i = 0; i < 100; i++) {
         memChunk.putAlignedRow(i, new Object[] {(long) i, (long) i * 2, (long) 
i * 3});
       }
@@ -265,8 +265,8 @@ public class FragmentInstanceExecutionTest {
       IMemTable memTable = createMemTable(deviceId, measurementId);
       assertEquals(1, memTable.getMemTableMap().size());
       IWritableMemChunkGroup memChunkGroup = 
memTable.getMemTableMap().values().iterator().next();
-      assertEquals(1, memChunkGroup.getMemChunkMap().size());
-      IWritableMemChunk memChunk = 
memChunkGroup.getMemChunkMap().values().iterator().next();
+      assertEquals(1, memChunkGroup.getMemChunkMap(true).size());
+      IWritableMemChunk memChunk = 
memChunkGroup.getMemChunkMap(true).values().iterator().next();
       TVList tvList = memChunk.getWorkingTVList();
       assertFalse(tvList.isSorted());
 
@@ -330,8 +330,8 @@ public class FragmentInstanceExecutionTest {
 
       assertEquals(1, memTable.getMemTableMap().size());
       IWritableMemChunkGroup memChunkGroup = 
memTable.getMemTableMap().values().iterator().next();
-      assertEquals(1, memChunkGroup.getMemChunkMap().size());
-      IWritableMemChunk memChunk = 
memChunkGroup.getMemChunkMap().values().iterator().next();
+      assertEquals(1, memChunkGroup.getMemChunkMap(true).size());
+      IWritableMemChunk memChunk = 
memChunkGroup.getMemChunkMap(true).values().iterator().next();
       AlignedTVList workingTvList = (AlignedTVList) 
memChunk.getWorkingTVList();
       assertFalse(workingTvList.isSorted());
       assertEquals(100, workingTvList.rowCount());
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedBitmapMemoryAccountingPerformanceTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedBitmapMemoryAccountingPerformanceTest.java
index b18b543a2d5..b9b9fd53685 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedBitmapMemoryAccountingPerformanceTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedBitmapMemoryAccountingPerformanceTest.java
@@ -266,14 +266,14 @@ public class AlignedBitmapMemoryAccountingPerformanceTest 
{
   private static AlignedWritableMemChunk[] createMemChunks(Scenario scenario, 
int count) {
     AlignedWritableMemChunk[] memChunks = new AlignedWritableMemChunk[count];
     for (int i = 0; i < count; i++) {
-      memChunks[i] = new AlignedWritableMemChunk(new 
ArrayList<>(scenario.schemas), false);
+      memChunks[i] = new AlignedWritableMemChunk(new 
ArrayList<>(scenario.schemas));
     }
     return memChunks;
   }
 
   private static AccountingTarget createAccountingTarget(Scenario scenario) {
     AlignedWritableMemChunk memChunk =
-        new AlignedWritableMemChunk(new ArrayList<>(scenario.schemas), false);
+        new AlignedWritableMemChunk(new ArrayList<>(scenario.schemas));
     memChunk.writeAlignedTablet(
         scenario.times,
         scenario.columns,
@@ -290,7 +290,7 @@ public class AlignedBitmapMemoryAccountingPerformanceTest {
             Collections.singletonMap(
                 deviceId,
                 new AlignedWritableMemChunkGroup(
-                    memChunk, new ArrayList<>(scenario.schemas), false)));
+                    memChunk, new ArrayList<>(scenario.schemas))));
     return new AccountingTarget(memTable, deviceId);
   }
 
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/MemChunkDeserializeTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/MemChunkDeserializeTest.java
index 5595390752a..682b4b287d2 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/MemChunkDeserializeTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/MemChunkDeserializeTest.java
@@ -239,7 +239,7 @@ public class MemChunkDeserializeTest {
             new MeasurementSchema("s4", TSDataType.FLOAT),
             new MeasurementSchema("s5", TSDataType.DOUBLE),
             new MeasurementSchema("s6", TSDataType.TEXT));
-    AlignedWritableMemChunk series = new AlignedWritableMemChunk(schemaList, 
false);
+    AlignedWritableMemChunk series = new AlignedWritableMemChunk(schemaList);
 
     int count = 1000;
     for (int i = 0; i < count; i++) {
@@ -261,7 +261,7 @@ public class MemChunkDeserializeTest {
     series.serializeToWAL(walBuffer);
     DataInputStream inputStream =
         new DataInputStream(new 
ByteArrayInputStream(walBuffer.getBuffer().array()));
-    AlignedWritableMemChunk memChunk = 
AlignedWritableMemChunk.deserialize(inputStream, false);
+    AlignedWritableMemChunk memChunk = 
AlignedWritableMemChunk.deserialize(inputStream);
 
     AlignedReadOnlyMemChunk readableChunk =
         (AlignedReadOnlyMemChunk) getAlignedReadOnlyChunk(memChunk, 
schemaList, measurementList);
@@ -293,7 +293,7 @@ public class MemChunkDeserializeTest {
     series.writeNonAlignedPoint(1, 1);
 
     WritableMemChunkGroup group = new WritableMemChunkGroup();
-    group.getMemChunkMap().put(measurement, series);
+    group.getMemChunkMap(true).put(measurement, series);
 
     WALByteBufferForTest walBuffer =
         new WALByteBufferForTest(ByteBuffer.allocate(group.serializedSize()));
@@ -303,7 +303,7 @@ public class MemChunkDeserializeTest {
     DataInputStream inputStream =
         new DataInputStream(new 
ByteArrayInputStream(walBuffer.getBuffer().array()));
     WritableMemChunkGroup deserialized = 
WritableMemChunkGroup.deserialize(inputStream);
-    Assert.assertTrue(deserialized.getMemChunkMap().containsKey(measurement));
+    
Assert.assertTrue(deserialized.getMemChunkMap(true).containsKey(measurement));
   }
 
   private WritableMemChunk createWritableMemChunkFromBytes(WritableMemChunk 
series)
@@ -319,7 +319,7 @@ public class MemChunkDeserializeTest {
   private ReadOnlyMemChunk getReadOnlyChunk(WritableMemChunk memChunk, 
TSDataType dataType)
       throws QueryProcessException, IOException, MetadataException {
     WritableMemChunkGroup memChunkGroup = new WritableMemChunkGroup();
-    memChunkGroup.getMemChunkMap().put("s1", memChunk);
+    memChunkGroup.getMemChunkMap(true).put("s1", memChunk);
     Map<IDeviceID, IWritableMemChunkGroup> memTableMap = new HashMap<>();
     memTableMap.put(deviceID, memChunkGroup);
     IMemTable memTable = new PrimitiveMemTable(storageGroup, dataRegionId, 
memTableMap);
@@ -343,7 +343,7 @@ public class MemChunkDeserializeTest {
       List<String> measurementList)
       throws QueryProcessException, IOException, MetadataException {
     AlignedWritableMemChunkGroup memChunkGroup =
-        new AlignedWritableMemChunkGroup(memChunk, schemaList, false);
+        new AlignedWritableMemChunkGroup(memChunk, schemaList);
     Map<IDeviceID, IWritableMemChunkGroup> memTableMap = new HashMap<>();
     memTableMap.put(deviceID, memChunkGroup);
     IMemTable memTable = new PrimitiveMemTable(storageGroup, dataRegionId, 
memTableMap);
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/MemTableFlushTaskTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/MemTableFlushTaskTest.java
index afe0384839b..ef4c520b135 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/MemTableFlushTaskTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/MemTableFlushTaskTest.java
@@ -97,7 +97,7 @@ public class MemTableFlushTaskTest {
         MemTableTestUtils.measurementId0,
         MemTableTestUtils.dataType0);
     MemTableFlushTask memTableFlushTask =
-        new MemTableFlushTask(memTable, writer, storageGroup, dataRegionId);
+        new MemTableFlushTask(memTable, writer, storageGroup, dataRegionId, 
true);
     assertTrue(
         writer
             .getVisibleMetadataList(
@@ -134,7 +134,7 @@ public class MemTableFlushTaskTest {
       throws ExecutionException, InterruptedException, IllegalPathException, 
WriteProcessException {
     MemTableTestUtils.produceVectorData(memTable);
     MemTableFlushTask memTableFlushTask =
-        new MemTableFlushTask(memTable, writer, storageGroup, dataRegionId);
+        new MemTableFlushTask(memTable, writer, storageGroup, dataRegionId, 
true);
     assertTrue(
         writer
             .getVisibleMetadataList(MemTableTestUtils.deviceId0, "sensor0", 
TSDataType.BOOLEAN)
@@ -162,7 +162,7 @@ public class MemTableFlushTaskTest {
       throws ExecutionException, InterruptedException, IllegalPathException, 
WriteProcessException {
     MemTableTestUtils.produceNullableVectorData(memTable);
     MemTableFlushTask memTableFlushTask =
-        new MemTableFlushTask(memTable, writer, storageGroup, dataRegionId);
+        new MemTableFlushTask(memTable, writer, storageGroup, dataRegionId, 
true);
     assertTrue(
         writer
             .getVisibleMetadataList(MemTableTestUtils.deviceId0, "sensor0", 
TSDataType.BOOLEAN)
@@ -192,7 +192,7 @@ public class MemTableFlushTaskTest {
     memChunk.sortTvListForFlush();
 
     BlockingQueue<Object> ioTaskQueue = new LinkedBlockingQueue<>();
-    memChunk.encodeWorkingAlignedTVList(ioTaskQueue, 100, 100);
+    memChunk.encodeWorkingAlignedTVList(ioTaskQueue, 100, 100, true);
 
     assertFalse(memChunk.isColumnMappingBuilt());
     assertFalse(ioTaskQueue.isEmpty());
@@ -206,7 +206,7 @@ public class MemTableFlushTaskTest {
     memChunk.sortTvListForFlush();
 
     BlockingQueue<Object> ioTaskQueue = new LinkedBlockingQueue<>();
-    memChunk.encodeWorkingAlignedTVList(ioTaskQueue, 100, 100);
+    memChunk.encodeWorkingAlignedTVList(ioTaskQueue, 100, 100, true);
 
     assertTrue(memChunk.isColumnMappingBuilt());
     assertFalse(ioTaskQueue.isEmpty());
@@ -228,7 +228,7 @@ public class MemTableFlushTaskTest {
         Arrays.asList(
             new MeasurementSchema("s0", TSDataType.INT64, TSEncoding.PLAIN),
             new MeasurementSchema("s1", TSDataType.INT64, TSEncoding.PLAIN));
-    AlignedWritableMemChunk memChunk = new AlignedWritableMemChunk(schemas, 
true);
+    AlignedWritableMemChunk memChunk = new AlignedWritableMemChunk(schemas);
     String alignedFilePath =
         TestConstant.OUTPUT_DATA_DIR.concat(
             "duplicateAlignedRows-" + removeSecondMeasurement + ".tsfile");
@@ -245,7 +245,7 @@ public class MemTableFlushTaskTest {
       memChunk.sortTvListForFlush();
 
       BlockingQueue<Object> ioTaskQueue = new LinkedBlockingQueue<>();
-      memChunk.encodeWorkingAlignedTVList(ioTaskQueue, 100, 100);
+      memChunk.encodeWorkingAlignedTVList(ioTaskQueue, 100, 100, false);
       try (TsFileIOWriter alignedWriter = new TsFileIOWriter(new 
File(alignedFilePath))) {
         
alignedWriter.startChunkGroup(IDeviceID.Factory.DEFAULT_FACTORY.create("root.d"));
         Object task;
@@ -304,7 +304,7 @@ public class MemTableFlushTaskTest {
         Arrays.asList(
             new MeasurementSchema("s0", TSDataType.INT64, TSEncoding.PLAIN),
             new MeasurementSchema("s1", TSDataType.INT64, TSEncoding.PLAIN));
-    AlignedWritableMemChunk memChunk = new AlignedWritableMemChunk(schemas, 
false);
+    AlignedWritableMemChunk memChunk = new AlignedWritableMemChunk(schemas);
     String alignedFilePath = 
TestConstant.OUTPUT_DATA_DIR.concat("testAlignedFastPath.tsfile");
 
     try {
@@ -320,7 +320,7 @@ public class MemTableFlushTaskTest {
       memChunk.sortTvListForFlush();
 
       BlockingQueue<Object> ioTaskQueue = new LinkedBlockingQueue<>();
-      memChunk.encodeWorkingAlignedTVList(ioTaskQueue, rowCount, 1024);
+      memChunk.encodeWorkingAlignedTVList(ioTaskQueue, rowCount, 1024, true);
       try (TsFileIOWriter alignedWriter = new TsFileIOWriter(new 
File(alignedFilePath))) {
         
alignedWriter.startChunkGroup(IDeviceID.Factory.DEFAULT_FACTORY.create("root.d"));
         Object task;
@@ -373,7 +373,7 @@ public class MemTableFlushTaskTest {
           Arrays.asList(
               new MeasurementSchema("s0", TSDataType.INT32, TSEncoding.PLAIN),
               new MeasurementSchema("s1", TSDataType.INT64, TSEncoding.PLAIN));
-      AlignedWritableMemChunk memChunk = new AlignedWritableMemChunk(schemas, 
false);
+      AlignedWritableMemChunk memChunk = new AlignedWritableMemChunk(schemas);
       String alignedFilePath =
           TestConstant.OUTPUT_DATA_DIR.concat("testAlignedTimeDeletion" + 
pageSize + ".tsfile");
       try {
@@ -389,7 +389,7 @@ public class MemTableFlushTaskTest {
 
         BlockingQueue<Object> ioTaskQueue = new LinkedBlockingQueue<>();
         // Cover a single page and boundaries between pages and chunks.
-        memChunk.encodeWorkingAlignedTVList(ioTaskQueue, pageSize + 1, 
pageSize);
+        memChunk.encodeWorkingAlignedTVList(ioTaskQueue, pageSize + 1, 
pageSize, true);
         try (TsFileIOWriter alignedWriter = new TsFileIOWriter(new 
File(alignedFilePath))) {
           
alignedWriter.startChunkGroup(IDeviceID.Factory.DEFAULT_FACTORY.create("root.d"));
           Object task;
@@ -464,7 +464,7 @@ public class MemTableFlushTaskTest {
       schemas.add(new MeasurementSchema("s" + column, types.get(column), 
TSEncoding.PLAIN));
     }
     schemas.add(new MeasurementSchema("empty", TSDataType.INT64, 
TSEncoding.PLAIN));
-    AlignedWritableMemChunk chunk = new AlignedWritableMemChunk(schemas, true);
+    AlignedWritableMemChunk chunk = new AlignedWritableMemChunk(schemas);
     Object[][] expected = new Object[rowCount][types.size()];
     String path = TestConstant.OUTPUT_DATA_DIR.concat("unmaterialized-" + 
moved + ".tsfile");
     try {
@@ -502,7 +502,7 @@ public class MemTableFlushTaskTest {
       }
       chunk.sortTvListForFlush();
       BlockingQueue<Object> queue = new LinkedBlockingQueue<>();
-      chunk.encodeWorkingAlignedTVList(queue, ARRAY_SIZE * 5 + 3, ARRAY_SIZE + 
3);
+      chunk.encodeWorkingAlignedTVList(queue, ARRAY_SIZE * 5 + 3, ARRAY_SIZE + 
3, false);
       try (TsFileIOWriter fileWriter = new TsFileIOWriter(new File(path))) {
         
fileWriter.startChunkGroup(IDeviceID.Factory.DEFAULT_FACTORY.create("root.d"));
         Object task;
@@ -559,7 +559,7 @@ public class MemTableFlushTaskTest {
     private boolean columnMappingBuilt;
 
     private TrackingAlignedWritableMemChunk(List<IMeasurementSchema> 
schemaList) {
-      super(schemaList, false);
+      super(schemaList);
     }
 
     @Override
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/PrimitiveMemTableTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/PrimitiveMemTableTest.java
index dffd4d941d0..5a0f8a1e800 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/PrimitiveMemTableTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/PrimitiveMemTableTest.java
@@ -183,11 +183,14 @@ public class PrimitiveMemTableTest {
           new StringArrayDeviceID("root.test.d1"), measurementSchemas, i, new 
Object[] {i, i, i});
     }
     memTable.delete(
-        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s1", 
TSDataType.INT32), 150, 160));
+        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s1", 
TSDataType.INT32), 150, 160),
+        true);
     memTable.delete(
-        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s2", 
TSDataType.INT32), 150, 160));
+        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s2", 
TSDataType.INT32), 150, 160),
+        true);
     memTable.delete(
-        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s3", 
TSDataType.INT32), 150, 160));
+        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s3", 
TSDataType.INT32), 150, 160),
+        true);
     ResourceByPathUtils resourcesByPathUtils =
         ResourceByPathUtils.getResourceInstance(
             new AlignedFullPath(
@@ -230,11 +233,14 @@ public class PrimitiveMemTableTest {
           new StringArrayDeviceID("root.test.d1"), measurementSchemas, i, new 
Object[] {i, i, i});
     }
     memTable.delete(
-        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s1", 
TSDataType.INT32), 150, 160));
+        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s1", 
TSDataType.INT32), 150, 160),
+        true);
     memTable.delete(
-        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s2", 
TSDataType.INT32), 150, 160));
+        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s2", 
TSDataType.INT32), 150, 160),
+        true);
     memTable.delete(
-        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s3", 
TSDataType.INT32), 150, 160));
+        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s3", 
TSDataType.INT32), 150, 160),
+        true);
     ResourceByPathUtils resourcesByPathUtils =
         ResourceByPathUtils.getResourceInstance(
             new AlignedFullPath(
@@ -290,11 +296,14 @@ public class PrimitiveMemTableTest {
       memTable.writeAlignedRow(deviceID, measurementSchemas, i, new Object[] 
{i, i, i});
     }
     memTable.delete(
-        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s1", 
TSDataType.INT32), 1, 10));
+        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s1", 
TSDataType.INT32), 1, 10),
+        true);
     memTable.delete(
-        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s2", 
TSDataType.INT32), 1, 10));
+        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s2", 
TSDataType.INT32), 1, 10),
+        true);
     memTable.delete(
-        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s3", 
TSDataType.INT32), 1, 10));
+        new TreeDeletionEntry(new MeasurementPath("root.test.d1.s3", 
TSDataType.INT32), 1, 10),
+        true);
     Assert.assertFalse(originalWorkingList.isSorted());
 
     AlignedReadOnlyMemChunk flushingQueryMemChunk =
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkRegionScanTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkRegionScanTest.java
index a1ba4cee074..d22e41c35f5 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkRegionScanTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkRegionScanTest.java
@@ -266,7 +266,8 @@ public class WritableMemChunkRegionScanTest {
       memTable.delete(
           new TreeDeletionEntry(
               new MeasurementPath(new StringArrayDeviceID("root.test.d1"), 
"s1"),
-              new TimeRange(1, 1500)));
+              new TimeRange(1, 1500)),
+          true);
       writableMemChunk =
           (AlignedWritableMemChunk)
               memTable.getWritableMemChunk(new 
StringArrayDeviceID("root.test.d1"), "");
@@ -296,7 +297,7 @@ public class WritableMemChunkRegionScanTest {
             new MeasurementSchema("s2", TSDataType.INT32),
             new MeasurementSchema("s3", TSDataType.INT32));
     AlignedWritableMemChunk writableMemChunk =
-        new AlignedWritableMemChunk(measurementSchemas, true);
+        new AlignedWritableMemChunk(measurementSchemas);
     int size = 100000;
     for (int i = 0; i < size; i++) {
       if (i <= 10000) {
@@ -429,7 +430,8 @@ public class WritableMemChunkRegionScanTest {
       memTable.delete(
           new TreeDeletionEntry(
               new MeasurementPath(new StringArrayDeviceID("root.test.d1"), 
"s1"),
-              new TimeRange(1, 1500)));
+              new TimeRange(1, 1500)),
+          true);
       WritableMemChunk writableMemChunk =
           (WritableMemChunk)
               memTable.getWritableMemChunk(new 
StringArrayDeviceID("root.test.d1"), "s1");
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/tools/ImportWALTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/tools/ImportWALTest.java
index aa71595d443..bcc5ee2df45 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/tools/ImportWALTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/tools/ImportWALTest.java
@@ -304,6 +304,49 @@ public class ImportWALTest {
     assertTrue(databases.values().stream().allMatch(database -> database == 
null));
   }
 
+  /**
+   * Every directory must declare a database before any replay starts, 
otherwise the data model of a
+   * WAL snapshot could only be guessed.
+   */
+  @Test
+  public void testUnresolvedDirectoryRequiresExplicitDatabase() {
+    final List<Path> files =
+        Arrays.asList(
+            Paths.get("factory-3/one.wal"),
+            Paths.get("0/two.wal"),
+            Paths.get("root.sg-4/three.wal"));
+    ImportWAL.requireResolvedDatabases(
+        ImportWAL.resolveDirectoryDatabases(files, "target", true, null));
+
+    final Map<Path, String> unresolved =
+        ImportWAL.resolveDirectoryDatabases(files, null, true, null);
+    final IllegalArgumentException failure =
+        assertThrows(
+            IllegalArgumentException.class,
+            () -> ImportWAL.requireResolvedDatabases(unresolved));
+    // The inferable directory is not reported, the others are listed in 
directory order.
+    assertTrue(failure.getMessage().contains("0, root.sg-4"));
+    assertTrue(failure.getMessage().contains("-db/--database"));
+  }
+
+  /** A directory whose database cannot be inferred must fail before any 
Session is opened. */
+  @Test
+  public void testUnresolvedDatabaseFailsBeforeReplay() throws Exception {
+    final Path directory = temporaryFolder.newFolder("0").toPath();
+    createWALFile(directory, 0);
+    final ByteArrayOutputStream error = new ByteArrayOutputStream();
+
+    assertEquals(
+        1,
+        ImportWAL.run(
+            new String[] {"-f", directory.toString(), "-pw", "password"},
+            new PrintStream(error),
+            new PrintStream(error)));
+
+    assertTrue(error.toString().contains(directory.toString()));
+    assertTrue(error.toString().contains("-db/--database"));
+  }
+
   /**
    * One thread may visit several databases; each directory needs its own 
Session and schema cache.
    */
@@ -1547,7 +1590,8 @@ public class ImportWALTest {
         new Object[] {10, null, 
DateUtils.parseDateExpressionToInt(firstDate)});
     final Session treeSession = mock(Session.class);
 
-    new ImportWAL.WALReplayer(treeSession, null, null).replay(new 
WALInfoEntry(1, memTable));
+    new ImportWAL.WALReplayer(treeSession, null, "root.sg")
+        .replay(new WALInfoEntry(1, memTable));
 
     final ArgumentCaptor<Tablet> tabletCaptor = 
ArgumentCaptor.forClass(Tablet.class);
     verify(treeSession, times(3)).insertTablet(tabletCaptor.capture());
@@ -1593,7 +1637,8 @@ public class ImportWALTest {
         new Object[] {10, 100L, 
DateUtils.parseDateExpressionToInt(firstDate)});
     final Session treeSession = mock(Session.class);
 
-    new ImportWAL.WALReplayer(treeSession, null, null).replay(new 
WALInfoEntry(1, memTable));
+    new ImportWAL.WALReplayer(treeSession, null, "root.sg")
+        .replay(new WALInfoEntry(1, memTable));
 
     final ArgumentCaptor<Tablet> tabletCaptor = 
ArgumentCaptor.forClass(Tablet.class);
     verify(treeSession).insertAlignedTablet(tabletCaptor.capture());
@@ -1623,7 +1668,7 @@ public class ImportWALTest {
     final ImportWAL.ReplayStatistics statistics =
         ImportWAL.replayWALFiles(
             Collections.singletonList(walFile.toPath()),
-            new ImportWAL.WALReplayer(treeSession, null, null));
+            new ImportWAL.WALReplayer(treeSession, null, "root.sg"));
 
     assertEquals(1, statistics.getReplayedOperationCount());
     final ArgumentCaptor<Tablet> tabletCaptor = 
ArgumentCaptor.forClass(Tablet.class);
@@ -1644,7 +1689,8 @@ public class ImportWALTest {
     }
     final Session treeSession = mock(Session.class);
 
-    new ImportWAL.WALReplayer(treeSession, null, null).replay(new 
WALInfoEntry(1, memTable));
+    new ImportWAL.WALReplayer(treeSession, null, "root.sg")
+        .replay(new WALInfoEntry(1, memTable));
 
     final ArgumentCaptor<Tablet> tabletCaptor = 
ArgumentCaptor.forClass(Tablet.class);
     verify(treeSession, times(2)).insertTablet(tabletCaptor.capture());

Reply via email to