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

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


The following commit(s) were added to refs/heads/master by this push:
     new 0d3304a106a Fix RPC buffer memory control activation (#18194)
0d3304a106a is described below

commit 0d3304a106a4ef2ea168682485ac0b7027f93f95
Author: Caideyipi <[email protected]>
AuthorDate: Tue Jul 14 09:32:30 2026 +0800

    Fix RPC buffer memory control activation (#18194)
    
    Avoid activating DataNode RPC buffer memory control during configuration 
loading, and bind auto-resizing buffers to the memory account used for their 
allocation.
---
 .../org/apache/iotdb/rpc/AutoResizingBuffer.java   | 24 +++++++++----
 .../iotdb/rpc/AutoResizingBufferMemoryManager.java | 25 ++++++++++++--
 .../apache/iotdb/rpc/AutoResizingBufferTest.java   | 37 ++++++++++++++++++++
 .../iotdb/confignode/service/ConfigNode.java       |  2 --
 .../apache/iotdb/db/conf/DataNodeMemoryConfig.java | 12 +++++--
 .../java/org/apache/iotdb/db/service/DataNode.java |  1 +
 .../iotdb/db/conf/DataNodeMemoryConfigTest.java    | 40 ++++++++++++++++++++++
 .../apache/iotdb/commons/memory/MemoryConfig.java  | 27 ++++++---------
 8 files changed, 137 insertions(+), 31 deletions(-)

diff --git 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/AutoResizingBuffer.java
 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/AutoResizingBuffer.java
index 397a5843171..aa0ea40541c 100644
--- 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/AutoResizingBuffer.java
+++ 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/AutoResizingBuffer.java
@@ -40,11 +40,18 @@ class AutoResizingBuffer implements AutoCloseable {
   private long lastShrinkTime;
   private int accountedCapacity;
   private boolean closed;
+  private AutoResizingBufferMemoryManager.MemoryAccount memoryAccount;
 
   public AutoResizingBuffer(int initialCapacity) throws IOException {
-    AutoResizingBufferMemoryManager.allocate(initialCapacity);
-    this.array = new byte[initialCapacity];
     this.initialCapacity = initialCapacity;
+    this.memoryAccount = AutoResizingBufferMemoryManager.createMemoryAccount();
+    memoryAccount.allocate(initialCapacity);
+    try {
+      this.array = new byte[initialCapacity];
+    } catch (RuntimeException | Error e) {
+      memoryAccount.release(initialCapacity);
+      throw e;
+    }
     this.accountedCapacity = initialCapacity;
   }
 
@@ -76,7 +83,7 @@ class AutoResizingBuffer implements AutoCloseable {
   @Override
   public void close() {
     if (!closed) {
-      AutoResizingBufferMemoryManager.release(accountedCapacity);
+      memoryAccount.release(accountedCapacity);
       accountedCapacity = 0;
       closed = true;
     }
@@ -86,25 +93,28 @@ class AutoResizingBuffer implements AutoCloseable {
     final int currentCapacity = array.length;
     if (newCapacity > currentCapacity) {
       final int delta = newCapacity - currentCapacity;
-      AutoResizingBufferMemoryManager.allocate(delta);
+      memoryAccount.allocate(delta);
       try {
         array = Arrays.copyOf(array, newCapacity);
         accountedCapacity += delta;
       } catch (RuntimeException | Error e) {
-        AutoResizingBufferMemoryManager.release(delta);
+        memoryAccount.release(delta);
         throw e;
       }
     } else if (newCapacity < currentCapacity) {
       array = Arrays.copyOf(array, newCapacity);
       final int delta = currentCapacity - newCapacity;
-      AutoResizingBufferMemoryManager.release(delta);
+      memoryAccount.release(delta);
       accountedCapacity -= delta;
     }
   }
 
   private void reserveCurrentCapacityIfReleased() throws IOException {
     if (closed) {
-      AutoResizingBufferMemoryManager.allocate(array.length);
+      AutoResizingBufferMemoryManager.MemoryAccount newMemoryAccount =
+          AutoResizingBufferMemoryManager.createMemoryAccount();
+      newMemoryAccount.allocate(array.length);
+      memoryAccount = newMemoryAccount;
       accountedCapacity = array.length;
       closed = false;
     }
diff --git 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/AutoResizingBufferMemoryManager.java
 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/AutoResizingBufferMemoryManager.java
index d95d51adb48..d33a15b44cb 100644
--- 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/AutoResizingBufferMemoryManager.java
+++ 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/AutoResizingBufferMemoryManager.java
@@ -68,7 +68,12 @@ public final class AutoResizingBufferMemoryManager {
         memoryAllocateRetryIntervalInMs;
   }
 
-  static void allocate(long sizeInBytes) throws IOException {
+  static MemoryAccount createMemoryAccount() {
+    return new MemoryAccount(memoryControl);
+  }
+
+  private static void allocate(AutoResizingBufferMemoryControl memoryControl, 
long sizeInBytes)
+      throws IOException {
     if (sizeInBytes <= 0) {
       return;
     }
@@ -93,7 +98,7 @@ public final class AutoResizingBufferMemoryManager {
             MEMORY_ALLOCATE_MAX_RETRIES));
   }
 
-  static void release(long sizeInBytes) {
+  private static void release(AutoResizingBufferMemoryControl memoryControl, 
long sizeInBytes) {
     if (sizeInBytes <= 0) {
       return;
     }
@@ -107,4 +112,20 @@ public final class AutoResizingBufferMemoryManager {
   public static long getMemoryAllocationFailureCount() {
     return memoryAllocationFailureCount.get();
   }
+
+  static final class MemoryAccount {
+    private final AutoResizingBufferMemoryControl memoryControl;
+
+    private MemoryAccount(AutoResizingBufferMemoryControl memoryControl) {
+      this.memoryControl = memoryControl;
+    }
+
+    void allocate(long sizeInBytes) throws IOException {
+      AutoResizingBufferMemoryManager.allocate(memoryControl, sizeInBytes);
+    }
+
+    void release(long sizeInBytes) {
+      AutoResizingBufferMemoryManager.release(memoryControl, sizeInBytes);
+    }
+  }
 }
diff --git 
a/iotdb-client/service-rpc/src/test/java/org/apache/iotdb/rpc/AutoResizingBufferTest.java
 
b/iotdb-client/service-rpc/src/test/java/org/apache/iotdb/rpc/AutoResizingBufferTest.java
index 800881208ee..164d0f9e287 100644
--- 
a/iotdb-client/service-rpc/src/test/java/org/apache/iotdb/rpc/AutoResizingBufferTest.java
+++ 
b/iotdb-client/service-rpc/src/test/java/org/apache/iotdb/rpc/AutoResizingBufferTest.java
@@ -152,6 +152,43 @@ public class AutoResizingBufferTest {
     }
   }
 
+  @Test
+  public void testBufferReleasesMemoryToTheControlUsedForAllocation() throws 
Exception {
+    TestMemoryControl firstMemoryControl = new TestMemoryControl();
+    AutoResizingBufferMemoryManager.setMemoryControl(firstMemoryControl);
+    AutoResizingBuffer firstBuffer = new AutoResizingBuffer(100);
+
+    TestMemoryControl secondMemoryControl = new TestMemoryControl();
+    AutoResizingBufferMemoryManager.setMemoryControl(secondMemoryControl);
+    AutoResizingBuffer secondBuffer = new AutoResizingBuffer(200);
+
+    firstBuffer.close();
+    Assert.assertEquals(0, firstMemoryControl.getUsedMemoryInBytes());
+    Assert.assertEquals(200, secondMemoryControl.getUsedMemoryInBytes());
+
+    secondBuffer.close();
+    Assert.assertEquals(0, secondMemoryControl.getUsedMemoryInBytes());
+  }
+
+  @Test
+  public void testBufferCreatedWithoutControlDoesNotReleaseToNewControl() 
throws Exception {
+    AutoResizingBuffer bufferWithoutControl = new AutoResizingBuffer(100);
+
+    AutoResizingBufferMemoryManager.setMemoryControl(memoryControl);
+    AutoResizingBuffer bufferWithControl = new AutoResizingBuffer(100);
+
+    bufferWithoutControl.close();
+    Assert.assertEquals(100, memoryControl.getUsedMemoryInBytes());
+
+    bufferWithoutControl.resizeIfNecessary(100);
+    Assert.assertEquals(200, memoryControl.getUsedMemoryInBytes());
+    bufferWithoutControl.close();
+    Assert.assertEquals(100, memoryControl.getUsedMemoryInBytes());
+
+    bufferWithControl.close();
+    Assert.assertEquals(0, memoryControl.getUsedMemoryInBytes());
+  }
+
   private void setLastShrinkTime(AutoResizingBuffer buffer, long 
lastShrinkTime) throws Exception {
     Field field = AutoResizingBuffer.class.getDeclaredField("lastShrinkTime");
     field.setAccessible(true);
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
index c5e0a95294b..ffd5ec2d33b 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
@@ -34,7 +34,6 @@ import 
org.apache.iotdb.commons.exception.ConfigurationException;
 import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.exception.IoTDBException;
 import org.apache.iotdb.commons.exception.StartupException;
-import org.apache.iotdb.commons.memory.MemoryConfig;
 import org.apache.iotdb.commons.service.JMXService;
 import org.apache.iotdb.commons.service.RegisterManager;
 import org.apache.iotdb.commons.service.ServiceType;
@@ -143,7 +142,6 @@ public class ConfigNode extends ServerCommandLine 
implements ConfigNodeMBean {
       LOGGER.info(ConfigNodeMessages.STARTING_IOTDB, 
IoTDBConstant.VERSION_WITH_BUILD);
       ConfigNodeStartupCheck checks = new 
ConfigNodeStartupCheck(IoTDBConstant.CN_ROLE);
       checks.startUpCheck();
-      MemoryConfig.getInstance();
     } catch (StartupException | ConfigurationException | IOException e) {
       LOGGER.error(ConfigNodeMessages.MEET_ERROR_WHEN_DOING_START_CHECKING, e);
       throw new IoTDBException(ConfigNodeMessages.ERROR_STARTING, -1);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeMemoryConfig.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeMemoryConfig.java
index 6612732441e..9476e84e15e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeMemoryConfig.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeMemoryConfig.java
@@ -77,6 +77,9 @@ public class DataNodeMemoryConfig {
   /** The memory manager of on heap */
   private MemoryManager onHeapMemoryManager;
 
+  /** Memory budget for RPC auto-resizing buffers */
+  private long autoResizingBufferMemorySize;
+
   /** Memory manager for the write process */
   private MemoryManager storageEngineMemoryManager;
 
@@ -168,7 +171,7 @@ public class DataNodeMemoryConfig {
     long schemaEngineMemorySize = Runtime.getRuntime().maxMemory() / 10;
     long consensusMemorySize = Runtime.getRuntime().maxMemory() / 10;
     long pipeMemorySize = Runtime.getRuntime().maxMemory() / 10;
-    long autoResizingBufferMemorySize = Runtime.getRuntime().maxMemory() / 20;
+    autoResizingBufferMemorySize = Runtime.getRuntime().maxMemory() / 20;
     if (memoryAllocateProportion != null) {
       String[] proportions = memoryAllocateProportion.split(":");
       int proportionSum = 0;
@@ -217,8 +220,6 @@ public class DataNodeMemoryConfig {
     consensusMemoryManager =
         onHeapMemoryManager.getOrCreateMemoryManager("Consensus", 
consensusMemorySize);
     pipeMemoryManager = onHeapMemoryManager.getOrCreateMemoryManager("Pipe", 
pipeMemorySize);
-    MemoryConfig.getInstance()
-        .setAutoResizingBufferMemoryControl(onHeapMemoryManager, 
autoResizingBufferMemorySize);
     LOGGER.info(
         DataNodeMiscMessages.MISC_LOG_INITIAL_ALLOCATEMEMORYFORWRITE_B90EC7D9,
         storageEngineMemoryManager.getTotalMemorySizeInBytes());
@@ -260,6 +261,11 @@ public class DataNodeMemoryConfig {
             "DirectBuffer", totalDirectBufferMemorySizeLimit);
   }
 
+  public void activateAutoResizingBufferMemoryControl() {
+    MemoryConfig.getInstance()
+        .setAutoResizingBufferMemoryControl(onHeapMemoryManager, 
autoResizingBufferMemorySize);
+  }
+
   @SuppressWarnings("squid:S3518")
   private void initSchemaMemoryAllocate(
       MemoryManager schemaEngineMemoryManager, TrimProperties properties) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java
index 5fc67446925..0489adb7646 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java
@@ -253,6 +253,7 @@ public class DataNode extends ServerCommandLine implements 
DataNodeMBean {
     logger.info(DataNodeMiscMessages.STARTING_DATANODE);
     boolean isFirstStart;
     try {
+      
IoTDBDescriptor.getInstance().getMemoryConfig().activateAutoResizingBufferMemoryControl();
       // Check if this DataNode is start for the first time and do other 
pre-checks
       isFirstStart = prepareDataNode();
 
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/DataNodeMemoryConfigTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/DataNodeMemoryConfigTest.java
new file mode 100644
index 00000000000..0d3447bbefb
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/DataNodeMemoryConfigTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.conf;
+
+import org.apache.iotdb.commons.memory.MemoryConfig;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class DataNodeMemoryConfigTest {
+
+  @Test
+  public void testRpcMemoryControlIsActivatedOnlyExplicitly() {
+    DataNodeMemoryConfig memoryConfig = 
IoTDBDescriptor.getInstance().getMemoryConfig();
+
+    Assert.assertEquals(
+        0, 
MemoryConfig.getInstance().getAutoResizingBufferMemoryTotalSizeInBytes());
+
+    memoryConfig.activateAutoResizingBufferMemoryControl();
+
+    
Assert.assertTrue(MemoryConfig.getInstance().getAutoResizingBufferMemoryTotalSizeInBytes()
 > 0);
+  }
+}
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/memory/MemoryConfig.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/memory/MemoryConfig.java
index c828120eab5..52b08556e3f 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/memory/MemoryConfig.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/memory/MemoryConfig.java
@@ -35,7 +35,6 @@ public class MemoryConfig {
   private boolean isAutoResizingBufferMemoryControlEnabled;
 
   private MemoryConfig() {
-    initAutoResizingBufferMemoryControl();
     MetricService.getInstance().addMetricSet(new 
AutoResizingBufferMemoryMetrics(this));
   }
 
@@ -53,39 +52,33 @@ public class MemoryConfig {
     private MemoryConfigHolder() {}
   }
 
-  private void initAutoResizingBufferMemoryControl() {
+  private void initAutoResizingBufferMemoryControl(IMemoryBlock memoryBlock) {
     AutoResizingBufferMemoryManager.setMemoryControl(
         new AutoResizingBufferMemoryControl() {
           @Override
-          public synchronized boolean allocate(long sizeInBytes) {
-            IMemoryBlock memoryBlock = getAutoResizingBufferMemoryBlock();
-            if (memoryBlock == null) {
-              return true;
-            }
+          public boolean allocate(long sizeInBytes) {
             return memoryBlock.allocate(sizeInBytes);
           }
 
           @Override
-          public synchronized void release(long sizeInBytes) {
-            IMemoryBlock memoryBlock = getAutoResizingBufferMemoryBlock();
-            if (memoryBlock != null) {
-              memoryBlock.release(sizeInBytes);
-            }
+          public void release(long sizeInBytes) {
+            memoryBlock.release(sizeInBytes);
           }
         });
   }
 
+  /**
+   * Installs RPC auto-resizing buffer memory control once. Replacing a live 
control would orphan
+   * the memory blocks retained by existing RPC buffers.
+   */
   public synchronized void setAutoResizingBufferMemoryControl(
       MemoryManager parentMemoryManager, long memorySizeInBytes) {
     if (autoResizingBufferMemoryManagerParent != null) {
-      autoResizingBufferMemoryManagerParent.releaseChildMemoryManager(
-          AUTO_RESIZING_BUFFER_MEMORY_MANAGER_NAME);
+      return;
     }
     autoResizingBufferMemoryManagerParent = parentMemoryManager;
-    autoResizingBufferMemoryBlock = null;
 
     if (memorySizeInBytes <= 0) {
-      isAutoResizingBufferMemoryControlEnabled = false;
       return;
     }
 
@@ -93,13 +86,13 @@ public class MemoryConfig {
         parentMemoryManager.getOrCreateMemoryManager(
             AUTO_RESIZING_BUFFER_MEMORY_MANAGER_NAME, memorySizeInBytes, true);
     if (autoResizingBufferMemoryManager == null) {
-      isAutoResizingBufferMemoryControlEnabled = false;
       return;
     }
     autoResizingBufferMemoryBlock =
         autoResizingBufferMemoryManager.exactAllocate(
             AUTO_RESIZING_BUFFER_MEMORY_BLOCK_NAME, memorySizeInBytes, 
MemoryBlockType.DYNAMIC);
     isAutoResizingBufferMemoryControlEnabled = true;
+    initAutoResizingBufferMemoryControl(autoResizingBufferMemoryBlock);
   }
 
   private synchronized IMemoryBlock getAutoResizingBufferMemoryBlock() {

Reply via email to