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

CRZbulabula 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 71e9c59634e Uncomment commented set-configuration-able items in the 
config template (fix enable_topology_probing & topology_probing_* hot/restart 
reload) (#17933)
71e9c59634e is described below

commit 71e9c59634efe6b22b1a64529d81124b6c64398e
Author: Yongzao <[email protected]>
AuthorDate: Mon Jun 15 11:40:11 2026 +0800

    Uncomment commented set-configuration-able items in the config template 
(fix enable_topology_probing & topology_probing_* hot/restart reload) (#17933)
---
 .../iotdb/db/it/IoTDBSetConfigurationIT.java       | 37 ++++++++++
 .../iotdb/db/utils/ConfigurationFileUtilsTest.java | 82 ++++++++++++++++++++++
 .../conf/iotdb-system.properties.template          | 12 ++--
 3 files changed, 125 insertions(+), 6 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSetConfigurationIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSetConfigurationIT.java
index 96ee0bc30c1..4b569bf1010 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSetConfigurationIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSetConfigurationIT.java
@@ -88,6 +88,35 @@ public class IoTDBSetConfigurationIT {
                         "enable_cross_space_compaction=false")));
   }
 
+  /**
+   * Regression test for V2-995: the topology-probing config items were left 
commented out in the
+   * template, so {@code getConfigurationItemsFromTemplate} never recorded 
them as known defaults
+   * and {@code set configuration} rejected them as "immutable or undefined". 
After uncommenting
+   * them, {@code set configuration} must accept and persist them: {@code 
enable_topology_probing}
+   * (hot_reload) and {@code topology_probing_base_interval_in_ms} / {@code
+   * topology_probing_timeout_ratio} (restart).
+   */
+  @Test
+  public void testSetTopologyProbingConfiguration() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("set configuration 
\"enable_topology_probing\"=\"true\"");
+      statement.execute("set configuration 
\"topology_probing_base_interval_in_ms\"=\"3000\"");
+      statement.execute("set configuration 
\"topology_probing_timeout_ratio\"=\"0.4\"");
+    } catch (Exception e) {
+      Assert.fail(e.getMessage());
+    }
+    Assert.assertTrue(
+        EnvFactory.getEnv().getConfigNodeWrapperList().stream()
+            .allMatch(
+                nodeWrapper ->
+                    checkConfigFileContains(
+                        nodeWrapper,
+                        "enable_topology_probing=true",
+                        "topology_probing_base_interval_in_ms=3000",
+                        "topology_probing_timeout_ratio=0.4")));
+  }
+
   @Test
   public void testSetClusterName() throws Exception {
     // set cluster name on cn and dn
@@ -207,6 +236,14 @@ public class IoTDBSetConfigurationIT {
             "509: An error occurred when executing 
getDeviceToDatabase():root.db1 is not a legal path, because it is no longer 
than default sg level: 3",
             e.getMessage());
       }
+    } finally {
+      // This test leaves default_database_level=-1 baked into the cluster's 
config file. Because
+      // tests in this class share one cluster and run in random order, a 
later 'set configuration'
+      // test would otherwise fail its hot-reload while re-validating the 
leftover illegal value
+      // ("Illegal defaultDatabaseLevel: -1, should >= 1"). Restore a clean 
cluster before leaving.
+      EnvFactory.getEnv().cleanClusterEnvironment();
+      
EnvFactory.getEnv().getConfig().getCommonConfig().setDefaultDatabaseLevel(1);
+      EnvFactory.getEnv().initClusterEnvironment();
     }
   }
 }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ConfigurationFileUtilsTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ConfigurationFileUtilsTest.java
index af0fc1ae83e..ae419c79ecd 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ConfigurationFileUtilsTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ConfigurationFileUtilsTest.java
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.db.utils;
 
+import org.apache.iotdb.commons.conf.CommonConfig;
 import org.apache.iotdb.commons.conf.ConfigurationFileUtils;
 import org.apache.iotdb.db.utils.constant.TestConstant;
 
@@ -26,13 +27,18 @@ import org.junit.After;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.nio.file.Files;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
+import java.util.Set;
 
 public class ConfigurationFileUtilsTest {
 
@@ -89,6 +95,82 @@ public class ConfigurationFileUtilsTest {
     }
   }
 
