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

xingtanzjr pushed a commit to branch rel/1.1
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/rel/1.1 by this push:
     new c1bec1bb82b [To rel/1.1] Rewrite compaction memory estimator (#10965)
c1bec1bb82b is described below

commit c1bec1bb82bccc8d786e16b77443c04a24115a1c
Author: shuwenwei <[email protected]>
AuthorDate: Tue Aug 29 11:49:07 2023 +0800

    [To rel/1.1] Rewrite compaction memory estimator (#10965)
---
 .../execute/task/AbstractCompactionTask.java       |   2 +
 .../execute/task/CrossSpaceCompactionTask.java     |   1 -
 .../execute/task/InnerSpaceCompactionTask.java     |  35 ++-
 .../compaction/selector/ICompactionSelector.java   |   4 +-
 .../estimator/AbstractCompactionEstimator.java     | 115 +++++++--
 .../estimator/AbstractCrossSpaceEstimator.java     |  28 ++-
 .../estimator/AbstractInnerSpaceEstimator.java     |  14 +-
 .../estimator/CompactionEstimateUtils.java         |  95 ++++++++
 .../selector/estimator/CompactionTaskInfo.java     | 101 ++++++++
 .../FastCompactionInnerCompactionEstimator.java    |  85 +++++++
 .../FastCrossSpaceCompactionEstimator.java         |  81 +++++++
 .../compaction/selector/estimator/FileInfo.java    |  48 ++++
 .../estimator/InplaceCompactionEstimator.java      | 171 --------------
 .../ReadChunkInnerCompactionEstimator.java         |  73 ++++++
 .../ReadPointCrossCompactionEstimator.java         | 262 ---------------------
 .../impl/RewriteCrossSpaceCompactionSelector.java  |  21 +-
 .../utils/CrossCompactionTaskResource.java         |   6 +-
 .../org/apache/iotdb/db/rescon/SystemInfo.java     |   3 +
 .../utils/CompactionTaskMemCostEstimatorTest.java  | 106 +++++++++
 .../iotdb/tsfile/read/TsFileSequenceReader.java    |  12 +-
 20 files changed, 784 insertions(+), 479 deletions(-)

diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/AbstractCompactionTask.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/AbstractCompactionTask.java
index 3246a133866..520a051b13e 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/AbstractCompactionTask.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/AbstractCompactionTask.java
@@ -55,6 +55,8 @@ public abstract class AbstractCompactionTask {
   protected boolean crossTask;
   protected boolean innerSeqTask;
 
+  protected long memoryCost = 0L;
+
   public AbstractCompactionTask(
       String storageGroupName,
       String dataRegionId,
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/CrossSpaceCompactionTask.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/CrossSpaceCompactionTask.java
index 11ec6228e8a..f260a4c7db8 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/CrossSpaceCompactionTask.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/CrossSpaceCompactionTask.java
@@ -64,7 +64,6 @@ public class CrossSpaceCompactionTask extends 
AbstractCompactionTask {
   protected List<TsFileResource> holdWriteLockList = new ArrayList<>();
   protected double selectedSeqFileSize = 0;
   protected double selectedUnseqFileSize = 0;
-  protected long memoryCost = 0L;
 
   public CrossSpaceCompactionTask(
       long timePartition,
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/InnerSpaceCompactionTask.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/InnerSpaceCompactionTask.java
index 2219fc8d08b..eebc5cc7d40 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/InnerSpaceCompactionTask.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/task/InnerSpaceCompactionTask.java
@@ -23,16 +23,21 @@ import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.engine.TsFileMetricManager;
 import 
org.apache.iotdb.db.engine.compaction.execute.exception.CompactionExceptionHandler;
+import 
org.apache.iotdb.db.engine.compaction.execute.exception.CompactionMemoryNotEnoughException;
 import 
org.apache.iotdb.db.engine.compaction.execute.performer.ICompactionPerformer;
 import 
org.apache.iotdb.db.engine.compaction.execute.performer.impl.FastCompactionPerformer;
 import 
org.apache.iotdb.db.engine.compaction.execute.task.subtask.FastCompactionTaskSummary;
 import org.apache.iotdb.db.engine.compaction.execute.utils.CompactionUtils;
 import 
org.apache.iotdb.db.engine.compaction.execute.utils.log.CompactionLogger;
+import 
org.apache.iotdb.db.engine.compaction.selector.estimator.AbstractInnerSpaceEstimator;
+import 
org.apache.iotdb.db.engine.compaction.selector.estimator.FastCompactionInnerCompactionEstimator;
+import 
org.apache.iotdb.db.engine.compaction.selector.estimator.ReadChunkInnerCompactionEstimator;
 import org.apache.iotdb.db.engine.storagegroup.TsFileManager;
 import org.apache.iotdb.db.engine.storagegroup.TsFileNameGenerator;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResourceList;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResourceStatus;
+import org.apache.iotdb.db.rescon.SystemInfo;
 import org.apache.iotdb.db.service.metrics.recorder.CompactionMetricsManager;
 import org.apache.iotdb.tsfile.common.conf.TSFileConfig;
 import org.apache.iotdb.tsfile.exception.write.TsFileNotCompleteException;
@@ -69,6 +74,8 @@ public class InnerSpaceCompactionTask extends 
AbstractCompactionTask {
 
   protected long maxModsFileSize;
 
+  protected AbstractInnerSpaceEstimator innerSpaceEstimator;
+
   public InnerSpaceCompactionTask(
       long timePartition,
       TsFileManager tsFileManager,
@@ -87,6 +94,13 @@ public class InnerSpaceCompactionTask extends 
AbstractCompactionTask {
     this.selectedTsFileResourceList = selectedTsFileResourceList;
     this.sequence = sequence;
     this.performer = performer;
+    if 
(IoTDBDescriptor.getInstance().getConfig().isEnableCompactionMemControl()) {
+      if (this.performer instanceof ReadChunkInnerCompactionEstimator) {
+        innerSpaceEstimator = new ReadChunkInnerCompactionEstimator();
+      } else if (!sequence && this.performer instanceof 
FastCompactionInnerCompactionEstimator) {
+        innerSpaceEstimator = new FastCompactionInnerCompactionEstimator();
+      }
+    }
     isHoldingReadLock = new boolean[selectedTsFileResourceList.size()];
     isHoldingWriteLock = new boolean[selectedTsFileResourceList.size()];
     for (int i = 0; i < selectedTsFileResourceList.size(); ++i) {
@@ -317,6 +331,7 @@ public class InnerSpaceCompactionTask extends 
AbstractCompactionTask {
             isSequence());
       }
     } finally {
+      SystemInfo.getInstance().resetCompactionMemoryCost(memoryCost);
       releaseAllLocksAndResetStatus();
       return isSuccess;
     }
@@ -458,9 +473,27 @@ public class InnerSpaceCompactionTask extends 
AbstractCompactionTask {
           return false;
         }
       }
+      if (innerSpaceEstimator != null) {
+        memoryCost = 
innerSpaceEstimator.estimateInnerCompactionMemory(selectedTsFileResourceList);
+      }
+      SystemInfo.getInstance().addCompactionMemoryCost(memoryCost, 60);
     } catch (Throwable e) {
+      if (e instanceof InterruptedException) {
+        LOGGER.warn("Interrupted when allocating memory for compaction", e);
+        Thread.currentThread().interrupt();
+      } else if (e instanceof CompactionMemoryNotEnoughException) {
+        LOGGER.warn("No enough memory for current compaction task {}", this, 
e);
+      }
       releaseAllLocksAndResetStatus();
-      throw e;
+      return false;
+    } finally {
+      try {
+        if (innerSpaceEstimator != null) {
+          innerSpaceEstimator.close();
+        }
+      } catch (IOException e) {
+        LOGGER.warn("Failed to close InnerSpaceCompactionMemoryEstimator");
+      }
     }
     return true;
   }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/ICompactionSelector.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/ICompactionSelector.java
index 5f10aeb02f5..f77b868dae5 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/ICompactionSelector.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/ICompactionSelector.java
@@ -21,7 +21,7 @@ package org.apache.iotdb.db.engine.compaction.selector;
 import 
org.apache.iotdb.db.engine.compaction.execute.performer.constant.CrossCompactionPerformer;
 import org.apache.iotdb.db.engine.compaction.schedule.CompactionTaskManager;
 import 
org.apache.iotdb.db.engine.compaction.selector.estimator.AbstractCompactionEstimator;
-import 
org.apache.iotdb.db.engine.compaction.selector.estimator.ReadPointCrossCompactionEstimator;
+import 
org.apache.iotdb.db.engine.compaction.selector.estimator.FastCrossSpaceCompactionEstimator;
 import 
org.apache.iotdb.db.engine.compaction.selector.utils.CrossCompactionTaskResource;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 
@@ -66,7 +66,7 @@ public interface ICompactionSelector {
       case READ_POINT:
       case FAST:
         if (!isInnerSpace) {
-          return new ReadPointCrossCompactionEstimator();
+          return new FastCrossSpaceCompactionEstimator();
         }
       default:
         throw new RuntimeException(
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractCompactionEstimator.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractCompactionEstimator.java
index af5a51be07b..47ac39e2049 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractCompactionEstimator.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractCompactionEstimator.java
@@ -16,55 +16,128 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 package org.apache.iotdb.db.engine.compaction.selector.estimator;
 
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.conf.adapter.CompressionRatio;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
+import org.apache.iotdb.db.engine.storagegroup.timeindex.DeviceTimeIndex;
+import org.apache.iotdb.db.engine.storagegroup.timeindex.FileTimeIndex;
+import org.apache.iotdb.db.engine.storagegroup.timeindex.ITimeIndex;
 import org.apache.iotdb.tsfile.read.TsFileSequenceReader;
 
+import java.io.Closeable;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Estimate the memory cost of one compaction task with specific source files 
based on its
  * corresponding implementation.
  */
-public abstract class AbstractCompactionEstimator {
+public abstract class AbstractCompactionEstimator implements Closeable {
 
-  protected Map<TsFileResource, TsFileSequenceReader> fileReaderCache = new 
HashMap<>();
+  protected Map<TsFileResource, FileInfo> fileInfoCache = new HashMap<>();
+  protected Map<TsFileResource, DeviceTimeIndex> deviceTimeIndexCache = new 
HashMap<>();
 
   protected IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
 
   protected long compressionRatio = (long) 
CompressionRatio.getInstance().getRatio() + 1;
 
-  /**
-   * Estimate the memory cost of compacting the unseq file and its 
corresponding overlapped seq
-   * files in cross space compaction task.
-   */
-  public abstract long estimateCrossCompactionMemory(
-      List<TsFileResource> seqResources, TsFileResource unseqResource) throws 
IOException;
+  protected abstract long calculatingMetadataMemoryCost(CompactionTaskInfo 
taskInfo);
 
-  /** Estimate the memory cost of compacting the source files in inner space 
compaction task. */
-  public abstract long estimateInnerCompactionMemory(List<TsFileResource> 
resources);
+  protected abstract long calculatingDataMemoryCost(CompactionTaskInfo 
taskInfo) throws IOException;
 
-  /** Construct a new or get an existing TsFileSequenceReader of a TsFile. */
-  protected TsFileSequenceReader getFileReader(TsFileResource tsFileResource) 
throws IOException {
-    TsFileSequenceReader reader = fileReaderCache.get(tsFileResource);
-    if (reader == null) {
-      reader = new TsFileSequenceReader(tsFileResource.getTsFilePath(), true, 
false);
-      fileReaderCache.put(tsFileResource, reader);
+  protected CompactionTaskInfo 
calculatingCompactionTaskInfo(List<TsFileResource> resources)
+      throws IOException {
+    List<FileInfo> fileInfoList = new ArrayList<>();
+    for (TsFileResource resource : resources) {
+      FileInfo fileInfo = getFileInfoFromCache(resource);
+      fileInfoList.add(fileInfo);
     }
-    return reader;
+    return new CompactionTaskInfo(resources, fileInfoList);
   }
 
-  public void close() throws IOException {
-    for (TsFileSequenceReader reader : fileReaderCache.values()) {
-      reader.close();
+  private FileInfo getFileInfoFromCache(TsFileResource resource) throws 
IOException {
+    if (fileInfoCache.containsKey(resource)) {
+      return fileInfoCache.get(resource);
+    }
+    try (TsFileSequenceReader reader =
+        new TsFileSequenceReader(resource.getTsFilePath(), true, false)) {
+      FileInfo fileInfo = CompactionEstimateUtils.calculateFileInfo(reader);
+      fileInfoCache.put(resource, fileInfo);
+      return fileInfo;
+    }
+  }
+
+  protected int 
calculatingMaxOverlapFileNumInSubCompactionTask(List<TsFileResource> resources)
+      throws IOException {
+    Set<String> devices = new HashSet<>();
+    List<DeviceTimeIndex> resourceDevices = new ArrayList<>(resources.size());
+    for (TsFileResource resource : resources) {
+      DeviceTimeIndex deviceTimeIndex = getDeviceTimeIndexFromCache(resource);
+      devices.addAll(deviceTimeIndex.getDevices());
+      resourceDevices.add(deviceTimeIndex);
+    }
+    int maxOverlapFileNumInSubCompactionTask = 1;
+    for (String device : devices) {
+      List<DeviceTimeIndex> resourcesContainsCurrentDevice =
+          resourceDevices.stream()
+              .filter(resource -> !resource.definitelyNotContains(device))
+              .sorted(Comparator.comparingLong(resource -> 
resource.getStartTime(device)))
+              .collect(Collectors.toList());
+      if (resourcesContainsCurrentDevice.size() < 
maxOverlapFileNumInSubCompactionTask) {
+        continue;
+      }
+
+      long maxEndTimeOfCurrentDevice = Long.MIN_VALUE;
+      int overlapFileNumOfCurrentDevice = 0;
+      for (DeviceTimeIndex resource : resourcesContainsCurrentDevice) {
+        long deviceStartTimeInCurrentFile = resource.getStartTime(device);
+        long deviceEndTimeInCurrentFile = resource.getEndTime(device);
+        if (deviceStartTimeInCurrentFile <= maxEndTimeOfCurrentDevice) {
+          // has overlap, update max end time
+          maxEndTimeOfCurrentDevice =
+              Math.max(maxEndTimeOfCurrentDevice, deviceEndTimeInCurrentFile);
+          overlapFileNumOfCurrentDevice++;
+          maxOverlapFileNumInSubCompactionTask =
+              Math.max(maxOverlapFileNumInSubCompactionTask, 
overlapFileNumOfCurrentDevice);
+        } else {
+          // reset max end time and overlap file num of current device
+          maxEndTimeOfCurrentDevice = deviceEndTimeInCurrentFile;
+          overlapFileNumOfCurrentDevice = 1;
+        }
+      }
+      // already reach the max value
+      if (maxOverlapFileNumInSubCompactionTask == resources.size()) {
+        return maxOverlapFileNumInSubCompactionTask;
+      }
     }
-    fileReaderCache.clear();
+    return maxOverlapFileNumInSubCompactionTask;
+  }
+
+  private DeviceTimeIndex getDeviceTimeIndexFromCache(TsFileResource resource) 
throws IOException {
+    if (deviceTimeIndexCache.containsKey(resource)) {
+      return deviceTimeIndexCache.get(resource);
+    }
+    ITimeIndex timeIndex = resource.getTimeIndex();
+    if (timeIndex instanceof FileTimeIndex) {
+      timeIndex = resource.buildDeviceTimeIndex();
+    }
+    deviceTimeIndexCache.put(resource, (DeviceTimeIndex) timeIndex);
+    return (DeviceTimeIndex) timeIndex;
+  }
+
+  public void close() throws IOException {
+    deviceTimeIndexCache.clear();
+    fileInfoCache.clear();
   }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractCrossSpaceEstimator.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractCrossSpaceEstimator.java
index 6b6f4744dbc..e0837a328c6 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractCrossSpaceEstimator.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractCrossSpaceEstimator.java
@@ -16,11 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 package org.apache.iotdb.db.engine.compaction.selector.estimator;
 
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -28,11 +30,27 @@ import java.util.List;
  * its corresponding implementation.
  */
 public abstract class AbstractCrossSpaceEstimator extends 
AbstractCompactionEstimator {
-  public abstract long estimateCrossCompactionMemory(
-      List<TsFileResource> seqResources, TsFileResource unseqResource) throws 
IOException;
 
-  public long estimateInnerCompactionMemory(List<TsFileResource> resources) {
-    throw new RuntimeException(
-        "This kind of estimator cannot be used to estimate inner space 
compaction task");
+  public long estimateCrossCompactionMemory(
+      List<TsFileResource> seqResources, List<TsFileResource> unseqResources) 
throws IOException {
+    if (!config.isEnableCompactionMemControl()) {
+      return 0;
+    }
+    List<TsFileResource> resources = new ArrayList<>(seqResources.size() + 
unseqResources.size());
+    resources.addAll(seqResources);
+    resources.addAll(unseqResources);
+    if (!CompactionEstimateUtils.addReadLock(resources)) {
+      return -1L;
+    }
+
+    long cost = 0;
+    try {
+      CompactionTaskInfo taskInfo = calculatingCompactionTaskInfo(resources);
+      cost += calculatingMetadataMemoryCost(taskInfo);
+      cost += calculatingDataMemoryCost(taskInfo);
+    } finally {
+      CompactionEstimateUtils.releaseReadLock(resources);
+    }
+    return cost;
   }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractInnerSpaceEstimator.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractInnerSpaceEstimator.java
index 7010a3cd7c6..e0dc4a7493a 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractInnerSpaceEstimator.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/AbstractInnerSpaceEstimator.java
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 package org.apache.iotdb.db.engine.compaction.selector.estimator;
 
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
@@ -28,11 +29,14 @@ import java.util.List;
  * its corresponding implementation.
  */
 public abstract class AbstractInnerSpaceEstimator extends 
AbstractCompactionEstimator {
-  public abstract long estimateInnerCompactionMemory(List<TsFileResource> 
resources);
 
-  public long estimateCrossCompactionMemory(
-      List<TsFileResource> seqResources, TsFileResource unseqResource) throws 
IOException {
-    throw new RuntimeException(
-        "This kind of estimator cannot be used to estimate cross space 
compaction task");
+  public long estimateInnerCompactionMemory(List<TsFileResource> resources) 
throws IOException {
+    if (!config.isEnableCompactionMemControl()) {
+      return 0;
+    }
+    CompactionTaskInfo taskInfo = calculatingCompactionTaskInfo(resources);
+    long cost = calculatingMetadataMemoryCost(taskInfo);
+    cost += calculatingDataMemoryCost(taskInfo);
+    return cost;
   }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/CompactionEstimateUtils.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/CompactionEstimateUtils.java
new file mode 100644
index 00000000000..e4afb109bcb
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/CompactionEstimateUtils.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.engine.compaction.selector.estimator;
+
+import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
+import org.apache.iotdb.tsfile.file.metadata.TimeseriesMetadata;
+import org.apache.iotdb.tsfile.read.TsFileSequenceReader;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+public class CompactionEstimateUtils {
+
+  /**
+   * Get the details of the tsfile, the returned array contains the following 
elements in sequence:
+   *
+   * <p>total chunk num in this tsfile
+   *
+   * <p>max chunk num of one timeseries in this tsfile
+   *
+   * <p>max aligned series num in one device. If there is no aligned series in 
this file, then it
+   * turns to be -1.
+   *
+   * <p>max chunk num of one device in this tsfile
+   *
+   * @throws IOException if io errors occurred
+   */
+  public static FileInfo calculateFileInfo(TsFileSequenceReader reader) throws 
IOException {
+    int totalChunkNum = 0;
+    int maxChunkNum = 0;
+    int maxAlignedSeriesNumInDevice = -1;
+    int maxDeviceChunkNum = 0;
+    Map<String, List<TimeseriesMetadata>> deviceMetadata = 
reader.getAllTimeseriesMetadata(true);
+    for (Map.Entry<String, List<TimeseriesMetadata>> entry : 
deviceMetadata.entrySet()) {
+      int deviceChunkNum = 0;
+      List<TimeseriesMetadata> deviceTimeseriesMetadata = entry.getValue();
+      if (deviceTimeseriesMetadata.get(0).getMeasurementId().equals("")) {
+        // aligned device
+        maxAlignedSeriesNumInDevice =
+            Math.max(maxAlignedSeriesNumInDevice, 
deviceTimeseriesMetadata.size());
+      }
+      for (TimeseriesMetadata timeseriesMetadata : deviceTimeseriesMetadata) {
+        deviceChunkNum += timeseriesMetadata.getChunkMetadataList().size();
+        totalChunkNum += timeseriesMetadata.getChunkMetadataList().size();
+        maxChunkNum = Math.max(maxChunkNum, 
timeseriesMetadata.getChunkMetadataList().size());
+      }
+      maxDeviceChunkNum = Math.max(maxDeviceChunkNum, deviceChunkNum);
+    }
+    long averageChunkMetadataSize =
+        totalChunkNum == 0 ? 0 : reader.getAllMetadataSize() / totalChunkNum;
+    return new FileInfo(
+        totalChunkNum,
+        maxChunkNum,
+        maxAlignedSeriesNumInDevice,
+        maxDeviceChunkNum,
+        averageChunkMetadataSize);
+  }
+
+  public static boolean addReadLock(List<TsFileResource> resources) {
+    for (int i = 0; i < resources.size(); i++) {
+      TsFileResource resource = resources.get(i);
+      resource.readLock();
+      if (resource.isDeleted()) {
+        // release read lock
+        for (int j = 0; j <= i; j++) {
+          resources.get(j).readUnlock();
+        }
+        return false;
+      }
+    }
+    return true;
+  }
+
+  public static void releaseReadLock(List<TsFileResource> resources) {
+    resources.forEach(TsFileResource::readUnlock);
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/CompactionTaskInfo.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/CompactionTaskInfo.java
new file mode 100644
index 00000000000..723505a8918
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/CompactionTaskInfo.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.engine.compaction.selector.estimator;
+
+import org.apache.iotdb.db.engine.modification.ModificationFile;
+import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
+
+import java.util.List;
+
+public class CompactionTaskInfo {
+  private final List<FileInfo> fileInfoList;
+  private final List<TsFileResource> resources;
+  private int maxConcurrentSeriesNum = 1;
+  private long maxChunkMetadataSize = 0;
+  private int maxChunkMetadataNumInDevice = 0;
+  private int maxChunkMetadataNumInSeries = 0;
+  private long modificationFileSize = 0;
+  private long totalFileSize = 0;
+  private long totalChunkNum = 0;
+  private long totalChunkMetadataSize = 0;
+
+  protected CompactionTaskInfo(List<TsFileResource> resources, List<FileInfo> 
fileInfoList) {
+    this.fileInfoList = fileInfoList;
+    this.resources = resources;
+    for (TsFileResource resource : resources) {
+      ModificationFile modificationFile = resource.getModFile();
+      if (modificationFile.exists()) {
+        modificationFileSize += modificationFile.getSize();
+      }
+      this.totalFileSize += resource.getTsFileSize();
+    }
+    for (FileInfo fileInfo : fileInfoList) {
+      maxConcurrentSeriesNum =
+          Math.max(maxConcurrentSeriesNum, 
fileInfo.maxAlignedSeriesNumInDevice);
+      maxChunkMetadataNumInSeries =
+          Math.max(maxChunkMetadataNumInSeries, fileInfo.maxSeriesChunkNum);
+      maxChunkMetadataNumInDevice =
+          Math.max(maxChunkMetadataNumInDevice, fileInfo.maxDeviceChunkNum);
+      maxChunkMetadataSize = Math.max(maxChunkMetadataSize, 
fileInfo.averageChunkMetadataSize);
+      totalChunkNum += fileInfo.totalChunkNum;
+      totalChunkMetadataSize += fileInfo.totalChunkNum * 
fileInfo.averageChunkMetadataSize;
+    }
+  }
+
+  public int getMaxChunkMetadataNumInDevice() {
+    return maxChunkMetadataNumInDevice;
+  }
+
+  public int getMaxChunkMetadataNumInSeries() {
+    return maxChunkMetadataNumInSeries;
+  }
+
+  public long getMaxChunkMetadataSize() {
+    return maxChunkMetadataSize;
+  }
+
+  public List<FileInfo> getFileInfoList() {
+    return fileInfoList;
+  }
+
+  public int getMaxConcurrentSeriesNum() {
+    return maxConcurrentSeriesNum;
+  }
+
+  public long getModificationFileSize() {
+    return modificationFileSize;
+  }
+
+  public long getTotalFileSize() {
+    return totalFileSize;
+  }
+
+  public long getTotalChunkNum() {
+    return totalChunkNum;
+  }
+
+  public List<TsFileResource> getResources() {
+    return resources;
+  }
+
+  public long getTotalChunkMetadataSize() {
+    return totalChunkMetadataSize;
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/FastCompactionInnerCompactionEstimator.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/FastCompactionInnerCompactionEstimator.java
new file mode 100644
index 00000000000..a43dd3c2770
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/FastCompactionInnerCompactionEstimator.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.engine.compaction.selector.estimator;
+
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.rescon.SystemInfo;
+
+import java.io.IOException;
+
+public class FastCompactionInnerCompactionEstimator extends 
AbstractInnerSpaceEstimator {
+
+  @Override
+  public long calculatingMetadataMemoryCost(CompactionTaskInfo taskInfo) {
+    long cost = 0;
+    // add ChunkMetadata size of MultiTsFileDeviceIterator
+    cost +=
+        Math.min(
+            taskInfo.getTotalChunkMetadataSize(),
+            taskInfo.getFileInfoList().size()
+                * taskInfo.getMaxChunkMetadataNumInSeries()
+                * taskInfo.getMaxChunkMetadataSize());
+
+    // add ChunkMetadata size of targetFileWriter
+    long sizeForFileWriter =
+        (long)
+            ((double) SystemInfo.getInstance().getMemorySizeForCompaction()
+                / 
IoTDBDescriptor.getInstance().getConfig().getCompactionThreadCount()
+                * 
IoTDBDescriptor.getInstance().getConfig().getChunkMetadataSizeProportion());
+    cost += sizeForFileWriter;
+
+    return cost;
+  }
+
+  /**
+   * The data algorithm is: targetChunkWriterSize + mods file size + read 
chunk size
+   *
+   * @return estimate data memory cost
+   */
+  @Override
+  public long calculatingDataMemoryCost(CompactionTaskInfo taskInfo) throws 
IOException {
+    if (taskInfo.getTotalChunkNum() == 0) {
+      return taskInfo.getModificationFileSize();
+    }
+    long maxConcurrentSeriesNum =
+        Math.max(config.getSubCompactionTaskNum(), 
taskInfo.getMaxConcurrentSeriesNum());
+    long averageUncompressedChunkSize =
+        taskInfo.getTotalFileSize() * compressionRatio / 
taskInfo.getTotalChunkNum();
+
+    long maxConcurrentSeriesSizeOfTotalFiles =
+        averageUncompressedChunkSize
+            * taskInfo.getFileInfoList().size()
+            * maxConcurrentSeriesNum
+            * taskInfo.getMaxChunkMetadataNumInSeries()
+            / compressionRatio;
+    long maxTargetChunkWriterSize = config.getTargetChunkSize() * 
maxConcurrentSeriesNum;
+    long targetChunkWriterSize =
+        Math.min(maxConcurrentSeriesSizeOfTotalFiles, 
maxTargetChunkWriterSize);
+
+    long maxConcurrentChunkSizeFromSourceFile =
+        averageUncompressedChunkSize
+            * maxConcurrentSeriesNum
+            * 
calculatingMaxOverlapFileNumInSubCompactionTask(taskInfo.getResources());
+
+    return targetChunkWriterSize
+        + maxConcurrentChunkSizeFromSourceFile
+        + taskInfo.getModificationFileSize();
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/FastCrossSpaceCompactionEstimator.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/FastCrossSpaceCompactionEstimator.java
new file mode 100644
index 00000000000..4359a2183a1
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/FastCrossSpaceCompactionEstimator.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.engine.compaction.selector.estimator;
+
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.rescon.SystemInfo;
+
+import java.io.IOException;
+
+public class FastCrossSpaceCompactionEstimator extends 
AbstractCrossSpaceEstimator {
+
+  @Override
+  protected long calculatingMetadataMemoryCost(CompactionTaskInfo taskInfo) {
+    long cost = 0;
+    // add ChunkMetadata size of MultiTsFileDeviceIterator
+    cost +=
+        Math.min(
+            taskInfo.getTotalChunkMetadataSize(),
+            taskInfo.getFileInfoList().size()
+                * taskInfo.getMaxChunkMetadataNumInDevice()
+                * taskInfo.getMaxChunkMetadataSize());
+
+    // add ChunkMetadata size of targetFileWriter
+    long sizeForFileWriter =
+        (long)
+            ((double) SystemInfo.getInstance().getMemorySizeForCompaction()
+                / 
IoTDBDescriptor.getInstance().getConfig().getCompactionThreadCount()
+                * 
IoTDBDescriptor.getInstance().getConfig().getChunkMetadataSizeProportion());
+    cost += sizeForFileWriter;
+
+    return cost;
+  }
+
+  @Override
+  protected long calculatingDataMemoryCost(CompactionTaskInfo taskInfo) throws 
IOException {
+    if (taskInfo.getTotalChunkNum() == 0) {
+      return taskInfo.getModificationFileSize();
+    }
+
+    long maxConcurrentSeriesNum =
+        Math.max(config.getSubCompactionTaskNum(), 
taskInfo.getMaxConcurrentSeriesNum());
+    long averageUncompressedChunkSize =
+        taskInfo.getTotalFileSize() * compressionRatio / 
taskInfo.getTotalChunkNum();
+
+    long maxConcurrentSeriesSizeOfTotalFiles =
+        averageUncompressedChunkSize
+            * taskInfo.getFileInfoList().size()
+            * maxConcurrentSeriesNum
+            * taskInfo.getMaxChunkMetadataNumInSeries()
+            / compressionRatio;
+    long maxTargetChunkWriterSize = config.getTargetChunkSize() * 
maxConcurrentSeriesNum;
+    long targetChunkWriterSize =
+        Math.min(maxConcurrentSeriesSizeOfTotalFiles, 
maxTargetChunkWriterSize);
+
+    long maxConcurrentChunkSizeFromSourceFile =
+        averageUncompressedChunkSize
+            * maxConcurrentSeriesNum
+            * 
calculatingMaxOverlapFileNumInSubCompactionTask(taskInfo.getResources());
+
+    return targetChunkWriterSize
+        + maxConcurrentChunkSizeFromSourceFile
+        + taskInfo.getModificationFileSize();
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/FileInfo.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/FileInfo.java
new file mode 100644
index 00000000000..ff90a1e21d9
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/FileInfo.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.engine.compaction.selector.estimator;
+
+public class FileInfo {
+  // total chunk num in this tsfile
+  int totalChunkNum = 0;
+  // max chunk num of one timeseries in this tsfile
+  int maxSeriesChunkNum = 0;
+  // max aligned series num in one device. If there is no aligned series in 
this file, then it
+  // turns to be -1.
+  int maxAlignedSeriesNumInDevice = -1;
+  // max chunk num of one device in this tsfile
+  @SuppressWarnings("squid:S1068")
+  int maxDeviceChunkNum = 0;
+
+  long averageChunkMetadataSize = 0;
+
+  public FileInfo(
+      int totalChunkNum,
+      int maxSeriesChunkNum,
+      int maxAlignedSeriesNumInDevice,
+      int maxDeviceChunkNum,
+      long averageChunkMetadataSize) {
+    this.totalChunkNum = totalChunkNum;
+    this.maxSeriesChunkNum = maxSeriesChunkNum;
+    this.maxAlignedSeriesNumInDevice = maxAlignedSeriesNumInDevice;
+    this.maxDeviceChunkNum = maxDeviceChunkNum;
+    this.averageChunkMetadataSize = averageChunkMetadataSize;
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/InplaceCompactionEstimator.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/InplaceCompactionEstimator.java
deleted file mode 100644
index d8c8e99942a..00000000000
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/InplaceCompactionEstimator.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.iotdb.db.engine.compaction.selector.estimator;
-
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
-import org.apache.iotdb.tsfile.file.metadata.ChunkMetadata;
-import org.apache.iotdb.tsfile.read.TsFileSequenceReader;
-import org.apache.iotdb.tsfile.read.common.Path;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class InplaceCompactionEstimator extends AbstractCrossSpaceEstimator {
-  private static final Logger logger = 
LoggerFactory.getLogger(InplaceCompactionEstimator.class);
-  private static final String LOG_FILE_COST = "Memory cost of file {} is {}";
-
-  private boolean tightEstimate;
-  private long maxSeqFileCost;
-
-  // the number of timeseries being compacted at the same time
-  private final int concurrentSeriesNum =
-      IoTDBDescriptor.getInstance().getConfig().getSubCompactionTaskNum();
-
-  /** Total metadata size of each file. */
-  private final Map<TsFileResource, Long> fileMetaSizeMap = new HashMap<>();
-
-  /** Maximum memory cost of querying a timeseries in each file. */
-  private final Map<TsFileResource, Long> maxSeriesQueryCostMap = new 
HashMap<>();
-
-  public InplaceCompactionEstimator() {
-    this.tightEstimate = false;
-    this.maxSeqFileCost = 0;
-  }
-
-  @Override
-  public long estimateCrossCompactionMemory(
-      List<TsFileResource> seqResources, TsFileResource unseqResource) throws 
IOException {
-    if (tightEstimate) {
-      return calculateTightMemoryCost(unseqResource, seqResources);
-    } else {
-      return calculateLooseMemoryCost(unseqResource, seqResources);
-    }
-  }
-
-  private long calculateMemoryCost(
-      TsFileResource unseqResource,
-      List<TsFileResource> seqResources,
-      IFileQueryMemMeasurement unseqMeasurement,
-      IFileQueryMemMeasurement seqMeasurement)
-      throws IOException {
-    long cost = 0;
-    Long fileCost = unseqMeasurement.measure(unseqResource);
-    cost += fileCost;
-
-    for (TsFileResource seqFile : seqResources) {
-      fileCost = seqMeasurement.measure(seqFile);
-      if (fileCost > maxSeqFileCost) {
-        // only one file will be read at the same time, so only the largest 
one is recorded here
-        cost -= maxSeqFileCost;
-        cost += fileCost;
-        maxSeqFileCost = fileCost;
-      }
-      // but writing data into a new file may generate the same amount of 
metadata in memory
-      cost += calculateMetadataSize(seqFile);
-    }
-    return cost;
-  }
-
-  private long calculateLooseMemoryCost(
-      TsFileResource unseqResource, List<TsFileResource> seqResources) throws 
IOException {
-    return calculateMemoryCost(
-        unseqResource, seqResources, TsFileResource::getTsFileSize, 
this::calculateMetadataSize);
-  }
-
-  private long calculateTightMemoryCost(
-      TsFileResource unseqResource, List<TsFileResource> seqResources) throws 
IOException {
-    return calculateMemoryCost(
-        unseqResource,
-        seqResources,
-        this::calculateTightUnseqMemoryCost,
-        this::calculateTightSeqMemoryCost);
-  }
-
-  private long calculateMetadataSize(TsFileResource seqFile) throws 
IOException {
-    Long cost = fileMetaSizeMap.get(seqFile);
-    if (cost == null) {
-      cost = getFileReader(seqFile).getFileMetadataSize();
-      fileMetaSizeMap.put(seqFile, cost);
-      logger.debug(LOG_FILE_COST, seqFile, cost);
-    }
-    return cost;
-  }
-
-  private long calculateTightFileMemoryCost(
-      TsFileResource seqFile, IFileQueryMemMeasurement measurement) throws 
IOException {
-    Long cost = maxSeriesQueryCostMap.get(seqFile);
-    if (cost == null) {
-      long[] chunkNums = findTotalAndLargestSeriesChunkNum(seqFile, 
getFileReader(seqFile));
-      long totalChunkNum = chunkNums[0];
-      long maxChunkNum = chunkNums[1];
-      cost = measurement.measure(seqFile) * maxChunkNum / totalChunkNum;
-      maxSeriesQueryCostMap.put(seqFile, cost);
-      logger.debug(LOG_FILE_COST, seqFile, cost);
-    }
-    return cost;
-  }
-
-  // this method traverses all ChunkMetadata to find out which series has the 
most chunks and uses
-  // its proportion to all series to get a maximum estimation
-  private long calculateTightSeqMemoryCost(TsFileResource seqFile) throws 
IOException {
-    long singleSeriesCost = calculateTightFileMemoryCost(seqFile, 
this::calculateMetadataSize);
-    long multiSeriesCost = concurrentSeriesNum * singleSeriesCost;
-    long maxCost = calculateMetadataSize(seqFile);
-    return Math.min(multiSeriesCost, maxCost);
-  }
-
-  // this method traverses all ChunkMetadata to find out which series has the 
most chunks and uses
-  // its proportion among all series to get a maximum estimation
-  private long calculateTightUnseqMemoryCost(TsFileResource unseqFile) throws 
IOException {
-    long singleSeriesCost = calculateTightFileMemoryCost(unseqFile, 
TsFileResource::getTsFileSize);
-    long multiSeriesCost = concurrentSeriesNum * singleSeriesCost;
-    long maxCost = unseqFile.getTsFileSize();
-    return Math.min(multiSeriesCost, maxCost);
-  }
-
-  // returns totalChunkNum of a file and the max number of chunks of a series
-  private long[] findTotalAndLargestSeriesChunkNum(
-      TsFileResource tsFileResource, TsFileSequenceReader sequenceReader) 
throws IOException {
-    long totalChunkNum = 0;
-    long maxChunkNum = Long.MIN_VALUE;
-    List<Path> paths = sequenceReader.getAllPaths();
-
-    for (Path path : paths) {
-      List<ChunkMetadata> chunkMetadataList = 
sequenceReader.getChunkMetadataList(path, true);
-      totalChunkNum += chunkMetadataList.size();
-      maxChunkNum = chunkMetadataList.size() > maxChunkNum ? 
chunkMetadataList.size() : maxChunkNum;
-    }
-    logger.debug(
-        "In file {}, total chunk num {}, series max chunk num {}",
-        tsFileResource,
-        totalChunkNum,
-        maxChunkNum);
-    return new long[] {totalChunkNum, maxChunkNum};
-  }
-
-  public void setTightEstimate(boolean tightEstimate) {
-    this.tightEstimate = tightEstimate;
-  }
-}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/ReadChunkInnerCompactionEstimator.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/ReadChunkInnerCompactionEstimator.java
new file mode 100644
index 00000000000..9eb64ec2917
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/ReadChunkInnerCompactionEstimator.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.engine.compaction.selector.estimator;
+
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.rescon.SystemInfo;
+
+public class ReadChunkInnerCompactionEstimator extends 
AbstractInnerSpaceEstimator {
+
+  @Override
+  public long calculatingMetadataMemoryCost(CompactionTaskInfo taskInfo) {
+    long cost = 0;
+    // add ChunkMetadata size of MultiTsFileDeviceIterator
+    cost +=
+        Math.min(
+            taskInfo.getTotalChunkMetadataSize(),
+            taskInfo.getFileInfoList().size()
+                * taskInfo.getMaxChunkMetadataNumInDevice()
+                * taskInfo.getMaxChunkMetadataSize());
+
+    // add ChunkMetadata size of targetFileWriter
+    long sizeForFileWriter =
+        (long)
+            ((double) SystemInfo.getInstance().getMemorySizeForCompaction()
+                / 
IoTDBDescriptor.getInstance().getConfig().getCompactionThreadCount()
+                * 
IoTDBDescriptor.getInstance().getConfig().getChunkMetadataSizeProportion());
+    cost += sizeForFileWriter;
+
+    return cost;
+  }
+
+  @Override
+  public long calculatingDataMemoryCost(CompactionTaskInfo taskInfo) {
+    if (taskInfo.getTotalChunkNum() == 0) {
+      return taskInfo.getModificationFileSize();
+    }
+    long averageUncompressedChunkSize =
+        taskInfo.getTotalFileSize() * compressionRatio / 
taskInfo.getTotalChunkNum();
+
+    long maxConcurrentSeriesSizeOfTotalFiles =
+        averageUncompressedChunkSize
+            * taskInfo.getFileInfoList().size()
+            * taskInfo.getMaxConcurrentSeriesNum()
+            * taskInfo.getMaxChunkMetadataNumInSeries()
+            / compressionRatio;
+    long maxTargetChunkWriterSize =
+        config.getTargetChunkSize() * taskInfo.getMaxConcurrentSeriesNum();
+    long targetChunkWriterSize =
+        Math.min(maxConcurrentSeriesSizeOfTotalFiles, 
maxTargetChunkWriterSize);
+
+    long chunkSizeFromSourceFile =
+        averageUncompressedChunkSize * taskInfo.getMaxConcurrentSeriesNum();
+
+    return targetChunkWriterSize + chunkSizeFromSourceFile + 
taskInfo.getModificationFileSize();
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/ReadPointCrossCompactionEstimator.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/ReadPointCrossCompactionEstimator.java
deleted file mode 100644
index 9891a48291d..00000000000
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/estimator/ReadPointCrossCompactionEstimator.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.iotdb.db.engine.compaction.selector.estimator;
-
-import org.apache.iotdb.commons.conf.IoTDBConstant;
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
-import org.apache.iotdb.tsfile.file.metadata.TimeseriesMetadata;
-import org.apache.iotdb.tsfile.read.TsFileSequenceReader;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-public class ReadPointCrossCompactionEstimator extends 
AbstractCrossSpaceEstimator {
-  private static final Logger logger =
-      LoggerFactory.getLogger(IoTDBConstant.COMPACTION_LOGGER_NAME);
-
-  // the max cost of reading source seq file among all source seq files of 
this cross compaction
-  // task
-  private long maxCostOfReadingSeqFile;
-
-  // the max cost of writing target file
-  private long maxCostOfWritingTargetFile;
-
-  private int maxConcurrentSeriesNum = 1;
-
-  // the number of timeseries being compacted at the same time
-  private final int subCompactionTaskNum =
-      IoTDBDescriptor.getInstance().getConfig().getSubCompactionTaskNum();
-
-  public ReadPointCrossCompactionEstimator() {
-    this.maxCostOfReadingSeqFile = 0;
-    this.maxCostOfWritingTargetFile = 0;
-  }
-
-  @Override
-  public long estimateCrossCompactionMemory(
-      List<TsFileResource> seqResources, TsFileResource unseqResource) throws 
IOException {
-    if (!addReadLock(seqResources, unseqResource)) {
-      // there is file been deleted during selection, return -1
-      return -1L;
-    }
-    try {
-      long cost = 0;
-      cost += calculateReadingUnseqFile(unseqResource);
-      cost += calculateReadingSeqFiles(seqResources);
-      cost += calculatingWritingTargetFiles(seqResources, unseqResource);
-      return cost;
-    } finally {
-      releaseReadLock(seqResources, unseqResource);
-    }
-  }
-
-  /** Add read lock. Return false if any of the file were deleted. */
-  private boolean addReadLock(List<TsFileResource> seqResources, 
TsFileResource unseqResource) {
-    List<TsFileResource> allResources = new ArrayList<>(seqResources);
-    allResources.add(unseqResource);
-    for (int i = 0; i < allResources.size(); i++) {
-      TsFileResource resource = allResources.get(i);
-      resource.readLock();
-      if (resource.isDeleted()) {
-        // release read lock
-        for (int j = 0; j <= i; j++) {
-          allResources.get(j).readUnlock();
-        }
-        return false;
-      }
-    }
-    return true;
-  }
-
-  private void releaseReadLock(List<TsFileResource> seqResources, 
TsFileResource unseqResource) {
-    seqResources.forEach(TsFileResource::readUnlock);
-    unseqResource.readUnlock();
-  }
-
-  /**
-   * Calculate memory cost of reading source unseq files in the cross space 
compaction. Double the
-   * total size of the timeseries to be compacted at the same time in all 
unseq files.
-   */
-  private long calculateReadingUnseqFile(TsFileResource unseqResource) throws 
IOException {
-    TsFileSequenceReader reader = getFileReader(unseqResource);
-    FileInfo fileInfo = getSeriesAndDeviceChunkNum(reader);
-    // it is max aligned series num of one device when tsfile contains aligned 
series,
-    // else is sub compaction task num.
-    int concurrentSeriesNum =
-        fileInfo.maxAlignedSeriesNumInDevice == -1
-            ? subCompactionTaskNum
-            : fileInfo.maxAlignedSeriesNumInDevice;
-    maxConcurrentSeriesNum = Math.max(maxConcurrentSeriesNum, 
concurrentSeriesNum);
-    if (fileInfo.totalChunkNum == 0) { // If totalChunkNum ==0, i.e. this 
unSeq tsFile has no chunk.
-      logger.warn(
-          "calculateReadingUnseqFile(), find 1 empty unSeq tsFile: {}.",
-          unseqResource.getTsFilePath());
-      return 0;
-    }
-    // it means the max size of a timeseries in this file when reading all of 
its chunk into memory.
-
-    long resourceFileSize =
-        compressionRatio
-            * concurrentSeriesNum
-            * (unseqResource.getTsFileSize() * fileInfo.maxSeriesChunkNum / 
fileInfo.totalChunkNum);
-
-    // add mod file size
-    long modFileSize = unseqResource.getModFile().getSize();
-    return resourceFileSize + modFileSize;
-  }
-
-  /**
-   * Calculate memory cost of reading source seq files in the cross space 
compaction. Select the
-   * maximun size of the timeseries to be compacted at the same time in one 
seq file, because only
-   * one seq file will be queried at the same time.
-   */
-  private long calculateReadingSeqFiles(List<TsFileResource> seqResources) 
throws IOException {
-    long cost = 0;
-    for (TsFileResource seqResource : seqResources) {
-      TsFileSequenceReader reader = getFileReader(seqResource);
-      FileInfo fileInfo = getSeriesAndDeviceChunkNum(reader);
-      // it is max aligned series num of one device when tsfile contains 
aligned series,
-      // else is sub compaction task num.
-      int concurrentSeriesNum =
-          fileInfo.maxAlignedSeriesNumInDevice == -1
-              ? subCompactionTaskNum
-              : fileInfo.maxAlignedSeriesNumInDevice;
-      maxConcurrentSeriesNum = Math.max(maxConcurrentSeriesNum, 
concurrentSeriesNum);
-      long seqFileCost;
-      if (fileInfo.totalChunkNum == 0) { // If totalChunkNum ==0, i.e. this 
seq tsFile has no chunk.
-        logger.warn(
-            "calculateReadingSeqFiles(), find 1 empty seq tsFile: {}.",
-            seqResource.getTsFilePath());
-        seqFileCost = 0;
-      } else {
-        // We need to multiply the compression ratio here.
-        seqFileCost =
-            compressionRatio
-                * seqResource.getTsFileSize()
-                * concurrentSeriesNum
-                / fileInfo.totalChunkNum;
-      }
-
-      if (seqFileCost > maxCostOfReadingSeqFile) {
-        // Only one seq file will be read at the same time.
-        // not only reading chunk into chunk cache, but also need to 
deserialize data point into
-        // merge reader. We have to add the cost in merge reader here and the 
cost of chunk cache is
-        // unnecessary.
-        cost -= maxCostOfReadingSeqFile;
-        cost += seqFileCost;
-        maxCostOfReadingSeqFile = seqFileCost;
-      }
-
-      // add mod file size
-      cost += seqResource.getModFile().getSize();
-    }
-    return cost;
-  }
-
-  /**
-   * Calculate memory cost of writing target files in the cross space 
compaction. Including metadata
-   * size of all source files and size of concurrent target chunks.
-   */
-  private long calculatingWritingTargetFiles(
-      List<TsFileResource> seqResources, TsFileResource unseqResource) throws 
IOException {
-    long cost = 0;
-    for (TsFileResource seqResource : seqResources) {
-      TsFileSequenceReader reader = getFileReader(seqResource);
-      // add seq file metadata size
-      cost += reader.getFileMetadataSize();
-    }
-    // add unseq file metadata size
-    cost += getFileReader(unseqResource).getFileMetadataSize();
-
-    // concurrent series chunk size
-    long writingTargetCost = maxConcurrentSeriesNum * 
config.getTargetChunkSize();
-    if (writingTargetCost > maxCostOfWritingTargetFile) {
-      cost -= maxCostOfWritingTargetFile;
-      cost += writingTargetCost;
-      maxCostOfWritingTargetFile = writingTargetCost;
-    }
-
-    return cost;
-  }
-
-  /**
-   * Get the details of the tsfile, the returned array contains the following 
elements in sequence:
-   *
-   * <p>total chunk num in this tsfile
-   *
-   * <p>max chunk num of one timeseries in this tsfile
-   *
-   * <p>max aligned series num in one device. If there is no aligned series in 
this file, then it
-   * turns to be -1.
-   *
-   * <p>max chunk num of one device in this tsfile
-   */
-  private FileInfo getSeriesAndDeviceChunkNum(TsFileSequenceReader reader) 
throws IOException {
-    int totalChunkNum = 0;
-    int maxChunkNum = 0;
-    int maxAlignedSeriesNumInDevice = -1;
-    int maxDeviceChunkNum = 0;
-    Map<String, List<TimeseriesMetadata>> deviceMetadata = 
reader.getAllTimeseriesMetadata(true);
-    for (Map.Entry<String, List<TimeseriesMetadata>> entry : 
deviceMetadata.entrySet()) {
-      int deviceChunkNum = 0;
-      List<TimeseriesMetadata> deviceTimeseriesMetadata = entry.getValue();
-      if (deviceTimeseriesMetadata.get(0).getMeasurementId().equals("")) {
-        // aligned device
-        maxAlignedSeriesNumInDevice =
-            Math.max(maxAlignedSeriesNumInDevice, 
deviceTimeseriesMetadata.size());
-      }
-      for (TimeseriesMetadata timeseriesMetadata : deviceTimeseriesMetadata) {
-        deviceChunkNum += timeseriesMetadata.getChunkMetadataList().size();
-        totalChunkNum += timeseriesMetadata.getChunkMetadataList().size();
-        maxChunkNum = Math.max(maxChunkNum, 
timeseriesMetadata.getChunkMetadataList().size());
-      }
-      maxDeviceChunkNum = Math.max(maxDeviceChunkNum, deviceChunkNum);
-    }
-    return new FileInfo(totalChunkNum, maxChunkNum, 
maxAlignedSeriesNumInDevice, maxDeviceChunkNum);
-  }
-
-  private class FileInfo {
-    // total chunk num in this tsfile
-    public int totalChunkNum = 0;
-    // max chunk num of one timeseries in this tsfile
-    public int maxSeriesChunkNum = 0;
-    // max aligned series num in one device. If there is no aligned series in 
this file, then it
-    // turns to be -1.
-    public int maxAlignedSeriesNumInDevice = -1;
-    // max chunk num of one device in this tsfile
-    public int maxDeviceChunkNum = 0;
-
-    public FileInfo(
-        int totalChunkNum,
-        int maxSeriesChunkNum,
-        int maxAlignedSeriesNumInDevice,
-        int maxDeviceChunkNum) {
-      this.totalChunkNum = totalChunkNum;
-      this.maxSeriesChunkNum = maxSeriesChunkNum;
-      this.maxAlignedSeriesNumInDevice = maxAlignedSeriesNumInDevice;
-      this.maxDeviceChunkNum = maxDeviceChunkNum;
-    }
-  }
-}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/impl/RewriteCrossSpaceCompactionSelector.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/impl/RewriteCrossSpaceCompactionSelector.java
index 596b663e161..4c7acaf1269 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/impl/RewriteCrossSpaceCompactionSelector.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/impl/RewriteCrossSpaceCompactionSelector.java
@@ -24,7 +24,7 @@ import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.engine.compaction.schedule.CompactionTaskManager;
 import org.apache.iotdb.db.engine.compaction.selector.ICompactionSelector;
 import org.apache.iotdb.db.engine.compaction.selector.ICrossSpaceSelector;
-import 
org.apache.iotdb.db.engine.compaction.selector.estimator.AbstractCompactionEstimator;
+import 
org.apache.iotdb.db.engine.compaction.selector.estimator.AbstractCrossSpaceEstimator;
 import 
org.apache.iotdb.db.engine.compaction.selector.utils.CrossCompactionTaskResource;
 import 
org.apache.iotdb.db.engine.compaction.selector.utils.CrossSpaceCompactionCandidate;
 import 
org.apache.iotdb.db.engine.compaction.selector.utils.CrossSpaceCompactionCandidate.CrossCompactionTaskResourceSplit;
@@ -39,6 +39,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -59,7 +60,7 @@ public class RewriteCrossSpaceCompactionSelector implements 
ICrossSpaceSelector
   private final int maxCrossCompactionFileNum;
   private final long maxCrossCompactionFileSize;
 
-  private AbstractCompactionEstimator compactionEstimator;
+  private final AbstractCrossSpaceEstimator compactionEstimator;
 
   public RewriteCrossSpaceCompactionSelector(
       String logicalStorageGroupName,
@@ -81,8 +82,9 @@ public class RewriteCrossSpaceCompactionSelector implements 
ICrossSpaceSelector
         
IoTDBDescriptor.getInstance().getConfig().getMaxCrossCompactionCandidateFileSize();
 
     this.compactionEstimator =
-        ICompactionSelector.getCompactionEstimator(
-            
IoTDBDescriptor.getInstance().getConfig().getCrossCompactionPerformer(), false);
+        (AbstractCrossSpaceEstimator)
+            ICompactionSelector.getCompactionEstimator(
+                
IoTDBDescriptor.getInstance().getConfig().getCrossCompactionPerformer(), false);
   }
 
   /**
@@ -168,8 +170,15 @@ public class RewriteCrossSpaceCompactionSelector 
implements ICrossSpaceSelector
         }
       }
 
+      List<TsFileResource> newSelectedSeqResources = new 
ArrayList<>(taskResource.getSeqFiles());
+      newSelectedSeqResources.addAll(targetSeqFiles);
+      List<TsFileResource> newSelectedUnseqResources =
+          new ArrayList<>(taskResource.getUnseqFiles());
+      newSelectedUnseqResources.add(unseqFile);
+
       long memoryCost =
-          compactionEstimator.estimateCrossCompactionMemory(targetSeqFiles, 
unseqFile);
+          compactionEstimator.estimateCrossCompactionMemory(
+              newSelectedSeqResources, newSelectedUnseqResources);
       if (!canAddToTaskResource(taskResource, unseqFile, targetSeqFiles, 
memoryCost)) {
         break;
       }
@@ -247,7 +256,7 @@ public class RewriteCrossSpaceCompactionSelector implements 
ICrossSpaceSelector
 
     if (taskResource.getTotalFileNums() + 1 + seqFiles.size() <= 
maxCrossCompactionFileNum
         && taskResource.getTotalFileSize() + totalFileSize <= 
maxCrossCompactionFileSize
-        && taskResource.getTotalMemoryCost() + memoryCost < memoryBudget) {
+        && memoryCost < memoryBudget) {
       return true;
     }
     return false;
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/utils/CrossCompactionTaskResource.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/utils/CrossCompactionTaskResource.java
index 1c9ae6f3d7d..3c46f790910 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/utils/CrossCompactionTaskResource.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/compaction/selector/utils/CrossCompactionTaskResource.java
@@ -69,7 +69,7 @@ public class CrossCompactionTaskResource {
       TsFileResource unseqFile, List<TsFileResource> seqFiles, long 
memoryCost) {
     addUnseqFile(unseqFile);
     addTargetSeqFiles(seqFiles);
-    increaseMemoryCost(memoryCost);
+    updateMemoryCost(memoryCost);
   }
 
   private void addUnseqFile(TsFileResource file) {
@@ -88,8 +88,8 @@ public class CrossCompactionTaskResource {
     countStatistic(file);
   }
 
-  private void increaseMemoryCost(long newMemoryCost) {
-    this.totalMemoryCost += newMemoryCost;
+  private void updateMemoryCost(long newMemoryCost) {
+    this.totalMemoryCost = Math.max(totalMemoryCost, newMemoryCost);
   }
 
   private void countStatistic(TsFileResource file) {
diff --git a/server/src/main/java/org/apache/iotdb/db/rescon/SystemInfo.java 
b/server/src/main/java/org/apache/iotdb/db/rescon/SystemInfo.java
index c77825ddd61..7bb52307adb 100644
--- a/server/src/main/java/org/apache/iotdb/db/rescon/SystemInfo.java
+++ b/server/src/main/java/org/apache/iotdb/db/rescon/SystemInfo.java
@@ -212,6 +212,9 @@ public class SystemInfo {
   }
 
   public synchronized void resetCompactionMemoryCost(long 
compactionMemoryCost) {
+    if (!config.isEnableCompactionMemControl()) {
+      return;
+    }
     this.compactionMemoryCost.addAndGet(-compactionMemoryCost);
   }
 
diff --git 
a/server/src/test/java/org/apache/iotdb/db/engine/compaction/utils/CompactionTaskMemCostEstimatorTest.java
 
b/server/src/test/java/org/apache/iotdb/db/engine/compaction/utils/CompactionTaskMemCostEstimatorTest.java
new file mode 100644
index 00000000000..e0f6864371d
--- /dev/null
+++ 
b/server/src/test/java/org/apache/iotdb/db/engine/compaction/utils/CompactionTaskMemCostEstimatorTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.engine.compaction.utils;
+
+import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.db.engine.compaction.AbstractCompactionTest;
+import 
org.apache.iotdb.db.engine.compaction.selector.estimator.FastCompactionInnerCompactionEstimator;
+import 
org.apache.iotdb.db.engine.compaction.selector.estimator.FastCrossSpaceCompactionEstimator;
+import 
org.apache.iotdb.db.engine.compaction.selector.estimator.ReadChunkInnerCompactionEstimator;
+import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
+import org.apache.iotdb.db.exception.StorageEngineException;
+import org.apache.iotdb.tsfile.exception.write.WriteProcessException;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+public class CompactionTaskMemCostEstimatorTest extends AbstractCompactionTest 
{
+
+  @Before
+  public void setUp()
+      throws IOException, WriteProcessException, MetadataException, 
InterruptedException {
+    super.setUp();
+  }
+
+  @After
+  public void tearDown() throws IOException, StorageEngineException {
+    super.tearDown();
+  }
+
+  @Test
+  public void testEstimateReadChunkInnerSpaceCompactionTaskMemCost()
+      throws IOException, MetadataException, WriteProcessException {
+    createFiles(3, 10, 5, 100000, 0, 0, 50, 50, true, true);
+    tsFileManager.addAll(seqResources, true);
+    List<TsFileResource> tsFileList = tsFileManager.getTsFileList(true);
+    System.out.println(tsFileList.get(0).getTsFile().getAbsolutePath());
+    long cost = new 
ReadChunkInnerCompactionEstimator().estimateInnerCompactionMemory(tsFileList);
+    Assert.assertTrue(cost > 0);
+  }
+
+  @Test
+  public void testEstimateReadChunkInnerSpaceCompactionTaskMemCost2()
+      throws IOException, MetadataException, WriteProcessException {
+    createFiles(3, 10, 5, 100, 0, 0, 50, 50, false, true);
+    tsFileManager.addAll(seqResources, true);
+    List<TsFileResource> tsFileList = tsFileManager.getTsFileList(true);
+    long cost = new 
ReadChunkInnerCompactionEstimator().estimateInnerCompactionMemory(tsFileList);
+    Assert.assertTrue(cost > 0);
+  }
+
+  @Test
+  public void testEstimateFastCompactionInnerSpaceCompactionTaskMemCost()
+      throws IOException, MetadataException, WriteProcessException {
+    createFiles(5, 10, 5, 10000, 0, 0, 50, 50, true, false);
+    createFiles(10, 4, 5, 10000, 1000, 0, 30, 90, true, false);
+
+    tsFileManager.addAll(unseqResources, false);
+    long cost =
+        new 
FastCompactionInnerCompactionEstimator().estimateInnerCompactionMemory(unseqResources);
+    Assert.assertTrue(cost > 0);
+  }
+
+  @Test
+  public void testEstimateFastCompactionInnerSpaceCompactionTaskMemCost2()
+      throws IOException, MetadataException, WriteProcessException {
+    createFiles(3, 10, 5, 100, 0, 0, 50, 50, false, true);
+    tsFileManager.addAll(seqResources, true);
+    List<TsFileResource> tsFileList = tsFileManager.getTsFileList(true);
+    long cost =
+        new 
FastCompactionInnerCompactionEstimator().estimateInnerCompactionMemory(tsFileList);
+    Assert.assertTrue(cost > 0);
+  }
+
+  @Test
+  public void testEstimateFastCompactionCrossSpaceCompactionTaskMemCost1()
+      throws IOException, MetadataException, WriteProcessException {
+    createFiles(3, 10, 5, 100, 0, 0, 50, 50, false, true);
+    createFiles(4, 10, 5, 400, 0, 0, 30, 50, false, false);
+    long cost =
+        new FastCrossSpaceCompactionEstimator()
+            .estimateCrossCompactionMemory(seqResources, unseqResources);
+    Assert.assertTrue(cost > 0);
+  }
+}
diff --git 
a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/TsFileSequenceReader.java 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/TsFileSequenceReader.java
index 6c29e7c4c44..1d896f53ca3 100644
--- 
a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/TsFileSequenceReader.java
+++ 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/TsFileSequenceReader.java
@@ -223,12 +223,20 @@ public class TsFileSequenceReader implements 
AutoCloseable {
     return fileMetadataSize;
   }
 
+  /** Return the tsfile meta data size of this tsfile. */
+  public long getFileMetadataSize() throws IOException {
+    return tsFileInput.size() - getFileMetadataPos();
+  }
+
   /**
    * Return the whole meta data size of this tsfile, including ChunkMetadata, 
TimeseriesMetadata and
    * etc.
    */
-  public long getFileMetadataSize() throws IOException {
-    return tsFileInput.size() - getFileMetadataPos();
+  public long getAllMetadataSize() throws IOException {
+    if (tsFileMetaData == null) {
+      readFileMetadata();
+    }
+    return tsFileInput.size() - tsFileMetaData.getMetaOffset();
   }
 
   /** this function does not modify the position of the file reader. */

Reply via email to