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

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


The following commit(s) were added to refs/heads/dev/1.3 by this push:
     new 8e213ddfffe Pipe: add ConfigNode memory control for log reducer 
(#18069) (#18087)
8e213ddfffe is described below

commit 8e213ddfffe7321bed0a2ad8596d0000836e5fbe
Author: Caideyipi <[email protected]>
AuthorDate: Fri Jul 3 11:01:09 2026 +0800

    Pipe: add ConfigNode memory control for log reducer (#18069) (#18087)
    
    * Pipe: add ConfigNode memory control for log reducer
    
    * Address ConfigNode memory config review
    
    (cherry picked from commit 9554e5d8ef09763c32d7af408c491e6b1b617c0a)
---
 .../confignode/conf/ConfigNodeDescriptor.java      |  9 +++
 .../confignode/conf/ConfigNodeMemoryConfig.java    | 82 ++++++++++++++++++++++
 .../agent/runtime/PipeConfigNodeRuntimeAgent.java  | 10 +++
 .../resource/PipeConfigNodeResourceManager.java    | 16 +++++
 .../conf/ConfigNodeMemoryConfigTest.java           | 42 +++++++++++
 .../org/apache/iotdb/db/conf/IoTDBDescriptor.java  |  2 +-
 .../agent/runtime/PipeDataNodeRuntimeAgent.java    | 22 +++++-
 .../protocol/thrift/IoTDBDataNodeReceiver.java     |  2 +-
 .../conf/iotdb-system.properties.template          |  5 ++
 .../resource/log/PipePeriodicalLogReducer.java     | 71 ++++++++++---------
 .../resource/log/PipePeriodicalLogReducerTest.java | 65 +++++++++++++++++
 11 files changed, 290 insertions(+), 36 deletions(-)

diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
index 83cf1b612d0..d91f6a2251c 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
@@ -56,6 +56,8 @@ public class ConfigNodeDescriptor {
 
   private final ConfigNodeConfig conf = new ConfigNodeConfig();
 
+  private final ConfigNodeMemoryConfig memoryConfig = new 
ConfigNodeMemoryConfig();
+
   static {
     URL systemConfigUrl = getPropsUrl(CommonConfig.SYSTEM_CONFIG_NAME);
     URL configNodeUrl = getPropsUrl(CommonConfig.OLD_CONFIG_NODE_CONFIG_NAME);
@@ -79,6 +81,10 @@ public class ConfigNodeDescriptor {
     return conf;
   }
 
+  public ConfigNodeMemoryConfig getMemoryConfig() {
+    return memoryConfig;
+  }
+
   /**
    * Get props url location.
    *
@@ -143,10 +149,13 @@ public class ConfigNodeDescriptor {
       LOGGER.warn(
           "Couldn't load the configuration {} from any of the known sources.",
           CommonConfig.SYSTEM_CONFIG_NAME);
+      memoryConfig.init(trimProperties);
     }
   }
 
   private void loadProperties(TrimProperties properties) throws 
BadNodeUrlException, IOException {
+    memoryConfig.init(properties);
+
     conf.setClusterName(
         properties.getProperty(IoTDBConstant.CLUSTER_NAME, 
conf.getClusterName()).trim());
 
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeMemoryConfig.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeMemoryConfig.java
new file mode 100644
index 00000000000..8791549c371
--- /dev/null
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeMemoryConfig.java
@@ -0,0 +1,82 @@
+/*
+ * 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.confignode.conf;
+
+import org.apache.iotdb.commons.conf.TrimProperties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigNodeMemoryConfig {
+  public static final String PIPE_MEMORY_MANAGER_NAME = "Pipe";
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ConfigNodeMemoryConfig.class);
+
+  private long maxMemorySizeInBytes;
+
+  private long pipeMemorySizeInBytes;
+
+  private long freeMemorySizeInBytes;
+
+  public void init(final TrimProperties properties) {
+    final String memoryAllocateProportion =
+        properties.getProperty("confignode_memory_proportion", null);
+
+    maxMemorySizeInBytes = Runtime.getRuntime().maxMemory();
+    pipeMemorySizeInBytes = maxMemorySizeInBytes / 10;
+    freeMemorySizeInBytes = maxMemorySizeInBytes - pipeMemorySizeInBytes;
+
+    if (memoryAllocateProportion != null) {
+      final String[] proportions = memoryAllocateProportion.split(":");
+      if (proportions.length >= 2) {
+        int proportionSum = 0;
+        for (final String proportion : proportions) {
+          proportionSum += Integer.parseInt(proportion.trim());
+        }
+
+        if (proportionSum != 0) {
+          pipeMemorySizeInBytes =
+              maxMemorySizeInBytes * Integer.parseInt(proportions[0].trim()) / 
proportionSum;
+          freeMemorySizeInBytes = maxMemorySizeInBytes - pipeMemorySizeInBytes;
+        }
+      } else {
+        LOGGER.warn(
+            "The parameter confignode_memory_proportion should be in the form 
of Pipe:Free, "
+                + "but got {}. Use default value 1:9.",
+            memoryAllocateProportion);
+      }
+    }
+
+    LOGGER.info("initial ConfigNode allocateMemoryForPipe = {}", 
pipeMemorySizeInBytes);
+    LOGGER.info("initial ConfigNode freeMemory = {}", freeMemorySizeInBytes);
+  }
+
+  public long getMaxMemorySizeInBytes() {
+    return maxMemorySizeInBytes;
+  }
+
+  public long getPipeMemorySizeInBytes() {
+    return pipeMemorySizeInBytes;
+  }
+
+  public long getFreeMemorySizeInBytes() {
+    return freeMemorySizeInBytes;
+  }
+}
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/agent/runtime/PipeConfigNodeRuntimeAgent.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/agent/runtime/PipeConfigNodeRuntimeAgent.java
index e8cc16a1edf..10c710a64ad 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/agent/runtime/PipeConfigNodeRuntimeAgent.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/agent/runtime/PipeConfigNodeRuntimeAgent.java
@@ -26,10 +26,13 @@ import 
org.apache.iotdb.commons.pipe.agent.runtime.PipePeriodicalPhantomReferenc
 import org.apache.iotdb.commons.pipe.agent.task.meta.PipeTaskMeta;
 import org.apache.iotdb.commons.pipe.config.PipeConfig;
 import org.apache.iotdb.commons.pipe.event.EnrichedEvent;
+import org.apache.iotdb.commons.pipe.resource.log.PipeLogger;
+import org.apache.iotdb.commons.pipe.resource.log.PipePeriodicalLogReducer;
 import org.apache.iotdb.commons.service.IService;
 import org.apache.iotdb.commons.service.ServiceType;
 import org.apache.iotdb.confignode.manager.pipe.agent.PipeConfigNodeAgent;
 import 
org.apache.iotdb.confignode.manager.pipe.resource.PipeConfigNodeCopiedFileDirStartupCleaner;
+import 
org.apache.iotdb.confignode.manager.pipe.resource.PipeConfigNodeResourceManager;
 import 
org.apache.iotdb.confignode.manager.pipe.source.ConfigRegionListeningQueue;
 import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameters;
 
@@ -55,6 +58,7 @@ public class PipeConfigNodeRuntimeAgent implements IService {
   @Override
   public synchronized void start() {
     PipeConfig.getInstance().printAllConfigs();
+    initPipePeriodicalLogReducer();
 
     // PipeTasks will not be started here and will be started by 
"HandleLeaderChange"
     // procedure when the consensus layer notify leader ready
@@ -91,6 +95,12 @@ public class PipeConfigNodeRuntimeAgent implements IService {
     LOGGER.info("PipeRuntimeConfigNodeAgent stopped");
   }
 
+  private void initPipePeriodicalLogReducer() {
+    PipePeriodicalLogReducer.setMemoryResizeFunction(
+        PipeConfigNodeResourceManager::resizeLogReducerMemory);
+    PipeLogger.setLogger(PipePeriodicalLogReducer::log);
+  }
+
   public boolean isShutdown() {
     return isShutdown.get();
   }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/resource/PipeConfigNodeResourceManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/resource/PipeConfigNodeResourceManager.java
index 33b68f63821..635e6b7b1f8 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/resource/PipeConfigNodeResourceManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/resource/PipeConfigNodeResourceManager.java
@@ -22,12 +22,16 @@ package org.apache.iotdb.confignode.manager.pipe.resource;
 import org.apache.iotdb.commons.pipe.resource.log.PipeLogManager;
 import org.apache.iotdb.commons.pipe.resource.ref.PipePhantomReferenceManager;
 import 
org.apache.iotdb.commons.pipe.resource.snapshot.PipeSnapshotResourceManager;
+import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
 import 
org.apache.iotdb.confignode.manager.pipe.resource.ref.PipeConfigNodePhantomReferenceManager;
 import 
org.apache.iotdb.confignode.manager.pipe.resource.snapshot.PipeConfigNodeSnapshotResourceManager;
 
+import java.util.concurrent.atomic.AtomicLong;
+
 public class PipeConfigNodeResourceManager {
 
   private final PipeSnapshotResourceManager pipeSnapshotResourceManager;
+  private final AtomicLong pipeLogReducerMemoryUsageInBytes = new 
AtomicLong(0);
   private final PipeLogManager pipeLogManager;
   private final PipePhantomReferenceManager pipePhantomReferenceManager;
 
@@ -36,6 +40,10 @@ public class PipeConfigNodeResourceManager {
         .pipeSnapshotResourceManager;
   }
 
+  public static long resizeLogReducerMemory(final long targetSizeInBytes) {
+    return 
PipeResourceManagerHolder.INSTANCE.resizePipeLogReducerMemory(targetSizeInBytes);
+  }
+
   public static PipeLogManager log() {
     return 
PipeConfigNodeResourceManager.PipeResourceManagerHolder.INSTANCE.pipeLogManager;
   }
@@ -46,6 +54,14 @@ public class PipeConfigNodeResourceManager {
 
   ///////////////////////////// SINGLETON /////////////////////////////
 
+  private long resizePipeLogReducerMemory(final long targetSizeInBytes) {
+    final long pipeMemorySizeInBytes =
+        
ConfigNodeDescriptor.getInstance().getMemoryConfig().getPipeMemorySizeInBytes();
+    final long resizedSizeInBytes = Math.min(Math.max(0, targetSizeInBytes), 
pipeMemorySizeInBytes);
+    pipeLogReducerMemoryUsageInBytes.set(resizedSizeInBytes);
+    return pipeLogReducerMemoryUsageInBytes.get();
+  }
+
   private PipeConfigNodeResourceManager() {
     pipeSnapshotResourceManager = new PipeConfigNodeSnapshotResourceManager();
     pipeLogManager = new PipeLogManager();
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/conf/ConfigNodeMemoryConfigTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/conf/ConfigNodeMemoryConfigTest.java
new file mode 100644
index 00000000000..ff615131a03
--- /dev/null
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/conf/ConfigNodeMemoryConfigTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.confignode.conf;
+
+import org.apache.iotdb.commons.conf.TrimProperties;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ConfigNodeMemoryConfigTest {
+
+  @Test
+  public void testConfigNodeMemoryProportion() {
+    final TrimProperties properties = new TrimProperties();
+    properties.setProperty("confignode_memory_proportion", "1:3");
+
+    final ConfigNodeMemoryConfig memoryConfig = new ConfigNodeMemoryConfig();
+    memoryConfig.init(properties);
+
+    Assert.assertEquals(
+        Runtime.getRuntime().maxMemory() / 4, 
memoryConfig.getPipeMemorySizeInBytes());
+    Assert.assertEquals(
+        Runtime.getRuntime().maxMemory() * 3 / 4, 
memoryConfig.getFreeMemorySizeInBytes());
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index a838203a943..792433829c6 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.conf.TrimProperties;
 import org.apache.iotdb.commons.exception.BadNodeUrlException;
 import org.apache.iotdb.commons.pipe.config.PipeDescriptor;
+import org.apache.iotdb.commons.pipe.resource.log.PipePeriodicalLogReducer;
 import org.apache.iotdb.commons.schema.SchemaConstant;
 import org.apache.iotdb.commons.service.metric.MetricService;
 import org.apache.iotdb.commons.utils.NodeUrlUtils;
@@ -34,7 +35,6 @@ import org.apache.iotdb.confignode.rpc.thrift.TGlobalConfig;
 import org.apache.iotdb.confignode.rpc.thrift.TRatisConfig;
 import org.apache.iotdb.db.consensus.DataRegionConsensusImpl;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
-import org.apache.iotdb.db.pipe.resource.log.PipePeriodicalLogReducer;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.LastCacheLoadStrategy;
 import org.apache.iotdb.db.service.metrics.IoTDBInternalLocalReporter;
 import org.apache.iotdb.db.storageengine.StorageEngine;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeDataNodeRuntimeAgent.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeDataNodeRuntimeAgent.java
index d47a8c4dbbd..f88e98d7165 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeDataNodeRuntimeAgent.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeDataNodeRuntimeAgent.java
@@ -32,13 +32,15 @@ import org.apache.iotdb.commons.pipe.config.PipeConfig;
 import org.apache.iotdb.commons.pipe.datastructure.pattern.IoTDBPipePattern;
 import org.apache.iotdb.commons.pipe.event.EnrichedEvent;
 import org.apache.iotdb.commons.pipe.resource.log.PipeLogger;
+import org.apache.iotdb.commons.pipe.resource.log.PipePeriodicalLogReducer;
 import org.apache.iotdb.commons.service.IService;
 import org.apache.iotdb.commons.service.ServiceType;
 import org.apache.iotdb.commons.utils.TestOnly;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent;
 import 
org.apache.iotdb.db.pipe.resource.PipeDataNodeHardlinkOrCopiedFileDirStartupCleaner;
-import org.apache.iotdb.db.pipe.resource.log.PipePeriodicalLogReducer;
+import org.apache.iotdb.db.pipe.resource.PipeDataNodeResourceManager;
+import org.apache.iotdb.db.pipe.resource.memory.PipeMemoryBlock;
 import org.apache.iotdb.db.pipe.source.schemaregion.SchemaRegionListeningQueue;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertNode;
 import org.apache.iotdb.db.service.ResourcesInformationHolder;
@@ -70,6 +72,8 @@ public class PipeDataNodeRuntimeAgent implements IService {
   private final PipePeriodicalPhantomReferenceCleaner 
pipePeriodicalPhantomReferenceCleaner =
       new PipePeriodicalPhantomReferenceCleaner();
 
+  private PipeMemoryBlock pipeLogReducerMemoryBlock;
+
   //////////////////////////// System Service Interface 
////////////////////////////
 
   public synchronized void preparePipeResources(
@@ -85,6 +89,22 @@ public class PipeDataNodeRuntimeAgent implements IService {
 
     IoTDBPipePattern.setDevicePathGetter(CompactionPathUtils::getPath);
     IoTDBPipePattern.setMeasurementPathGetter(CompactionPathUtils::getPath);
+    initPipePeriodicalLogReducer();
+  }
+
+  private void initPipePeriodicalLogReducer() {
+    if (pipeLogReducerMemoryBlock == null) {
+      pipeLogReducerMemoryBlock =
+          PipeDataNodeResourceManager.memory()
+              
.tryAllocate(PipeConfig.getInstance().getPipeLoggerCacheMaxSizeInBytes());
+    }
+
+    PipePeriodicalLogReducer.setMemoryResizeFunction(
+        targetSizeInBytes -> {
+          PipeDataNodeResourceManager.memory()
+              .resize(pipeLogReducerMemoryBlock, Math.max(0, 
targetSizeInBytes), false);
+          return pipeLogReducerMemoryBlock.getMemoryUsageInBytes();
+        });
     PipeLogger.setLogger(PipePeriodicalLogReducer::log);
   }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/thrift/IoTDBDataNodeReceiver.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/thrift/IoTDBDataNodeReceiver.java
index 23f537fa2ae..3cf0b434fea 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/thrift/IoTDBDataNodeReceiver.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/thrift/IoTDBDataNodeReceiver.java
@@ -31,6 +31,7 @@ import 
org.apache.iotdb.commons.pipe.datastructure.pattern.PipePattern;
 import org.apache.iotdb.commons.pipe.receiver.IoTDBFileReceiver;
 import org.apache.iotdb.commons.pipe.receiver.PipeReceiverStatusHandler;
 import org.apache.iotdb.commons.pipe.resource.log.PipeLogger;
+import org.apache.iotdb.commons.pipe.resource.log.PipePeriodicalLogReducer;
 import 
org.apache.iotdb.commons.pipe.sink.payload.airgap.AirGapPseudoTPipeTransferRequest;
 import 
org.apache.iotdb.commons.pipe.sink.payload.thrift.common.PipeTransferSliceReqHandler;
 import 
org.apache.iotdb.commons.pipe.sink.payload.thrift.request.PipeRequestType;
@@ -52,7 +53,6 @@ import 
org.apache.iotdb.db.pipe.receiver.visitor.PipeStatementPatternParseVisito
 import org.apache.iotdb.db.pipe.receiver.visitor.PipeStatementTSStatusVisitor;
 import org.apache.iotdb.db.pipe.receiver.visitor.PipeStatementToBatchVisitor;
 import org.apache.iotdb.db.pipe.resource.PipeDataNodeResourceManager;
-import org.apache.iotdb.db.pipe.resource.log.PipePeriodicalLogReducer;
 import org.apache.iotdb.db.pipe.resource.memory.PipeMemoryBlock;
 import 
org.apache.iotdb.db.pipe.sink.payload.evolvable.request.PipeTransferDataNodeHandshakeV1Req;
 import 
org.apache.iotdb.db.pipe.sink.payload.evolvable.request.PipeTransferDataNodeHandshakeV2Req;
diff --git 
a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
 
b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
index 9b5b69b304d..b977ce9de8c 100644
--- 
a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
+++ 
b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
@@ -730,6 +730,11 @@ disk_space_warning_threshold=0.05
 # effectiveMode: restart
 datanode_memory_proportion=3:3:1:1:1:1
 
+# ConfigNode Memory Allocation Ratio: Pipe and Free Memory.
+# The parameter form is a:b, where a and b are integers. Currently, only 
PipePeriodicalLogReducer is connected to Pipe memory on ConfigNode.
+# effectiveMode: restart
+confignode_memory_proportion=1:9
+
 # Schema Memory Allocation Ratio: SchemaRegion, SchemaCache, and 
PartitionCache.
 # The parameter form is a:b:c, where a, b and c are integers. for example: 
1:1:1 , 6:2:1
 # effectiveMode: restart
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/log/PipePeriodicalLogReducer.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/resource/log/PipePeriodicalLogReducer.java
similarity index 52%
rename from 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/log/PipePeriodicalLogReducer.java
rename to 
iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/resource/log/PipePeriodicalLogReducer.java
index 3f5a013320d..fa3f29ccbe3 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/log/PipePeriodicalLogReducer.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/resource/log/PipePeriodicalLogReducer.java
@@ -17,11 +17,9 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.pipe.resource.log;
+package org.apache.iotdb.commons.pipe.resource.log;
 
 import org.apache.iotdb.commons.pipe.config.PipeConfig;
-import org.apache.iotdb.db.pipe.resource.PipeDataNodeResourceManager;
-import org.apache.iotdb.db.pipe.resource.memory.PipeMemoryBlock;
 
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
@@ -31,43 +29,57 @@ import org.slf4j.LoggerFactory;
 
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
+import java.util.function.LongUnaryOperator;
 
 public class PipePeriodicalLogReducer {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(PipePeriodicalLogReducer.class);
-  private static final PipeMemoryBlock block;
-  protected static final Cache<String, String> loggerCache;
 
-  static {
-    // Never close because it's static
-    block =
-        PipeDataNodeResourceManager.memory()
-            
.tryAllocate(PipeConfig.getInstance().getPipeLoggerCacheMaxSizeInBytes());
-    loggerCache =
-        Caffeine.newBuilder()
-            .expireAfterWrite(
-                
PipeConfig.getInstance().getPipePeriodicalLogMinIntervalSeconds(), 
TimeUnit.SECONDS)
-            .weigher(
-                (k, v) ->
-                    Math.toIntExact(
-                        RamUsageEstimator.sizeOf((String) k)
-                            + RamUsageEstimator.HASHTABLE_RAM_BYTES_PER_ENTRY))
-            .maximumWeight(block.getMemoryUsageInBytes())
-            .build();
+  private static final LongUnaryOperator DEFAULT_MEMORY_RESIZE_FUNCTION =
+      sizeInBytes -> sizeInBytes;
+
+  private static volatile LongUnaryOperator memoryResizeFunction = 
DEFAULT_MEMORY_RESIZE_FUNCTION;
+
+  protected static final Cache<String, String> LOGGER_CACHE =
+      Caffeine.newBuilder()
+          .expireAfterWrite(
+              
PipeConfig.getInstance().getPipePeriodicalLogMinIntervalSeconds(), 
TimeUnit.SECONDS)
+          .weigher(PipePeriodicalLogReducer::estimateSize)
+          
.maximumWeight(PipeConfig.getInstance().getPipeLoggerCacheMaxSizeInBytes())
+          .build();
+
+  private static int estimateSize(final String key, final String value) {
+    return Math.toIntExact(
+        RamUsageEstimator.sizeOf(key) + 
RamUsageEstimator.HASHTABLE_RAM_BYTES_PER_ENTRY);
   }
 
   public static boolean log(
       final Consumer<String> loggerFunction, final String rawMessage, final 
Object... formatter) {
     final String loggerMessage = String.format(rawMessage, formatter);
-    if (!loggerCache.asMap().containsKey(loggerMessage)) {
-      loggerCache.put(loggerMessage, loggerMessage);
+    if (!LOGGER_CACHE.asMap().containsKey(loggerMessage)) {
+      LOGGER_CACHE.put(loggerMessage, loggerMessage);
       loggerFunction.accept(loggerMessage);
       return true;
     }
     return false;
   }
 
-  public static void update() {
-    loggerCache
+  public static synchronized void setMemoryResizeFunction(
+      final LongUnaryOperator memoryResizeFunction) {
+    PipePeriodicalLogReducer.memoryResizeFunction =
+        memoryResizeFunction == null ? DEFAULT_MEMORY_RESIZE_FUNCTION : 
memoryResizeFunction;
+    update();
+  }
+
+  public static synchronized void update() {
+    final long maxWeight =
+        memoryResizeFunction.applyAsLong(
+            PipeConfig.getInstance().getPipeLoggerCacheMaxSizeInBytes());
+    LOGGER.info("PipePeriodicalLogReducer is allocated to {} bytes.", 
maxWeight);
+    update(maxWeight);
+  }
+
+  public static synchronized void update(final long maxWeight) {
+    LOGGER_CACHE
         .policy()
         .expireAfterWrite()
         .ifPresent(
@@ -75,14 +87,7 @@ public class PipePeriodicalLogReducer {
                 time.setExpiresAfter(
                     
PipeConfig.getInstance().getPipePeriodicalLogMinIntervalSeconds(),
                     TimeUnit.SECONDS));
-    PipeDataNodeResourceManager.memory()
-        .resize(block, 
PipeConfig.getInstance().getPipeLoggerCacheMaxSizeInBytes(), false);
-    LOGGER.info(
-        "PipePeriodicalLogReducer is allocated to {} bytes.", 
block.getMemoryUsageInBytes());
-    loggerCache
-        .policy()
-        .eviction()
-        .ifPresent(eviction -> 
eviction.setMaximum(block.getMemoryUsageInBytes()));
+    LOGGER_CACHE.policy().eviction().ifPresent(eviction -> 
eviction.setMaximum(maxWeight));
   }
 
   private PipePeriodicalLogReducer() {
diff --git 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/resource/log/PipePeriodicalLogReducerTest.java
 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/resource/log/PipePeriodicalLogReducerTest.java
new file mode 100644
index 00000000000..d390cbb9fdd
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/pipe/resource/log/PipePeriodicalLogReducerTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.commons.pipe.resource.log;
+
+import org.apache.iotdb.commons.pipe.config.PipeConfig;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class PipePeriodicalLogReducerTest {
+
+  @After
+  public void tearDown() {
+    PipePeriodicalLogReducer.setMemoryResizeFunction(null);
+  }
+
+  @Test
+  public void testLogReducesDuplicateMessages() {
+    final AtomicInteger logCount = new AtomicInteger(0);
+    final String message = "PipePeriodicalLogReducerTest-" + System.nanoTime();
+
+    Assert.assertTrue(PipePeriodicalLogReducer.log(log -> 
logCount.incrementAndGet(), message));
+    Assert.assertFalse(PipePeriodicalLogReducer.log(log -> 
logCount.incrementAndGet(), message));
+    Assert.assertEquals(1, logCount.get());
+  }
+
+  @Test
+  public void testUpdateUsesMemoryResizeFunction() {
+    final AtomicLong requestedSizeInBytes = new AtomicLong(-1);
+    final long allocatedSizeInBytes = 1024;
+
+    PipePeriodicalLogReducer.setMemoryResizeFunction(
+        sizeInBytes -> {
+          requestedSizeInBytes.set(sizeInBytes);
+          return allocatedSizeInBytes;
+        });
+
+    Assert.assertEquals(
+        PipeConfig.getInstance().getPipeLoggerCacheMaxSizeInBytes(), 
requestedSizeInBytes.get());
+    Assert.assertEquals(
+        allocatedSizeInBytes,
+        
PipePeriodicalLogReducer.LOGGER_CACHE.policy().eviction().get().getMaximum());
+  }
+}

Reply via email to