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

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


The following commit(s) were added to refs/heads/rel/1.2 by this push:
     new c5ab6bdcc35 [To rel/1.2] Reimplement compaction memory estimator 
(#10964)
c5ab6bdcc35 is described below

commit c5ab6bdcc35922e78f06026b4f1d8a76882baa3e
Author: shuwenwei <[email protected]>
AuthorDate: Tue Aug 29 11:48:51 2023 +0800

    [To rel/1.2] Reimplement compaction memory estimator (#10964)
---
 .../compaction/selector/ICompactionSelector.java   |   4 +-
 .../estimator/AbstractCompactionEstimator.java     | 121 ++++++++++---
 .../estimator/AbstractCrossSpaceEstimator.java     |  27 ++-
 .../estimator/AbstractInnerSpaceEstimator.java     |  77 +-------
 .../estimator/CompactionEstimateUtils.java         |   3 +-
 .../selector/estimator/CompactionTaskInfo.java     | 101 +++++++++++
 .../FastCompactionInnerCompactionEstimator.java    |  72 +++++---
 .../FastCrossSpaceCompactionEstimator.java         |  81 +++++++++
 .../estimator/InplaceCompactionEstimator.java      | 172 ------------------
 .../ReadChunkInnerCompactionEstimator.java         |  38 ++--
 .../ReadPointCrossCompactionEstimator.java         | 197 ---------------------
 .../impl/RewriteCrossSpaceCompactionSelector.java  |  21 ++-
 .../utils/CrossCompactionTaskResource.java         |   6 +-
 .../db/storageengine/rescon/memory/SystemInfo.java |   3 +
 .../compaction/CompactionSchedulerTest.java        |   1 -
 .../utils/CompactionTaskMemCostEstimatorTest.java  |  22 ++-
 16 files changed, 418 insertions(+), 528 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/ICompactionSelector.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/ICompactionSelector.java
index fc3e50a8ec7..52e8640cbc4 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/ICompactionSelector.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/ICompactionSelector.java
@@ -21,7 +21,7 @@ package 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.execute.performer.constant.CrossCompactionPerformer;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.schedule.CompactionTaskManager;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator.AbstractCompactionEstimator;
-import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator.ReadPointCrossCompactionEstimator;
+import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator.FastCrossSpaceCompactionEstimator;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.utils.CrossCompactionTaskResource;
 import org.apache.iotdb.db.storageengine.dataregion.tsfile.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/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractCompactionEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractCompactionEstimator.java
index c4450637344..8879d96ee98 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractCompactionEstimator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractCompactionEstimator.java
@@ -23,56 +23,121 @@ import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.storageengine.dataregion.flush.CompressionRatio;
 import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource;
+import 
org.apache.iotdb.db.storageengine.dataregion.tsfile.timeindex.DeviceTimeIndex;
+import 
org.apache.iotdb.db.storageengine.dataregion.tsfile.timeindex.FileTimeIndex;
+import 
org.apache.iotdb.db.storageengine.dataregion.tsfile.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.
-   *
-   * @throws IOException if io errors occurred
-   */
-  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)
-      throws IOException;
+  protected abstract long calculatingDataMemoryCost(CompactionTaskInfo 
taskInfo) throws IOException;
 
-  /**
-   * Construct a new or get an existing TsFileSequenceReader of a TsFile.
-   *
-   * @throws IOException if io errors occurred
-   */
-  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/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractCrossSpaceEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractCrossSpaceEstimator.java
index 4e82ab7e692..0c072f4002f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractCrossSpaceEstimator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractCrossSpaceEstimator.java
@@ -22,6 +22,7 @@ package 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimat
 import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -29,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/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractInnerSpaceEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractInnerSpaceEstimator.java
index a5309aaff30..df28012bd12 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractInnerSpaceEstimator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/AbstractInnerSpaceEstimator.java
@@ -19,14 +19,9 @@
 
 package 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator;
 
-import org.apache.iotdb.db.conf.IoTDBConfig;
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import 
org.apache.iotdb.db.storageengine.dataregion.modification.ModificationFile;
 import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource;
-import org.apache.iotdb.tsfile.read.TsFileSequenceReader;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -34,78 +29,14 @@ import java.util.List;
  * its corresponding implementation.
  */
 public abstract class AbstractInnerSpaceEstimator extends 
AbstractCompactionEstimator {
-  protected IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
 
   public long estimateInnerCompactionMemory(List<TsFileResource> resources) 
throws IOException {
-    InnerCompactionTaskInfo taskInfo = 
calculatingCompactionTaskInfo(resources);
+    if (!config.isEnableCompactionMemControl()) {
+      return 0;
+    }
+    CompactionTaskInfo taskInfo = calculatingCompactionTaskInfo(resources);
     long cost = calculatingMetadataMemoryCost(taskInfo);
     cost += calculatingDataMemoryCost(taskInfo);
     return cost;
   }
-
-  public abstract long calculatingMetadataMemoryCost(InnerCompactionTaskInfo 
taskInfo);
-
-  public abstract long calculatingDataMemoryCost(InnerCompactionTaskInfo 
taskInfo);
-
-  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");
-  }
-
-  protected InnerCompactionTaskInfo 
calculatingCompactionTaskInfo(List<TsFileResource> resources)
-      throws IOException {
-    List<FileInfo> fileInfoList = new ArrayList<>();
-    for (TsFileResource resource : resources) {
-      TsFileSequenceReader reader = getFileReader(resource);
-      FileInfo fileInfo = 
CompactionEstimateUtils.getSeriesAndDeviceChunkNum(reader);
-      fileInfoList.add(fileInfo);
-    }
-    return new InnerCompactionTaskInfo(resources, fileInfoList);
-  }
-
-  protected static class InnerCompactionTaskInfo {
-    private final List<FileInfo> fileInfoList;
-    private int maxConcurrentSeriesNum = 1;
-    private long maxChunkMetadataSize = 0;
-    private int maxChunkMetadataNumInDevice = 0;
-    private long modificationFileSize = 0;
-
-    protected InnerCompactionTaskInfo(List<TsFileResource> resources, 
List<FileInfo> fileInfoList) {
-      this.fileInfoList = fileInfoList;
-      for (TsFileResource resource : resources) {
-        ModificationFile modificationFile = resource.getModFile();
-        if (modificationFile.exists()) {
-          modificationFileSize += modificationFile.getSize();
-        }
-      }
-      for (FileInfo fileInfo : fileInfoList) {
-        maxConcurrentSeriesNum =
-            Math.max(maxConcurrentSeriesNum, 
fileInfo.maxAlignedSeriesNumInDevice);
-        maxChunkMetadataNumInDevice =
-            Math.max(maxChunkMetadataNumInDevice, fileInfo.maxDeviceChunkNum);
-        maxChunkMetadataSize = Math.max(maxChunkMetadataSize, 
fileInfo.averageChunkMetadataSize);
-      }
-    }
-
-    public int getMaxChunkMetadataNumInDevice() {
-      return maxChunkMetadataNumInDevice;
-    }
-
-    public long getMaxChunkMetadataSize() {
-      return maxChunkMetadataSize;
-    }
-
-    public List<FileInfo> getFileInfoList() {
-      return fileInfoList;
-    }
-
-    public int getMaxConcurrentSeriesNum() {
-      return maxConcurrentSeriesNum;
-    }
-
-    public long getModificationFileSize() {
-      return modificationFileSize;
-    }
-  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/CompactionEstimateUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/CompactionEstimateUtils.java
index fe6f24fcfb4..cded2049b9c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/CompactionEstimateUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/CompactionEstimateUtils.java
@@ -43,8 +43,7 @@ public class CompactionEstimateUtils {
    *
    * @throws IOException if io errors occurred
    */
-  public static FileInfo getSeriesAndDeviceChunkNum(TsFileSequenceReader 
reader)
-      throws IOException {
+  public static FileInfo calculateFileInfo(TsFileSequenceReader reader) throws 
IOException {
     int totalChunkNum = 0;
     int maxChunkNum = 0;
     int maxAlignedSeriesNumInDevice = -1;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/CompactionTaskInfo.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/CompactionTaskInfo.java
new file mode 100644
index 00000000000..32803fb944f
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/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.storageengine.dataregion.compaction.selector.estimator;
+
+import 
org.apache.iotdb.db.storageengine.dataregion.modification.ModificationFile;
+import org.apache.iotdb.db.storageengine.dataregion.tsfile.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/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/FastCompactionInnerCompactionEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/FastCompactionInnerCompactionEstimator.java
index 9de3f58af9b..8be9b210a52 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/FastCompactionInnerCompactionEstimator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/FastCompactionInnerCompactionEstimator.java
@@ -19,34 +19,62 @@
 
 package 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator;
 
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.storageengine.rescon.memory.SystemInfo;
+
+import java.io.IOException;
+
 public class FastCompactionInnerCompactionEstimator extends 
AbstractInnerSpaceEstimator {
 
-  /**
-   * The metadata algorithm is: maxChunkMetaDataSize * maxChunkNumber * 
fileSize * maxSeriesNumber
-   *
-   * @return estimate metadata memory cost
-   */
   @Override
-  public long calculatingMetadataMemoryCost(InnerCompactionTaskInfo taskInfo) {
-    return taskInfo.getFileInfoList().size()
-        * taskInfo.getMaxChunkMetadataNumInDevice()
-        * taskInfo.getMaxChunkMetadataSize()
-        * Math.max(config.getSubCompactionTaskNum(), 
taskInfo.getMaxConcurrentSeriesNum());
+  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;
   }
 
-  /**
-   * The data algorithm is: (targetChunkSize * fileSize * compressionRatio * 
maxSeriesNumber) +
-   * modsFileSize
-   *
-   * @return estimate data memory cost
-   */
   @Override
-  public long calculatingDataMemoryCost(InnerCompactionTaskInfo taskInfo) {
-    long cost =
-        config.getTargetChunkSize()
+  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()
-            * Math.max(config.getSubCompactionTaskNum(), 
taskInfo.getMaxConcurrentSeriesNum());
-    cost += taskInfo.getModificationFileSize();
-    return cost;
+            * 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/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/FastCrossSpaceCompactionEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/FastCrossSpaceCompactionEstimator.java
new file mode 100644
index 00000000000..1ac3b5d5be1
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/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.storageengine.dataregion.compaction.selector.estimator;
+
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.storageengine.rescon.memory.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/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/InplaceCompactionEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/InplaceCompactionEstimator.java
deleted file mode 100644
index 2d7d6a9a590..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/InplaceCompactionEstimator.java
+++ /dev/null
@@ -1,172 +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.storageengine.dataregion.compaction.selector.estimator;
-
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.storageengine.dataregion.tsfile.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/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/ReadChunkInnerCompactionEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/ReadChunkInnerCompactionEstimator.java
index 02924768952..e432b1eac5d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/ReadChunkInnerCompactionEstimator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/ReadChunkInnerCompactionEstimator.java
@@ -25,13 +25,15 @@ import 
org.apache.iotdb.db.storageengine.rescon.memory.SystemInfo;
 public class ReadChunkInnerCompactionEstimator extends 
AbstractInnerSpaceEstimator {
 
   @Override
-  public long calculatingMetadataMemoryCost(InnerCompactionTaskInfo taskInfo) {
+  public long calculatingMetadataMemoryCost(CompactionTaskInfo taskInfo) {
     long cost = 0;
     // add ChunkMetadata size of MultiTsFileDeviceIterator
     cost +=
-        taskInfo.getFileInfoList().size()
-            * taskInfo.getMaxChunkMetadataNumInDevice()
-            * taskInfo.getMaxChunkMetadataSize();
+        Math.min(
+            taskInfo.getTotalChunkMetadataSize(),
+            taskInfo.getFileInfoList().size()
+                * taskInfo.getMaxChunkMetadataNumInDevice()
+                * taskInfo.getMaxChunkMetadataSize());
 
     // add ChunkMetadata size of targetFileWriter
     long sizeForFileWriter =
@@ -45,15 +47,27 @@ public class ReadChunkInnerCompactionEstimator extends 
AbstractInnerSpaceEstimat
   }
 
   @Override
-  public long calculatingDataMemoryCost(InnerCompactionTaskInfo taskInfo) {
-    // add max target chunk size and max source chunk size
-    long cost =
-        2
+  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()
-            * IoTDBDescriptor.getInstance().getConfig().getTargetChunkSize();
+            * taskInfo.getMaxChunkMetadataNumInSeries()
+            / compressionRatio;
+    long maxTargetChunkWriterSize =
+        config.getTargetChunkSize() * taskInfo.getMaxConcurrentSeriesNum();
+    long targetChunkWriterSize =
+        Math.min(maxConcurrentSeriesSizeOfTotalFiles, 
maxTargetChunkWriterSize);
 
-    // add modification file size
-    cost += taskInfo.getModificationFileSize();
-    return cost;
+    long chunkSizeFromSourceFile =
+        averageUncompressedChunkSize * taskInfo.getMaxConcurrentSeriesNum();
+
+    return targetChunkWriterSize + chunkSizeFromSourceFile + 
taskInfo.getModificationFileSize();
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/ReadPointCrossCompactionEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/ReadPointCrossCompactionEstimator.java
deleted file mode 100644
index d8908cfd0e6..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/estimator/ReadPointCrossCompactionEstimator.java
+++ /dev/null
@@ -1,197 +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.storageengine.dataregion.compaction.selector.estimator;
-
-import org.apache.iotdb.commons.conf.IoTDBConstant;
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource;
-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;
-
-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);
-    return CompactionEstimateUtils.addReadLock(allResources);
-  }
-
-  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.
-   *
-   * @throws IOException if io errors occurred
-   */
-  private long calculateReadingUnseqFile(TsFileResource unseqResource) throws 
IOException {
-    TsFileSequenceReader reader = getFileReader(unseqResource);
-    FileInfo fileInfo = 
CompactionEstimateUtils.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.
-   *
-   * @throws IOException if io errors occurred
-   */
-  private long calculateReadingSeqFiles(List<TsFileResource> seqResources) 
throws IOException {
-    long cost = 0;
-    for (TsFileResource seqResource : seqResources) {
-      TsFileSequenceReader reader = getFileReader(seqResource);
-      FileInfo fileInfo = 
CompactionEstimateUtils.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.
-   *
-   * @throws IOException if io errors occurred
-   */
-  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;
-  }
-}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/impl/RewriteCrossSpaceCompactionSelector.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/impl/RewriteCrossSpaceCompactionSelector.java
index 38ca5250b2c..9cb670b0be4 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/impl/RewriteCrossSpaceCompactionSelector.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/impl/RewriteCrossSpaceCompactionSelector.java
@@ -26,7 +26,7 @@ import org.apache.iotdb.db.exception.MergeException;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.schedule.CompactionTaskManager;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.ICompactionSelector;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.ICrossSpaceSelector;
-import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator.AbstractCompactionEstimator;
+import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator.AbstractCrossSpaceEstimator;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.utils.CrossCompactionTaskResource;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.utils.CrossSpaceCompactionCandidate;
 import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileManager;
@@ -38,6 +38,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;
@@ -58,7 +59,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,
@@ -80,8 +81,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);
   }
 
   /**
@@ -173,8 +175,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;
       }
@@ -254,7 +263,7 @@ public class RewriteCrossSpaceCompactionSelector implements 
ICrossSpaceSelector
 
     return taskResource.getTotalFileNums() + 1 + seqFiles.size() <= 
maxCrossCompactionFileNum
         && taskResource.getTotalFileSize() + totalFileSize <= 
maxCrossCompactionFileSize
-        && taskResource.getTotalMemoryCost() + memoryCost < memoryBudget;
+        && memoryCost < memoryBudget;
   }
 
   private boolean canSubmitCrossTask(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/utils/CrossCompactionTaskResource.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/utils/CrossCompactionTaskResource.java
index 1585314deaa..1bfecfc661d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/utils/CrossCompactionTaskResource.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/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/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/memory/SystemInfo.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/memory/SystemInfo.java
index 6eb3d991189..50cbe144f61 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/memory/SystemInfo.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/memory/SystemInfo.java
@@ -242,6 +242,9 @@ public class SystemInfo {
   }
 
   public synchronized void resetCompactionMemoryCost(long 
compactionMemoryCost) {
+    if (!config.isEnableCompactionMemControl()) {
+      return;
+    }
     this.compactionMemoryCost.addAndGet(-compactionMemoryCost);
   }
 
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/CompactionSchedulerTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/CompactionSchedulerTest.java
index d417eab7f7f..198e865dd07 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/CompactionSchedulerTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/CompactionSchedulerTest.java
@@ -101,7 +101,6 @@ public class CompactionSchedulerTest {
         .getConfig()
         
.setInnerUnseqCompactionPerformer(InnerUnseqCompactionPerformer.READ_POINT);
     
IoTDBDescriptor.getInstance().getConfig().setMinCrossCompactionUnseqFileLevel(0);
-    
IoTDBDescriptor.getInstance().getConfig().setEnableCompactionMemControl(false);
     CompactionTaskManager.getInstance().start();
     while (CompactionTaskManager.getInstance().getExecutingTaskCount() > 0) {
       try {
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/utils/CompactionTaskMemCostEstimatorTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/utils/CompactionTaskMemCostEstimatorTest.java
index fc0e5d3d4c4..044fa0e95ce 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/utils/CompactionTaskMemCostEstimatorTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/utils/CompactionTaskMemCostEstimatorTest.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.commons.exception.MetadataException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.AbstractCompactionTest;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator.FastCompactionInnerCompactionEstimator;
+import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator.FastCrossSpaceCompactionEstimator;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.selector.estimator.ReadChunkInnerCompactionEstimator;
 import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource;
 import org.apache.iotdb.tsfile.exception.write.WriteProcessException;
@@ -72,12 +73,12 @@ public class CompactionTaskMemCostEstimatorTest extends 
AbstractCompactionTest {
   @Test
   public void testEstimateFastCompactionInnerSpaceCompactionTaskMemCost()
       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());
+    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(tsFileList);
+        new 
FastCompactionInnerCompactionEstimator().estimateInnerCompactionMemory(unseqResources);
     Assert.assertTrue(cost > 0);
   }
 
@@ -91,4 +92,15 @@ public class CompactionTaskMemCostEstimatorTest extends 
AbstractCompactionTest {
         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);
+  }
 }

Reply via email to