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 e615946bab0 Fix startup with invalid storage memory proportions
(#18979)
e615946bab0 is described below
commit e615946bab03616d8b960e5752fdf2beb52267e2
Author: Hongzhi Gao <[email protected]>
AuthorDate: Fri Oct 23 11:29:35 2026 +0800
Fix startup with invalid storage memory proportions (#18979)
---
.../apache/iotdb/db/conf/DataNodeMemoryConfig.java | 102 ++++++++++-----------
.../iotdb/db/conf/DataNodeMemoryConfigTest.java | 98 ++++++++++++++++++++
2 files changed, 147 insertions(+), 53 deletions(-)
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 12ac2293d3d..6f93f057ccf 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
@@ -399,59 +399,30 @@ public class DataNodeMemoryConfig {
Double.toString(getBufferedArraysMemoryProportion()))));
long storageMemoryTotal =
storageEngineMemoryManager.getTotalMemorySizeInBytes();
- String valueOfStorageEngineMemoryProportion =
- properties.getProperty("storage_engine_memory_proportion");
- long writeMemorySize = storageMemoryTotal * 8 / 10;
- long compactionMemorySize = storageMemoryTotal * 2 / 10;
- long memtableMemorySize = writeMemorySize * 19 / 20;
- long timePartitionInfoMemorySize = writeMemorySize / 20;
- if (valueOfStorageEngineMemoryProportion != null) {
- String[] storageProportionArray =
valueOfStorageEngineMemoryProportion.split(":");
- int storageEngineMemoryProportion = 0;
- for (String proportion : storageProportionArray) {
- int proportionValue = Integer.parseInt(proportion.trim());
- if (proportionValue <= 0) {
- LOGGER.warn(
- DataNodeMiscMessages
-
.MISC_LOG_THE_VALUE_OF_STORAGE_ENGINE_MEMORY_PROPORTION_IS_ILLEGAL_22CA9433);
- return;
- }
- storageEngineMemoryProportion += proportionValue;
- }
- writeMemorySize =
- storageMemoryTotal
- * Integer.parseInt(storageProportionArray[0].trim())
- / storageEngineMemoryProportion;
- compactionMemorySize =
- storageMemoryTotal
- * Integer.parseInt(storageProportionArray[1].trim())
- / storageEngineMemoryProportion;
-
- String valueOfWriteMemoryProportion =
properties.getProperty("write_memory_proportion");
- if (valueOfWriteMemoryProportion != null) {
- String[] writeProportionArray =
valueOfWriteMemoryProportion.split(":");
- int writeMemoryProportion = 0;
- for (String proportion : writeProportionArray) {
- int proportionValue = Integer.parseInt(proportion.trim());
- writeMemoryProportion += proportionValue;
- if (proportionValue <= 0) {
- LOGGER.warn(
- DataNodeMiscMessages
-
.MISC_LOG_THE_VALUE_OF_WRITE_MEMORY_PROPORTION_IS_ILLEGAL_USE_DEFAULT_EE4FA112);
- return;
- }
- }
-
- memtableMemorySize =
- writeMemorySize
- * Integer.parseInt(writeProportionArray[0].trim())
- / writeMemoryProportion;
- timePartitionInfoMemorySize =
- writeMemorySize
- * Integer.parseInt(writeProportionArray[1].trim())
- / writeMemoryProportion;
- }
- }
+ int[] storageProportions =
+ resolveStorageMemoryProportions(
+ properties.getProperty("storage_engine_memory_proportion"),
+ 8,
+ 2,
+ DataNodeMiscMessages
+
.MISC_LOG_THE_VALUE_OF_STORAGE_ENGINE_MEMORY_PROPORTION_IS_ILLEGAL_22CA9433);
+ long storageProportionSum = (long) storageProportions[0] +
storageProportions[1];
+ long writeMemorySize =
+ calculateMemoryShare(storageMemoryTotal, storageProportions[0],
storageProportionSum);
+ long compactionMemorySize =
+ calculateMemoryShare(storageMemoryTotal, storageProportions[1],
storageProportionSum);
+ int[] writeProportions =
+ resolveStorageMemoryProportions(
+ properties.getProperty("write_memory_proportion"),
+ 19,
+ 1,
+ DataNodeMiscMessages
+
.MISC_LOG_THE_VALUE_OF_WRITE_MEMORY_PROPORTION_IS_ILLEGAL_USE_DEFAULT_EE4FA112);
+ long writeProportionSum = (long) writeProportions[0] + writeProportions[1];
+ long memtableMemorySize =
+ calculateMemoryShare(writeMemorySize, writeProportions[0],
writeProportionSum);
+ long timePartitionInfoMemorySize =
+ calculateMemoryShare(writeMemorySize, writeProportions[1],
writeProportionSum);
writeMemoryManager =
storageEngineMemoryManager.getOrCreateMemoryManager("Write",
writeMemorySize);
initCompactionMemoryManager(compactionMemorySize);
@@ -473,6 +444,31 @@ public class DataNodeMemoryConfig {
memtableMemoryManager.getOrCreateMemoryManager("WalBufferQueue",
walBufferQueueMemorySize);
}
+ private static int[] resolveStorageMemoryProportions(
+ String configuredProportions, int defaultFirst, int defaultSecond,
String warningMessage) {
+ if (configuredProportions != null) {
+ String[] proportions = configuredProportions.split(":", -1);
+ if (proportions.length == 2) {
+ try {
+ int first = Integer.parseInt(proportions[0].trim());
+ int second = Integer.parseInt(proportions[1].trim());
+ if (first > 0 && second > 0) {
+ return new int[] {first, second};
+ }
+ } catch (NumberFormatException e) {
+ // Malformed or out-of-range configuration values use the default
proportions.
+ }
+ }
+ LOGGER.warn(warningMessage);
+ }
+ return new int[] {defaultFirst, defaultSecond};
+ }
+
+ private static long calculateMemoryShare(long total, int proportion, long
proportionSum) {
+ // Divide first to avoid overflowing when a valid proportion is close to
Integer.MAX_VALUE.
+ return total / proportionSum * proportion + total % proportionSum *
proportion / proportionSum;
+ }
+
private void initCompactionMemoryManager(long compactionMemorySize) {
long fixedMemoryCost =
AbstractCompactionEstimator.allocateMemoryCostForFileInfoCache(compactionMemorySize);
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
index 6aeeb22f2f6..af73f0a78cd 100644
---
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
@@ -26,7 +26,9 @@ import org.apache.iotdb.db.i18n.DataNodeMiscMessages;
import org.junit.Test;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.math.BigInteger;
import java.util.Arrays;
import static org.junit.Assert.assertArrayEquals;
@@ -178,6 +180,102 @@ public class DataNodeMemoryConfigTest {
DataNodeMemoryConfig.calculateAutoResizingBufferMemorySizeInBytes(properties));
}
+ @Test
+ public void testInvalidStorageMemoryProportionsUseDefaults() throws
ReflectiveOperationException {
+ for (String invalid :
+ new String[] {
+ "0:10", "10:0", "-1:2", "10", "a:b", "", ":2", "8:", "8:2:",
"8:2:1", "2147483648:1"
+ }) {
+ TrimProperties properties = new TrimProperties();
+ properties.setProperty("storage_engine_memory_proportion", invalid);
+ properties.setProperty("write_memory_proportion", "3:1");
+ assertStorageMemoryBudgets(properties, 800_000, 600_000, 200_000);
+
+ properties.setProperty("storage_engine_memory_proportion", "1:1");
+ properties.setProperty("write_memory_proportion", invalid);
+ assertStorageMemoryBudgets(properties, 500_000, 475_000, 25_000);
+ }
+ }
+
+ @Test
+ public void testStorageMemoryProportionsAreResolvedIndependently()
+ throws ReflectiveOperationException {
+ TrimProperties properties = new TrimProperties();
+ assertStorageMemoryBudgets(properties, 800_000, 760_000, 40_000);
+ properties.setProperty("write_memory_proportion", " 3 : 1 ");
+ assertStorageMemoryBudgets(properties, 800_000, 600_000, 200_000);
+ properties.remove("write_memory_proportion");
+ properties.setProperty("storage_engine_memory_proportion", " 1 : 1 ");
+ assertStorageMemoryBudgets(properties, 500_000, 475_000, 25_000);
+ properties.setProperty("storage_engine_memory_proportion", "0:10");
+ properties.setProperty("write_memory_proportion", "0:1");
+ assertStorageMemoryBudgets(properties, 800_000, 760_000, 40_000);
+ }
+
+ @Test
+ public void testLargeStorageMemoryProportionsDoNotOverflow() throws
ReflectiveOperationException {
+ TrimProperties properties = new TrimProperties();
+ properties.setProperty("storage_engine_memory_proportion",
"2147483647:2147483647");
+ properties.setProperty("write_memory_proportion", "2147483647:2147483647");
+ DataNodeMemoryConfig memoryConfig =
initializeStorageEngineMemory(properties, 32L << 30);
+ assertEquals(16L << 30,
memoryConfig.getWriteMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(8L << 30,
memoryConfig.getMemtableMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(
+ 8L << 30,
memoryConfig.getTimePartitionInfoMemoryManager().getTotalMemorySizeInBytes());
+
+ properties.setProperty("storage_engine_memory_proportion", "2147483646:1");
+ properties.setProperty("write_memory_proportion", "2147483646:1");
+ memoryConfig = initializeStorageEngineMemory(properties, 32L << 30);
+ BigInteger proportion = BigInteger.valueOf(Integer.MAX_VALUE - 1L);
+ BigInteger sum = proportion.add(BigInteger.ONE);
+ BigInteger expectedWrite = BigInteger.valueOf(32L <<
30).multiply(proportion).divide(sum);
+ assertEquals(
+ expectedWrite.longValueExact(),
+ memoryConfig.getWriteMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(
+ expectedWrite.multiply(proportion).divide(sum).longValueExact(),
+ memoryConfig.getMemtableMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(
+ expectedWrite.divide(sum).longValueExact(),
+
memoryConfig.getTimePartitionInfoMemoryManager().getTotalMemorySizeInBytes());
+ }
+
+ private void assertStorageMemoryBudgets(
+ TrimProperties properties, long write, long memtable, long timePartition)
+ throws ReflectiveOperationException {
+ DataNodeMemoryConfig memoryConfig =
initializeStorageEngineMemory(properties, 1_000_000L);
+ assertEquals(write,
memoryConfig.getWriteMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(memtable,
memoryConfig.getMemtableMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(
+ timePartition,
+
memoryConfig.getTimePartitionInfoMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(
+ 1_000_000L - write,
memoryConfig.getCompactionMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(
+ (long) (memtable * memoryConfig.getDevicePathCacheProportion()),
+
memoryConfig.getDevicePathCacheMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(
+ (long) (memtable * memoryConfig.getWalBufferQueueProportion()),
+
memoryConfig.getWalBufferQueueMemoryManager().getTotalMemorySizeInBytes());
+ assertEquals(
+ 600_000L,
memoryConfig.getBufferedArraysMemoryManager().getTotalMemorySizeInBytes());
+ }
+
+ private DataNodeMemoryConfig initializeStorageEngineMemory(TrimProperties
properties, long total)
+ throws ReflectiveOperationException {
+ DataNodeMemoryConfig memoryConfig = new DataNodeMemoryConfig();
+ MemoryManager storageMemoryManager = new MemoryManager(total);
+ Field storageField =
DataNodeMemoryConfig.class.getDeclaredField("storageEngineMemoryManager");
+ storageField.setAccessible(true);
+ storageField.set(memoryConfig, storageMemoryManager);
+ Method initialize =
+ DataNodeMemoryConfig.class.getDeclaredMethod(
+ "initStorageEngineAllocate", MemoryManager.class,
TrimProperties.class);
+ initialize.setAccessible(true);
+ initialize.invoke(memoryConfig, storageMemoryManager, properties);
+ return memoryConfig;
+ }
+
private DataNodeMemoryConfig initializeQueryEngineMemory(TrimProperties
properties)
throws ReflectiveOperationException {
final DataNodeMemoryConfig memoryConfig = new DataNodeMemoryConfig();