+  /**
+   * Regression guard for V2-995: a configuration item whose {@code 
effectiveMode} allows {@code set
+   * configuration} (i.e. anything except {@code FIRST_START}) must have its 
{@code key=value} line
+   * left uncommented in the template. {@code 
getConfigurationItemsFromTemplate} only parses
+   * uncommented lines, so a commented item never enters {@code 
configuration2DefaultValue}; {@code
+   * filterInvalidConfigItems} then treats it as undefined and {@code set 
configuration} rejects it
+   * with "immutable or undefined" — silently disabling the advertised 
dynamic-config entry point.
+   * This was the root cause for {@code enable_topology_probing} (hot_reload) 
and the two {@code
+   * topology_probing_*} items (restart).
+   */
+  @Test
+  public void checkSettableItemsAreUncommentedInTemplate() throws IOException {
+    // Keys whose value line appears uncommented at least once. Some keys 
(e.g. dn_data_dirs) list a
+    // commented Windows-path variant next to an uncommented Unix-path 
variant; only the uncommented
+    // one is parsed, so such keys are fine and must not be flagged.
+    Set<String> uncommentedKeys = new HashSet<>();
+    // Keys with a commented value line whose enclosing block declares a 
settable effectiveMode.
+    Set<String> commentedSettableKeys = new HashSet<>();
+    try (InputStream inputStream =
+            ConfigurationFileUtilsTest.class
+                .getClassLoader()
+                .getResourceAsStream(CommonConfig.SYSTEM_CONFIG_TEMPLATE_NAME);
+        BufferedReader reader =
+            new BufferedReader(new 
InputStreamReader(Objects.requireNonNull(inputStream)))) {
+      String line;
+      ConfigurationFileUtils.EffectiveModeType currentMode = null;
+      while ((line = reader.readLine()) != null) {
+        line = line.trim();
+        if (line.isEmpty()) {
+          // Blank line separates configuration blocks; reset the accumulated 
effectiveMode.
+          currentMode = null;
+          continue;
+        }
+        if (line.startsWith("# effectiveMode:")) {
+          currentMode =
+              ConfigurationFileUtils.EffectiveModeType.getEffectiveMode(
+                  line.substring("# effectiveMode:".length()).trim());
+          continue;
+        }
+        // Detect the (possibly commented) "key=value" line that closes a 
block.
+        String stripped = line.startsWith("#") ? line.substring(1).trim() : 
line;
+        int equalsIndex = stripped.indexOf('=');
+        boolean isValueLine =
+            equalsIndex > 0 && stripped.substring(0, 
equalsIndex).trim().matches("[a-zA-Z0-9_.]+");
+        if (!isValueLine) {
+          continue;
+        }
+        String key = stripped.substring(0, equalsIndex).trim();
+        if (line.startsWith("#")) {
+          // FIRST_START items are intentionally rejected by 'set 
configuration'; UNKNOWN items have
+          // no declared mode. Only flag items that 'set configuration' is 
supposed to accept.
+          if (isSettableByConfiguration(currentMode)) {
+            commentedSettableKeys.add(key);
+          }
+        } else {
+          uncommentedKeys.add(key);
+        }
+        // A value line ends the current block's effectiveMode scope.
+        currentMode = null;
+      }
+    }
+    commentedSettableKeys.removeAll(uncommentedKeys);
+    Assert.assertTrue(
+        "configuration items settable via 'set configuration' must be 
uncommented in the template "
+            + "so the command can reach them instead of rejecting them as 
undefined; "
+            + "commented settable items found: "
+            + commentedSettableKeys,
+        commentedSettableKeys.isEmpty());
+  }
+
+  private static boolean 
isSettableByConfiguration(ConfigurationFileUtils.EffectiveModeType mode) {
+    return mode == ConfigurationFileUtils.EffectiveModeType.HOT_RELOAD
+        || mode == ConfigurationFileUtils.EffectiveModeType.RESTART
+        || mode == 
ConfigurationFileUtils.EffectiveModeType.FIRST_START_OR_SET_CONFIGURATION;
+  }
+
   private void generateFile(File file, String content) throws IOException {
     Files.write(file.toPath(), content.getBytes());
   }
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 8e4808cec2f..1e855a9704c 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
@@ -512,7 +512,7 @@ cn_max_client_count_for_each_node_in_client_manager=1000
 # 0 means no idle clients will be retained, connections are destroyed 
immediately upon return.
 # effectiveMode: restart
 # Datatype: int
-# cn_max_idle_client_count_for_each_node_in_client_manager=1000
+cn_max_idle_client_count_for_each_node_in_client_manager=1000
 
 # The maximum session idle time. unit: ms
 # Idle sessions are the ones that performs neither query or non-query 
operations for a period of time
@@ -571,7 +571,7 @@ dn_max_client_count_for_each_node_in_client_manager=1000
 # 0 means no idle clients will be retained, connections are destroyed 
immediately upon return.
 # effectiveMode: restart
 # Datatype: int
-# dn_max_idle_client_count_for_each_node_in_client_manager=1000
+dn_max_idle_client_count_for_each_node_in_client_manager=1000
 
 ####################
 ### REST Service Configuration
@@ -686,7 +686,7 @@ data_region_per_data_node=0
 # 3. PGP (Partite-Graph Placement; based on the PGP paper, with database-aware 
balance)
 # effectiveMode: restart
 # Datatype: String
-# region_group_allocate_policy=GCR
+region_group_allocate_policy=GCR
 
 # Whether to enable auto leader balance for Ratis consensus protocol.
 # The ConfigNode-leader will balance the leader of Ratis-RegionGroups by 
leader_distribution_policy if set true.
@@ -747,17 +747,17 @@ failure_detector_phi_acceptable_pause_in_ms=10000
 # Whether to enable topology probing between DataNodes
 # effectiveMode: hot_reload
 # Datatype: Boolean
-# enable_topology_probing=false
+enable_topology_probing=false
 
 # Base interval in ms for topology probing between DataNodes
 # effectiveMode: restart
 # Datatype: long
-# topology_probing_base_interval_in_ms=5000
+topology_probing_base_interval_in_ms=5000
 
 # Ratio of probing timeout to probing interval (must be less than 1.0)
 # effectiveMode: restart
 # Datatype: double
-# topology_probing_timeout_ratio=0.5
+topology_probing_timeout_ratio=0.5
 
 # Disk remaining threshold at which DataNode is set to ReadOnly status
 # effectiveMode: restart

Reply via email to