You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by qi...@apache.org on 2022/06/13 11:02:23 UTC

[iotdb] branch master updated: [IOTDB-3445][IOTDB-3446] Fixed empty dirs are not deleted after data … (#6242)

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

qiaojialin 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 1e31ab278d [IOTDB-3445][IOTDB-3446] Fixed empty dirs are not deleted after data … (#6242)
1e31ab278d is described below

commit 1e31ab278dc569832aa0ec8db395cab97de68051
Author: cmlmakahts <82...@users.noreply.github.com>
AuthorDate: Mon Jun 13 19:02:17 2022 +0800

    [IOTDB-3445][IOTDB-3446] Fixed empty dirs are not deleted after data … (#6242)
---
 .../confignode/client/SyncDataNodeClientPool.java  | 15 ++--
 .../iotdb/confignode/manager/ProcedureManager.java |  3 +-
 .../persistence/partition/PartitionInfo.java       | 82 ++++++++--------------
 .../partition/StorageGroupPartitionTable.java      | 17 ++++-
 .../confignode/persistence/PartitionInfoTest.java  |  4 --
 .../org/apache/iotdb/commons/utils/FileUtils.java  | 10 +++
 .../org/apache/iotdb/db/engine/StorageEngine.java  |  3 +-
 .../apache/iotdb/db/engine/StorageEngineV2.java    |  2 +
 .../iotdb/db/engine/storagegroup/DataRegion.java   | 14 ++--
 .../dataregion/StorageGroupManager.java            |  4 +-
 .../metadata/schemaregion/SchemaRegionUtils.java   |  5 ++
 11 files changed, 80 insertions(+), 79 deletions(-)

diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/SyncDataNodeClientPool.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/SyncDataNodeClientPool.java
index 9510180dc3..90f17ce679 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/SyncDataNodeClientPool.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/SyncDataNodeClientPool.java
@@ -92,17 +92,16 @@ public class SyncDataNodeClientPool {
     Map<TDataNodeLocation, List<TConsensusGroupId>> regionLocationMap = new HashMap<>();
     deletedRegionSet.forEach(
         (tRegionReplicaSet) -> {
-          final List<TDataNodeLocation> dataNodeLocations =
-              tRegionReplicaSet.getDataNodeLocations();
-          regionLocationMap
-              .computeIfAbsent(dataNodeLocations.get(0), k -> new ArrayList<>())
-              .add(tRegionReplicaSet.getRegionId());
+          for (TDataNodeLocation dataNodeLocation : tRegionReplicaSet.getDataNodeLocations()) {
+            regionLocationMap
+                .computeIfAbsent(dataNodeLocation, k -> new ArrayList<>())
+                .add(tRegionReplicaSet.getRegionId());
+          }
         });
     LOGGER.info("Current regionLocationMap {} ", regionLocationMap);
     regionLocationMap.forEach(
-        (dataNodeLocation, regionIds) -> {
-          deleteRegions(dataNodeLocation.getInternalEndPoint(), regionIds, deletedRegionSet);
-        });
+        (dataNodeLocation, regionIds) ->
+            deleteRegions(dataNodeLocation.getInternalEndPoint(), regionIds, deletedRegionSet));
   }
 
   private void deleteRegions(
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
index 97619cce6c..baedc62cd2 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
@@ -97,7 +97,8 @@ public class ProcedureManager {
     List<TSStatus> procedureStatus = new ArrayList<>();
     boolean isSucceed = getProcedureStatus(this.executor, procIdList, procedureStatus);
     // clear the previously deleted regions
-    getConfigManager().getPartitionManager().clearDeletedRegions();
+    final PartitionManager partitionManager = getConfigManager().getPartitionManager();
+    partitionManager.getRegionCleaner().submit(partitionManager::clearDeletedRegions);
     if (isSucceed) {
       return StatusUtils.OK;
     } else {
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/PartitionInfo.java b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/PartitionInfo.java
index 73a72f803d..742356df4d 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/PartitionInfo.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/PartitionInfo.java
@@ -28,7 +28,6 @@ import org.apache.iotdb.common.rpc.thrift.TTimePartitionSlot;
 import org.apache.iotdb.commons.partition.DataPartition;
 import org.apache.iotdb.commons.partition.SchemaPartition;
 import org.apache.iotdb.commons.snapshot.SnapshotProcessor;
-import org.apache.iotdb.commons.utils.TestOnly;
 import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
 import org.apache.iotdb.confignode.consensus.request.read.GetDataPartitionReq;
 import org.apache.iotdb.confignode.consensus.request.read.GetSchemaPartitionReq;
@@ -68,7 +67,6 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.Vector;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -86,8 +84,6 @@ public class PartitionInfo implements SnapshotProcessor {
   // Map<StorageGroupName, StorageGroupPartitionInfo>
   private final ConcurrentHashMap<String, StorageGroupPartitionTable> storageGroupPartitionTables;
 
-  // preDeleted TODO: Combine it with Partition.class
-  private final Set<String> preDeletedStorageGroup;
   private final Set<TRegionReplicaSet> deletedRegionSet;
 
   private final String snapshotFileName = "partition_info.bin";
@@ -98,7 +94,6 @@ public class PartitionInfo implements SnapshotProcessor {
 
     // Ensure that the PartitionTables of the StorageGroups who've been logically deleted
     // are unreadable and un-writable
-    this.preDeletedStorageGroup = new CopyOnWriteArraySet<>();
     // For RegionCleaner
     this.deletedRegionSet = Collections.synchronizedSet(new HashSet<>());
   }
@@ -167,10 +162,10 @@ public class PartitionInfo implements SnapshotProcessor {
     final String storageGroup = preDeleteStorageGroupReq.getStorageGroup();
     switch (preDeleteType) {
       case EXECUTE:
-        preDeletedStorageGroup.add(storageGroup);
+        storageGroupPartitionTables.get(storageGroup).setPredeleted(true);
         break;
       case ROLLBACK:
-        preDeletedStorageGroup.remove(storageGroup);
+        storageGroupPartitionTables.get(storageGroup).setPredeleted(false);
         break;
     }
     return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
@@ -213,7 +208,7 @@ public class PartitionInfo implements SnapshotProcessor {
       // Return all SchemaPartitions when the queried PartitionSlots are empty
       storageGroupPartitionTables.forEach(
           (storageGroup, storageGroupPartitionTable) -> {
-            if (!preDeletedStorageGroup.contains(storageGroup)) {
+            if (!storageGroupPartitionTable.isPredeleted()) {
               schemaPartition.put(storageGroup, new ConcurrentHashMap<>());
               storageGroupPartitionTable.getSchemaPartition(
                   new ArrayList<>(), schemaPartition.get(storageGroup));
@@ -229,8 +224,7 @@ public class PartitionInfo implements SnapshotProcessor {
       req.getPartitionSlotsMap()
           .forEach(
               (storageGroup, partitionSlots) -> {
-                if (storageGroupPartitionTables.containsKey(storageGroup)
-                    && !preDeletedStorageGroup.contains(storageGroup)) {
+                if (isStorageGroupExisted(storageGroup)) {
                   schemaPartition.put(storageGroup, new ConcurrentHashMap<>());
 
                   if (!storageGroupPartitionTables
@@ -274,8 +268,7 @@ public class PartitionInfo implements SnapshotProcessor {
     req.getPartitionSlotsMap()
         .forEach(
             (storageGroup, partitionSlots) -> {
-              if (storageGroupPartitionTables.containsKey(storageGroup)
-                  && !preDeletedStorageGroup.contains(storageGroup)) {
+              if (isStorageGroupExisted(storageGroup)) {
                 dataPartition.put(storageGroup, new ConcurrentHashMap<>());
                 if (!storageGroupPartitionTables
                     .get(storageGroup)
@@ -302,6 +295,12 @@ public class PartitionInfo implements SnapshotProcessor {
     return dataPartitionResp;
   }
 
+  private boolean isStorageGroupExisted(String storageGroup) {
+    final StorageGroupPartitionTable storageGroupPartitionTable =
+        storageGroupPartitionTables.get(storageGroup);
+    return storageGroupPartitionTable != null && !storageGroupPartitionTable.isPredeleted();
+  }
+
   /**
    * Create SchemaPartition
    *
@@ -312,8 +311,7 @@ public class PartitionInfo implements SnapshotProcessor {
     req.getAssignedSchemaPartition()
         .forEach(
             (storageGroup, schemaPartitionTable) -> {
-              if (storageGroupPartitionTables.containsKey(storageGroup)
-                  && !preDeletedStorageGroup.contains(storageGroup)) {
+              if (isStorageGroupExisted(storageGroup)) {
                 storageGroupPartitionTables
                     .get(storageGroup)
                     .createSchemaPartition(schemaPartitionTable);
@@ -333,8 +331,7 @@ public class PartitionInfo implements SnapshotProcessor {
     req.getAssignedDataPartition()
         .forEach(
             (storageGroup, dataPartitionTable) -> {
-              if (storageGroupPartitionTables.containsKey(storageGroup)
-                  && !preDeletedStorageGroup.contains(storageGroup)) {
+              if (isStorageGroupExisted(storageGroup)) {
                 storageGroupPartitionTables
                     .get(storageGroup)
                     .createDataPartition(dataPartitionTable);
@@ -350,18 +347,20 @@ public class PartitionInfo implements SnapshotProcessor {
     Map<String, Map<TSeriesPartitionSlot, TRegionReplicaSet>> schemaPartitionMap =
         new ConcurrentHashMap<>();
 
-    matchedStorageGroups.forEach(
-        storageGroup -> {
-          schemaPartitionMap.put(storageGroup, new ConcurrentHashMap<>());
-          storageGroupPartitionTables
-              .get(storageGroup)
-              .getSchemaPartition(new ArrayList<>(), schemaPartitionMap.get(storageGroup));
+    matchedStorageGroups.stream()
+        .filter(this::isStorageGroupExisted)
+        .forEach(
+            storageGroup -> {
+              schemaPartitionMap.put(storageGroup, new ConcurrentHashMap<>());
+              storageGroupPartitionTables
+                  .get(storageGroup)
+                  .getSchemaPartition(new ArrayList<>(), schemaPartitionMap.get(storageGroup));
 
-          if (schemaPartitionMap.get(storageGroup).size() == 0) {
-            // Remove empty Map
-            schemaPartitionMap.remove(storageGroup);
-          }
-        });
+              if (schemaPartitionMap.get(storageGroup).size() == 0) {
+                // Remove empty Map
+                schemaPartitionMap.remove(storageGroup);
+              }
+            });
 
     schemaNodeManagementResp.setSchemaPartition(
         new SchemaPartition(
@@ -389,8 +388,7 @@ public class PartitionInfo implements SnapshotProcessor {
 
     partitionSlotsMap.forEach(
         (storageGroup, partitionSlots) -> {
-          if (storageGroupPartitionTables.containsKey(storageGroup)
-              && !preDeletedStorageGroup.contains(storageGroup)) {
+          if (isStorageGroupExisted(storageGroup)) {
             result.put(
                 storageGroup,
                 storageGroupPartitionTables
@@ -418,8 +416,7 @@ public class PartitionInfo implements SnapshotProcessor {
 
     partitionSlotsMap.forEach(
         (storageGroup, partitionSlots) -> {
-          if (storageGroupPartitionTables.containsKey(storageGroup)
-              && !preDeletedStorageGroup.contains(storageGroup)) {
+          if (isStorageGroupExisted(storageGroup)) {
             result.put(
                 storageGroup,
                 storageGroupPartitionTables
@@ -457,8 +454,7 @@ public class PartitionInfo implements SnapshotProcessor {
    */
   public int getRegionCount(String storageGroup, TConsensusGroupType type)
       throws StorageGroupNotExistsException {
-    if (!storageGroupPartitionTables.containsKey(storageGroup)
-        || preDeletedStorageGroup.contains(storageGroup)) {
+    if (!isStorageGroupExisted(storageGroup)) {
       throw new StorageGroupNotExistsException(storageGroup);
     }
 
@@ -516,11 +512,6 @@ public class PartitionInfo implements SnapshotProcessor {
         ReadWriteIOUtils.write(storageGroupPartitionTableEntry.getKey(), fileOutputStream);
         storageGroupPartitionTableEntry.getValue().serialize(fileOutputStream, protocol);
       }
-      // serialize preDeletedStorageGroup
-      ReadWriteIOUtils.write(preDeletedStorageGroup.size(), fileOutputStream);
-      for (String storageGroup : preDeletedStorageGroup) {
-        ReadWriteIOUtils.write(storageGroup, fileOutputStream);
-      }
       // serialize deletedRegionSet
       ReadWriteIOUtils.write(deletedRegionSet.size(), fileOutputStream);
       for (TRegionReplicaSet regionReplicaSet : deletedRegionSet) {
@@ -572,12 +563,6 @@ public class PartitionInfo implements SnapshotProcessor {
         storageGroupPartitionTable.deserialize(fileInputStream, protocol);
         storageGroupPartitionTables.put(storageGroup, storageGroupPartitionTable);
       }
-      // restore preDeletedStorageGroup
-      length = ReadWriteIOUtils.readInt(fileInputStream);
-      for (int i = 0; i < length; i++) {
-        String storageGroup = ReadWriteIOUtils.readString(fileInputStream);
-        preDeletedStorageGroup.add(storageGroup);
-      }
       // restore deletedRegionSet
       length = ReadWriteIOUtils.readInt(fileInputStream);
       for (int i = 0; i < length; i++) {
@@ -591,27 +576,20 @@ public class PartitionInfo implements SnapshotProcessor {
   public void clear() {
     nextRegionGroupId.set(0);
     storageGroupPartitionTables.clear();
-    preDeletedStorageGroup.clear();
     deletedRegionSet.clear();
   }
 
-  @TestOnly
-  public Set<String> getPreDeletedStorageGroup() {
-    return preDeletedStorageGroup;
-  }
-
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;
     PartitionInfo that = (PartitionInfo) o;
     return storageGroupPartitionTables.equals(that.storageGroupPartitionTables)
-        && preDeletedStorageGroup.equals(that.preDeletedStorageGroup)
         && deletedRegionSet.equals(that.deletedRegionSet);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(storageGroupPartitionTables, preDeletedStorageGroup, deletedRegionSet);
+    return Objects.hash(storageGroupPartitionTables, deletedRegionSet);
   }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/StorageGroupPartitionTable.java b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/StorageGroupPartitionTable.java
index e857ffe2b9..6384b52058 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/StorageGroupPartitionTable.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/StorageGroupPartitionTable.java
@@ -45,7 +45,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 public class StorageGroupPartitionTable {
-
+  private volatile boolean isPredeleted = false;
   // Total number of SeriesPartitionSlots occupied by schema,
   // determines whether a new Region needs to be created
   private final AtomicInteger seriesPartitionSlotsCount;
@@ -72,6 +72,14 @@ public class StorageGroupPartitionTable {
     this.dataPartitionTable = new DataPartitionTable();
   }
 
+  public boolean isPredeleted() {
+    return isPredeleted;
+  }
+
+  public void setPredeleted(boolean predeleted) {
+    isPredeleted = predeleted;
+  }
+
   /**
    * Cache allocation result of new Regions
    *
@@ -274,6 +282,7 @@ public class StorageGroupPartitionTable {
 
   public void serialize(OutputStream outputStream, TProtocol protocol)
       throws IOException, TException {
+    ReadWriteIOUtils.write(isPredeleted, outputStream);
     ReadWriteIOUtils.write(seriesPartitionSlotsCount.get(), outputStream);
 
     ReadWriteIOUtils.write(regionInfoMap.size(), outputStream);
@@ -288,6 +297,7 @@ public class StorageGroupPartitionTable {
 
   public void deserialize(InputStream inputStream, TProtocol protocol)
       throws IOException, TException {
+    isPredeleted = ReadWriteIOUtils.readBool(inputStream);
     seriesPartitionSlotsCount.set(ReadWriteIOUtils.readInt(inputStream));
 
     int length = ReadWriteIOUtils.readInt(inputStream);
@@ -308,13 +318,14 @@ public class StorageGroupPartitionTable {
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;
     StorageGroupPartitionTable that = (StorageGroupPartitionTable) o;
-    return regionInfoMap.equals(that.regionInfoMap)
+    return isPredeleted == that.isPredeleted
+        && regionInfoMap.equals(that.regionInfoMap)
         && schemaPartitionTable.equals(that.schemaPartitionTable)
         && dataPartitionTable.equals(that.dataPartitionTable);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(regionInfoMap, schemaPartitionTable, dataPartitionTable);
+    return Objects.hash(isPredeleted, regionInfoMap, schemaPartitionTable, dataPartitionTable);
   }
 }
diff --git a/confignode/src/test/java/org/apache/iotdb/confignode/persistence/PartitionInfoTest.java b/confignode/src/test/java/org/apache/iotdb/confignode/persistence/PartitionInfoTest.java
index 1eb83c8ad4..007d599ad8 100644
--- a/confignode/src/test/java/org/apache/iotdb/confignode/persistence/PartitionInfoTest.java
+++ b/confignode/src/test/java/org/apache/iotdb/confignode/persistence/PartitionInfoTest.java
@@ -133,10 +133,6 @@ public class PartitionInfoTest {
                 testFlag.DataPartition.getFlag(), TConsensusGroupType.DataRegion));
     partitionInfo.createDataPartition(createDataPartitionReq);
 
-    partitionInfo.getPreDeletedStorageGroup().add("A");
-    partitionInfo.getPreDeletedStorageGroup().add("B");
-    partitionInfo.getPreDeletedStorageGroup().add("C");
-
     partitionInfo.getDeletedRegionSet().add(dataRegionReplicaSet);
     partitionInfo.getDeletedRegionSet().add(schemaRegionReplicaSet);
 
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java b/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
index 6296a46e42..aa70788e6e 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
@@ -33,6 +33,7 @@ import java.nio.file.DirectoryNotEmptyException;
 import java.nio.file.Files;
 import java.nio.file.NoSuchFileException;
 import java.util.Arrays;
+import java.util.Objects;
 
 public class FileUtils {
   private static Logger logger = LoggerFactory.getLogger(FileUtils.class);
@@ -56,6 +57,15 @@ public class FileUtils {
     }
   }
 
+  public static void deleteDirectoryAndParent(File folder) {
+    deleteDirectory(folder);
+    final File parentFolder = folder.getParentFile();
+    if (parentFolder.isDirectory()
+        && Objects.requireNonNull(parentFolder.listFiles()).length == 0) {
+      parentFolder.delete();
+    }
+  }
+
   public static boolean copyDir(File sourceDir, File targetDir) throws IOException {
     if (!sourceDir.exists() || !sourceDir.isDirectory()) {
       logger.error(
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
index 13640094c0..322c24e742 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
@@ -855,8 +855,7 @@ public class StorageEngine implements IService {
     abortCompactionTaskForStorageGroup(storageGroupPath);
     deleteAllDataFilesInOneStorageGroup(storageGroupPath);
     StorageGroupManager storageGroupManager = processorMap.remove(storageGroupPath);
-    storageGroupManager.deleteStorageGroupSystemFolder(
-        systemDir + File.pathSeparator + storageGroupPath);
+    storageGroupManager.deleteStorageGroupSystemFolder(systemDir);
     storageGroupManager.stopSchedulerPool();
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java
index 43411ef759..cebe743047 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java
@@ -608,7 +608,9 @@ public class StorageEngineV2 implements IService {
   public void deleteDataRegion(DataRegionId regionId) {
     DataRegion region = dataRegionMap.remove(regionId);
     if (region != null) {
+      region.abortCompaction();
       region.syncDeleteDataFiles();
+      region.deleteFolder(systemDir);
     }
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/DataRegion.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/DataRegion.java
index 0f571931f0..93abb953b0 100755
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/DataRegion.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/DataRegion.java
@@ -1618,10 +1618,10 @@ public class DataRegion {
         systemDir);
     writeLock("deleteFolder");
     try {
-      File storageGroupFolder = SystemFileFactory.INSTANCE.getFile(systemDir, dataRegionId);
-      if (storageGroupFolder.exists()) {
-        org.apache.iotdb.commons.utils.FileUtils.deleteDirectory(storageGroupFolder);
-      }
+      File dataRegionSystemFolder =
+          SystemFileFactory.INSTANCE.getFile(
+              systemDir + File.separator + logicalStorageGroupName, dataRegionId);
+      org.apache.iotdb.commons.utils.FileUtils.deleteDirectoryAndParent(dataRegionSystemFolder);
     } finally {
       writeUnlock();
     }
@@ -1674,10 +1674,10 @@ public class DataRegion {
 
   private void deleteAllSGFolders(List<String> folder) {
     for (String tsfilePath : folder) {
-      File storageGroupFolder =
+      File dataRegionDataFolder =
           fsFactory.getFile(tsfilePath, logicalStorageGroupName + File.separator + dataRegionId);
-      if (storageGroupFolder.exists()) {
-        org.apache.iotdb.commons.utils.FileUtils.deleteDirectory(storageGroupFolder);
+      if (dataRegionDataFolder.exists()) {
+        org.apache.iotdb.commons.utils.FileUtils.deleteDirectoryAndParent(dataRegionDataFolder);
       }
     }
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/dataregion/StorageGroupManager.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/dataregion/StorageGroupManager.java
index aa7f8c2c26..9af9b4ee84 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/dataregion/StorageGroupManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/dataregion/StorageGroupManager.java
@@ -385,10 +385,10 @@ public class StorageGroupManager {
   }
 
   /** push deleteStorageGroup operation down to all virtual storage group processors */
-  public void deleteStorageGroupSystemFolder(String path) {
+  public void deleteStorageGroupSystemFolder(String systemDir) {
     for (DataRegion processor : dataRegion) {
       if (processor != null) {
-        processor.deleteFolder(path);
+        processor.deleteFolder(systemDir);
       }
     }
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionUtils.java b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionUtils.java
index bdad187d1f..4a8d57613c 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionUtils.java
@@ -31,6 +31,7 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.slf4j.Logger;
 
 import java.io.File;
+import java.util.Objects;
 
 public class SchemaRegionUtils {
 
@@ -61,6 +62,10 @@ public class SchemaRegionUtils {
           String.format(
               "Failed to delete schema region folder %s", schemaRegionDir.getAbsolutePath()));
     }
+    final File storageGroupDir = schemaRegionDir.getParentFile();
+    if (Objects.requireNonNull(storageGroupDir.listFiles()).length == 0) {
+      storageGroupDir.delete();
+    }
   }
 
   public static void checkDataTypeMatch(InsertPlan plan, int loc, TSDataType dataType)