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 feba0c62b8a feat(load): reject active load listening dirs under data 
directory (#18405)
feba0c62b8a is described below

commit feba0c62b8a4e0542bb514740c42de6c49f966a3
Author: Zhenyu Luo <[email protected]>
AuthorDate: Thu Aug 6 19:02:52 2026 +0800

    feat(load): reject active load listening dirs under data directory (#18405)
    
    Skip invalid load_active_listening_dirs and load_active_listening_pipe_dir
    updates when they fall under the data directory, log a warning with the
    retained configuration, and ignore such dirs during hot reload scanning.
---
 .../apache/iotdb/db/i18n/DataNodeMiscMessages.java |   8 ++
 .../iotdb/db/i18n/StorageEngineMessages.java       |   6 +
 .../apache/iotdb/db/i18n/DataNodeMiscMessages.java |   6 +
 .../iotdb/db/i18n/StorageEngineMessages.java       |   4 +
 .../java/org/apache/iotdb/db/conf/IoTDBConfig.java |  63 +++++++++-
 .../load/active/ActiveLoadDirScanner.java          |  29 ++++-
 .../db/conf/ActiveLoadListeningDirConfigTest.java  | 139 +++++++++++++++++++++
 7 files changed, 249 insertions(+), 6 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
index f3e8154dcde..0853e59b9fa 100644
--- 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
@@ -1509,5 +1509,13 @@ public final class DataNodeMiscMessages {
   public static final String 
EXCEPTION_CONTINUOUS_QUERY_MIN_EVERY_INTERVAL_IN_MS_SHOULD_BE_GREATER_THAN_0_BUT_CURRENT_VALUE_IS_F9A1BEC4
 = "continuous_query_min_every_interval_in_ms should be greater than 0, but 
current value is ";
   public static final String 
EXCEPTION_UNKNOWN_READ_CONSISTENCY_LEVEL_ARG_PLEASE_SET_TO_STRONG_OR_WEAK_8CF29949
 = "Unknown read_consistency_level: %s, please set to \"strong\" or \"weak\"";
   public static final String 
MESSAGE_INITIAL_ALLOCATEMEMORYFORAUTORESIZINGBUFFER_ARG_A0DB6DA0 = "initial 
allocateMemoryForAutoResizingBuffer = {}";
+  public static final String 
LOG_SKIP_SETTING_ARG_TO_ARG_BECAUSE_IT_IS_UNDER_DATA_DIRECTORY_KEEP_USING_ORIGINAL_CONFIGURATION_EE87FFD9
 =
+      "Skip setting {} to {} because it is under data directory. Keep using 
the original "
+          + "configuration: {}.";
+  public static final String 
LOG_SKIP_SETTING_ARG_TO_ARG_BECAUSE_ITS_CANONICAL_PATH_CANNOT_BE_RESOLVED_ARG_KEEP_USING_ORIGINAL_CONFIGURATION_C0A8ED09
 =
+      "Skip setting {} to {} because its canonical path cannot be resolved: 
{}. Keep using the "
+          + "original configuration: {}.";
+  public static final String 
MISC_EXCEPTION_FAILED_TO_RESOLVE_CANONICAL_PATH_FOR_ACTIVE_LOAD_LISTENING_DIRECTORY_S_ARG_0E6A508E
 =
+      "Failed to resolve canonical path for active load listening directory 
%s: %s";
 
 }
diff --git 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/StorageEngineMessages.java
 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/StorageEngineMessages.java
index ffa6c918d48..a104bf3576c 100644
--- 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/StorageEngineMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/StorageEngineMessages.java
@@ -1227,6 +1227,12 @@ public final class StorageEngineMessages {
           + "File will be moved to fail directory.";
   public static final String 
STORAGE_LOG_ERROR_OCCURRED_DURING_HOT_RELOAD_ACTIVE_LOAD_DIRS_CURRENT_673AFC0F =
       "Error occurred during hot reload active load dirs. Current active load 
listening dirs: {}.";
+  public static final String 
LOG_ACTIVE_LOAD_LISTENING_DIRECTORY_S_IS_SKIPPED_DURING_HOT_RELOAD_BECAUSE_IT_IS_UNDER_IOTDB_DATA_DIRECTORY_DA90CAE1
 =
+      "Active load listening directory {} is skipped during hot reload because 
it is under data "
+          + "directory.";
+  public static final String 
LOG_FAILED_TO_VALIDATE_ACTIVE_LOAD_LISTENING_DIRECTORY_S_SKIP_SCANNING_ARG_0E6A508E
 =
+      "Failed to validate active load listening directory {}. Skip scanning 
this directory. "
+          + "Reason: {}";
   public static final String 
STORAGE_LOG_CURRENT_DIR_PATH_IS_NOT_READABLE_SKIP_SCANNING_THIS_DIR_9C8B7E00 =
       "Current dir path is not readable: {}.Skip scanning this dir. Please 
check the permission.";
   public static final String 
STORAGE_LOG_CURRENT_DIR_PATH_IS_NOT_WRITABLE_SKIP_SCANNING_THIS_DIR_4885E78F =
diff --git 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
index 5dd49c8804e..1abc4bb25dc 100644
--- 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeMiscMessages.java
@@ -1487,5 +1487,11 @@ public final class DataNodeMiscMessages {
   public static final String 
EXCEPTION_CONTINUOUS_QUERY_MIN_EVERY_INTERVAL_IN_MS_SHOULD_BE_GREATER_THAN_0_BUT_CURRENT_VALUE_IS_F9A1BEC4
 = "continuous_query_min_every_interval_in_ms 必须大于 0,但当前值为 ";
   public static final String 
EXCEPTION_UNKNOWN_READ_CONSISTENCY_LEVEL_ARG_PLEASE_SET_TO_STRONG_OR_WEAK_8CF29949
 = "未知的 read_consistency_level:%s,请设置为 \"strong\" 或 \"weak\"";
   public static final String 
MESSAGE_INITIAL_ALLOCATEMEMORYFORAUTORESIZINGBUFFER_ARG_A0DB6DA0 = "初始 
allocateMemoryForAutoResizingBuffer = {}";
+  public static final String 
LOG_SKIP_SETTING_ARG_TO_ARG_BECAUSE_IT_IS_UNDER_DATA_DIRECTORY_KEEP_USING_ORIGINAL_CONFIGURATION_EE87FFD9
 =
+      "跳过设置 {} 为 {},因为其位于 data 目录下。继续使用原配置:{}。";
+  public static final String 
LOG_SKIP_SETTING_ARG_TO_ARG_BECAUSE_ITS_CANONICAL_PATH_CANNOT_BE_RESOLVED_ARG_KEEP_USING_ORIGINAL_CONFIGURATION_C0A8ED09
 =
+      "跳过设置 {} 为 {},因为无法解析其 canonical 路径:{}。继续使用原配置:{}。";
+  public static final String 
MISC_EXCEPTION_FAILED_TO_RESOLVE_CANONICAL_PATH_FOR_ACTIVE_LOAD_LISTENING_DIRECTORY_S_ARG_0E6A508E
 =
+      "无法解析 Active Load 监听目录 %s 的 canonical 路径:%s";
 
 }
diff --git 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/StorageEngineMessages.java
 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/StorageEngineMessages.java
index e30108f7a26..ba857ecfa91 100644
--- 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/StorageEngineMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/StorageEngineMessages.java
@@ -1171,6 +1171,10 @@ public final class StorageEngineMessages {
       "自动加载 TsFile {} (isGeneratedByPipe = {}) 失败,原因:发生未知异常。文件将被移动到失败目录。";
   public static final String 
STORAGE_LOG_ERROR_OCCURRED_DURING_HOT_RELOAD_ACTIVE_LOAD_DIRS_CURRENT_673AFC0F =
       "热重载 active load 目录时发生错误。当前 active load 监听目录:{}。";
+  public static final String 
LOG_ACTIVE_LOAD_LISTENING_DIRECTORY_S_IS_SKIPPED_DURING_HOT_RELOAD_BECAUSE_IT_IS_UNDER_IOTDB_DATA_DIRECTORY_DA90CAE1
 =
+      "Active Load 监听目录 {} 位于 data 目录下,热重载时将跳过该目录。";
+  public static final String 
LOG_FAILED_TO_VALIDATE_ACTIVE_LOAD_LISTENING_DIRECTORY_S_SKIP_SCANNING_ARG_0E6A508E
 =
+      "无法校验 Active Load 监听目录 {},将跳过扫描该目录。原因:{}";
   public static final String 
STORAGE_LOG_CURRENT_DIR_PATH_IS_NOT_READABLE_SKIP_SCANNING_THIS_DIR_9C8B7E00 =
       "当前目录路径不可读:{}。跳过扫描该目录。请检查权限。";
   public static final String 
STORAGE_LOG_CURRENT_DIR_PATH_IS_NOT_WRITABLE_SKIP_SCANNING_THIS_DIR_4885E78F =
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index 19c3cc6217f..1d726366ddd 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -1570,6 +1570,50 @@ public class IoTDBConfig {
     return internalDataDirCanonicalPaths.getPaths();
   }
 
+  public boolean isUnderInternalDataDir(final String dirPath) {
+    try {
+      final Path sourcePath = new File(dirPath).getCanonicalFile().toPath();
+      for (final Path internalDataDirCanonicalPath : 
getInternalDataDirCanonicalPaths()) {
+        if (sourcePath.startsWith(internalDataDirCanonicalPath)
+            || internalDataDirCanonicalPath.startsWith(sourcePath)) {
+          return true;
+        }
+      }
+      return false;
+    } catch (final Exception e) {
+      return true;
+    }
+  }
+
+  private static final String LOAD_ACTIVE_LISTENING_DIRS_CONFIG_KEY = 
"load_active_listening_dirs";
+  private static final String LOAD_ACTIVE_LISTENING_PIPE_DIR_CONFIG_KEY =
+      "load_active_listening_pipe_dir";
+
+  private boolean tryAcceptActiveLoadListeningDir(
+      final String configKey, final String dirPath, final String 
currentConfigValue) {
+    try {
+      if (isUnderInternalDataDir(dirPath)) {
+        logger.warn(
+            DataNodeMiscMessages
+                
.LOG_SKIP_SETTING_ARG_TO_ARG_BECAUSE_IT_IS_UNDER_DATA_DIRECTORY_KEEP_USING_ORIGINAL_CONFIGURATION_EE87FFD9,
+            configKey,
+            dirPath,
+            currentConfigValue);
+        return false;
+      }
+      return true;
+    } catch (final IllegalArgumentException e) {
+      logger.warn(
+          DataNodeMiscMessages
+              
.LOG_SKIP_SETTING_ARG_TO_ARG_BECAUSE_ITS_CANONICAL_PATH_CANNOT_BE_RESOLVED_ARG_KEEP_USING_ORIGINAL_CONFIGURATION_C0A8ED09,
+          configKey,
+          dirPath,
+          e.getMessage(),
+          currentConfigValue);
+      return false;
+    }
+  }
+
   public String[][] getTierDataDirs() {
     return tierDataDirs;
   }
@@ -4246,7 +4290,14 @@ public class IoTDBConfig {
   }
 
   public void setLoadActiveListeningPipeDir(String loadActiveListeningPipeDir) 
{
-    this.loadActiveListeningPipeDir = 
addDataHomeDir(loadActiveListeningPipeDir);
+    final String normalizedDir = addDataHomeDir(loadActiveListeningPipeDir);
+    if (!tryAcceptActiveLoadListeningDir(
+        LOAD_ACTIVE_LISTENING_PIPE_DIR_CONFIG_KEY,
+        normalizedDir,
+        getLoadActiveListeningPipeDir())) {
+      return;
+    }
+    this.loadActiveListeningPipeDir = normalizedDir;
   }
 
   public String[] getLoadActiveListeningDirs() {
@@ -4263,10 +4314,16 @@ public class IoTDBConfig {
   }
 
   public void setLoadActiveListeningDirs(String[] loadActiveListeningDirs) {
+    final String currentConfigValue = 
Arrays.toString(getLoadActiveListeningDirs());
+    final String[] normalizedDirs = new String[loadActiveListeningDirs.length];
     for (int i = 0; i < loadActiveListeningDirs.length; i++) {
-      loadActiveListeningDirs[i] = addDataHomeDir(loadActiveListeningDirs[i]);
+      normalizedDirs[i] = addDataHomeDir(loadActiveListeningDirs[i]);
+      if (!tryAcceptActiveLoadListeningDir(
+          LOAD_ACTIVE_LISTENING_DIRS_CONFIG_KEY, normalizedDirs[i], 
currentConfigValue)) {
+        return;
+      }
     }
-    this.loadActiveListeningDirs = loadActiveListeningDirs;
+    this.loadActiveListeningDirs = normalizedDirs;
   }
 
   public boolean getLoadActiveListeningEnable() {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/load/active/ActiveLoadDirScanner.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/load/active/ActiveLoadDirScanner.java
index 9d1ad235ecb..31f2bd9dd23 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/load/active/ActiveLoadDirScanner.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/load/active/ActiveLoadDirScanner.java
@@ -40,7 +40,6 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
-import java.util.Arrays;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -199,7 +198,9 @@ public class ActiveLoadDirScanner extends 
ActiveLoadScheduledExecutorService {
               listeningDirs.clear();
 
               
listeningDirsConfig.set(IOTDB_CONFIG.getLoadActiveListeningDirs());
-              
listeningDirs.addAll(Arrays.asList(IOTDB_CONFIG.getLoadActiveListeningDirs()));
+              for (final String dir : 
IOTDB_CONFIG.getLoadActiveListeningDirs()) {
+                addActiveLoadListeningDirIfAllowed(dir);
+              }
               LoadUtil.updateLoadDiskSelector();
             }
           }
@@ -221,7 +222,7 @@ public class ActiveLoadDirScanner extends 
ActiveLoadScheduledExecutorService {
       }
 
       // Active load is always enabled for pipe data sync.
-      listeningDirs.add(IOTDB_CONFIG.getLoadActiveListeningPipeDir());
+      
addActiveLoadListeningDirIfAllowed(IOTDB_CONFIG.getLoadActiveListeningPipeDir());
 
       // Create directories if not exists
       listeningDirs.forEach(this::createDirectoriesIfNotExists);
@@ -245,6 +246,28 @@ public class ActiveLoadDirScanner extends 
ActiveLoadScheduledExecutorService {
     }
   }
 
+  private void addActiveLoadListeningDirIfAllowed(final String dirPath) {
+    if (dirPath == null || dirPath.isEmpty()) {
+      return;
+    }
+    try {
+      if (IOTDB_CONFIG.isUnderInternalDataDir(dirPath)) {
+        LOGGER.warn(
+            StorageEngineMessages
+                
.LOG_ACTIVE_LOAD_LISTENING_DIRECTORY_S_IS_SKIPPED_DURING_HOT_RELOAD_BECAUSE_IT_IS_UNDER_IOTDB_DATA_DIRECTORY_DA90CAE1,
+            dirPath);
+        return;
+      }
+      listeningDirs.add(dirPath);
+    } catch (final IllegalArgumentException e) {
+      LOGGER.warn(
+          StorageEngineMessages
+              
.LOG_FAILED_TO_VALIDATE_ACTIVE_LOAD_LISTENING_DIRECTORY_S_SKIP_SCANNING_ARG_0E6A508E,
+          dirPath,
+          e.getMessage());
+    }
+  }
+
   // Metrics
   public long countAndReportActiveListeningDirsFileNumber() {
     long totalFileCount = 0;
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/ActiveLoadListeningDirConfigTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/ActiveLoadListeningDirConfigTest.java
new file mode 100644
index 00000000000..e78008719c2
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/ActiveLoadListeningDirConfigTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Comparator;
+import java.util.stream.Stream;
+
+public class ActiveLoadListeningDirConfigTest {
+
+  // Reject listening dirs under data/ and keep the original config; dirs 
under ext/load/ are
+  // allowed.
+  @Test
+  public void testActiveLoadListeningDirUnderDataDirIsSkipped() throws 
Exception {
+    final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
+    final String[][] originalTierDataDirs = config.getTierDataDirs();
+    final String[] originalListeningDirs = 
config.getLoadActiveListeningDirs().clone();
+    final String originalPipeListeningDir = 
config.getLoadActiveListeningPipeDir();
+    final Path dataNodeDir = 
Files.createTempDirectory("active-load-listening-config");
+    final Path dataDir = dataNodeDir.resolve("data");
+    final Path allowedDir = 
dataNodeDir.resolve("ext").resolve("load").resolve("pending");
+    Files.createDirectories(allowedDir);
+
+    try {
+      config.setTierDataDirs(new String[][] {{dataDir.toString()}});
+
+      config.setLoadActiveListeningDirs(new String[] 
{dataDir.resolve("pending").toString()});
+      Assert.assertArrayEquals(originalListeningDirs, 
config.getLoadActiveListeningDirs());
+
+      config.setLoadActiveListeningPipeDir(dataDir.resolve("pipe").toString());
+      Assert.assertEquals(originalPipeListeningDir, 
config.getLoadActiveListeningPipeDir());
+
+      config.setLoadActiveListeningDirs(new String[] {allowedDir.toString()});
+      config.setLoadActiveListeningPipeDir(
+          
dataNodeDir.resolve("ext").resolve("load").resolve("pipe").toString());
+      Assert.assertFalse(config.isUnderInternalDataDir(allowedDir.toString()));
+    } finally {
+      config.setTierDataDirs(originalTierDataDirs);
+      config.setLoadActiveListeningDirs(originalListeningDirs);
+      config.setLoadActiveListeningPipeDir(originalPipeListeningDir);
+      deleteRecursively(dataNodeDir);
+    }
+  }
+
+  // Reject the data directory itself as load_active_listening_dirs and keep 
the original config.
+  @Test
+  public void testDataDirectoryItselfIsSkippedAsActiveLoadListeningDir() 
throws Exception {
+    final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
+    final String[][] originalTierDataDirs = config.getTierDataDirs();
+    final String[] originalListeningDirs = 
config.getLoadActiveListeningDirs().clone();
+    final Path dataNodeDir = 
Files.createTempDirectory("active-load-listening-data-root");
+    final Path dataDir = Files.createDirectories(dataNodeDir.resolve("data"));
+
+    try {
+      config.setTierDataDirs(new String[][] {{dataDir.toString()}});
+
+      config.setLoadActiveListeningDirs(new String[] {dataDir.toString()});
+      Assert.assertArrayEquals(originalListeningDirs, 
config.getLoadActiveListeningDirs());
+    } finally {
+      config.setTierDataDirs(originalTierDataDirs);
+      config.setLoadActiveListeningDirs(originalListeningDirs);
+      deleteRecursively(dataNodeDir);
+    }
+  }
+
+  // Invalid data-dir updates must not overwrite previously accepted 
pending/pipe listening dirs.
+  @Test
+  public void 
testInvalidActiveLoadListeningConfigDoesNotOverwriteExistingValue() throws 
Exception {
+    final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
+    final String[][] originalTierDataDirs = config.getTierDataDirs();
+    final String[] originalListeningDirs = 
config.getLoadActiveListeningDirs().clone();
+    final String originalPipeListeningDir = 
config.getLoadActiveListeningPipeDir();
+    final Path dataNodeDir = 
Files.createTempDirectory("active-load-listening-rollback");
+    final Path dataDir = dataNodeDir.resolve("data");
+    final Path allowedDir = 
dataNodeDir.resolve("ext").resolve("load").resolve("pending");
+    final Path allowedPipeDir = 
dataNodeDir.resolve("ext").resolve("load").resolve("pipe");
+    Files.createDirectories(allowedDir);
+    Files.createDirectories(allowedPipeDir);
+
+    try {
+      config.setTierDataDirs(new String[][] {{dataDir.toString()}});
+      config.setLoadActiveListeningDirs(new String[] {allowedDir.toString()});
+      config.setLoadActiveListeningPipeDir(allowedPipeDir.toString());
+
+      config.setLoadActiveListeningPipeDir(dataDir.resolve("pipe").toString());
+      Assert.assertEquals(allowedPipeDir.toString(), 
config.getLoadActiveListeningPipeDir());
+
+      config.setLoadActiveListeningDirs(new String[] 
{dataDir.resolve("pending").toString()});
+      Assert.assertArrayEquals(
+          new String[] {allowedDir.toString()}, 
config.getLoadActiveListeningDirs());
+    } finally {
+      config.setTierDataDirs(originalTierDataDirs);
+      config.setLoadActiveListeningDirs(originalListeningDirs);
+      config.setLoadActiveListeningPipeDir(originalPipeListeningDir);
+      deleteRecursively(dataNodeDir);
+    }
+  }
+
+  private static void deleteRecursively(final Path path) throws IOException {
+    if (path == null || !Files.exists(path)) {
+      return;
+    }
+
+    try (final Stream<Path> pathStream = Files.walk(path)) {
+      pathStream
+          .sorted(Comparator.reverseOrder())
+          .forEach(
+              currentPath -> {
+                try {
+                  Files.deleteIfExists(currentPath);
+                } catch (IOException e) {
+                  throw new RuntimeException(e);
+                }
+              });
+    }
+  }
+}

Reply via email to