[IOTDB-4479] Add pattern overlap check when deleting timeseries (#7373)

[IOTDB-4479] Add pattern overlap check when deleting timeseries (#7373)
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteTimeseriesIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteTimeseriesIT.java
index ca75bd9..e0b091e 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteTimeseriesIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteTimeseriesIT.java
@@ -331,6 +331,29 @@
       }
       Assert.assertEquals(retArray1.length, cnt);
     }
+
+    statement.execute("delete timeseries root.sg1.d1.s2, root.sg2.**");
+    try (ResultSet resultSet = statement.executeQuery("select s2 from root.sg1.*")) {
+      Assert.assertFalse(resultSet.next());
+    }
+
+    try (ResultSet resultSet = statement.executeQuery("show timeseries root.sg2.*.s2")) {
+      Assert.assertFalse(resultSet.next());
+    }
+
+    retArray1 = new String[] {"0,4,4"};
+    cnt = 0;
+    try (ResultSet resultSet = statement.executeQuery("select count(s2) from root.*.*")) {
+      while (resultSet.next()) {
+        StringBuilder ans = new StringBuilder(resultSet.getString(TIMESTAMP_STR));
+        for (int i = 3; i <= 4; i++) {
+          ans.append(",").append(resultSet.getString(count("root.sg" + i + ".d1.s2")));
+        }
+        Assert.assertEquals(retArray1[cnt], ans.toString());
+        cnt++;
+      }
+      Assert.assertEquals(retArray1.length, cnt);
+    }
   }
 
   @Test
diff --git a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeInternalRPCServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeInternalRPCServiceImpl.java
index 2e1a9f7..aaf807b 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeInternalRPCServiceImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeInternalRPCServiceImpl.java
@@ -31,6 +31,7 @@
 import org.apache.iotdb.commons.consensus.ConsensusGroupId;
 import org.apache.iotdb.commons.consensus.DataRegionId;
 import org.apache.iotdb.commons.consensus.SchemaRegionId;
+import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.exception.MetadataException;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternTree;
@@ -55,6 +56,7 @@
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.cache.DataNodeSchemaCache;
+import org.apache.iotdb.db.metadata.schemaregion.ISchemaRegion;
 import org.apache.iotdb.db.metadata.schemaregion.SchemaEngine;
 import org.apache.iotdb.db.metadata.template.ClusterTemplateManager;
 import org.apache.iotdb.db.metadata.template.TemplateInternalRPCUpdateType;
@@ -145,6 +147,8 @@
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
+import static org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
+
 public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface {
 
   private static final Logger LOGGER =
@@ -341,10 +345,18 @@
     TSStatus status;
     int preDeletedNum = 0;
     for (TConsensusGroupId consensusGroupId : req.getSchemaRegionIdList()) {
+      String storageGroup =
+          schemaEngine
+              .getSchemaRegion(new SchemaRegionId(consensusGroupId.getId()))
+              .getStorageGroupFullPath();
+      PathPatternTree filteredPatternTree = filterPathPatternTree(patternTree, storageGroup);
+      if (filteredPatternTree.isEmpty()) {
+        continue;
+      }
       status =
           regionManager.executeSchemaPlanNode(
               new SchemaRegionId(consensusGroupId.getId()),
-              new ConstructSchemaBlackListNode(new PlanNodeId(""), patternTree));
+              new ConstructSchemaBlackListNode(new PlanNodeId(""), filteredPatternTree));
       if (status.code == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
         preDeletedNum += Integer.parseInt(status.getMessage());
       } else {
@@ -366,10 +378,18 @@
     List<TSStatus> failureList = new ArrayList<>();
     TSStatus status;
     for (TConsensusGroupId consensusGroupId : req.getSchemaRegionIdList()) {
+      String storageGroup =
+          schemaEngine
+              .getSchemaRegion(new SchemaRegionId(consensusGroupId.getId()))
+              .getStorageGroupFullPath();
+      PathPatternTree filteredPatternTree = filterPathPatternTree(patternTree, storageGroup);
+      if (filteredPatternTree.isEmpty()) {
+        continue;
+      }
       status =
           regionManager.executeSchemaPlanNode(
               new SchemaRegionId(consensusGroupId.getId()),
-              new RollbackSchemaBlackListNode(new PlanNodeId(""), patternTree));
+              new RollbackSchemaBlackListNode(new PlanNodeId(""), filteredPatternTree));
       if (status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
         failureList.add(status);
       }
@@ -408,10 +428,14 @@
     for (TConsensusGroupId consensusGroupId : req.getSchemaRegionIdList()) {
       // todo implement as consensus layer read request
       try {
-        for (PartialPath path :
-            schemaEngine
-                .getSchemaRegion(new SchemaRegionId(consensusGroupId.getId()))
-                .fetchSchemaBlackList(patternTree)) {
+        ISchemaRegion schemaRegion =
+            schemaEngine.getSchemaRegion(new SchemaRegionId(consensusGroupId.getId()));
+        PathPatternTree filteredPatternTree =
+            filterPathPatternTree(patternTree, schemaRegion.getStorageGroupFullPath());
+        if (filteredPatternTree.isEmpty()) {
+          continue;
+        }
+        for (PartialPath path : schemaRegion.fetchSchemaBlackList(filteredPatternTree)) {
           result.appendFullPath(path);
         }
       } catch (MetadataException e) {
@@ -465,10 +489,18 @@
     List<TSStatus> failureList = new ArrayList<>();
     TSStatus status;
     for (TConsensusGroupId consensusGroupId : req.getSchemaRegionIdList()) {
+      String storageGroup =
+          schemaEngine
+              .getSchemaRegion(new SchemaRegionId(consensusGroupId.getId()))
+              .getStorageGroupFullPath();
+      PathPatternTree filteredPatternTree = filterPathPatternTree(patternTree, storageGroup);
+      if (filteredPatternTree.isEmpty()) {
+        continue;
+      }
       status =
           regionManager.executeSchemaPlanNode(
               new SchemaRegionId(consensusGroupId.getId()),
-              new DeleteTimeSeriesNode(new PlanNodeId(""), patternTree));
+              new DeleteTimeSeriesNode(new PlanNodeId(""), filteredPatternTree));
       if (status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
         failureList.add(status);
       }
@@ -481,6 +513,21 @@
     return RpcUtils.SUCCESS_STATUS;
   }
 
+  private PathPatternTree filterPathPatternTree(PathPatternTree patternTree, String storageGroup) {
+    PathPatternTree filteredPatternTree = new PathPatternTree();
+    try {
+      PartialPath storageGroupPattern =
+          new PartialPath(storageGroup).concatNode(MULTI_LEVEL_PATH_WILDCARD);
+      for (PartialPath pathPattern : patternTree.getOverlappedPathPatterns(storageGroupPattern)) {
+        filteredPatternTree.appendPathPattern(pathPattern);
+      }
+      filteredPatternTree.constructTree();
+    } catch (IllegalPathException e) {
+      // won't reach here
+    }
+    return filteredPatternTree;
+  }
+
   @Override
   public THeartbeatResp getDataNodeHeartBeat(THeartbeatReq req) throws TException {
     THeartbeatResp resp = new THeartbeatResp();