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

jiangtian 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 ffaf1d2e44d [to dev/1.3] apply new configurations in memory before 
update file (#14501)
ffaf1d2e44d is described below

commit ffaf1d2e44ddc8b7864c3c0609e0aef0ecb21b8d
Author: shuwenwei <[email protected]>
AuthorDate: Fri Dec 20 14:52:48 2024 +0800

    [to dev/1.3] apply new configurations in memory before update file (#14501)
    
    * apply new configurations in memory before update file
    
    * fix spell
    
    * modify some Properties usages to TrimProperties
    
    * Add TrimProperties to trim properties auto (#14289)
    
    * Add TrimProperties to trim properties auto
    
    * add license
    
    * fix compile
    
    ---------
    
    Co-authored-by: Yukim1 <[email protected]>
---
 .../iotdb/db/it/IoTDBSetConfigurationIT.java       |  10 +-
 iotdb-core/confignode/pom.xml                      |   6 ++
 .../confignode/conf/ConfigNodeDescriptor.java      |  18 ++--
 .../iotdb/confignode/manager/ConfigManager.java    |  12 ++-
 .../confignode/conf/ConfigNodePropertiesTest.java  |  50 ++++++++++
 iotdb-core/datanode/pom.xml                        |   6 ++
 .../org/apache/iotdb/db/conf/IoTDBDescriptor.java  |  85 ++++++++--------
 .../db/conf/rest/IoTDBRestServiceDescriptor.java   |  18 ++--
 .../iotdb/db/storageengine/StorageEngine.java      |  29 +++---
 .../org/apache/iotdb/db/conf/PropertiesTest.java   | 107 +++++++++++++++++++++
 .../metrics/config/MetricConfigDescriptor.java     |   6 +-
 .../iotdb/commons/conf/CommonDescriptor.java       |  11 +--
 .../iotdb/commons/conf/ConfigurationFileUtils.java |  22 ++++-
 .../apache/iotdb/commons/conf/TrimProperties.java  |  50 ++++++++++
 14 files changed, 347 insertions(+), 83 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 fa8a450d675..8a792aacc38 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
@@ -169,7 +169,7 @@ public class IoTDBSetConfigurationIT {
     // Modify the config file manually because the datanode can not restart
     Properties properties = new Properties();
     properties.put("cluster_name", "xx");
-    ConfigurationFileUtils.updateConfigurationFile(getConfigFile(datanode), 
properties);
+    ConfigurationFileUtils.updateConfiguration(getConfigFile(datanode), 
properties, null);
     EnvFactory.getEnv().getDataNodeWrapper(0).stop();
     EnvFactory.getEnv().getDataNodeWrapper(0).start();
     // wait the datanode restart successfully (won't do any meaningful 
modification)
@@ -235,6 +235,14 @@ public class IoTDBSetConfigurationIT {
       } catch (SQLException e) {
         assertTrue(e.getMessage().contains("Illegal defaultStorageGroupLevel: 
-1, should >= 1"));
       }
+
+      // Failed updates will not change the files.
+      assertFalse(
+          checkConfigFileContains(
+              EnvFactory.getEnv().getDataNodeWrapper(0), 
"default_storage_group_level=-1"));
+      assertTrue(
+          checkConfigFileContains(
+              EnvFactory.getEnv().getDataNodeWrapper(0), 
"default_storage_group_level=3"));
     }
 
     // can start with an illegal value
diff --git a/iotdb-core/confignode/pom.xml b/iotdb-core/confignode/pom.xml
index 8d480477080..dd30ea1becd 100644
--- a/iotdb-core/confignode/pom.xml
+++ b/iotdb-core/confignode/pom.xml
@@ -154,6 +154,12 @@
             <artifactId>mockito-core</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.tngtech.archunit</groupId>
+            <artifactId>archunit</artifactId>
+            <version>1.3.0</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
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 77190535876..918c1856a00 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
@@ -23,6 +23,7 @@ import org.apache.iotdb.commons.conf.CommonConfig;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.conf.ConfigurationFileUtils;
 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.schema.SchemaConstant;
 import org.apache.iotdb.commons.utils.NodeUrlUtils;
@@ -46,7 +47,6 @@ import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.Optional;
-import java.util.Properties;
 
 public class ConfigNodeDescriptor {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(ConfigNodeDescriptor.class);
@@ -118,13 +118,13 @@ public class ConfigNodeDescriptor {
   }
 
   private void loadProps() {
-    Properties commonProperties = new Properties();
+    TrimProperties trimProperties = new TrimProperties();
     URL url = getPropsUrl(CommonConfig.SYSTEM_CONFIG_NAME);
     if (url != null) {
       try (InputStream inputStream = url.openStream()) {
         LOGGER.info("start reading ConfigNode conf file: {}", url);
-        commonProperties.load(new InputStreamReader(inputStream, 
StandardCharsets.UTF_8));
-        loadProperties(commonProperties);
+        trimProperties.load(new InputStreamReader(inputStream, 
StandardCharsets.UTF_8));
+        loadProperties(trimProperties);
       } catch (IOException | BadNodeUrlException e) {
         LOGGER.error("Couldn't load ConfigNode conf file, reject ConfigNode 
startup.", e);
         System.exit(-1);
@@ -133,7 +133,7 @@ public class ConfigNodeDescriptor {
         commonDescriptor
             .getConfig()
             .updatePath(System.getProperty(ConfigNodeConstant.CONFIGNODE_HOME, 
null));
-        MetricConfigDescriptor.getInstance().loadProps(commonProperties, true);
+        MetricConfigDescriptor.getInstance().loadProps(trimProperties, true);
         MetricConfigDescriptor.getInstance()
             .getMetricConfig()
             .updateRpcInstance(NodeType.CONFIGNODE, 
SchemaConstant.SYSTEM_DATABASE);
@@ -145,7 +145,7 @@ public class ConfigNodeDescriptor {
     }
   }
 
-  private void loadProperties(Properties properties) throws 
BadNodeUrlException, IOException {
+  private void loadProperties(TrimProperties properties) throws 
BadNodeUrlException, IOException {
     conf.setClusterName(
         properties.getProperty(IoTDBConstant.CLUSTER_NAME, 
conf.getClusterName()).trim());
 
@@ -401,7 +401,7 @@ public class ConfigNodeDescriptor {
     loadCQConfig(properties);
   }
 
-  private void loadRatisConsensusConfig(Properties properties) {
+  private void loadRatisConsensusConfig(TrimProperties properties) {
     conf.setDataRegionRatisConsensusLogAppenderBufferSize(
         Long.parseLong(
             properties
@@ -813,7 +813,7 @@ public class ConfigNodeDescriptor {
                 .trim()));
   }
 
-  private void loadCQConfig(Properties properties) {
+  private void loadCQConfig(TrimProperties properties) {
     int cqSubmitThread =
         Integer.parseInt(
             properties
@@ -871,7 +871,7 @@ public class ConfigNodeDescriptor {
     }
   }
 
-  public void loadHotModifiedProps(Properties properties) {
+  public void loadHotModifiedProps(TrimProperties properties) {
     Optional.ofNullable(properties.getProperty(IoTDBConstant.CLUSTER_NAME))
         .ifPresent(conf::setClusterName);
   }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index 71c5746ba6c..87ceac0acac 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -42,6 +42,7 @@ import org.apache.iotdb.commons.conf.CommonConfig;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.conf.ConfigurationFileUtils;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.conf.TrimProperties;
 import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.exception.MetadataException;
 import org.apache.iotdb.commons.path.PartialPath;
@@ -244,7 +245,6 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -1582,13 +1582,18 @@ public class ConfigManager implements IManager {
     if (currentNodeId == req.getNodeId() || req.getNodeId() < 0) {
       URL url = 
ConfigNodeDescriptor.getPropsUrl(CommonConfig.SYSTEM_CONFIG_NAME);
       boolean configurationFileFound = (url != null && new 
File(url.getFile()).exists());
-      Properties properties = new Properties();
+      TrimProperties properties = new TrimProperties();
       properties.putAll(req.getConfigs());
 
       if (configurationFileFound) {
         File file = new File(url.getFile());
         try {
-          ConfigurationFileUtils.updateConfigurationFile(file, properties);
+          ConfigurationFileUtils.updateConfiguration(
+              file,
+              properties,
+              mergedProps -> {
+                
ConfigNodeDescriptor.getInstance().loadHotModifiedProps(mergedProps);
+              });
         } catch (Exception e) {
           tsStatus = RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR, 
e.getMessage());
         }
@@ -1598,7 +1603,6 @@ public class ConfigManager implements IManager {
         tsStatus = RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR, 
msg);
         LOGGER.warn(msg);
       }
-      ConfigNodeDescriptor.getInstance().loadHotModifiedProps(properties);
       if (currentNodeId == req.getNodeId()) {
         return tsStatus;
       }
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/conf/ConfigNodePropertiesTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/conf/ConfigNodePropertiesTest.java
new file mode 100644
index 00000000000..1101fcc3f11
--- /dev/null
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/conf/ConfigNodePropertiesTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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 com.tngtech.archunit.core.domain.JavaClasses;
+import com.tngtech.archunit.core.importer.ClassFileImporter;
+import com.tngtech.archunit.core.importer.ImportOption;
+import com.tngtech.archunit.lang.ArchRule;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
+
+public class ConfigNodePropertiesTest {
+  @Test
+  public void TrimPropertiesOnly() {
+    JavaClasses allClasses =
+        new ClassFileImporter()
+            .withImportOption(new ImportOption.DoNotIncludeTests())
+            .importPackages("org.apache.iotdb");
+
+    ArchRule rule =
+        noClasses()
+            .that()
+            
.areAssignableTo("org.apache.iotdb.confignode.conf.ConfigNodeDescriptor")
+            .should()
+            .callMethod(Properties.class, "getProperty", String.class)
+            .orShould()
+            .callMethod(Properties.class, "getProperty", String.class, 
String.class);
+
+    rule.check(allClasses);
+  }
+}
diff --git a/iotdb-core/datanode/pom.xml b/iotdb-core/datanode/pom.xml
index 510db46ad4c..6194b6272a4 100644
--- a/iotdb-core/datanode/pom.xml
+++ b/iotdb-core/datanode/pom.xml
@@ -368,6 +368,12 @@
             <artifactId>awaitility</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.tngtech.archunit</groupId>
+            <artifactId>archunit</artifactId>
+            <version>1.3.0</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
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 e7b7139ce51..7d6426f0bc7 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
@@ -23,6 +23,7 @@ import org.apache.iotdb.commons.conf.CommonConfig;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.conf.ConfigurationFileUtils;
 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.schema.SchemaConstant;
 import org.apache.iotdb.commons.service.metric.MetricService;
@@ -131,8 +132,10 @@ public class IoTDBDescriptor {
     for (IPropertiesLoader loader : propertiesLoaderServiceLoader) {
       LOGGER.info("Will reload properties from {} ", 
loader.getClass().getName());
       Properties properties = loader.loadProperties();
+      TrimProperties trimProperties = new TrimProperties();
+      trimProperties.putAll(properties);
       try {
-        loadProperties(properties);
+        loadProperties(trimProperties);
       } catch (Exception e) {
         LOGGER.error(
             "Failed to reload properties from {}, reject DataNode startup.",
@@ -199,13 +202,13 @@ public class IoTDBDescriptor {
   /** load a property file and set TsfileDBConfig variables. */
   @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity 
warning
   private void loadProps() {
-    Properties commonProperties = new Properties();
+    TrimProperties commonProperties = new TrimProperties();
     // if new properties file exist, skip old properties files
     URL url = getPropsUrl(CommonConfig.SYSTEM_CONFIG_NAME);
     if (url != null) {
       try (InputStream inputStream = url.openStream()) {
         LOGGER.info("Start to read config file {}", url);
-        Properties properties = new Properties();
+        Properties properties = new TrimProperties();
         properties.load(new InputStreamReader(inputStream, 
StandardCharsets.UTF_8));
         commonProperties.putAll(properties);
         loadProperties(commonProperties);
@@ -234,7 +237,7 @@ public class IoTDBDescriptor {
     }
   }
 
-  public void loadProperties(Properties properties) throws 
BadNodeUrlException, IOException {
+  public void loadProperties(TrimProperties properties) throws 
BadNodeUrlException, IOException {
     conf.setClusterName(
         properties.getProperty(IoTDBConstant.CLUSTER_NAME, 
conf.getClusterName()).trim());
 
@@ -1095,13 +1098,13 @@ public class IoTDBDescriptor {
     loadPipeConsensusProps(properties);
   }
 
-  private void reloadConsensusProps(Properties properties) throws IOException {
+  private void reloadConsensusProps(TrimProperties properties) throws 
IOException {
     loadIoTConsensusProps(properties);
     loadPipeConsensusProps(properties);
     DataRegionConsensusImpl.reloadConsensusConfig();
   }
 
-  private void loadIoTConsensusProps(Properties properties) throws IOException 
{
+  private void loadIoTConsensusProps(TrimProperties properties) throws 
IOException {
     conf.setMaxLogEntriesNumPerBatch(
         Integer.parseInt(
             properties
@@ -1144,7 +1147,7 @@ public class IoTDBDescriptor {
                 .trim()));
   }
 
-  private void loadPipeConsensusProps(Properties properties) throws 
IOException {
+  private void loadPipeConsensusProps(TrimProperties properties) throws 
IOException {
     conf.setPipeConsensusPipelineSize(
         Integer.parseInt(
             properties.getProperty(
@@ -1156,7 +1159,7 @@ public class IoTDBDescriptor {
     }
   }
 
-  private void loadAuthorCache(Properties properties) {
+  private void loadAuthorCache(TrimProperties properties) {
     conf.setAuthorCacheSize(
         Integer.parseInt(
             properties.getProperty(
@@ -1167,7 +1170,7 @@ public class IoTDBDescriptor {
                 "author_cache_expire_time", 
String.valueOf(conf.getAuthorCacheExpireTime()))));
   }
 
-  private void loadWALProps(Properties properties) throws IOException {
+  private void loadWALProps(TrimProperties properties) throws IOException {
     conf.setWalMode(
         WALMode.valueOf((properties.getProperty("wal_mode", 
conf.getWalMode().toString()))));
 
@@ -1199,7 +1202,7 @@ public class IoTDBDescriptor {
     loadWALHotModifiedProps(properties);
   }
 
-  private void loadCompactionHotModifiedProps(Properties properties)
+  private void loadCompactionHotModifiedProps(TrimProperties properties)
       throws InterruptedException, IOException {
     boolean compactionTaskConfigHotModified = 
loadCompactionTaskHotModifiedProps(properties);
     if (compactionTaskConfigHotModified) {
@@ -1240,7 +1243,7 @@ public class IoTDBDescriptor {
                 Boolean.toString(conf.isEnableAutoRepairCompaction()))));
   }
 
-  private boolean loadCompactionTaskHotModifiedProps(Properties properties) 
throws IOException {
+  private boolean loadCompactionTaskHotModifiedProps(TrimProperties 
properties) throws IOException {
     boolean configModified = false;
     // update merge_write_throughput_mb_per_sec
     int compactionWriteThroughput = 
conf.getCompactionWriteThroughputMbPerSec();
@@ -1426,7 +1429,7 @@ public class IoTDBDescriptor {
     return configModified;
   }
 
-  private boolean loadCompactionThreadCountHotModifiedProps(Properties 
properties)
+  private boolean loadCompactionThreadCountHotModifiedProps(TrimProperties 
properties)
       throws IOException {
     int newConfigCompactionThreadCount =
         Integer.parseInt(
@@ -1447,7 +1450,7 @@ public class IoTDBDescriptor {
     return true;
   }
 
-  private boolean loadCompactionSubTaskCountHotModifiedProps(Properties 
properties)
+  private boolean loadCompactionSubTaskCountHotModifiedProps(TrimProperties 
properties)
       throws IOException {
     int newConfigSubtaskNum =
         Integer.parseInt(
@@ -1465,7 +1468,7 @@ public class IoTDBDescriptor {
     return true;
   }
 
-  private boolean loadCompactionIsEnabledHotModifiedProps(Properties 
properties)
+  private boolean loadCompactionIsEnabledHotModifiedProps(TrimProperties 
properties)
       throws IOException {
     boolean isCompactionEnabled =
         conf.isEnableSeqSpaceCompaction()
@@ -1500,7 +1503,7 @@ public class IoTDBDescriptor {
     return !isCompactionEnabled && compactionEnabledInNewConfig;
   }
 
-  private void loadWALHotModifiedProps(Properties properties) throws 
IOException {
+  private void loadWALHotModifiedProps(TrimProperties properties) throws 
IOException {
     long walAsyncModeFsyncDelayInMs =
         Long.parseLong(
             properties.getProperty(
@@ -1587,7 +1590,7 @@ public class IoTDBDescriptor {
     }
   }
 
-  private String getWalThrottleThreshold(Properties prop) throws IOException {
+  private String getWalThrottleThreshold(TrimProperties prop) throws 
IOException {
     String old_throttleThreshold = 
prop.getProperty(DEFAULT_WAL_THRESHOLD_NAME[0], null);
     if (old_throttleThreshold != null) {
       LOGGER.warn(
@@ -1628,7 +1631,7 @@ public class IoTDBDescriptor {
     return Math.max(Math.min(newThrottleThreshold, MAX_THROTTLE_THRESHOLD), 
MIN_THROTTLE_THRESHOLD);
   }
 
-  private void loadAutoCreateSchemaProps(Properties properties, boolean 
startUp)
+  private void loadAutoCreateSchemaProps(TrimProperties properties, boolean 
startUp)
       throws IOException {
     conf.setAutoCreateSchemaEnabled(
         Boolean.parseBoolean(
@@ -1689,7 +1692,7 @@ public class IoTDBDescriptor {
             
ConfigurationFileUtils.getConfigurationDefaultValue("default_text_encoding")));
   }
 
-  private void loadTsFileProps(Properties properties) throws IOException {
+  private void loadTsFileProps(TrimProperties properties) throws IOException {
     TSFileDescriptor.getInstance()
         .getConfig()
         .setGroupSizeInByte(
@@ -1766,8 +1769,11 @@ public class IoTDBDescriptor {
   }
 
   // Mqtt related
-  private void loadMqttProps(Properties properties) {
-    conf.setMqttDir(properties.getProperty("mqtt_root_dir", 
conf.getMqttDir()));
+  private void loadMqttProps(TrimProperties properties) {
+    conf.setMqttDir(
+        Optional.ofNullable(properties.getProperty("mqtt_root_dir", 
conf.getMqttDir()))
+            .map(String::trim)
+            .orElse(conf.getMqttDir()));
 
     if (properties.getProperty(IoTDBConstant.MQTT_HOST_NAME) != null) {
       conf.setMqttHost(properties.getProperty(IoTDBConstant.MQTT_HOST_NAME));
@@ -1803,7 +1809,7 @@ public class IoTDBDescriptor {
   }
 
   // timed flush memtable
-  private void loadTimedService(Properties properties) throws IOException {
+  private void loadTimedService(TrimProperties properties) throws IOException {
     conf.setEnableTimedFlushSeqMemtable(
         Boolean.parseBoolean(
             properties.getProperty(
@@ -1876,7 +1882,7 @@ public class IoTDBDescriptor {
     return tierDataDirs;
   }
 
-  public synchronized void loadHotModifiedProps(Properties properties)
+  public synchronized void loadHotModifiedProps(TrimProperties properties)
       throws QueryProcessException {
     try {
       // update data dirs
@@ -2070,7 +2076,7 @@ public class IoTDBDescriptor {
       return;
     }
 
-    Properties commonProperties = new Properties();
+    TrimProperties commonProperties = new TrimProperties();
     try (InputStream inputStream = url.openStream()) {
       LOGGER.info("Start to reload config file {}", url);
       commonProperties.load(new InputStreamReader(inputStream, 
StandardCharsets.UTF_8));
@@ -2086,7 +2092,7 @@ public class IoTDBDescriptor {
     reloadMetricProperties(commonProperties);
   }
 
-  public void reloadMetricProperties(Properties properties) {
+  public void reloadMetricProperties(TrimProperties properties) {
     ReloadLevel reloadLevel = 
MetricConfigDescriptor.getInstance().loadHotProps(properties, false);
     LOGGER.info("Reload metric service in level {}", reloadLevel);
     if (reloadLevel == ReloadLevel.RESTART_INTERNAL_REPORTER) {
@@ -2103,7 +2109,7 @@ public class IoTDBDescriptor {
     }
   }
 
-  private void initMemoryAllocate(Properties properties) {
+  private void initMemoryAllocate(TrimProperties properties) {
     String memoryAllocateProportion = 
properties.getProperty("datanode_memory_proportion", null);
     if (memoryAllocateProportion == null) {
       memoryAllocateProportion =
@@ -2215,7 +2221,7 @@ public class IoTDBDescriptor {
   }
 
   @SuppressWarnings("java:S3518")
-  private void initStorageEngineAllocate(Properties properties) {
+  private void initStorageEngineAllocate(TrimProperties properties) {
     long storageMemoryTotal = conf.getAllocateMemoryForStorageEngine();
     String valueOfStorageEngineMemoryProportion =
         properties.getProperty("storage_engine_memory_proportion");
@@ -2270,7 +2276,7 @@ public class IoTDBDescriptor {
   }
 
   @SuppressWarnings("squid:S3518")
-  private void initSchemaMemoryAllocate(Properties properties) {
+  private void initSchemaMemoryAllocate(TrimProperties properties) {
     long schemaMemoryTotal = conf.getAllocateMemoryForSchema();
 
     String schemaMemoryPortionInput = 
properties.getProperty("schema_memory_proportion");
@@ -2328,7 +2334,7 @@ public class IoTDBDescriptor {
     LOGGER.info("allocateMemoryForPartitionCache = {}", 
conf.getAllocateMemoryForPartitionCache());
   }
 
-  private void loadLoadTsFileProps(Properties properties) {
+  private void loadLoadTsFileProps(TrimProperties properties) {
     conf.setMaxAllocateMemoryRatioForLoad(
         Double.parseDouble(
             properties.getProperty(
@@ -2406,7 +2412,7 @@ public class IoTDBDescriptor {
     }
   }
 
-  private void loadLoadTsFileHotModifiedProp(Properties properties) throws 
IOException {
+  private void loadLoadTsFileHotModifiedProp(TrimProperties properties) throws 
IOException {
     conf.setLoadCleanupTaskExecutionDelayTimeSeconds(
         Long.parseLong(
             properties.getProperty(
@@ -2447,7 +2453,7 @@ public class IoTDBDescriptor {
   }
 
   @SuppressWarnings("squid:S3518") // "proportionSum" can't be zero
-  private void loadUDFProps(Properties properties) {
+  private void loadUDFProps(TrimProperties properties) {
     String initialByteArrayLengthForMemoryControl =
         
properties.getProperty("udf_initial_byte_array_length_for_memory_control");
     if (initialByteArrayLengthForMemoryControl != null) {
@@ -2490,7 +2496,7 @@ public class IoTDBDescriptor {
     }
   }
 
-  private void initThriftSSL(Properties properties) {
+  private void initThriftSSL(TrimProperties properties) {
     conf.setEnableSSL(
         Boolean.parseBoolean(
             properties.getProperty("enable_thrift_ssl", 
Boolean.toString(conf.isEnableSSL()))));
@@ -2498,8 +2504,8 @@ public class IoTDBDescriptor {
     conf.setKeyStorePwd(properties.getProperty("key_store_pwd", 
conf.getKeyStorePath()).trim());
   }
 
-  private void loadTriggerProps(Properties properties) {
-    conf.setTriggerDir(properties.getProperty("trigger_lib_dir", 
conf.getTriggerDir()));
+  private void loadTriggerProps(TrimProperties properties) {
+    conf.setTriggerDir(properties.getProperty("trigger_lib_dir", 
conf.getTriggerDir()).trim());
     conf.setRetryNumToFindStatefulTrigger(
         Integer.parseInt(
             properties.getProperty(
@@ -2545,8 +2551,11 @@ public class IoTDBDescriptor {
                 Integer.toString(conf.getTriggerForwardMQTTPoolSize()))));
   }
 
-  private void loadPipeProps(Properties properties) {
-    conf.setPipeLibDir(properties.getProperty("pipe_lib_dir", 
conf.getPipeLibDir()));
+  private void loadPipeProps(TrimProperties properties) {
+    conf.setPipeLibDir(
+        Optional.ofNullable(properties.getProperty("pipe_lib_dir", 
conf.getPipeLibDir()))
+            .map(String::trim)
+            .orElse(conf.getPipeLibDir()));
 
     conf.setPipeReceiverFileDirs(
         Arrays.stream(
@@ -2572,7 +2581,7 @@ public class IoTDBDescriptor {
             .toArray(String[]::new));
   }
 
-  private void loadCQProps(Properties properties) {
+  private void loadCQProps(TrimProperties properties) {
     conf.setContinuousQueryThreadNum(
         Integer.parseInt(
             properties.getProperty(
@@ -2589,7 +2598,7 @@ public class IoTDBDescriptor {
             false));
   }
 
-  public void loadClusterProps(Properties properties) throws IOException {
+  public void loadClusterProps(TrimProperties properties) throws IOException {
     String configNodeUrls = 
properties.getProperty(IoTDBConstant.DN_SEED_CONFIG_NODE);
     if (configNodeUrls == null) {
       configNodeUrls = 
properties.getProperty(IoTDBConstant.DN_TARGET_CONFIG_NODE_LIST);
@@ -2644,7 +2653,7 @@ public class IoTDBDescriptor {
                 .trim()));
   }
 
-  public void loadShuffleProps(Properties properties) {
+  public void loadShuffleProps(TrimProperties properties) {
     conf.setMppDataExchangePort(
         Integer.parseInt(
             properties.getProperty(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
index 48725ef1839..2e9f49917f0 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.db.conf.rest;
 
 import org.apache.iotdb.commons.conf.CommonConfig;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.conf.TrimProperties;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 
 import org.slf4j.Logger;
@@ -33,7 +34,6 @@ import java.io.InputStreamReader;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
-import java.util.Properties;
 
 public class IoTDBRestServiceDescriptor {
   private static final Logger logger = 
LoggerFactory.getLogger(IoTDBRestServiceDescriptor.class);
@@ -43,9 +43,9 @@ public class IoTDBRestServiceDescriptor {
   protected IoTDBRestServiceDescriptor() {
     URL systemConfig = getPropsUrl(CommonConfig.SYSTEM_CONFIG_NAME);
     if (systemConfig != null) {
-      Properties properties = loadProps(CommonConfig.SYSTEM_CONFIG_NAME);
-      if (properties != null) {
-        loadProps(properties);
+      TrimProperties trimProperties = 
loadProps(CommonConfig.SYSTEM_CONFIG_NAME);
+      if (trimProperties != null) {
+        loadProps(trimProperties);
       }
     }
   }
@@ -56,7 +56,7 @@ public class IoTDBRestServiceDescriptor {
 
   /** load an property file. */
   @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity 
warning
-  private Properties loadProps(String configName) {
+  private TrimProperties loadProps(String configName) {
     URL url = getPropsUrl(configName);
     if (url == null) {
       logger.warn("Couldn't load the REST Service configuration from any of 
the known sources.");
@@ -64,9 +64,9 @@ public class IoTDBRestServiceDescriptor {
     }
     try (InputStream inputStream = url.openStream()) {
       logger.info("Start to read config file {}", url);
-      Properties properties = new Properties();
-      properties.load(new InputStreamReader(inputStream, 
StandardCharsets.UTF_8));
-      return properties;
+      TrimProperties trimProperties = new TrimProperties();
+      trimProperties.load(new InputStreamReader(inputStream, 
StandardCharsets.UTF_8));
+      return trimProperties;
     } catch (FileNotFoundException e) {
       logger.warn("REST service fail to find config file {}", url, e);
     } catch (IOException e) {
@@ -77,7 +77,7 @@ public class IoTDBRestServiceDescriptor {
     return null;
   }
 
-  private void loadProps(Properties properties) {
+  private void loadProps(TrimProperties properties) {
     conf.setEnableRestService(
         Boolean.parseBoolean(
             properties.getProperty(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java
index 56470075c77..68f76c942f0 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java
@@ -30,6 +30,7 @@ import org.apache.iotdb.commons.conf.CommonConfig;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.conf.ConfigurationFileUtils;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.conf.TrimProperties;
 import org.apache.iotdb.commons.consensus.DataRegionId;
 import org.apache.iotdb.commons.consensus.index.ProgressIndex;
 import org.apache.iotdb.commons.exception.IllegalPathException;
@@ -91,7 +92,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Properties;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
@@ -656,8 +656,8 @@ public class StorageEngine implements IService {
     if (newConfigItems.isEmpty()) {
       return tsStatus;
     }
-    Properties properties = new Properties();
-    properties.putAll(newConfigItems);
+    TrimProperties newConfigProperties = new TrimProperties();
+    newConfigProperties.putAll(newConfigItems);
 
     URL configFileUrl = 
IoTDBDescriptor.getPropsUrl(CommonConfig.SYSTEM_CONFIG_NAME);
     if (configFileUrl == null || !(new 
File(configFileUrl.getFile()).exists())) {
@@ -667,30 +667,31 @@ public class StorageEngine implements IService {
       tsStatus = RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR, msg);
       LOGGER.warn(msg);
       try {
-        IoTDBDescriptor.getInstance().loadHotModifiedProps(properties);
-        IoTDBDescriptor.getInstance().reloadMetricProperties(properties);
+        
IoTDBDescriptor.getInstance().loadHotModifiedProps(newConfigProperties);
+        
IoTDBDescriptor.getInstance().reloadMetricProperties(newConfigProperties);
       } catch (Exception e) {
         return RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR, 
e.getMessage());
       }
       return tsStatus;
     }
 
-    // 1. append new configuration properties to configuration file
     try {
-      ConfigurationFileUtils.updateConfigurationFile(new 
File(configFileUrl.getFile()), properties);
+      ConfigurationFileUtils.updateConfiguration(
+          new File(configFileUrl.getFile()),
+          newConfigProperties,
+          mergedProperties -> {
+            try {
+              
IoTDBDescriptor.getInstance().loadHotModifiedProps(mergedProperties);
+            } catch (Exception e) {
+              throw new IllegalArgumentException(e);
+            }
+          });
     } catch (Exception e) {
       if (e instanceof InterruptedException) {
         Thread.currentThread().interrupt();
       }
       return RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR, 
e.getMessage());
     }
-
-    // 2. load hot modified properties
-    try {
-      IoTDBDescriptor.getInstance().loadHotModifiedProps();
-    } catch (Exception e) {
-      return RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR, 
e.getMessage());
-    }
     return tsStatus;
   }
 
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/PropertiesTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/PropertiesTest.java
new file mode 100755
index 00000000000..d547963d322
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/PropertiesTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.conf.TrimProperties;
+
+import com.tngtech.archunit.core.domain.JavaClasses;
+import com.tngtech.archunit.core.importer.ClassFileImporter;
+import com.tngtech.archunit.core.importer.ImportOption;
+import com.tngtech.archunit.lang.ArchRule;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
+
+public class PropertiesTest {
+  @Test
+  public void PropertiesWithSpace() {
+    IoTDBDescriptor descriptor = IoTDBDescriptor.getInstance();
+    TrimProperties properties = new TrimProperties();
+    properties.setProperty("load_active_listening_max_thread_num", "8 "); // 
data type: int
+    properties.setProperty("load_active_listening_enable", "true "); // data 
type: Boolean
+    properties.setProperty("into_operation_buffer_size_in_byte", "104857600 
"); // data type: long
+    properties.setProperty("wal_min_effective_info_ratio", "0.1 "); // data 
type: Double
+    properties.setProperty("floating_string_infer_type", "DOUBLE "); // data 
type: TSDataType
+    properties.setProperty("default_boolean_encoding", "RLE "); // data type: 
TSEncoding
+    properties.setProperty("expired_data_ratio", "0.3 "); // data type: float
+
+    try {
+      descriptor.loadProperties(properties);
+      Assert.assertEquals(8, 
descriptor.getConfig().getLoadActiveListeningMaxThreadNum());
+      Assert.assertTrue(descriptor.getConfig().getLoadActiveListeningEnable());
+      Assert.assertEquals(104857600, 
descriptor.getConfig().getIntoOperationBufferSizeInByte());
+      Assert.assertEquals(0.1, 
descriptor.getConfig().getWalMinEffectiveInfoRatio(), 0.000001);
+      Assert.assertEquals(TSDataType.DOUBLE, 
descriptor.getConfig().getFloatingStringInferType());
+      Assert.assertEquals(TSEncoding.RLE, 
descriptor.getConfig().getDefaultBooleanEncoding());
+      Assert.assertEquals(0.3, descriptor.getConfig().getExpiredDataRatio(), 
0.000001);
+    } catch (Exception e) {
+      Assert.fail(e.getMessage());
+    }
+
+    properties.setProperty("load_active_listening_max_thread_num", " 8 ");
+    properties.setProperty("load_active_listening_enable", " true ");
+    properties.setProperty("into_operation_buffer_size_in_byte", " 104857600 
");
+    properties.setProperty("wal_min_effective_info_ratio", " 0.1 ");
+    properties.setProperty("floating_string_infer_type", " DOUBLE ");
+    properties.setProperty("default_boolean_encoding", " RLE ");
+    properties.setProperty("expired_data_ratio", " 0.3 ");
+
+    try {
+      descriptor.loadHotModifiedProps(properties);
+      Assert.assertEquals(8, 
descriptor.getConfig().getLoadActiveListeningMaxThreadNum());
+      Assert.assertTrue(descriptor.getConfig().getLoadActiveListeningEnable());
+      Assert.assertEquals(104857600, 
descriptor.getConfig().getIntoOperationBufferSizeInByte());
+      Assert.assertEquals(0.1, 
descriptor.getConfig().getWalMinEffectiveInfoRatio(), 0.000001);
+      Assert.assertEquals(TSDataType.DOUBLE, 
descriptor.getConfig().getFloatingStringInferType());
+      Assert.assertEquals(TSEncoding.RLE, 
descriptor.getConfig().getDefaultBooleanEncoding());
+      Assert.assertEquals(0.3, descriptor.getConfig().getExpiredDataRatio(), 
0.000001);
+    } catch (Exception e) {
+      Assert.fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void TrimPropertiesOnly() {
+    JavaClasses allClasses =
+        new ClassFileImporter()
+            .withImportOption(new ImportOption.DoNotIncludeTests())
+            .importPackages("org.apache.iotdb");
+
+    ArchRule rule =
+        noClasses()
+            .that()
+            .areAssignableTo("org.apache.iotdb.db.conf.IoTDBDescriptor")
+            .or()
+            
.areAssignableTo("org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor")
+            .or()
+            .areAssignableTo("org.apache.iotdb.commons.conf.CommonDescriptor")
+            .should()
+            .callMethod(Properties.class, "getProperty", String.class)
+            .orShould()
+            .callMethod(Properties.class, "getProperty", String.class, 
String.class);
+
+    rule.check(allClasses);
+  }
+}
diff --git 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java
 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java
index f1ec288d47a..11decb83369 100644
--- 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java
+++ 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java
@@ -24,6 +24,7 @@ import org.apache.iotdb.metrics.utils.InternalReporterType;
 import org.apache.iotdb.metrics.utils.MetricLevel;
 import org.apache.iotdb.metrics.utils.ReporterType;
 
+import java.util.Optional;
 import java.util.Properties;
 import java.util.stream.Collectors;
 
@@ -174,7 +175,10 @@ public class MetricConfigDescriptor {
   /** Get property from confignode or datanode. */
   private String getProperty(
       String target, String defaultValue, Properties properties, boolean 
isConfigNode) {
-    return properties.getProperty((isConfigNode ? "cn_" : "dn_") + target, 
defaultValue);
+    return Optional.ofNullable(
+            properties.getProperty((isConfigNode ? "cn_" : "dn_") + target, 
defaultValue))
+        .map(String::trim)
+        .orElse(defaultValue);
   }
 
   private static class MetricConfigDescriptorHolder {
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
index 361f3031d4f..1026ed6aa0a 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
@@ -27,7 +27,6 @@ import org.apache.iotdb.confignode.rpc.thrift.TGlobalConfig;
 import java.io.File;
 import java.io.IOException;
 import java.util.Optional;
-import java.util.Properties;
 
 public class CommonDescriptor {
 
@@ -71,7 +70,7 @@ public class CommonDescriptor {
     config.setProcedureWalFolder(systemDir + File.separator + "procedure");
   }
 
-  public void loadCommonProps(Properties properties) throws IOException {
+  public void loadCommonProps(TrimProperties properties) throws IOException {
     config.setAuthorizerProvider(
         properties.getProperty("authorizer_provider_class", 
config.getAuthorizerProvider()).trim());
     // if using org.apache.iotdb.db.auth.authorizer.OpenIdAuthorizer, 
openID_url is needed.
@@ -248,7 +247,7 @@ public class CommonDescriptor {
     loadBinaryAllocatorProps(properties);
   }
 
-  private void loadPipeProps(Properties properties) {
+  private void loadPipeProps(TrimProperties properties) {
     config.setPipeNonForwardingEventsProgressReportInterval(
         Integer.parseInt(
             properties.getProperty(
@@ -639,7 +638,7 @@ public class CommonDescriptor {
                 
String.valueOf(config.getPipeEventReferenceEliminateIntervalSeconds()))));
   }
 
-  private void loadSubscriptionProps(Properties properties) {
+  private void loadSubscriptionProps(TrimProperties properties) {
     config.setSubscriptionCacheMemoryUsagePercentage(
         Float.parseFloat(
             properties.getProperty(
@@ -727,7 +726,7 @@ public class CommonDescriptor {
                 
String.valueOf(config.getSubscriptionMetaSyncerSyncIntervalMinutes()))));
   }
 
-  public void loadRetryProperties(Properties properties) throws IOException {
+  public void loadRetryProperties(TrimProperties properties) throws 
IOException {
     config.setRemoteWriteMaxRetryDurationInMs(
         Long.parseLong(
             properties.getProperty(
@@ -743,7 +742,7 @@ public class CommonDescriptor {
                     "enable_retry_for_unknown_error"))));
   }
 
-  public void loadBinaryAllocatorProps(Properties properties) {
+  public void loadBinaryAllocatorProps(TrimProperties properties) {
     config.setEnableBinaryAllocator(
         Boolean.parseBoolean(
             properties.getProperty(
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/ConfigurationFileUtils.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/ConfigurationFileUtils.java
index 0857b493b9a..f5702143dd9 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/ConfigurationFileUtils.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/ConfigurationFileUtils.java
@@ -31,6 +31,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.RandomAccessFile;
+import java.io.StringReader;
 import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
@@ -247,19 +248,32 @@ public class ConfigurationFileUtils {
     return ignoredConfigItems;
   }
 
-  public static void updateConfigurationFile(File file, Properties 
newConfigItems)
+  public static void updateConfiguration(
+      File file, Properties newConfigItems, LoadHotModifiedPropsFunc 
loadHotModifiedPropertiesFunc)
       throws IOException, InterruptedException {
     File lockFile = new File(file.getPath() + lockFileSuffix);
     acquireTargetFileLock(lockFile);
     try {
       // read configuration file
       List<String> lines = new ArrayList<>();
+      TrimProperties mergedProps = new TrimProperties();
       try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
         String line = null;
         while ((line = reader.readLine()) != null) {
           lines.add(line);
+          mergedProps.load(new StringReader(line));
         }
       }
+      // overwrite old configuration with new value
+      for (String key : newConfigItems.stringPropertyNames()) {
+        mergedProps.put(key, newConfigItems.getProperty(key));
+      }
+
+      // load hot modified properties
+      if (loadHotModifiedPropertiesFunc != null) {
+        loadHotModifiedPropertiesFunc.loadHotModifiedProperties(mergedProps);
+      }
+
       // generate new configuration file content in memory
       StringBuilder contentsOfNewConfigurationFile = new StringBuilder();
       for (String currentLine : lines) {
@@ -341,4 +355,10 @@ public class ConfigurationFileUtils {
   private static void releaseFileLock(File file) throws IOException {
     Files.deleteIfExists(file.toPath());
   }
+
+  @FunctionalInterface
+  public interface LoadHotModifiedPropsFunc {
+    void loadHotModifiedProperties(TrimProperties properties)
+        throws IOException, InterruptedException;
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/TrimProperties.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/TrimProperties.java
new file mode 100644
index 00000000000..aa627367e82
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/TrimProperties.java
@@ -0,0 +1,50 @@
+/*
+ * 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.conf;
+
+import java.util.Optional;
+import java.util.Properties;
+
+public class TrimProperties extends Properties {
+  @Override
+  public synchronized Object get(Object key) {
+    Object value = super.get(key);
+    if (value instanceof String) {
+      return ((String) value).trim();
+    }
+    return value;
+  }
+
+  @Override
+  public synchronized Object put(Object key, Object value) {
+    if (value instanceof String) {
+      value = ((String) value).trim();
+    }
+    return super.put(key, value);
+  }
+
+  @Override
+  public synchronized String getProperty(String key, String defaultValue) {
+    String val = getProperty(key);
+    if (defaultValue != null) {
+      defaultValue = defaultValue.trim();
+    }
+    return Optional.ofNullable(val).map(String::trim).orElse(defaultValue);
+  }
+}

Reply via email to