You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by zy...@apache.org on 2022/09/16 07:15:28 UTC

[iotdb] branch master updated: [IOTDB-3184] Implement Delete Timeseries for Cluster (#7242)

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

zyk 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 2f61131359 [IOTDB-3184] Implement Delete Timeseries for Cluster (#7242)
2f61131359 is described below

commit 2f6113135904f9217b7f357f182d9cd15ce59bb1
Author: Marcos_Zyk <38...@users.noreply.github.com>
AuthorDate: Fri Sep 16 15:15:20 2022 +0800

    [IOTDB-3184] Implement Delete Timeseries for Cluster (#7242)
    
    [IOTDB-3184] Implement Delete Timeseries for Cluster (#7242)
---
 .../confignode/client/DataNodeRequestType.java     |   7 +
 .../async/datanode/AsyncDataNodeClientPool.java    |  94 +++
 .../async/handlers/AbstractRetryHandler.java       |  19 +
 .../handlers/ConstructSchemaBlackListHandler.java  |  95 +++
 .../DeleteDataForDeleteTimeSeriesHandler.java      | 103 ++++
 .../async/handlers/DeleteTimeSeriesHandler.java    |  93 +++
 .../handlers/FetchSchemaBlackLsitHandler.java      | 101 ++++
 .../InvalidateMatchedSchemaCacheHandler.java       |  95 +++
 .../handlers/RollbackSchemaBlackListHandler.java   |  99 ++++
 .../AbstractDataNodeTask.java}                     |  45 +-
 .../ConstructSchemaBlackListDataNodeTask.java}     |  39 +-
 ...DeleteDataForDeleteTimeSeriesDataNodeTask.java} |  38 +-
 .../DeleteTimeSeriesDataNodeTask.java}             |  39 +-
 .../FetchSchemaBlackListDataNodeTask.java}         |  40 +-
 .../InvalidateMatchedSchemaCacheDataNodeTask.java} |  38 +-
 .../RollbackSchemaBlackListDataNodeTask.java}      |  39 +-
 .../iotdb/confignode/manager/ConfigManager.java    |  80 +++
 .../apache/iotdb/confignode/manager/IManager.java  |   7 +
 .../iotdb/confignode/manager/ProcedureManager.java |  69 ++-
 .../procedure/impl/DeleteTimeSeriesProcedure.java  | 639 +++++++++++++++++++++
 .../state/DeleteTimeSeriesState.java}              |  33 +-
 .../procedure/store/ProcedureFactory.java          |   9 +-
 .../thrift/ConfigNodeRPCServiceProcessor.java      |   6 +
 .../impl/DeleteTimeSeriesProcedureTest.java        |  67 +++
 .../org/apache/iotdb/db/it/IoTDBCompleteIT.java    | 495 ----------------
 .../it/schema/IoTDBCreateAlignedTimeseriesIT.java  |   9 +-
 .../it/schema/IoTDBDeleteAlignedTimeseriesIT.java  | 248 ++++++++
 .../db/it/schema/IoTDBDeleteTimeseriesIT.java      | 406 +++++++++++++
 .../org/apache/iotdb/db/it/schema/IoTDBTagIT.java  |  23 +-
 .../iotdb/db/integration/IoTDBCompleteIT.java      | 491 ----------------
 .../IoTDBCreateAlignedTimeseriesIT.java            | 115 ----
 .../db/integration/IoTDBDeleteTimeseriesIT.java    | 215 -------
 .../apache/iotdb/db/integration/IoTDBTagIT.java    | 315 ----------
 .../aligned/IoTDBDeleteTimeseriesIT.java           | 281 ---------
 .../schemaregion/rocksdb/RSchemaRegion.java        |  22 +
 .../rocksdb/mnode/RMeasurementMNode.java           |   8 +
 .../apache/iotdb/db/client/ConfigNodeClient.java   |  17 +
 .../iotdb/db/client/DataNodeClientPoolFactory.java |  20 +
 .../metadata/MeasurementInBlackListException.java} |  30 +-
 .../db/metadata/cache/DataNodeSchemaCache.java     |  33 ++
 .../idtable/entry/InsertMeasurementMNode.java      |   8 +
 .../iotdb/db/metadata/mnode/IMeasurementMNode.java |   4 +
 .../iotdb/db/metadata/mnode/MeasurementMNode.java  |  12 +
 .../db/metadata/mtree/MTreeBelowSGMemoryImpl.java  |  39 +-
 .../mtree/snapshot/MemMTreeSnapshotUtil.java       |   2 +
 .../db/metadata/schemaregion/ISchemaRegion.java    |  27 +
 .../schemaregion/SchemaRegionMemoryImpl.java       | 103 ++++
 .../schemaregion/SchemaRegionSchemaFileImpl.java   |  22 +
 .../metadata/visitor/SchemaExecutionVisitor.java   |  38 ++
 .../db/mpp/common/schematree/PathPatternTree.java  |  10 +
 .../db/mpp/plan/analyze/ClusterSchemaFetcher.java  | 139 ++---
 .../mpp/plan/execution/config/ConfigExecution.java |   5 +-
 .../plan/execution/config/ConfigTaskVisitor.java   |  21 +-
 .../config/executor/ClusterConfigTaskExecutor.java |  67 +++
 .../config/executor/IConfigTaskExecutor.java       |   4 +
 .../executor/StandaloneConfigTaskExecutor.java     |  12 +
 .../config/metadata/DeleteTimeSeriesTask.java      |  45 ++
 .../iotdb/db/mpp/plan/parser/ASTVisitor.java       |   2 +-
 .../mpp/plan/planner/plan/node/PlanNodeType.java   |  10 +-
 .../db/mpp/plan/planner/plan/node/PlanVisitor.java |  10 +
 .../write/ConstructSchemaBlackListNode.java        |  91 +++
 .../node/metedata/write/DeleteTimeSeriesNode.java  |  63 +-
 .../write/RollbackSchemaBlackListNode.java         |  91 +++
 .../metadata/DeleteTimeSeriesStatement.java        |  27 +-
 .../org/apache/iotdb/db/qp/logical/Operator.java   |   4 +-
 .../apache/iotdb/db/qp/physical/PhysicalPlan.java  |  12 +-
 .../qp/physical/sys/PreDeleteTimeSeriesPlan.java   |  79 +++
 .../sys/RollbackPreDeleteTimeSeriesPlan.java       |  79 +++
 .../impl/DataNodeInternalRPCServiceImpl.java       | 326 ++++++-----
 .../service/thrift/impl/DataNodeRegionManager.java | 317 ++++++++++
 .../write/DeleteTimeSeriesNodeSerdeTest.java       |  15 +-
 .../java/org/apache/iotdb/rpc/TSStatusCode.java    |   4 +-
 .../src/main/thrift/confignode.thrift              |  14 +
 thrift/src/main/thrift/datanode.thrift             |  71 +++
 74 files changed, 3965 insertions(+), 2430 deletions(-)

diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java
index 7ed20d7e94..6dd63a384d 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java
@@ -45,4 +45,11 @@ public enum DataNodeRequestType {
   FULL_MERGE,
   LOAD_CONFIGURATION,
   SET_SYSTEM_STATUS,
+
+  CONSTRUCT_SCHEMA_BLACK_LIST,
+  ROLLBACK_SCHEMA_BLACK_LIST,
+  FETCH_SCHEMA_BLACK_LIST,
+  INVALIDATE_MATCHED_SCHEMA_CACHE,
+  DELETE_DATA_FOR_DELETE_TIMESERIES,
+  DELETE_TIMESERIES
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/datanode/AsyncDataNodeClientPool.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/datanode/AsyncDataNodeClientPool.java
index 557d898ca3..e477fa4105 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/datanode/AsyncDataNodeClientPool.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/datanode/AsyncDataNodeClientPool.java
@@ -32,21 +32,34 @@ import org.apache.iotdb.commons.client.async.AsyncDataNodeInternalServiceClient;
 import org.apache.iotdb.confignode.client.DataNodeRequestType;
 import org.apache.iotdb.confignode.client.async.handlers.AbstractRetryHandler;
 import org.apache.iotdb.confignode.client.async.handlers.ClearCacheHandler;
+import org.apache.iotdb.confignode.client.async.handlers.ConstructSchemaBlackListHandler;
 import org.apache.iotdb.confignode.client.async.handlers.CreateRegionHandler;
+import org.apache.iotdb.confignode.client.async.handlers.DeleteDataForDeleteTimeSeriesHandler;
+import org.apache.iotdb.confignode.client.async.handlers.DeleteTimeSeriesHandler;
+import org.apache.iotdb.confignode.client.async.handlers.FetchSchemaBlackLsitHandler;
 import org.apache.iotdb.confignode.client.async.handlers.FlushHandler;
 import org.apache.iotdb.confignode.client.async.handlers.FunctionManagementHandler;
+import org.apache.iotdb.confignode.client.async.handlers.InvalidateMatchedSchemaCacheHandler;
 import org.apache.iotdb.confignode.client.async.handlers.LoadConfigurationHandler;
 import org.apache.iotdb.confignode.client.async.handlers.MergeHandler;
+import org.apache.iotdb.confignode.client.async.handlers.RollbackSchemaBlackListHandler;
 import org.apache.iotdb.confignode.client.async.handlers.SetSystemStatusHandler;
 import org.apache.iotdb.confignode.client.async.handlers.SetTTLHandler;
 import org.apache.iotdb.confignode.client.async.handlers.UpdateConfigNodeGroupHandler;
 import org.apache.iotdb.confignode.client.async.handlers.UpdateRegionRouteMapHandler;
+import org.apache.iotdb.confignode.client.async.task.AbstractDataNodeTask;
 import org.apache.iotdb.confignode.consensus.request.write.CreateRegionGroupsPlan;
+import org.apache.iotdb.mpp.rpc.thrift.TConstructSchemaBlackListReq;
 import org.apache.iotdb.mpp.rpc.thrift.TCreateDataRegionReq;
 import org.apache.iotdb.mpp.rpc.thrift.TCreateFunctionRequest;
 import org.apache.iotdb.mpp.rpc.thrift.TCreateSchemaRegionReq;
+import org.apache.iotdb.mpp.rpc.thrift.TDeleteDataForDeleteTimeSeriesReq;
+import org.apache.iotdb.mpp.rpc.thrift.TDeleteTimeSeriesReq;
 import org.apache.iotdb.mpp.rpc.thrift.TDropFunctionRequest;
+import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListReq;
+import org.apache.iotdb.mpp.rpc.thrift.TInvalidateMatchedSchemaCacheReq;
 import org.apache.iotdb.mpp.rpc.thrift.TRegionRouteReq;
+import org.apache.iotdb.mpp.rpc.thrift.TRollbackSchemaBlackListReq;
 import org.apache.iotdb.mpp.rpc.thrift.TUpdateConfigNodeGroupReq;
 
 import org.slf4j.Logger;
@@ -166,6 +179,35 @@ public class AsyncDataNodeClientPool {
                 new UpdateConfigNodeGroupHandler(
                     countDownLatch, requestType, targetDataNode, dataNodeLocationMap);
             break;
+          case CONSTRUCT_SCHEMA_BLACK_LIST:
+            handler =
+                new ConstructSchemaBlackListHandler(
+                    countDownLatch, targetDataNode, dataNodeLocationMap);
+            break;
+          case ROLLBACK_SCHEMA_BLACK_LIST:
+            handler =
+                new RollbackSchemaBlackListHandler(
+                    countDownLatch, targetDataNode, dataNodeLocationMap);
+            break;
+          case FETCH_SCHEMA_BLACK_LIST:
+            handler =
+                new FetchSchemaBlackLsitHandler(
+                    countDownLatch, targetDataNode, dataNodeLocationMap);
+            break;
+          case INVALIDATE_MATCHED_SCHEMA_CACHE:
+            handler =
+                new InvalidateMatchedSchemaCacheHandler(
+                    countDownLatch, targetDataNode, dataNodeLocationMap);
+            break;
+          case DELETE_DATA_FOR_DELETE_TIMESERIES:
+            handler =
+                new DeleteDataForDeleteTimeSeriesHandler(
+                    countDownLatch, targetDataNode, dataNodeLocationMap);
+            break;
+          case DELETE_TIMESERIES:
+            handler =
+                new DeleteTimeSeriesHandler(countDownLatch, targetDataNode, dataNodeLocationMap);
+            break;
           default:
             return;
         }
@@ -183,6 +225,33 @@ public class AsyncDataNodeClientPool {
     }
   }
 
+  public void sendAsyncRequestToDataNodeWithRetry(
+      Object req, AbstractDataNodeTask<?> dataNodeTask) {
+    Map<Integer, TDataNodeLocation> dataNodeLocationMap = dataNodeTask.getDataNodeLocationMap();
+    if (dataNodeLocationMap.isEmpty()) {
+      return;
+    }
+    for (int retry = 0; retry < MAX_RETRY_NUM; retry++) {
+      CountDownLatch countDownLatch = new CountDownLatch(dataNodeLocationMap.size());
+      for (TDataNodeLocation targetDataNode : dataNodeLocationMap.values()) {
+        AbstractRetryHandler handler = dataNodeTask.getSingleRequestHandler();
+        handler.setCountDownLatch(countDownLatch);
+        handler.setTargetDataNode(targetDataNode);
+        sendAsyncRequestToDataNode(targetDataNode, req, handler, retry);
+      }
+
+      try {
+        countDownLatch.await();
+      } catch (InterruptedException e) {
+        LOGGER.error("Interrupted during {} on ConfigNode", dataNodeTask.getDataNodeRequestType());
+      }
+      // Check if there is a node that fails to send the request, and retry if there is one
+      if (dataNodeLocationMap.isEmpty()) {
+        break;
+      }
+    }
+  }
+
   public void sendAsyncRequestToDataNode(
       TDataNodeLocation dataNodeLocation,
       Object req,
@@ -230,6 +299,31 @@ public class AsyncDataNodeClientPool {
           client.updateConfigNodeGroup(
               (TUpdateConfigNodeGroupReq) req, (UpdateConfigNodeGroupHandler) handler);
           break;
+        case CONSTRUCT_SCHEMA_BLACK_LIST:
+          client.constructSchemaBlackList(
+              (TConstructSchemaBlackListReq) req, (ConstructSchemaBlackListHandler) handler);
+          break;
+        case ROLLBACK_SCHEMA_BLACK_LIST:
+          client.rollbackSchemaBlackList(
+              (TRollbackSchemaBlackListReq) req, (RollbackSchemaBlackListHandler) handler);
+          break;
+        case FETCH_SCHEMA_BLACK_LIST:
+          client.fetchSchemaBlackList(
+              (TFetchSchemaBlackListReq) req, (FetchSchemaBlackLsitHandler) handler);
+          break;
+        case INVALIDATE_MATCHED_SCHEMA_CACHE:
+          client.invalidateMatchedSchemaCache(
+              (TInvalidateMatchedSchemaCacheReq) req,
+              (InvalidateMatchedSchemaCacheHandler) handler);
+          break;
+        case DELETE_DATA_FOR_DELETE_TIMESERIES:
+          client.deleteDataForDeleteTimeSeries(
+              (TDeleteDataForDeleteTimeSeriesReq) req,
+              (DeleteDataForDeleteTimeSeriesHandler) handler);
+          break;
+        case DELETE_TIMESERIES:
+          client.deleteTimeSeries((TDeleteTimeSeriesReq) req, (DeleteTimeSeriesHandler) handler);
+          break;
         default:
           LOGGER.error(
               "Unexpected DataNode Request Type: {} when sendAsyncRequestToDataNode",
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
index 6d882ecbd2..b3a5fd9328 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
@@ -50,7 +50,26 @@ public abstract class AbstractRetryHandler {
     this.targetDataNode = targetDataNode;
   }
 
+  public AbstractRetryHandler(
+      DataNodeRequestType dataNodeRequestType,
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    this.dataNodeLocationMap = dataNodeLocationMap;
+    this.dataNodeRequestType = dataNodeRequestType;
+  }
+
   public DataNodeRequestType getDataNodeRequestType() {
     return dataNodeRequestType;
   }
+
+  public Map<Integer, TDataNodeLocation> getDataNodeLocationMap() {
+    return dataNodeLocationMap;
+  }
+
+  public void setCountDownLatch(CountDownLatch countDownLatch) {
+    this.countDownLatch = countDownLatch;
+  }
+
+  public void setTargetDataNode(TDataNodeLocation targetDataNode) {
+    this.targetDataNode = targetDataNode;
+  }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/ConstructSchemaBlackListHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/ConstructSchemaBlackListHandler.java
new file mode 100644
index 0000000000..bce6a47d5b
--- /dev/null
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/ConstructSchemaBlackListHandler.java
@@ -0,0 +1,95 @@
+/*
+ * 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.client.async.handlers;
+
+import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.rpc.RpcUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+public class ConstructSchemaBlackListHandler extends AbstractRetryHandler
+    implements AsyncMethodCallback<TSStatus> {
+
+  private static final Logger LOGGER =
+      LoggerFactory.getLogger(ConstructSchemaBlackListHandler.class);
+
+  private Map<Integer, TSStatus> dataNodeResponseStatusMap;
+
+  public ConstructSchemaBlackListHandler(
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap,
+      Map<Integer, TSStatus> dataNodeResponseStatusMap) {
+    super(DataNodeRequestType.CONSTRUCT_SCHEMA_BLACK_LIST, dataNodeLocationMap);
+    this.dataNodeResponseStatusMap = dataNodeResponseStatusMap;
+  }
+
+  public ConstructSchemaBlackListHandler(
+      CountDownLatch countDownLatch,
+      TDataNodeLocation targetDataNode,
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(
+        countDownLatch,
+        DataNodeRequestType.CONSTRUCT_SCHEMA_BLACK_LIST,
+        targetDataNode,
+        dataNodeLocationMap);
+    this.dataNodeResponseStatusMap = new ConcurrentHashMap<>();
+  }
+
+  @Override
+  public void onComplete(TSStatus tsStatus) {
+    dataNodeResponseStatusMap.put(targetDataNode.getDataNodeId(), tsStatus);
+    if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.info("Successfully construct schema black list on DataNode: {}", targetDataNode);
+    } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.error(
+          "Failed to construct schema black list on DataNode {}, {}", targetDataNode, tsStatus);
+    } else {
+      LOGGER.error(
+          "Failed to construct schema black list on DataNode {}, {}", targetDataNode, tsStatus);
+    }
+    countDownLatch.countDown();
+  }
+
+  @Override
+  public void onError(Exception e) {
+    countDownLatch.countDown();
+    dataNodeResponseStatusMap.put(
+        targetDataNode.dataNodeId,
+        new TSStatus(
+            RpcUtils.getStatus(
+                TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(),
+                "Construct schema black list error on DataNode: {id="
+                    + targetDataNode.getDataNodeId()
+                    + ", internalEndPoint="
+                    + targetDataNode.getInternalEndPoint()
+                    + "}"
+                    + e.getMessage())));
+  }
+}
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/DeleteDataForDeleteTimeSeriesHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/DeleteDataForDeleteTimeSeriesHandler.java
new file mode 100644
index 0000000000..d72fee586a
--- /dev/null
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/DeleteDataForDeleteTimeSeriesHandler.java
@@ -0,0 +1,103 @@
+/*
+ * 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.client.async.handlers;
+
+import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.rpc.RpcUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+public class DeleteDataForDeleteTimeSeriesHandler extends AbstractRetryHandler
+    implements AsyncMethodCallback<TSStatus> {
+
+  private static final Logger LOGGER =
+      LoggerFactory.getLogger(DeleteDataForDeleteTimeSeriesHandler.class);
+
+  private Map<Integer, TSStatus> dataNodeResponseStatusMap;
+
+  public DeleteDataForDeleteTimeSeriesHandler(
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap,
+      Map<Integer, TSStatus> dataNodeResponseStatusMap) {
+    super(DataNodeRequestType.DELETE_DATA_FOR_DELETE_TIMESERIES, dataNodeLocationMap);
+    this.dataNodeResponseStatusMap = dataNodeResponseStatusMap;
+  }
+
+  public DeleteDataForDeleteTimeSeriesHandler(
+      CountDownLatch countDownLatch,
+      TDataNodeLocation targetDataNode,
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(
+        countDownLatch,
+        DataNodeRequestType.DELETE_DATA_FOR_DELETE_TIMESERIES,
+        targetDataNode,
+        dataNodeLocationMap);
+    this.dataNodeResponseStatusMap = new ConcurrentHashMap<>();
+  }
+
+  public Map<Integer, TSStatus> getDataNodeResponseStatusMap() {
+    return dataNodeResponseStatusMap;
+  }
+
+  @Override
+  public void onComplete(TSStatus tsStatus) {
+    dataNodeResponseStatusMap.put(targetDataNode.getDataNodeId(), tsStatus);
+    if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.info("Successfully delete data for delete timeseries on DataNode: {}", targetDataNode);
+    } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.error(
+          "Failed to delete data for delete timeseries on DataNode {}, {}",
+          targetDataNode,
+          tsStatus);
+    } else {
+      LOGGER.error(
+          "Failed to delete data for delete timeseries on DataNode {}, {}",
+          targetDataNode,
+          tsStatus);
+    }
+    countDownLatch.countDown();
+  }
+
+  @Override
+  public void onError(Exception e) {
+    countDownLatch.countDown();
+    dataNodeResponseStatusMap.put(
+        targetDataNode.dataNodeId,
+        new TSStatus(
+            RpcUtils.getStatus(
+                TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(),
+                "Delete data for delete timeseries error on DataNode: {id="
+                    + targetDataNode.getDataNodeId()
+                    + ", internalEndPoint="
+                    + targetDataNode.getInternalEndPoint()
+                    + "}"
+                    + e.getMessage())));
+  }
+}
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/DeleteTimeSeriesHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/DeleteTimeSeriesHandler.java
new file mode 100644
index 0000000000..e7c0cea47b
--- /dev/null
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/DeleteTimeSeriesHandler.java
@@ -0,0 +1,93 @@
+/*
+ * 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.client.async.handlers;
+
+import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.rpc.RpcUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+public class DeleteTimeSeriesHandler extends AbstractRetryHandler
+    implements AsyncMethodCallback<TSStatus> {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(DeleteTimeSeriesHandler.class);
+
+  private Map<Integer, TSStatus> dataNodeResponseStatusMap;
+
+  public DeleteTimeSeriesHandler(
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap,
+      Map<Integer, TSStatus> dataNodeResponseStatusMap) {
+    super(DataNodeRequestType.DELETE_TIMESERIES, dataNodeLocationMap);
+    this.dataNodeResponseStatusMap = dataNodeResponseStatusMap;
+  }
+
+  public DeleteTimeSeriesHandler(
+      CountDownLatch countDownLatch,
+      TDataNodeLocation targetDataNode,
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(
+        countDownLatch, DataNodeRequestType.DELETE_TIMESERIES, targetDataNode, dataNodeLocationMap);
+    dataNodeResponseStatusMap = new ConcurrentHashMap<>();
+  }
+
+  public Map<Integer, TSStatus> getDataNodeResponseStatusMap() {
+    return dataNodeResponseStatusMap;
+  }
+
+  @Override
+  public void onComplete(TSStatus tsStatus) {
+    dataNodeResponseStatusMap.put(targetDataNode.getDataNodeId(), tsStatus);
+    if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.info("Successfully delete timeseries on DataNode: {}", targetDataNode);
+    } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.error("Failed to delete timeseries on DataNode {}, {}", targetDataNode, tsStatus);
+    } else {
+      LOGGER.error("Failed to delete timeseries on DataNode {}, {}", targetDataNode, tsStatus);
+    }
+    countDownLatch.countDown();
+  }
+
+  @Override
+  public void onError(Exception e) {
+    countDownLatch.countDown();
+    dataNodeResponseStatusMap.put(
+        targetDataNode.dataNodeId,
+        new TSStatus(
+            RpcUtils.getStatus(
+                TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(),
+                "Delete timeseries error on DataNode: {id="
+                    + targetDataNode.getDataNodeId()
+                    + ", internalEndPoint="
+                    + targetDataNode.getInternalEndPoint()
+                    + "}"
+                    + e.getMessage())));
+  }
+}
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/FetchSchemaBlackLsitHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/FetchSchemaBlackLsitHandler.java
new file mode 100644
index 0000000000..9db74c5f59
--- /dev/null
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/FetchSchemaBlackLsitHandler.java
@@ -0,0 +1,101 @@
+/*
+ * 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.client.async.handlers;
+
+import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListResp;
+import org.apache.iotdb.rpc.RpcUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+public class FetchSchemaBlackLsitHandler extends AbstractRetryHandler
+    implements AsyncMethodCallback<TFetchSchemaBlackListResp> {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(FetchSchemaBlackLsitHandler.class);
+
+  private Map<Integer, TFetchSchemaBlackListResp> dataNodeResponseMap;
+
+  public FetchSchemaBlackLsitHandler(
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap,
+      Map<Integer, TFetchSchemaBlackListResp> dataNodeResponseMap) {
+    super(DataNodeRequestType.FETCH_SCHEMA_BLACK_LIST, dataNodeLocationMap);
+    this.dataNodeResponseMap = dataNodeResponseMap;
+  }
+
+  public FetchSchemaBlackLsitHandler(
+      CountDownLatch countDownLatch,
+      TDataNodeLocation targetDataNode,
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(
+        countDownLatch,
+        DataNodeRequestType.FETCH_SCHEMA_BLACK_LIST,
+        targetDataNode,
+        dataNodeLocationMap);
+    this.dataNodeResponseMap = new ConcurrentHashMap<>();
+  }
+
+  public Map<Integer, TFetchSchemaBlackListResp> getDataNodeResponseMap() {
+    return dataNodeResponseMap;
+  }
+
+  @Override
+  public void onComplete(TFetchSchemaBlackListResp tFetchSchemaBlackListResp) {
+    TSStatus tsStatus = tFetchSchemaBlackListResp.getStatus();
+    dataNodeResponseMap.put(targetDataNode.getDataNodeId(), tFetchSchemaBlackListResp);
+    if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.info("Successfully fetch schema black list on DataNode: {}", targetDataNode);
+    } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.error(
+          "Failed to fetch schema black list on DataNode {}, {}", targetDataNode, tsStatus);
+    } else {
+      LOGGER.error(
+          "Failed to fetch schema black list on DataNode {}, {}", targetDataNode, tsStatus);
+    }
+    countDownLatch.countDown();
+  }
+
+  @Override
+  public void onError(Exception e) {
+    countDownLatch.countDown();
+    TFetchSchemaBlackListResp resp = new TFetchSchemaBlackListResp();
+    resp.setStatus(
+        new TSStatus(
+            RpcUtils.getStatus(
+                TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(),
+                "Fetch schema black list error on DataNode: {id="
+                    + targetDataNode.getDataNodeId()
+                    + ", internalEndPoint="
+                    + targetDataNode.getInternalEndPoint()
+                    + "}"
+                    + e.getMessage())));
+    dataNodeResponseMap.put(targetDataNode.getDataNodeId(), resp);
+  }
+}
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/InvalidateMatchedSchemaCacheHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/InvalidateMatchedSchemaCacheHandler.java
new file mode 100644
index 0000000000..b620560fad
--- /dev/null
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/InvalidateMatchedSchemaCacheHandler.java
@@ -0,0 +1,95 @@
+/*
+ * 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.client.async.handlers;
+
+import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.rpc.RpcUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+public class InvalidateMatchedSchemaCacheHandler extends AbstractRetryHandler
+    implements AsyncMethodCallback<TSStatus> {
+
+  private static final Logger LOGGER =
+      LoggerFactory.getLogger(InvalidateMatchedSchemaCacheHandler.class);
+
+  private Map<Integer, TSStatus> dataNodeResponseStatusMap;
+
+  public InvalidateMatchedSchemaCacheHandler(
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap,
+      Map<Integer, TSStatus> dataNodeResponseStatusMap) {
+    super(DataNodeRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, dataNodeLocationMap);
+    this.dataNodeResponseStatusMap = dataNodeResponseStatusMap;
+  }
+
+  public InvalidateMatchedSchemaCacheHandler(
+      CountDownLatch countDownLatch,
+      TDataNodeLocation targetDataNode,
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(
+        countDownLatch,
+        DataNodeRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE,
+        targetDataNode,
+        dataNodeLocationMap);
+    this.dataNodeResponseStatusMap = new ConcurrentHashMap<>();
+  }
+
+  public Map<Integer, TSStatus> getDataNodeResponseStatusMap() {
+    return dataNodeResponseStatusMap;
+  }
+
+  @Override
+  public void onComplete(TSStatus tsStatus) {
+    dataNodeResponseStatusMap.put(targetDataNode.getDataNodeId(), tsStatus);
+    if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.info("Successfully invalidate matched schema cache on DataNode: {}", targetDataNode);
+    } else {
+      LOGGER.error(
+          "Failed to invalidate matched schema cache on DataNode {}, {}", targetDataNode, tsStatus);
+    }
+    countDownLatch.countDown();
+  }
+
+  @Override
+  public void onError(Exception e) {
+    countDownLatch.countDown();
+    dataNodeResponseStatusMap.put(
+        targetDataNode.getDataNodeId(),
+        new TSStatus(
+            RpcUtils.getStatus(
+                TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(),
+                "Invalidate matched schema cache error on DataNode: {id="
+                    + targetDataNode.getDataNodeId()
+                    + ", internalEndPoint="
+                    + targetDataNode.getInternalEndPoint()
+                    + "}"
+                    + e.getMessage())));
+  }
+}
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/RollbackSchemaBlackListHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/RollbackSchemaBlackListHandler.java
new file mode 100644
index 0000000000..c1ea9b08f1
--- /dev/null
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/RollbackSchemaBlackListHandler.java
@@ -0,0 +1,99 @@
+/*
+ * 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.client.async.handlers;
+
+import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.rpc.RpcUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+public class RollbackSchemaBlackListHandler extends AbstractRetryHandler
+    implements AsyncMethodCallback<TSStatus> {
+
+  private static final Logger LOGGER =
+      LoggerFactory.getLogger(RollbackSchemaBlackListHandler.class);
+
+  private Map<Integer, TSStatus> dataNodeResponseStatusMap;
+
+  public RollbackSchemaBlackListHandler(
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap,
+      Map<Integer, TSStatus> dataNodeResponseStatusMap) {
+    super(DataNodeRequestType.ROLLBACK_SCHEMA_BLACK_LIST, dataNodeLocationMap);
+    this.dataNodeResponseStatusMap = dataNodeResponseStatusMap;
+  }
+
+  public RollbackSchemaBlackListHandler(
+      CountDownLatch countDownLatch,
+      TDataNodeLocation targetDataNode,
+      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(
+        countDownLatch,
+        DataNodeRequestType.ROLLBACK_SCHEMA_BLACK_LIST,
+        targetDataNode,
+        dataNodeLocationMap);
+    this.dataNodeResponseStatusMap = new ConcurrentHashMap<>();
+  }
+
+  public Map<Integer, TSStatus> getDataNodeResponseStatusMap() {
+    return dataNodeResponseStatusMap;
+  }
+
+  @Override
+  public void onComplete(TSStatus tsStatus) {
+    dataNodeResponseStatusMap.put(targetDataNode.getDataNodeId(), tsStatus);
+    if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.info("Successfully rollback schema black list on DataNode: {}", targetDataNode);
+    } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) {
+      dataNodeLocationMap.remove(targetDataNode.getDataNodeId());
+      LOGGER.error(
+          "Failed to rollback schema black list on DataNode {}, {}", targetDataNode, tsStatus);
+    } else {
+      LOGGER.error(
+          "Failed to rollback schema black list on DataNode {}, {}", targetDataNode, tsStatus);
+    }
+    countDownLatch.countDown();
+  }
+
+  @Override
+  public void onError(Exception e) {
+    countDownLatch.countDown();
+    dataNodeResponseStatusMap.put(
+        targetDataNode.getDataNodeId(),
+        new TSStatus(
+            RpcUtils.getStatus(
+                TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(),
+                "Rollback schema black list error on DataNode: {id="
+                    + targetDataNode.getDataNodeId()
+                    + ", internalEndPoint="
+                    + targetDataNode.getInternalEndPoint()
+                    + "}"
+                    + e.getMessage())));
+  }
+}
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/AbstractDataNodeTask.java
similarity index 54%
copy from confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
copy to confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/AbstractDataNodeTask.java
index 6d882ecbd2..10671031f0 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/AbstractDataNodeTask.java
@@ -17,40 +17,37 @@
  * under the License.
  */
 
-package org.apache.iotdb.confignode.client.async.handlers;
+package org.apache.iotdb.confignode.client.async.task;
 
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
 import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.confignode.client.async.handlers.AbstractRetryHandler;
 
 import java.util.Map;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ConcurrentHashMap;
 
-public abstract class AbstractRetryHandler {
+public abstract class AbstractDataNodeTask<T> {
 
-  protected CountDownLatch countDownLatch;
-
-  /**
-   * Map<DataNodeId, TDataNodeLocation> The DataNode that successfully execute the request will be
-   * removed from this list
-   */
   protected Map<Integer, TDataNodeLocation> dataNodeLocationMap;
-  /** Request type to DataNode */
-  protected DataNodeRequestType dataNodeRequestType;
-  /** Target DataNode */
-  protected TDataNodeLocation targetDataNode;
-
-  public AbstractRetryHandler(
-      CountDownLatch countDownLatch,
-      DataNodeRequestType dataNodeRequestType,
-      TDataNodeLocation targetDataNode,
-      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
-    this.countDownLatch = countDownLatch;
+
+  protected Map<Integer, T> dataNodeResponseMap = new ConcurrentHashMap<>();
+
+  /** Must provide thread-safe map */
+  public AbstractDataNodeTask(Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
     this.dataNodeLocationMap = dataNodeLocationMap;
-    this.dataNodeRequestType = dataNodeRequestType;
-    this.targetDataNode = targetDataNode;
   }
 
-  public DataNodeRequestType getDataNodeRequestType() {
-    return dataNodeRequestType;
+  public Map<Integer, TDataNodeLocation> getDataNodeLocationMap() {
+    return dataNodeLocationMap;
+  }
+
+  public abstract DataNodeRequestType getDataNodeRequestType();
+
+  /** Provide the handler for single rpc process */
+  public abstract AbstractRetryHandler getSingleRequestHandler();
+
+  /** Get the final responses from all dataNodes */
+  public Map<Integer, T> getDataNodeResponseMap() {
+    return dataNodeResponseMap;
   }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/ConstructSchemaBlackListDataNodeTask.java
similarity index 50%
copy from confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
copy to confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/ConstructSchemaBlackListDataNodeTask.java
index 6d882ecbd2..9e12a1b61b 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/ConstructSchemaBlackListDataNodeTask.java
@@ -17,40 +17,29 @@
  * under the License.
  */
 
-package org.apache.iotdb.confignode.client.async.handlers;
+package org.apache.iotdb.confignode.client.async.task;
 
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.confignode.client.async.handlers.AbstractRetryHandler;
+import org.apache.iotdb.confignode.client.async.handlers.ConstructSchemaBlackListHandler;
 
 import java.util.Map;
-import java.util.concurrent.CountDownLatch;
 
-public abstract class AbstractRetryHandler {
+public class ConstructSchemaBlackListDataNodeTask extends AbstractDataNodeTask<TSStatus> {
 
-  protected CountDownLatch countDownLatch;
-
-  /**
-   * Map<DataNodeId, TDataNodeLocation> The DataNode that successfully execute the request will be
-   * removed from this list
-   */
-  protected Map<Integer, TDataNodeLocation> dataNodeLocationMap;
-  /** Request type to DataNode */
-  protected DataNodeRequestType dataNodeRequestType;
-  /** Target DataNode */
-  protected TDataNodeLocation targetDataNode;
-
-  public AbstractRetryHandler(
-      CountDownLatch countDownLatch,
-      DataNodeRequestType dataNodeRequestType,
-      TDataNodeLocation targetDataNode,
-      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
-    this.countDownLatch = countDownLatch;
-    this.dataNodeLocationMap = dataNodeLocationMap;
-    this.dataNodeRequestType = dataNodeRequestType;
-    this.targetDataNode = targetDataNode;
+  public ConstructSchemaBlackListDataNodeTask(Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(dataNodeLocationMap);
   }
 
+  @Override
   public DataNodeRequestType getDataNodeRequestType() {
-    return dataNodeRequestType;
+    return DataNodeRequestType.CONSTRUCT_SCHEMA_BLACK_LIST;
+  }
+
+  @Override
+  public AbstractRetryHandler getSingleRequestHandler() {
+    return new ConstructSchemaBlackListHandler(dataNodeLocationMap, dataNodeResponseMap);
   }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/DeleteDataForDeleteTimeSeriesDataNodeTask.java
similarity index 53%
copy from confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
copy to confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/DeleteDataForDeleteTimeSeriesDataNodeTask.java
index 6d882ecbd2..089068aa51 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/DeleteDataForDeleteTimeSeriesDataNodeTask.java
@@ -17,40 +17,30 @@
  * under the License.
  */
 
-package org.apache.iotdb.confignode.client.async.handlers;
+package org.apache.iotdb.confignode.client.async.task;
 
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.confignode.client.async.handlers.AbstractRetryHandler;
+import org.apache.iotdb.confignode.client.async.handlers.DeleteDataForDeleteTimeSeriesHandler;
 
 import java.util.Map;
-import java.util.concurrent.CountDownLatch;
 
-public abstract class AbstractRetryHandler {
+public class DeleteDataForDeleteTimeSeriesDataNodeTask extends AbstractDataNodeTask<TSStatus> {
 
-  protected CountDownLatch countDownLatch;
-
-  /**
-   * Map<DataNodeId, TDataNodeLocation> The DataNode that successfully execute the request will be
-   * removed from this list
-   */
-  protected Map<Integer, TDataNodeLocation> dataNodeLocationMap;
-  /** Request type to DataNode */
-  protected DataNodeRequestType dataNodeRequestType;
-  /** Target DataNode */
-  protected TDataNodeLocation targetDataNode;
-
-  public AbstractRetryHandler(
-      CountDownLatch countDownLatch,
-      DataNodeRequestType dataNodeRequestType,
-      TDataNodeLocation targetDataNode,
+  public DeleteDataForDeleteTimeSeriesDataNodeTask(
       Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
-    this.countDownLatch = countDownLatch;
-    this.dataNodeLocationMap = dataNodeLocationMap;
-    this.dataNodeRequestType = dataNodeRequestType;
-    this.targetDataNode = targetDataNode;
+    super(dataNodeLocationMap);
   }
 
+  @Override
   public DataNodeRequestType getDataNodeRequestType() {
-    return dataNodeRequestType;
+    return DataNodeRequestType.DELETE_DATA_FOR_DELETE_TIMESERIES;
+  }
+
+  @Override
+  public AbstractRetryHandler getSingleRequestHandler() {
+    return new DeleteDataForDeleteTimeSeriesHandler(dataNodeLocationMap, dataNodeResponseMap);
   }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/DeleteTimeSeriesDataNodeTask.java
similarity index 50%
copy from confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
copy to confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/DeleteTimeSeriesDataNodeTask.java
index 6d882ecbd2..caf67790c2 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/DeleteTimeSeriesDataNodeTask.java
@@ -17,40 +17,29 @@
  * under the License.
  */
 
-package org.apache.iotdb.confignode.client.async.handlers;
+package org.apache.iotdb.confignode.client.async.task;
 
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.confignode.client.async.handlers.AbstractRetryHandler;
+import org.apache.iotdb.confignode.client.async.handlers.DeleteTimeSeriesHandler;
 
 import java.util.Map;
-import java.util.concurrent.CountDownLatch;
 
-public abstract class AbstractRetryHandler {
+public class DeleteTimeSeriesDataNodeTask extends AbstractDataNodeTask<TSStatus> {
 
-  protected CountDownLatch countDownLatch;
-
-  /**
-   * Map<DataNodeId, TDataNodeLocation> The DataNode that successfully execute the request will be
-   * removed from this list
-   */
-  protected Map<Integer, TDataNodeLocation> dataNodeLocationMap;
-  /** Request type to DataNode */
-  protected DataNodeRequestType dataNodeRequestType;
-  /** Target DataNode */
-  protected TDataNodeLocation targetDataNode;
-
-  public AbstractRetryHandler(
-      CountDownLatch countDownLatch,
-      DataNodeRequestType dataNodeRequestType,
-      TDataNodeLocation targetDataNode,
-      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
-    this.countDownLatch = countDownLatch;
-    this.dataNodeLocationMap = dataNodeLocationMap;
-    this.dataNodeRequestType = dataNodeRequestType;
-    this.targetDataNode = targetDataNode;
+  public DeleteTimeSeriesDataNodeTask(Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(dataNodeLocationMap);
   }
 
+  @Override
   public DataNodeRequestType getDataNodeRequestType() {
-    return dataNodeRequestType;
+    return DataNodeRequestType.DELETE_TIMESERIES;
+  }
+
+  @Override
+  public AbstractRetryHandler getSingleRequestHandler() {
+    return new DeleteTimeSeriesHandler(dataNodeLocationMap, dataNodeResponseMap);
   }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/FetchSchemaBlackListDataNodeTask.java
similarity index 50%
copy from confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
copy to confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/FetchSchemaBlackListDataNodeTask.java
index 6d882ecbd2..8545b7dd5c 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/FetchSchemaBlackListDataNodeTask.java
@@ -17,40 +17,30 @@
  * under the License.
  */
 
-package org.apache.iotdb.confignode.client.async.handlers;
+package org.apache.iotdb.confignode.client.async.task;
 
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
 import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.confignode.client.async.handlers.AbstractRetryHandler;
+import org.apache.iotdb.confignode.client.async.handlers.FetchSchemaBlackLsitHandler;
+import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListResp;
 
 import java.util.Map;
-import java.util.concurrent.CountDownLatch;
 
-public abstract class AbstractRetryHandler {
+public class FetchSchemaBlackListDataNodeTask
+    extends AbstractDataNodeTask<TFetchSchemaBlackListResp> {
 
-  protected CountDownLatch countDownLatch;
-
-  /**
-   * Map<DataNodeId, TDataNodeLocation> The DataNode that successfully execute the request will be
-   * removed from this list
-   */
-  protected Map<Integer, TDataNodeLocation> dataNodeLocationMap;
-  /** Request type to DataNode */
-  protected DataNodeRequestType dataNodeRequestType;
-  /** Target DataNode */
-  protected TDataNodeLocation targetDataNode;
-
-  public AbstractRetryHandler(
-      CountDownLatch countDownLatch,
-      DataNodeRequestType dataNodeRequestType,
-      TDataNodeLocation targetDataNode,
-      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
-    this.countDownLatch = countDownLatch;
-    this.dataNodeLocationMap = dataNodeLocationMap;
-    this.dataNodeRequestType = dataNodeRequestType;
-    this.targetDataNode = targetDataNode;
+  public FetchSchemaBlackListDataNodeTask(Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(dataNodeLocationMap);
   }
 
+  @Override
   public DataNodeRequestType getDataNodeRequestType() {
-    return dataNodeRequestType;
+    return DataNodeRequestType.FETCH_SCHEMA_BLACK_LIST;
+  }
+
+  @Override
+  public AbstractRetryHandler getSingleRequestHandler() {
+    return new FetchSchemaBlackLsitHandler(dataNodeLocationMap, dataNodeResponseMap);
   }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/InvalidateMatchedSchemaCacheDataNodeTask.java
similarity index 53%
copy from confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
copy to confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/InvalidateMatchedSchemaCacheDataNodeTask.java
index 6d882ecbd2..2a08fdcb99 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/InvalidateMatchedSchemaCacheDataNodeTask.java
@@ -17,40 +17,30 @@
  * under the License.
  */
 
-package org.apache.iotdb.confignode.client.async.handlers;
+package org.apache.iotdb.confignode.client.async.task;
 
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.confignode.client.async.handlers.AbstractRetryHandler;
+import org.apache.iotdb.confignode.client.async.handlers.InvalidateMatchedSchemaCacheHandler;
 
 import java.util.Map;
-import java.util.concurrent.CountDownLatch;
 
-public abstract class AbstractRetryHandler {
+public class InvalidateMatchedSchemaCacheDataNodeTask extends AbstractDataNodeTask<TSStatus> {
 
-  protected CountDownLatch countDownLatch;
-
-  /**
-   * Map<DataNodeId, TDataNodeLocation> The DataNode that successfully execute the request will be
-   * removed from this list
-   */
-  protected Map<Integer, TDataNodeLocation> dataNodeLocationMap;
-  /** Request type to DataNode */
-  protected DataNodeRequestType dataNodeRequestType;
-  /** Target DataNode */
-  protected TDataNodeLocation targetDataNode;
-
-  public AbstractRetryHandler(
-      CountDownLatch countDownLatch,
-      DataNodeRequestType dataNodeRequestType,
-      TDataNodeLocation targetDataNode,
+  public InvalidateMatchedSchemaCacheDataNodeTask(
       Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
-    this.countDownLatch = countDownLatch;
-    this.dataNodeLocationMap = dataNodeLocationMap;
-    this.dataNodeRequestType = dataNodeRequestType;
-    this.targetDataNode = targetDataNode;
+    super(dataNodeLocationMap);
   }
 
+  @Override
   public DataNodeRequestType getDataNodeRequestType() {
-    return dataNodeRequestType;
+    return DataNodeRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE;
+  }
+
+  @Override
+  public AbstractRetryHandler getSingleRequestHandler() {
+    return new InvalidateMatchedSchemaCacheHandler(dataNodeLocationMap, dataNodeResponseMap);
   }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/RollbackSchemaBlackListDataNodeTask.java
similarity index 50%
copy from confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
copy to confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/RollbackSchemaBlackListDataNodeTask.java
index 6d882ecbd2..3a24ae7898 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AbstractRetryHandler.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/client/async/task/RollbackSchemaBlackListDataNodeTask.java
@@ -17,40 +17,29 @@
  * under the License.
  */
 
-package org.apache.iotdb.confignode.client.async.handlers;
+package org.apache.iotdb.confignode.client.async.task;
 
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.confignode.client.DataNodeRequestType;
+import org.apache.iotdb.confignode.client.async.handlers.AbstractRetryHandler;
+import org.apache.iotdb.confignode.client.async.handlers.RollbackSchemaBlackListHandler;
 
 import java.util.Map;
-import java.util.concurrent.CountDownLatch;
 
-public abstract class AbstractRetryHandler {
+public class RollbackSchemaBlackListDataNodeTask extends AbstractDataNodeTask<TSStatus> {
 
-  protected CountDownLatch countDownLatch;
-
-  /**
-   * Map<DataNodeId, TDataNodeLocation> The DataNode that successfully execute the request will be
-   * removed from this list
-   */
-  protected Map<Integer, TDataNodeLocation> dataNodeLocationMap;
-  /** Request type to DataNode */
-  protected DataNodeRequestType dataNodeRequestType;
-  /** Target DataNode */
-  protected TDataNodeLocation targetDataNode;
-
-  public AbstractRetryHandler(
-      CountDownLatch countDownLatch,
-      DataNodeRequestType dataNodeRequestType,
-      TDataNodeLocation targetDataNode,
-      Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
-    this.countDownLatch = countDownLatch;
-    this.dataNodeLocationMap = dataNodeLocationMap;
-    this.dataNodeRequestType = dataNodeRequestType;
-    this.targetDataNode = targetDataNode;
+  public RollbackSchemaBlackListDataNodeTask(Map<Integer, TDataNodeLocation> dataNodeLocationMap) {
+    super(dataNodeLocationMap);
   }
 
+  @Override
   public DataNodeRequestType getDataNodeRequestType() {
-    return dataNodeRequestType;
+    return DataNodeRequestType.ROLLBACK_SCHEMA_BLACK_LIST;
+  }
+
+  @Override
+  public AbstractRetryHandler getSingleRequestHandler() {
+    return new RollbackSchemaBlackListHandler(dataNodeLocationMap, dataNodeResponseMap);
   }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index d19b889a7a..77766d78ed 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -25,8 +25,10 @@ import org.apache.iotdb.common.rpc.thrift.TConsensusGroupType;
 import org.apache.iotdb.common.rpc.thrift.TDataNodeConfiguration;
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
 import org.apache.iotdb.common.rpc.thrift.TFlushReq;
+import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.common.rpc.thrift.TSeriesPartitionSlot;
+import org.apache.iotdb.common.rpc.thrift.TTimePartitionSlot;
 import org.apache.iotdb.commons.cluster.RegionRoleType;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
@@ -79,6 +81,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterReq;
 import org.apache.iotdb.confignode.rpc.thrift.TCreateSchemaTemplateReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDataNodeInfo;
 import org.apache.iotdb.confignode.rpc.thrift.TDataPartitionTableResp;
+import org.apache.iotdb.confignode.rpc.thrift.TDeleteTimeSeriesReq;
 import org.apache.iotdb.confignode.rpc.thrift.TGetAllTemplatesResp;
 import org.apache.iotdb.confignode.rpc.thrift.TGetPathsSetTemplatesResp;
 import org.apache.iotdb.confignode.rpc.thrift.TGetTemplateResp;
@@ -106,6 +109,7 @@ import org.slf4j.LoggerFactory;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -966,4 +970,80 @@ public class ConfigManager implements IManager {
       return new TGetPathsSetTemplatesResp(status);
     }
   }
+
+  @Override
+  public TSStatus deleteTimeSeries(TDeleteTimeSeriesReq req) {
+    TSStatus status = confirmLeader();
+    if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      return procedureManager.deleteTimeSeries(req);
+    } else {
+      return status;
+    }
+  }
+
+  /** Get all related schemaRegion which may contains the timeseries matched by given patternTree */
+  public Map<TConsensusGroupId, TRegionReplicaSet> getRelatedSchemaRegionGroup(
+      PathPatternTree patternTree) {
+    Map<String, Map<TSeriesPartitionSlot, TConsensusGroupId>> schemaPartitionTable =
+        getSchemaPartition(patternTree).getSchemaPartitionTable();
+
+    List<TRegionReplicaSet> allRegionReplicaSets = getPartitionManager().getAllReplicaSets();
+    Set<TConsensusGroupId> groupIdSet =
+        schemaPartitionTable.values().stream()
+            .flatMap(m -> m.values().stream())
+            .collect(Collectors.toSet());
+    Map<TConsensusGroupId, TRegionReplicaSet> filteredRegionReplicaSets = new HashMap<>();
+    for (TRegionReplicaSet regionReplicaSet : allRegionReplicaSets) {
+      if (groupIdSet.contains(regionReplicaSet.getRegionId())) {
+        filteredRegionReplicaSets.put(regionReplicaSet.getRegionId(), regionReplicaSet);
+      }
+    }
+    return filteredRegionReplicaSets;
+  }
+
+  /**
+   * Get all related dataRegion which may contains the data of specific timeseries matched by given
+   * patternTree
+   */
+  public Map<TConsensusGroupId, TRegionReplicaSet> getRelatedDataRegionGroup(
+      PathPatternTree patternTree) {
+    // get all storage group and slot by getting schema partition
+    Map<String, Map<TSeriesPartitionSlot, TConsensusGroupId>> schemaPartitionTable =
+        getSchemaPartition(patternTree).getSchemaPartitionTable();
+
+    // construct request for getting data partition
+    Map<String, Map<TSeriesPartitionSlot, List<TTimePartitionSlot>>> partitionSlotsMap =
+        new HashMap<>();
+    schemaPartitionTable.forEach(
+        (key, value) -> {
+          Map<TSeriesPartitionSlot, List<TTimePartitionSlot>> slotListMap = new HashMap<>();
+          value.keySet().forEach(slot -> slotListMap.put(slot, Collections.emptyList()));
+          partitionSlotsMap.put(key, slotListMap);
+        });
+
+    // get all data partitions
+    GetDataPartitionPlan getDataPartitionPlan = new GetDataPartitionPlan(partitionSlotsMap);
+    Map<String, Map<TSeriesPartitionSlot, Map<TTimePartitionSlot, List<TConsensusGroupId>>>>
+        dataPartitionTable = getDataPartition(getDataPartitionPlan).getDataPartitionTable();
+
+    // get all region replicaset of target data partitions
+    List<TRegionReplicaSet> allRegionReplicaSets = getPartitionManager().getAllReplicaSets();
+    Set<TConsensusGroupId> groupIdSet =
+        dataPartitionTable.values().stream()
+            .flatMap(
+                tSeriesPartitionSlotMapMap ->
+                    tSeriesPartitionSlotMapMap.values().stream()
+                        .flatMap(
+                            tTimePartitionSlotListMap ->
+                                tTimePartitionSlotListMap.values().stream()
+                                    .flatMap(Collection::stream)))
+            .collect(Collectors.toSet());
+    Map<TConsensusGroupId, TRegionReplicaSet> filteredRegionReplicaSets = new HashMap<>();
+    for (TRegionReplicaSet regionReplicaSet : allRegionReplicaSets) {
+      if (groupIdSet.contains(regionReplicaSet.getRegionId())) {
+        filteredRegionReplicaSets.put(regionReplicaSet.getRegionId(), regionReplicaSet);
+      }
+    }
+    return filteredRegionReplicaSets;
+  }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java b/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java
index b989356542..08024d440f 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java
@@ -41,6 +41,7 @@ import org.apache.iotdb.confignode.manager.load.LoadManager;
 import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterReq;
 import org.apache.iotdb.confignode.rpc.thrift.TCreateSchemaTemplateReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDataPartitionTableResp;
+import org.apache.iotdb.confignode.rpc.thrift.TDeleteTimeSeriesReq;
 import org.apache.iotdb.confignode.rpc.thrift.TGetAllTemplatesResp;
 import org.apache.iotdb.confignode.rpc.thrift.TGetPathsSetTemplatesResp;
 import org.apache.iotdb.confignode.rpc.thrift.TGetTemplateResp;
@@ -350,4 +351,10 @@ public interface IManager {
    * @return TGetPathsSetTemplatesResp
    */
   TGetPathsSetTemplatesResp getPathsSetTemplate(String req);
+
+  /*
+   * delete timeseries
+   *
+   */
+  TSStatus deleteTimeSeries(TDeleteTimeSeriesReq req);
 }
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 a1cc6ad5f2..54f77248b0 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
@@ -20,6 +20,7 @@
 package org.apache.iotdb.confignode.manager;
 
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.exception.IoTDBException;
 import org.apache.iotdb.commons.utils.StatusUtils;
 import org.apache.iotdb.confignode.conf.ConfigNodeConfig;
 import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
@@ -33,6 +34,7 @@ import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv;
 import org.apache.iotdb.confignode.procedure.impl.AddConfigNodeProcedure;
 import org.apache.iotdb.confignode.procedure.impl.CreateRegionGroupsProcedure;
 import org.apache.iotdb.confignode.procedure.impl.DeleteStorageGroupProcedure;
+import org.apache.iotdb.confignode.procedure.impl.DeleteTimeSeriesProcedure;
 import org.apache.iotdb.confignode.procedure.impl.RegionMigrateProcedure;
 import org.apache.iotdb.confignode.procedure.impl.RemoveConfigNodeProcedure;
 import org.apache.iotdb.confignode.procedure.impl.RemoveDataNodeProcedure;
@@ -40,16 +42,20 @@ import org.apache.iotdb.confignode.procedure.scheduler.ProcedureScheduler;
 import org.apache.iotdb.confignode.procedure.scheduler.SimpleProcedureScheduler;
 import org.apache.iotdb.confignode.procedure.store.ConfigProcedureStore;
 import org.apache.iotdb.confignode.procedure.store.IProcedureStore;
+import org.apache.iotdb.confignode.procedure.store.ProcedureFactory;
 import org.apache.iotdb.confignode.procedure.store.ProcedureStore;
 import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterReq;
+import org.apache.iotdb.confignode.rpc.thrift.TDeleteTimeSeriesReq;
 import org.apache.iotdb.confignode.rpc.thrift.TRegionMigrateResultReportReq;
 import org.apache.iotdb.confignode.rpc.thrift.TStorageGroupSchema;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -121,6 +127,52 @@ public class ProcedureManager {
     }
   }
 
+  public TSStatus deleteTimeSeries(TDeleteTimeSeriesReq req) {
+    String queryId = req.getQueryId();
+    PathPatternTree patternTree =
+        PathPatternTree.deserialize(ByteBuffer.wrap(req.getPathPatternTree()));
+    long procedureId = -1;
+    synchronized (this) {
+      boolean hasOverlappedTask = false;
+      ProcedureFactory.ProcedureType type;
+      DeleteTimeSeriesProcedure deleteTimeSeriesProcedure;
+      for (Procedure<?> procedure : executor.getProcedures().values()) {
+        type = ProcedureFactory.getProcedureType(procedure);
+        if (type == null
+            || !type.equals(ProcedureFactory.ProcedureType.DELETE_TIMESERIES_PROCEDURE)) {
+          continue;
+        }
+        deleteTimeSeriesProcedure = ((DeleteTimeSeriesProcedure) procedure);
+        if (queryId.equals(deleteTimeSeriesProcedure.getQueryId())) {
+          procedureId = deleteTimeSeriesProcedure.getProcId();
+          break;
+        }
+        if (patternTree.isOverlapWith(deleteTimeSeriesProcedure.getPatternTree())) {
+          hasOverlappedTask = true;
+          break;
+        }
+      }
+
+      if (procedureId == -1) {
+        if (hasOverlappedTask) {
+          return RpcUtils.getStatus(
+              TSStatusCode.OVERLAP_WITH_EXISTING_DELETE_TIMESERIES_TASK,
+              "Some other task is deleting some target timeseries.");
+        }
+        procedureId =
+            this.executor.submitProcedure(new DeleteTimeSeriesProcedure(queryId, patternTree));
+      }
+    }
+    List<TSStatus> procedureStatus = new ArrayList<>();
+    boolean isSucceed =
+        waitingProcedureFinished(Collections.singletonList(procedureId), procedureStatus);
+    if (isSucceed) {
+      return StatusUtils.OK;
+    } else {
+      return procedureStatus.get(0);
+    }
+  }
+
   /** Generate a AddConfigNodeProcedure, and serially execute all the AddConfigNodeProcedure */
   public void addConfigNode(TConfigNodeRegisterReq req) {
     AddConfigNodeProcedure addConfigNodeProcedure =
@@ -189,12 +241,23 @@ public class ProcedureManager {
       }
       Procedure<ConfigNodeProcedureEnv> finishedProcedure =
           executor.getResultOrProcedure(procedureId);
+      if (!finishedProcedure.isFinished()) {
+        // the procedure is still executing
+        statusList.add(RpcUtils.getStatus(TSStatusCode.STILL_EXECUTING_STATUS));
+        isSucceed = false;
+        continue;
+      }
       if (finishedProcedure.isSuccess()) {
         statusList.add(StatusUtils.OK);
       } else {
-        statusList.add(
-            StatusUtils.EXECUTE_STATEMENT_ERROR.setMessage(
-                finishedProcedure.getException().getMessage()));
+        if (finishedProcedure.getException().getCause() instanceof IoTDBException) {
+          IoTDBException e = (IoTDBException) finishedProcedure.getException().getCause();
+          statusList.add(RpcUtils.getStatus(e.getErrorCode(), e.getMessage()));
+        } else {
+          statusList.add(
+              StatusUtils.EXECUTE_STATEMENT_ERROR.setMessage(
+                  finishedProcedure.getException().getMessage()));
+        }
         isSucceed = false;
       }
     }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/DeleteTimeSeriesProcedure.java b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/DeleteTimeSeriesProcedure.java
new file mode 100644
index 0000000000..970ac36569
--- /dev/null
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/DeleteTimeSeriesProcedure.java
@@ -0,0 +1,639 @@
+/*
+ * 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.procedure.impl;
+
+import org.apache.iotdb.common.rpc.thrift.TConsensusGroupId;
+import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.confignode.client.async.datanode.AsyncDataNodeClientPool;
+import org.apache.iotdb.confignode.client.async.task.ConstructSchemaBlackListDataNodeTask;
+import org.apache.iotdb.confignode.client.async.task.DeleteDataForDeleteTimeSeriesDataNodeTask;
+import org.apache.iotdb.confignode.client.async.task.DeleteTimeSeriesDataNodeTask;
+import org.apache.iotdb.confignode.client.async.task.FetchSchemaBlackListDataNodeTask;
+import org.apache.iotdb.confignode.client.async.task.InvalidateMatchedSchemaCacheDataNodeTask;
+import org.apache.iotdb.confignode.client.async.task.RollbackSchemaBlackListDataNodeTask;
+import org.apache.iotdb.confignode.procedure.StateMachineProcedure;
+import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv;
+import org.apache.iotdb.confignode.procedure.exception.ProcedureException;
+import org.apache.iotdb.confignode.procedure.exception.ProcedureSuspendedException;
+import org.apache.iotdb.confignode.procedure.exception.ProcedureYieldException;
+import org.apache.iotdb.confignode.procedure.state.DeleteTimeSeriesState;
+import org.apache.iotdb.confignode.procedure.store.ProcedureFactory;
+import org.apache.iotdb.db.exception.metadata.PathNotExistException;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
+import org.apache.iotdb.mpp.rpc.thrift.TConstructSchemaBlackListReq;
+import org.apache.iotdb.mpp.rpc.thrift.TDeleteDataForDeleteTimeSeriesReq;
+import org.apache.iotdb.mpp.rpc.thrift.TDeleteTimeSeriesReq;
+import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListReq;
+import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListResp;
+import org.apache.iotdb.mpp.rpc.thrift.TInvalidateMatchedSchemaCacheReq;
+import org.apache.iotdb.mpp.rpc.thrift.TRollbackSchemaBlackListReq;
+import org.apache.iotdb.rpc.TSStatusCode;
+import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+public class DeleteTimeSeriesProcedure
+    extends StateMachineProcedure<ConfigNodeProcedureEnv, DeleteTimeSeriesState> {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(DeleteTimeSeriesProcedure.class);
+
+  private String queryId;
+
+  private PathPatternTree patternTree;
+  private ByteBuffer patternTreeBytes;
+
+  private String requestMessage;
+
+  public DeleteTimeSeriesProcedure() {
+    super();
+  }
+
+  public DeleteTimeSeriesProcedure(String queryId, PathPatternTree patternTree) {
+    super();
+    this.queryId = queryId;
+    setPatternTree(patternTree);
+  }
+
+  @Override
+  protected Flow executeFromState(ConfigNodeProcedureEnv env, DeleteTimeSeriesState state)
+      throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
+    switch (state) {
+      case CONSTRUCT_BLACK_LIST:
+        LOGGER.info("Construct schema black list of timeseries {}", requestMessage);
+        if (constructBlackList(env) > 0) {
+          setNextState(DeleteTimeSeriesState.CLEAN_DATANODE_SCHEMA_CACHE);
+          break;
+        } else {
+          setFailure(
+              new ProcedureException(
+                  new PathNotExistException(
+                      patternTree.getAllPathPatterns().stream()
+                          .map(PartialPath::getFullPath)
+                          .collect(Collectors.toList()))));
+          return Flow.NO_MORE_STATE;
+        }
+      case CLEAN_DATANODE_SCHEMA_CACHE:
+        LOGGER.info("Invalidate cache of timeseries {}", requestMessage);
+        invalidateCache(env);
+        break;
+      case DELETE_DATA:
+        LOGGER.info("Delete data of timeseries {}", requestMessage);
+        deleteData(env);
+        break;
+      case DELETE_TIMESERIES:
+        LOGGER.info("Delete timeseries schema of {}", requestMessage);
+        deleteTimeSeries(env);
+        return Flow.NO_MORE_STATE;
+      default:
+        setFailure(new ProcedureException("Unrecognized state " + state.toString()));
+        return Flow.NO_MORE_STATE;
+    }
+    return Flow.HAS_MORE_STATE;
+  }
+
+  // return the total num of timeseries in schema black list
+  private int constructBlackList(ConfigNodeProcedureEnv env) {
+    Map<TConsensusGroupId, TRegionReplicaSet> targetSchemaRegionGroup =
+        env.getConfigManager().getRelatedSchemaRegionGroup(patternTree);
+    if (targetSchemaRegionGroup.isEmpty()) {
+      return 0;
+    }
+    RegionTask<TSStatus> constructBlackListTask =
+        new RegionTask<TSStatus>("construct schema black list", env, targetSchemaRegionGroup) {
+          @Override
+          Map<Integer, TSStatus> sendRequest(
+              TDataNodeLocation dataNodeLocation, List<TConsensusGroupId> consensusGroupIdList) {
+            // construct request and send
+            Map<Integer, TDataNodeLocation> dataNodeLocationMap = new HashMap<>();
+            dataNodeLocationMap.put(dataNodeLocation.getDataNodeId(), dataNodeLocation);
+            ConstructSchemaBlackListDataNodeTask dataNodeTask =
+                new ConstructSchemaBlackListDataNodeTask(dataNodeLocationMap);
+            AsyncDataNodeClientPool.getInstance()
+                .sendAsyncRequestToDataNodeWithRetry(
+                    new TConstructSchemaBlackListReq(consensusGroupIdList, patternTreeBytes),
+                    dataNodeTask);
+            dataNodeTask
+                .getDataNodeResponseMap()
+                .forEach(
+                    (k, v) -> {
+                      if (v.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+                        responseMap.put(k, v);
+                      }
+                    });
+            return dataNodeTask.getDataNodeResponseMap();
+          }
+        };
+    constructBlackListTask.execute();
+
+    if (isFailed()) {
+      return 0;
+    }
+
+    int preDeletedNum = 0;
+    for (TSStatus resp : constructBlackListTask.getResponseMap().values()) {
+      preDeletedNum += Integer.parseInt(resp.getMessage());
+    }
+    return preDeletedNum;
+  }
+
+  private void invalidateCache(ConfigNodeProcedureEnv env) {
+    Map<Integer, TDataNodeLocation> dataNodeLocationMap =
+        env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations();
+    InvalidateMatchedSchemaCacheDataNodeTask dataNodeTask =
+        new InvalidateMatchedSchemaCacheDataNodeTask(dataNodeLocationMap);
+    AsyncDataNodeClientPool.getInstance()
+        .sendAsyncRequestToDataNodeWithRetry(
+            new TInvalidateMatchedSchemaCacheReq(patternTreeBytes), dataNodeTask);
+    Map<Integer, TSStatus> statusMap = dataNodeTask.getDataNodeResponseMap();
+    for (TSStatus status : statusMap.values()) {
+      // all dataNodes must clear the related schema cache
+      if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        LOGGER.error("Failed to invalidate schema cache of timeseries {}", requestMessage);
+        setFailure(new ProcedureException(new MetadataException("Invalidate schema cache failed")));
+        return;
+      }
+    }
+
+    setNextState(DeleteTimeSeriesState.DELETE_DATA);
+  }
+
+  private void deleteData(ConfigNodeProcedureEnv env) {
+    Map<TConsensusGroupId, TRegionReplicaSet> relatedSchemaRegionGroup =
+        env.getConfigManager().getRelatedSchemaRegionGroup(patternTree);
+    Map<TDataNodeLocation, List<TConsensusGroupId>> dataNodeSchemaRegionGroupGroupIdMap =
+        getLeaderDataNodeRegionGroupMap(
+            env.getConfigManager().getPartitionManager().getAllLeadership(),
+            relatedSchemaRegionGroup);
+
+    // fetch schema black list by dataNode
+    for (Map.Entry<TDataNodeLocation, List<TConsensusGroupId>> entry :
+        dataNodeSchemaRegionGroupGroupIdMap.entrySet()) {
+      Map<TConsensusGroupId, TRegionReplicaSet> targetSchemaRegionGroup = new HashMap<>();
+      entry
+          .getValue()
+          .forEach(
+              consensusGroupId ->
+                  targetSchemaRegionGroup.put(
+                      consensusGroupId, relatedSchemaRegionGroup.get(consensusGroupId)));
+      // resolve original path pattern into specific timeseries full path
+      PathPatternTree patternTree =
+          fetchSchemaBlackListOnTargetDataNode(env, targetSchemaRegionGroup);
+      if (isFailed()) {
+        return;
+      }
+      if (patternTree == null) {
+        LOGGER.error(
+            "Failed to fetch schema black list for delete data of timeseries {} on {}",
+            requestMessage,
+            entry.getKey());
+        setFailure(
+            new ProcedureException(
+                new MetadataException("Fetch schema black list forDelete data failed")));
+        return;
+      }
+
+      if (patternTree.isEmpty()) {
+        continue;
+      }
+
+      Map<TConsensusGroupId, TRegionReplicaSet> relatedDataRegionGroup =
+          env.getConfigManager().getRelatedDataRegionGroup(patternTree);
+
+      // target timeseries has no data
+      if (relatedDataRegionGroup.isEmpty()) {
+        continue;
+      }
+
+      RegionTask<TSStatus> deleteDataTask =
+          new RegionTask<TSStatus>("delete data", env, relatedDataRegionGroup) {
+            @Override
+            Map<Integer, TSStatus> sendRequest(
+                TDataNodeLocation dataNodeLocation, List<TConsensusGroupId> consensusGroupIdList) {
+              Map<Integer, TDataNodeLocation> dataNodeLocationMap = new HashMap<>();
+              dataNodeLocationMap.put(dataNodeLocation.getDataNodeId(), dataNodeLocation);
+              DeleteDataForDeleteTimeSeriesDataNodeTask dataNodeTask =
+                  new DeleteDataForDeleteTimeSeriesDataNodeTask(dataNodeLocationMap);
+              AsyncDataNodeClientPool.getInstance()
+                  .sendAsyncRequestToDataNodeWithRetry(
+                      new TDeleteDataForDeleteTimeSeriesReq(
+                          new ArrayList<>(consensusGroupIdList),
+                          preparePatternTreeBytesData(patternTree)),
+                      dataNodeTask);
+              return dataNodeTask.getDataNodeResponseMap();
+            }
+          };
+      deleteDataTask.setExecuteOnAllReplicaset(true);
+      deleteDataTask.execute();
+      if (isFailed()) {
+        return;
+      }
+    }
+    setNextState(DeleteTimeSeriesState.DELETE_TIMESERIES);
+  }
+
+  private PathPatternTree fetchSchemaBlackListOnTargetDataNode(
+      ConfigNodeProcedureEnv env,
+      Map<TConsensusGroupId, TRegionReplicaSet> targetSchemaRegionGroup) {
+    RegionTask<TFetchSchemaBlackListResp> fetchSchemaBlackListTask =
+        new RegionTask<TFetchSchemaBlackListResp>(
+            "fetch schema black list", env, targetSchemaRegionGroup) {
+          @Override
+          Map<Integer, TSStatus> sendRequest(
+              TDataNodeLocation dataNodeLocation, List<TConsensusGroupId> consensusGroupIdList) {
+            Map<Integer, TDataNodeLocation> dataNodeLocationMap = new HashMap<>();
+            dataNodeLocationMap.put(dataNodeLocation.getDataNodeId(), dataNodeLocation);
+            FetchSchemaBlackListDataNodeTask dataNodeTask =
+                new FetchSchemaBlackListDataNodeTask(dataNodeLocationMap);
+            AsyncDataNodeClientPool.getInstance()
+                .sendAsyncRequestToDataNodeWithRetry(
+                    new TFetchSchemaBlackListReq(consensusGroupIdList, patternTreeBytes),
+                    dataNodeTask);
+            Map<Integer, TFetchSchemaBlackListResp> respMap = dataNodeTask.getDataNodeResponseMap();
+            Map<Integer, TSStatus> statusMap = new HashMap<>();
+            respMap.forEach(
+                (k, v) -> {
+                  if (v.getStatus().getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+                    responseMap.put(k, v);
+                  }
+                  statusMap.put(k, v.getStatus());
+                });
+            return statusMap;
+          }
+        };
+    fetchSchemaBlackListTask.execute();
+    if (isFailed()) {
+      return null;
+    }
+
+    Map<Integer, TFetchSchemaBlackListResp> respMap = fetchSchemaBlackListTask.getResponseMap();
+    PathPatternTree patternTree = new PathPatternTree();
+    for (TFetchSchemaBlackListResp resp : respMap.values()) {
+      for (PartialPath path :
+          PathPatternTree.deserialize(ByteBuffer.wrap(resp.getPathPatternTree()))
+              .getAllPathPatterns()) {
+        patternTree.appendFullPath(path);
+      }
+    }
+    patternTree.constructTree();
+    return patternTree;
+  }
+
+  private void deleteTimeSeries(ConfigNodeProcedureEnv env) {
+    RegionTask<TSStatus> deleteTimeSeriesTask =
+        new RegionTask<TSStatus>(
+            "delete timeseries",
+            env,
+            env.getConfigManager().getRelatedSchemaRegionGroup(patternTree)) {
+          @Override
+          Map<Integer, TSStatus> sendRequest(
+              TDataNodeLocation dataNodeLocation, List<TConsensusGroupId> consensusGroupIdList) {
+            Map<Integer, TDataNodeLocation> dataNodeLocationMap = new HashMap<>();
+            dataNodeLocationMap.put(dataNodeLocation.getDataNodeId(), dataNodeLocation);
+            DeleteTimeSeriesDataNodeTask dataNodeTask =
+                new DeleteTimeSeriesDataNodeTask(dataNodeLocationMap);
+            AsyncDataNodeClientPool.getInstance()
+                .sendAsyncRequestToDataNodeWithRetry(
+                    new TDeleteTimeSeriesReq(consensusGroupIdList, patternTreeBytes), dataNodeTask);
+            return dataNodeTask.getDataNodeResponseMap();
+          }
+        };
+    deleteTimeSeriesTask.execute();
+  }
+
+  /**
+   * Try to get and execute request on consensus group leader as possible. If fail to get leader,
+   * select some other replica for execution.
+   */
+  private Map<TDataNodeLocation, List<TConsensusGroupId>> getLeaderDataNodeRegionGroupMap(
+      Map<TConsensusGroupId, Integer> leaderMap,
+      Map<TConsensusGroupId, TRegionReplicaSet> regionReplicaSetMap) {
+    Map<TDataNodeLocation, List<TConsensusGroupId>> dataNodeConsensusGroupIdMap = new HashMap<>();
+    regionReplicaSetMap.forEach(
+        (consensusGroupId, regionReplicaSet) -> {
+          Integer leaderId = leaderMap.get(consensusGroupId);
+          TDataNodeLocation leaderDataNodeLocation = null;
+          if (leaderId == null || leaderId == -1) {
+            leaderDataNodeLocation = regionReplicaSet.getDataNodeLocations().get(0);
+          } else {
+            for (TDataNodeLocation dataNodeLocation : regionReplicaSet.getDataNodeLocations()) {
+              if (dataNodeLocation.getDataNodeId() == leaderId) {
+                leaderDataNodeLocation = dataNodeLocation;
+                break;
+              }
+            }
+          }
+          dataNodeConsensusGroupIdMap
+              .computeIfAbsent(leaderDataNodeLocation, k -> new ArrayList<>())
+              .add(regionReplicaSet.getRegionId());
+        });
+    return dataNodeConsensusGroupIdMap;
+  }
+
+  /**
+   * Try to execute request on all replica of one consensus group. If some replica failed, execute
+   * according request on some other replica and let consensus layer to sync it.
+   */
+  private Map<TDataNodeLocation, List<TConsensusGroupId>> getAllReplicaDataNodeRegionGroupMap(
+      Map<TConsensusGroupId, TRegionReplicaSet> regionReplicaSetMap) {
+    Map<TDataNodeLocation, List<TConsensusGroupId>> dataNodeConsensusGroupIdMap = new HashMap<>();
+    regionReplicaSetMap.forEach(
+        (consensusGroupId, regionReplicaSet) -> {
+          for (TDataNodeLocation dataNodeLocation : regionReplicaSet.getDataNodeLocations()) {
+            dataNodeConsensusGroupIdMap
+                .computeIfAbsent(dataNodeLocation, k -> new ArrayList<>())
+                .add(regionReplicaSet.getRegionId());
+          }
+        });
+    return dataNodeConsensusGroupIdMap;
+  }
+
+  @Override
+  protected void rollbackState(
+      ConfigNodeProcedureEnv env, DeleteTimeSeriesState deleteTimeSeriesState)
+      throws IOException, InterruptedException, ProcedureException {
+    RegionTask<TSStatus> rollbackStateTask =
+        new RegionTask<TSStatus>(
+            "roll back schema black list",
+            env,
+            env.getConfigManager().getRelatedSchemaRegionGroup(patternTree)) {
+          @Override
+          Map<Integer, TSStatus> sendRequest(
+              TDataNodeLocation dataNodeLocation, List<TConsensusGroupId> consensusGroupIdList) {
+            Map<Integer, TDataNodeLocation> dataNodeLocationMap = new HashMap<>();
+            dataNodeLocationMap.put(dataNodeLocation.getDataNodeId(), dataNodeLocation);
+            RollbackSchemaBlackListDataNodeTask dataNodeTask =
+                new RollbackSchemaBlackListDataNodeTask(dataNodeLocationMap);
+            AsyncDataNodeClientPool.getInstance()
+                .sendAsyncRequestToDataNodeWithRetry(
+                    new TRollbackSchemaBlackListReq(consensusGroupIdList, patternTreeBytes),
+                    dataNodeTask);
+            return dataNodeTask.getDataNodeResponseMap();
+          }
+        };
+    rollbackStateTask.execute();
+  }
+
+  @Override
+  protected boolean isRollbackSupported(DeleteTimeSeriesState deleteTimeSeriesState) {
+    return true;
+  }
+
+  @Override
+  protected DeleteTimeSeriesState getState(int stateId) {
+    return DeleteTimeSeriesState.values()[stateId];
+  }
+
+  @Override
+  protected int getStateId(DeleteTimeSeriesState deleteTimeSeriesState) {
+    return deleteTimeSeriesState.ordinal();
+  }
+
+  @Override
+  protected DeleteTimeSeriesState getInitialState() {
+    return DeleteTimeSeriesState.CONSTRUCT_BLACK_LIST;
+  }
+
+  public String getQueryId() {
+    return queryId;
+  }
+
+  public PathPatternTree getPatternTree() {
+    return patternTree;
+  }
+
+  public void setPatternTree(PathPatternTree patternTree) {
+    this.patternTree = patternTree;
+    requestMessage = patternTree.getAllPathPatterns().toString();
+    patternTreeBytes = preparePatternTreeBytesData(patternTree);
+  }
+
+  private ByteBuffer preparePatternTreeBytesData(PathPatternTree patternTree) {
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
+    try {
+      patternTree.serialize(dataOutputStream);
+    } catch (IOException ignored) {
+
+    }
+    return ByteBuffer.wrap(byteArrayOutputStream.toByteArray());
+  }
+
+  @Override
+  public void serialize(DataOutputStream stream) throws IOException {
+    stream.writeInt(ProcedureFactory.ProcedureType.DELETE_TIMESERIES_PROCEDURE.ordinal());
+    super.serialize(stream);
+    ReadWriteIOUtils.write(queryId, stream);
+    patternTree.serialize(stream);
+  }
+
+  @Override
+  public void deserialize(ByteBuffer byteBuffer) {
+    super.deserialize(byteBuffer);
+    queryId = ReadWriteIOUtils.readString(byteBuffer);
+    setPatternTree(PathPatternTree.deserialize(byteBuffer));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+    DeleteTimeSeriesProcedure that = (DeleteTimeSeriesProcedure) o;
+    return this.getProcId() == that.getProcId()
+        && this.getState() == that.getState()
+        && patternTree.equals(that.patternTree);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(getProcId(), getState(), patternTree);
+  }
+
+  private abstract class RegionTask<T> {
+
+    private final String taskName;
+    private final ConfigNodeProcedureEnv env;
+    private final Map<TConsensusGroupId, TRegionReplicaSet> targetSchemaRegionGroup;
+
+    private boolean executeOnAllReplicaset = false;
+
+    protected Map<Integer, T> responseMap = new ConcurrentHashMap<>();
+
+    RegionTask(
+        String taskName,
+        ConfigNodeProcedureEnv env,
+        Map<TConsensusGroupId, TRegionReplicaSet> targetSchemaRegionGroup) {
+      this.taskName = taskName;
+      this.env = env;
+      this.targetSchemaRegionGroup = targetSchemaRegionGroup;
+    }
+
+    private void execute() {
+      // organize schema region by dataNode
+      Set<TDataNodeLocation> allFailedDataNodeSet = new HashSet<>();
+      Map<TDataNodeLocation, List<TConsensusGroupId>> dataNodeConsensusGroupIdMap =
+          executeOnAllReplicaset
+              ? getAllReplicaDataNodeRegionGroupMap(targetSchemaRegionGroup)
+              : getLeaderDataNodeRegionGroupMap(
+                  env.getConfigManager().getPartitionManager().getAllLeadership(),
+                  targetSchemaRegionGroup);
+      while (!dataNodeConsensusGroupIdMap.isEmpty()) {
+        Map<TDataNodeLocation, List<TConsensusGroupId>> currentFailedDataNodeMap =
+            sendRegionRequest(dataNodeConsensusGroupIdMap);
+        if (isFailed()) {
+          // some dataNode execution failure
+          return;
+        }
+
+        if (currentFailedDataNodeMap.isEmpty()) {
+          // all succeeded
+          break;
+        }
+
+        // retry failed dataNode requests caused by unexpected error on other replicas on other
+        // dataNodes
+        currentFailedDataNodeMap.forEach(dataNodeConsensusGroupIdMap::remove);
+        // remove dataNodes that successfully executed request
+        allFailedDataNodeSet.removeAll(dataNodeConsensusGroupIdMap.keySet());
+        dataNodeConsensusGroupIdMap =
+            getAvailableDataNodeLocationForRetry(currentFailedDataNodeMap, allFailedDataNodeSet);
+        if (isFailed()) {
+          // some consensus group has no available dataNode
+          return;
+        }
+      }
+    }
+
+    private Map<TDataNodeLocation, List<TConsensusGroupId>> sendRegionRequest(
+        Map<TDataNodeLocation, List<TConsensusGroupId>> dataNodeConsensusGroupIdMap) {
+      // send request to each dataNode
+      Map<TDataNodeLocation, List<TConsensusGroupId>> failedDataNodeMap = new HashMap<>();
+      for (Map.Entry<TDataNodeLocation, List<TConsensusGroupId>> entry :
+          dataNodeConsensusGroupIdMap.entrySet()) {
+        // process response
+        Map<Integer, TSStatus> dataNodeResponseMap = sendRequest(entry.getKey(), entry.getValue());
+        TSStatus currentDataNodeResponse = dataNodeResponseMap.get(entry.getKey().getDataNodeId());
+        if (currentDataNodeResponse.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+          if (currentDataNodeResponse.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) {
+            // dataNode execution error
+            LOGGER.error(
+                "Failed to execute [{}] of delete timeseries {} on {}",
+                taskName,
+                requestMessage,
+                entry.getKey());
+            setFailure(
+                new ProcedureException(
+                    new MetadataException(
+                        String.format(
+                            "Delete timeseries %s failed when [%s]", requestMessage, taskName))));
+            break;
+          } else {
+            // unexpected error, retry on other replicates on other dataNodes
+            failedDataNodeMap.put(entry.getKey(), entry.getValue());
+          }
+        }
+      }
+      return failedDataNodeMap;
+    }
+
+    private Map<TDataNodeLocation, List<TConsensusGroupId>> getAvailableDataNodeLocationForRetry(
+        Map<TDataNodeLocation, List<TConsensusGroupId>> failedDataNodeConsensusGroupIdMap,
+        Set<TDataNodeLocation> allFailedDataNodeSet) {
+      Map<TConsensusGroupId, Integer> leaderMap =
+          env.getConfigManager().getPartitionManager().getAllLeadership();
+      Map<TDataNodeLocation, List<TConsensusGroupId>> availableDataNodeLocation = new HashMap<>();
+      for (List<TConsensusGroupId> consensusGroupIdList :
+          failedDataNodeConsensusGroupIdMap.values()) {
+        for (TConsensusGroupId consensusGroupId : consensusGroupIdList) {
+          TRegionReplicaSet regionReplicaSet = targetSchemaRegionGroup.get(consensusGroupId);
+          TDataNodeLocation selectedDataNode = null;
+          Integer leaderId = leaderMap.get(consensusGroupId);
+          if (leaderId == null || leaderId == -1) {
+            for (TDataNodeLocation candidateDataNode : regionReplicaSet.getDataNodeLocations()) {
+              if (!allFailedDataNodeSet.contains(candidateDataNode)) {
+                // since leader of this group is unknown, take the first available one
+                selectedDataNode = candidateDataNode;
+                break;
+              }
+            }
+          } else {
+            for (TDataNodeLocation candidateDataNode : regionReplicaSet.getDataNodeLocations()) {
+              if (!allFailedDataNodeSet.contains(candidateDataNode)) {
+                if (leaderId == candidateDataNode.getDataNodeId()) {
+                  // retry on the new leader as possible
+                  selectedDataNode = candidateDataNode;
+                  break;
+                }
+                if (selectedDataNode == null) {
+                  selectedDataNode = candidateDataNode;
+                }
+              }
+            }
+          }
+
+          if (selectedDataNode == null) {
+            setFailure(
+                new ProcedureException(
+                    new MetadataException(
+                        String.format(
+                            "Delete timeseries %s failed when [%s] because all replicaset of schemaRegion %s failed.",
+                            requestMessage, taskName, consensusGroupId.id))));
+            return availableDataNodeLocation;
+          } else {
+            availableDataNodeLocation
+                .compute(selectedDataNode, (k, v) -> new ArrayList<>())
+                .add(consensusGroupId);
+          }
+        }
+      }
+      return availableDataNodeLocation;
+    }
+
+    Map<Integer, T> getResponseMap() {
+      return responseMap == null ? Collections.emptyMap() : responseMap;
+    }
+
+    void setExecuteOnAllReplicaset(boolean executeOnAllReplicaset) {
+      this.executeOnAllReplicaset = executeOnAllReplicaset;
+    }
+
+    abstract Map<Integer, TSStatus> sendRequest(
+        TDataNodeLocation dataNodeLocation, List<TConsensusGroupId> consensusGroupIdList);
+  }
+}
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/DeleteTimeSeriesState.java
similarity index 58%
copy from confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java
copy to confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/DeleteTimeSeriesState.java
index 7ed20d7e94..1cf6e7e9e5 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/DeleteTimeSeriesState.java
@@ -17,32 +17,11 @@
  * under the License.
  */
 
-package org.apache.iotdb.confignode.client;
+package org.apache.iotdb.confignode.procedure.state;
 
-public enum DataNodeRequestType {
-  DELETE_REGIONS,
-  INVALIDATE_PARTITION_CACHE,
-  INVALIDATE_PERMISSION_CACHE,
-  INVALIDATE_SCHEMA_CACHE,
-  CREATE_NEW_REGION_PEER,
-  ADD_REGION_PEER,
-  REMOVE_REGION_PEER,
-  DELETE_OLD_REGION_PEER,
-  DISABLE_DATA_NODE,
-  STOP_DATA_NODE,
-
-  SET_TTL,
-  CREATE_DATA_REGIONS,
-  CREATE_SCHEMA_REGIONS,
-  CREATE_FUNCTION,
-  DROP_FUNCTION,
-  FLUSH,
-  UPDATE_REGION_ROUTE_MAP,
-  BROADCAST_LATEST_CONFIG_NODE_GROUP,
-  UPDATE_TEMPLATE,
-  CLEAR_CACHE,
-  MERGE,
-  FULL_MERGE,
-  LOAD_CONFIGURATION,
-  SET_SYSTEM_STATUS,
+public enum DeleteTimeSeriesState {
+  CONSTRUCT_BLACK_LIST,
+  CLEAN_DATANODE_SCHEMA_CACHE,
+  DELETE_DATA,
+  DELETE_TIMESERIES
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java
index 57119408c9..fff4260307 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.confignode.procedure.Procedure;
 import org.apache.iotdb.confignode.procedure.impl.AddConfigNodeProcedure;
 import org.apache.iotdb.confignode.procedure.impl.CreateRegionGroupsProcedure;
 import org.apache.iotdb.confignode.procedure.impl.DeleteStorageGroupProcedure;
+import org.apache.iotdb.confignode.procedure.impl.DeleteTimeSeriesProcedure;
 import org.apache.iotdb.confignode.procedure.impl.RegionMigrateProcedure;
 import org.apache.iotdb.confignode.procedure.impl.RemoveConfigNodeProcedure;
 import org.apache.iotdb.confignode.procedure.impl.RemoveDataNodeProcedure;
@@ -65,6 +66,9 @@ public class ProcedureFactory implements IProcedureFactory {
       case CREATE_REGION_GROUPS:
         procedure = new CreateRegionGroupsProcedure();
         break;
+      case DELETE_TIMESERIES_PROCEDURE:
+        procedure = new DeleteTimeSeriesProcedure();
+        break;
       default:
         LOGGER.error("unknown Procedure type: " + typeNum);
         throw new IOException("unknown Procedure type: " + typeNum);
@@ -86,6 +90,8 @@ public class ProcedureFactory implements IProcedureFactory {
       return ProcedureType.REGION_MIGRATE_PROCEDURE;
     } else if (procedure instanceof CreateRegionGroupsProcedure) {
       return ProcedureType.CREATE_REGION_GROUPS;
+    } else if (procedure instanceof DeleteTimeSeriesProcedure) {
+      return ProcedureType.DELETE_TIMESERIES_PROCEDURE;
     }
     return null;
   }
@@ -96,7 +102,8 @@ public class ProcedureFactory implements IProcedureFactory {
     REMOVE_CONFIG_NODE_PROCEDURE,
     REMOVE_DATA_NODE_PROCEDURE,
     REGION_MIGRATE_PROCEDURE,
-    CREATE_REGION_GROUPS
+    CREATE_REGION_GROUPS,
+    DELETE_TIMESERIES_PROCEDURE
   }
 
   private static class ProcedureFactoryHolder {
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
index 28e22d33ce..7c008ecc0a 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
@@ -76,6 +76,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TDataPartitionReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDataPartitionTableResp;
 import org.apache.iotdb.confignode.rpc.thrift.TDeleteStorageGroupReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDeleteStorageGroupsReq;
+import org.apache.iotdb.confignode.rpc.thrift.TDeleteTimeSeriesReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDropFunctionReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDropTriggerReq;
 import org.apache.iotdb.confignode.rpc.thrift.TGetAllTemplatesResp;
@@ -583,4 +584,9 @@ public class ConfigNodeRPCServiceProcessor implements IConfigNodeRPCService.Ifac
   public TGetPathsSetTemplatesResp getPathsSetTemplate(String req) throws TException {
     return configManager.getPathsSetTemplate(req);
   }
+
+  @Override
+  public TSStatus deleteTimeSeries(TDeleteTimeSeriesReq req) throws TException {
+    return configManager.deleteTimeSeries(req);
+  }
 }
diff --git a/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/DeleteTimeSeriesProcedureTest.java b/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/DeleteTimeSeriesProcedureTest.java
new file mode 100644
index 0000000000..cc62f1c0f8
--- /dev/null
+++ b/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/DeleteTimeSeriesProcedureTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.procedure.impl;
+
+import org.apache.iotdb.commons.exception.IllegalPathException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.confignode.procedure.store.ProcedureFactory;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class DeleteTimeSeriesProcedureTest {
+
+  @Test
+  public void serializeDeserializeTest() throws IllegalPathException, IOException {
+    String queryId = "1";
+    PathPatternTree patternTree = new PathPatternTree();
+    patternTree.appendPathPattern(new PartialPath("root.sg1.**"));
+    patternTree.appendPathPattern(new PartialPath("root.sg2.*.s1"));
+    patternTree.constructTree();
+    DeleteTimeSeriesProcedure deleteTimeSeriesProcedure =
+        new DeleteTimeSeriesProcedure(queryId, patternTree);
+
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
+    deleteTimeSeriesProcedure.serialize(dataOutputStream);
+
+    ByteBuffer byteBuffer = ByteBuffer.wrap(byteArrayOutputStream.toByteArray());
+
+    Assert.assertEquals(
+        ProcedureFactory.ProcedureType.DELETE_TIMESERIES_PROCEDURE.ordinal(), byteBuffer.getInt());
+
+    DeleteTimeSeriesProcedure deserializedProcedure = new DeleteTimeSeriesProcedure();
+    deserializedProcedure.deserialize(byteBuffer);
+
+    Assert.assertEquals(queryId, deserializedProcedure.getQueryId());
+
+    List<PartialPath> pathList = deserializedProcedure.getPatternTree().getAllPathPatterns();
+    pathList.sort(PartialPath::compareTo);
+    Assert.assertEquals("root.sg1.**", pathList.get(0).getFullPath());
+    Assert.assertEquals("root.sg2.*.s1", pathList.get(1).getFullPath());
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBCompleteIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBCompleteIT.java
deleted file mode 100644
index 716d4d3702..0000000000
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBCompleteIT.java
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * 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.it;
-
-import org.apache.iotdb.it.env.ConfigFactory;
-import org.apache.iotdb.it.env.EnvFactory;
-import org.apache.iotdb.it.framework.IoTDBTestRunner;
-import org.apache.iotdb.itbase.category.ClusterIT;
-import org.apache.iotdb.itbase.category.LocalStandaloneIT;
-import org.apache.iotdb.itbase.constant.TestConstant;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.Statement;
-
-/**
- * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
- * IoTDB server should be defined as integration test.
- */
-@Ignore
-@RunWith(IoTDBTestRunner.class)
-@Category({LocalStandaloneIT.class, ClusterIT.class})
-public class IoTDBCompleteIT {
-  private int prevDataRegionNum;
-
-  @Before
-  public void setUp() throws InterruptedException {
-    // test different partition
-    prevDataRegionNum = ConfigFactory.getConfig().getDataRegionNum();
-    ConfigFactory.getConfig().setDataRegionNum(16);
-    EnvFactory.getEnv().initBeforeClass();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    EnvFactory.getEnv().cleanAfterClass();
-    ConfigFactory.getConfig().setDataRegionNum(prevDataRegionNum);
-  }
-
-  @Ignore
-  @Test
-  public void test() {
-    String[] sqls = {"SET STORAGE GROUP TO root.vehicle"};
-    executeSQL(sqls);
-    // simpleTest();
-    //    insertTest();
-    // selectTest();
-    deleteTest();
-    //    groupByTest();
-    //    funcTest();
-
-    //    funcTestWithOutTimeGenerator();
-  }
-
-  public void simpleTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "SHOW TIMESERIES",
-      "===  Timeseries Tree  ===\n"
-          + "\n"
-          + "{\n"
-          + "\t\"root\":{\n"
-          + "\t\t\"vehicle\":{\n"
-          + "\t\t\t\"d0\":{\n"
-          + "\t\t\t\t\"s0\":{\n"
-          + "\t\t\t\t\t\"args\":\"{}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t}\n"
-          + "\t\t}\n"
-          + "\t}\n"
-          + "}",
-      "DELETE TIMESERIES root.vehicle.d0.s0",
-      "SHOW TIMESERIES",
-      "===  Timeseries Tree  ===\n"
-          + "\n"
-          + "{\n"
-          + "\t\"root\":{\n"
-          + "\t\t\"vehicle\":{}\n"
-          + "\t}\n"
-          + "}",
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=BOOLEAN,ENCODING=PLAIN",
-      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT64,ENCODING=TS_2DIFF",
-      "CREATE TIMESERIES root.vehicle.d0.s2 WITH DATATYPE=FLOAT,ENCODING=GORILLA",
-      "CREATE TIMESERIES root.vehicle.d0.s4 WITH DATATYPE=DOUBLE,ENCODING=RLE",
-      "CREATE TIMESERIES root.vehicle.d1.s5 WITH DATATYPE=TEXT,ENCODING=PLAIN",
-      "CREATE TIMESERIES root.vehicle.d2.s6 WITH DATATYPE=INT32,ENCODING=TS_2DIFF,compressor=UNCOMPRESSED",
-      "CREATE TIMESERIES root.vehicle.d3.s7 WITH DATATYPE=INT32,ENCODING=RLE,compressor=SNAPPY",
-      "CREATE TIMESERIES root.vehicle.d4.s8 WITH DATATYPE=INT32,ENCODING=RLE,MAX_POINT_NUMBER=100",
-      "CREATE TIMESERIES root.vehicle.d5.s9 WITH DATATYPE=FLOAT,ENCODING=PLAIN,compressor=SNAPPY,MAX_POINT_NUMBER=10",
-      "CREATE TIMESERIES root.vehicle.d6.s10 WITH DATATYPE=DOUBLE,ENCODING=RLE,compressor=UNCOMPRESSED,MAX_POINT_NUMBER=10",
-      "DELETE TIMESERIES root.vehicle.d0.**",
-      "SHOW TIMESERIES",
-      "===  Timeseries Tree  ===\n"
-          + "\n"
-          + "{\n"
-          + "\t\"root\":{\n"
-          + "\t\t\"vehicle\":{\n"
-          + "\t\t\t\"d4\":{\n"
-          + "\t\t\t\t\"s8\":{\n"
-          + "\t\t\t\t\t\"args\":\"{max_point_number=100}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d5\":{\n"
-          + "\t\t\t\t\"s9\":{\n"
-          + "\t\t\t\t\t\"args\":\"{max_point_number=10}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"FLOAT\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"SNAPPY\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"PLAIN\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d6\":{\n"
-          + "\t\t\t\t\"s10\":{\n"
-          + "\t\t\t\t\t\"args\":\"{max_point_number=10}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"DOUBLE\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d1\":{\n"
-          + "\t\t\t\t\"s5\":{\n"
-          + "\t\t\t\t\t\"args\":\"{}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"TEXT\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"PLAIN\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d2\":{\n"
-          + "\t\t\t\t\"s6\":{\n"
-          + "\t\t\t\t\t\"args\":\"{}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"TS_2DIFF\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d3\":{\n"
-          + "\t\t\t\t\"s7\":{\n"
-          + "\t\t\t\t\t\"args\":\"{}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"SNAPPY\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t}\n"
-          + "\t\t}\n"
-          + "\t}\n"
-          + "}",
-      "DELETE TIMESERIES root.vehicle.**",
-      "SHOW TIMESERIES",
-      "===  Timeseries Tree  ===\n"
-          + "\n"
-          + "{\n"
-          + "\t\"root\":{\n"
-          + "\t\t\"vehicle\":{}\n"
-          + "\t}\n"
-          + "}"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void insertTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,101)",
-      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0,s1) values(2,102,202)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2000-01-01T08:00:00+08:00,105)",
-      "SELECT * FROM root.vehicle.d0",
-      "1,101,null,\n" + "2,102,202,\n" + "946684800000,105,null,\n" + "NOW(),104,null,\n",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void deleteTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,101)",
-      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0,s1) values(2,102,202)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2000-01-01T08:00:00+08:00,105)",
-      "SELECT * FROM root.vehicle.d0",
-      "1,101,null,\n" + "2,102,202,\n" + "946684800000,105,null,\n" + "NOW(),104,null,\n",
-      "DELETE TIMESERIES root.vehicle.**",
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,1)",
-      "SELECT * FROM root.vehicle.d0",
-      "1,1,\n" + "2,1,\n" + "3,1,\n" + "4,1,\n" + "5,1,\n" + "6,1,\n" + "7,1,\n" + "8,1,\n"
-          + "9,1,\n" + "10,1,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time < 8",
-      "SELECT * FROM root.vehicle.d0",
-      "8,1,\n" + "9,1,\n" + "10,1,\n",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2000-01-01T08:00:00+08:00,1)",
-      "SELECT * FROM root.vehicle.d0",
-      "8,1,\n" + "9,1,\n" + "10,1,\n" + "946684800000,1,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time < 2000-01-02T08:00:00+08:00",
-      "SELECT * FROM root.vehicle.d0",
-      "",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),1)",
-      "SELECT * FROM root.vehicle.d0",
-      "NOW(),1,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= NOW()",
-      "SELECT * FROM root.vehicle.d0",
-      "",
-      "CREATE TIMESERIES root.vehicle.d1.s1 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,1)",
-      "INSERT INTO root.vehicle.d1(timestamp,s1) values(1,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,5)",
-      "INSERT INTO root.vehicle.d1(timestamp,s1) values(5,5)",
-      "SELECT * FROM root.vehicle.*",
-      "1,1,1,\n" + "5,5,5,\n",
-      "DELETE FROM root.vehicle.d0.s0,root.vehicle.d1.s1 WHERE time < 3",
-      "SELECT * FROM root.vehicle.*",
-      "5,5,5,\n",
-      "DELETE FROM root.vehicle.** WHERE time < 7",
-      "SELECT * FROM root.vehicle.*",
-      "",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void selectTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,101)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,110)",
-      "SELECT * FROM root.vehicle.d0 WHERE s0 < 104",
-      "1,101,\n" + "2,102,\n" + "3,103,\n",
-      "SELECT * FROM root.vehicle.d0 WHERE s0 > 105 and time < 8",
-      "6,106,\n" + "7,107,\n",
-      "SELECT * FROM root.vehicle.d0",
-      "1,101,\n"
-          + "2,102,\n"
-          + "3,103,\n"
-          + "4,104,\n"
-          + "5,105,\n"
-          + "6,106,\n"
-          + "7,107,\n"
-          + "8,108,\n"
-          + "9,109,\n"
-          + "10,110,\n",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void funcTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,110)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,101)",
-      "SELECT COUNT(s0) FROM root.vehicle.d0",
-      "0,10,\n",
-      "SELECT COUNT(s0) FROM root.vehicle.d0 WHERE root.vehicle.d0.s0 < 105",
-      "0,4,\n",
-      "SELECT MAX_TIME(s0) FROM root.vehicle.d0",
-      "0,10,\n",
-      "SELECT MAX_TIME(s0) FROM root.vehicle.d0 WHERE root.vehicle.d0.s0 > 105",
-      "0,5,\n",
-      "SELECT MIN_TIME(s0) FROM root.vehicle.d0",
-      "0,1,\n",
-      "SELECT MIN_TIME(s0) FROM root.vehicle.d0 WHERE root.vehicle.d0.s0 < 106",
-      "0,6,\n",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0",
-      "0,110,\n",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0 WHERE time > 4",
-      "0,106,\n",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0",
-      "0,101,\n",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0 WHERE time < 5",
-      "0,107,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= 10",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),5)",
-      "SELECT * FROM root.vehicle.d0",
-      "NOW(),5,\n",
-      "UPDATE root.vehicle.d0 SET s0 = 10 WHERE time <= NOW()",
-      "SELECT * FROM root.vehicle.d0",
-      "NOW(),10,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= NOW()",
-      "SELECT * FROM root.vehicle.d0",
-      "",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void funcTestWithOutTimeGenerator() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,110)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,101)",
-      "SELECT COUNT(s0) FROM root.vehicle.d0",
-      "0,10,\n",
-      "SELECT MAX_TIME(s0) FROM root.vehicle.d0",
-      "0,10,\n",
-      "SELECT MIN_TIME(s0) FROM root.vehicle.d0",
-      "0,1,\n",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0",
-      "0,110,\n",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0 WHERE time > 4",
-      "0,106,\n",
-      "SELECT SUM(s0) FROM root.vehicle.d0 WHERE time > 4",
-      "0,621.0,\n",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0",
-      "0,101,\n",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0 WHERE time < 5",
-      "0,107,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= 10",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),5)",
-      "SELECT * FROM root.vehicle.d0",
-      "NOW(),5,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= NOW()",
-      "SELECT * FROM root.vehicle.d0",
-      "",
-      "SELECT COUNT(s0) FROM root.vehicle.d0",
-      "0,0,\n",
-      "SELECT MAX_TIME(s0) FROM root.vehicle.d0",
-      "",
-      "SELECT MIN_TIME(s0) FROM root.vehicle.d0",
-      "",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0",
-      "",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0 WHERE time > 4",
-      "",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0",
-      "",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0 WHERE time < 5",
-      "",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void groupByTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,110)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,101)",
-      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(1,101)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(2,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(3,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(4,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(5,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(6,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(7,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(8,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(9,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(10,110)",
-      "SELECT COUNT(s0), COUNT(s1) FROM root.vehicle.d0 WHERE s1 < 109 GROUP BY(4ms,[1,10])",
-      "1,3,3,\n" + "4,4,4,\n" + "8,1,1,\n",
-      "SELECT COUNT(s0), MAX_VALUE(s1) FROM root.vehicle.d0 WHERE time < 7 GROUP BY(3ms,2,[1,5])",
-      "1,1,101,\n" + "2,3,104,\n" + "5,1,105,\n",
-      "SELECT MIN_VALUE(s0), MAX_TIME(s1) FROM root.vehicle.d0 WHERE s1 > 102 and time < 9 GROUP BY(3ms,1,[1,4],[6,9])",
-      "1,108,3,\n" + "4,105,6,\n" + "7,103,8,\n",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  private void executeSQL(String[] sqls) {
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-      String result = "";
-      Long now_start = 0L;
-      boolean cmp = false;
-
-      for (String sql : sqls) {
-        if (cmp) {
-          Assert.assertEquals(sql, result);
-          cmp = false;
-        } else if (sql.equals("SHOW TIMESERIES")) {
-          DatabaseMetaData data = connection.getMetaData();
-          result = data.toString();
-          cmp = true;
-        } else {
-          if (sql.contains("NOW()") && now_start == 0L) {
-            now_start = System.currentTimeMillis();
-          }
-
-          if (sql.split(" ")[0].equals("SELECT")) {
-            ResultSet resultSet = statement.executeQuery(sql);
-            ResultSetMetaData metaData = resultSet.getMetaData();
-            int count = metaData.getColumnCount();
-            String[] column = new String[count];
-            for (int i = 0; i < count; i++) {
-              column[i] = metaData.getColumnName(i + 1);
-            }
-            result = "";
-            while (resultSet.next()) {
-              for (int i = 1; i <= count; i++) {
-                if (now_start > 0L && column[i - 1].equals(TestConstant.TIMESTAMP_STR)) {
-                  String timestr = resultSet.getString(i);
-                  Long tn = Long.valueOf(timestr);
-                  Long now = System.currentTimeMillis();
-                  if (tn >= now_start && tn <= now) {
-                    timestr = "NOW()";
-                  }
-                  result += timestr + ',';
-                } else {
-                  result += resultSet.getString(i) + ',';
-                }
-              }
-              result += '\n';
-            }
-            cmp = true;
-          }
-        }
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java
index c61f215e87..3116295ad2 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java
@@ -26,7 +26,6 @@ import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
@@ -41,7 +40,6 @@ import java.sql.Statement;
  * IoTDB server should be defined as integration test.
  */
 @RunWith(IoTDBTestRunner.class)
-@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBCreateAlignedTimeseriesIT {
 
   private Statement statement;
@@ -63,6 +61,7 @@ public class IoTDBCreateAlignedTimeseriesIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void testCreateAlignedTimeseries() throws Exception {
     String[] timeSeriesArray =
         new String[] {
@@ -90,8 +89,8 @@ public class IoTDBCreateAlignedTimeseriesIT {
     //    assertTimeseriesEquals(timeSeriesArray);
   }
 
-  @Ignore
   @Test
+  @Category({ClusterIT.class})
   public void testCreateAlignedTimeseriesWithDeletion() throws Exception {
     String[] timeSeriesArray =
         new String[] {
@@ -112,11 +111,9 @@ public class IoTDBCreateAlignedTimeseriesIT {
     // ensure that current storage group in cache is right.
     assertTimeseriesEquals(timeSeriesArray);
 
-    statement.close();
-    connection.close();
     // todo
     //    EnvironmentUtils.stopDaemon();
-    setUp();
+    //    setUp();
 
     // ensure storage group in cache is right after recovering.
     assertTimeseriesEquals(timeSeriesArray);
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteAlignedTimeseriesIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteAlignedTimeseriesIT.java
new file mode 100644
index 0000000000..7d9d71ad7a
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteAlignedTimeseriesIT.java
@@ -0,0 +1,248 @@
+/*
+ * 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.it.schema;
+
+import org.apache.iotdb.it.env.ConfigFactory;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.apache.iotdb.itbase.constant.TestConstant.TIMESTAMP_STR;
+import static org.apache.iotdb.itbase.constant.TestConstant.count;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({ClusterIT.class})
+public class IoTDBDeleteAlignedTimeseriesIT {
+
+  private long memtableSizeThreshold;
+
+  private Statement statement;
+  private Connection connection;
+
+  @Before
+  public void setUp() throws ClassNotFoundException, SQLException, InterruptedException {
+    memtableSizeThreshold = ConfigFactory.getConfig().getMemtableSizeThreshold();
+    ConfigFactory.getConfig().setMemtableSizeThreshold(2);
+
+    EnvFactory.getEnv().initBeforeTest();
+
+    connection = EnvFactory.getEnv().getConnection();
+    statement = connection.createStatement();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    statement.close();
+    connection.close();
+    EnvFactory.getEnv().cleanAfterTest();
+    ConfigFactory.getConfig().setMemtableSizeThreshold(memtableSizeThreshold);
+  }
+
+  @Test
+  public void deleteTimeseriesAndCreateDifferentTypeTest() throws Exception {
+    String[] retArray = new String[] {"1,1,", "2,1.1,"};
+    int cnt = 0;
+
+    statement.execute(
+        "create aligned timeseries root.turbine1.d1(s1 INT64 encoding=PLAIN compression=SNAPPY, "
+            + "s2 INT64 encoding=PLAIN compression=SNAPPY)");
+    statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1,s2) ALIGNED VALUES(1,1,2)");
+    try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.turbine1.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+
+    statement.execute("DELETE timeseries root.turbine1.d1.s1");
+    statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1) ALIGNED VALUES(2,1.1)");
+    statement.execute("FLUSH");
+
+    try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.turbine1.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+
+    // todo
+    //    EnvironmentUtils.restartDaemon();
+    //
+    //    hasResult = statement.execute("SELECT * FROM root.**");
+    //    Assert.assertTrue(hasResult);
+  }
+
+  @Test
+  public void deleteTimeseriesAndCreateSameTypeTest() throws Exception {
+    String[] retArray = new String[] {"1,1.0,", "2,5.0,"};
+    int cnt = 0;
+
+    statement.execute(
+        "create aligned timeseries root.turbine1.d1(s1 FLOAT encoding=PLAIN compression=SNAPPY, "
+            + "s2 INT64 encoding=PLAIN compression=SNAPPY)");
+    statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1,s2) ALIGNED VALUES(1,1,2)");
+
+    try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.turbine1.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+    statement.execute("DELETE timeseries root.turbine1.d1.s1");
+    statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1) ALIGNED VALUES(2,5)");
+    statement.execute("FLUSH");
+
+    try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.turbine1.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+
+    // todo
+    //    EnvironmentUtils.restartDaemon();
+    //
+    //    hasResult = statement.execute("SELECT * FROM root.**");
+    //    Assert.assertTrue(hasResult);
+  }
+
+  @Test
+  public void deleteTimeseriesAndChangeDeviceAlignmentTest() throws Exception {
+    String[] retArray = new String[] {"1,1.0,2.0,"};
+    int cnt = 0;
+
+    statement.execute("INSERT INTO root.sg3.d1(timestamp,s1,s2) ALIGNED VALUES(1,1,2)");
+    try (ResultSet resultSet = statement.executeQuery("SHOW DEVICES")) {
+      while (resultSet.next()) {
+        Assert.assertEquals("true", resultSet.getString("isAligned"));
+      }
+    }
+    cnt = 0;
+    statement.execute("DELETE timeseries root.sg3.d1.s1");
+    statement.execute("DELETE timeseries root.sg3.d1.s2");
+    statement.execute("INSERT INTO root.sg3.d1(timestamp,s1,s2) VALUES(1,1,2)");
+    try (ResultSet resultSet = statement.executeQuery("SHOW DEVICES")) {
+      while (resultSet.next()) {
+        Assert.assertEquals("false", resultSet.getString("isAligned"));
+      }
+    }
+
+    try (ResultSet resultSet = statement.executeQuery("SELECT * FROM root.sg3.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+    cnt = 0;
+    statement.execute("DELETE timeseries root.sg3.d1.s1");
+    statement.execute("DELETE timeseries root.sg3.d1.s2");
+    statement.execute("INSERT INTO root.sg3.d1(timestamp,s1,s2) ALIGNED VALUES(1,1,2)");
+    try (ResultSet resultSet = statement.executeQuery("SHOW DEVICES")) {
+      while (resultSet.next()) {
+        Assert.assertEquals("true", resultSet.getString("isAligned"));
+      }
+    }
+
+    try (ResultSet resultSet = statement.executeQuery("SELECT * FROM root.sg3.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+  }
+
+  @Test
+  public void deleteTimeSeriesMultiIntervalTest() {
+    String[] retArray1 = new String[] {"0,0"};
+
+    try {
+      String insertSql = "insert into root.sg.d1(time, s1) aligned values(%d, %d)";
+      for (int i = 1; i <= 4; i++) {
+        statement.execute(String.format(insertSql, i, i));
+      }
+      statement.execute("flush");
+
+      statement.execute("delete from root.sg.d1.s1 where time >= 1 and time <= 2");
+      statement.execute("delete from root.sg.d1.s1 where time >= 3 and time <= 4");
+
+      int cnt = 0;
+      try (ResultSet resultSet =
+          statement.executeQuery(
+              "select count(s1) from root.sg.d1 where time >= 3 and time <= 4")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(count("root.sg.d1.s1"));
+          Assert.assertEquals(retArray1[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(retArray1.length, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+}
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
new file mode 100644
index 0000000000..ca75bd914c
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteTimeseriesIT.java
@@ -0,0 +1,406 @@
+/*
+ * 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.it.schema;
+
+import org.apache.iotdb.it.env.ConfigFactory;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.apache.iotdb.itbase.constant.TestConstant.TIMESTAMP_STR;
+import static org.apache.iotdb.itbase.constant.TestConstant.count;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({ClusterIT.class})
+public class IoTDBDeleteTimeseriesIT {
+
+  private long memtableSizeThreshold;
+
+  private Statement statement;
+  private Connection connection;
+
+  @Before
+  public void setUp() throws Exception {
+    memtableSizeThreshold = ConfigFactory.getConfig().getMemtableSizeThreshold();
+    ConfigFactory.getConfig().setMemtableSizeThreshold(2);
+
+    EnvFactory.getEnv().initBeforeTest();
+
+    connection = EnvFactory.getEnv().getConnection();
+    statement = connection.createStatement();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    statement.close();
+    connection.close();
+    EnvFactory.getEnv().cleanAfterTest();
+    ConfigFactory.getConfig().setMemtableSizeThreshold(memtableSizeThreshold);
+  }
+
+  @Test
+  public void deleteTimeseriesAndCreateDifferentTypeTest() throws Exception {
+    String[] retArray = new String[] {"1,1,", "2,1.1,"};
+    int cnt = 0;
+
+    statement.execute(
+        "create timeseries root.turbine1.d1.s1 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
+    statement.execute(
+        "create timeseries root.turbine1.d1.s2 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
+    statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1,s2) VALUES(1,1,2)");
+
+    try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.turbine1.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+    statement.execute("DELETE timeseries root.turbine1.d1.s1");
+    statement.execute(
+        "create timeseries root.turbine1.d1.s1 with datatype=DOUBLE, encoding=PLAIN, compression=SNAPPY");
+    statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1) VALUES(2,1.1)");
+    statement.execute("FLUSH");
+
+    try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.turbine1.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+
+    //    EnvironmentUtils.restartDaemon();
+    //
+    //    try (Connection connection = EnvFactory.getEnv().getConnection();
+    //        Statement statement = connection.createStatement()) {
+    //      boolean hasResult = statement.execute("SELECT * FROM root.**");
+    //      Assert.assertTrue(hasResult);
+    //    }
+  }
+
+  @Test
+  public void deleteTimeseriesAndCreateSameTypeTest() throws Exception {
+    String[] retArray = new String[] {"1,1,", "2,5,"};
+    int cnt = 0;
+
+    statement.execute(
+        "create timeseries root.turbine1.d1.s1 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
+    statement.execute(
+        "create timeseries root.turbine1.d1.s2 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
+    statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1,s2) VALUES(1,1,2)");
+
+    try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.turbine1.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+    statement.execute("DELETE timeseries root.turbine1.d1.s1");
+    statement.execute(
+        "create timeseries root.turbine1.d1.s1 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
+    statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1) VALUES(2,5)");
+    statement.execute("FLUSH");
+
+    try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.turbine1.d1")) {
+      ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+      while (resultSet.next()) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          builder.append(resultSet.getString(i)).append(",");
+        }
+        Assert.assertEquals(retArray[cnt], builder.toString());
+        cnt++;
+      }
+    }
+
+    //    EnvironmentUtils.restartDaemon();
+    //
+    //    try (Connection connection = EnvFactory.getEnv().getConnection();
+    //        Statement statement = connection.createStatement()) {
+    //      boolean hasResult = statement.execute("SELECT * FROM root.**");
+    //      Assert.assertTrue(hasResult);
+    //    }
+  }
+
+  @Test
+  public void deleteTimeSeriesMultiIntervalTest() {
+    String[] retArray1 = new String[] {"0,0"};
+
+    try {
+      String insertSql = "insert into root.sg.d1(time, s1) values(%d, %d)";
+      for (int i = 1; i <= 4; i++) {
+        statement.execute(String.format(insertSql, i, i));
+      }
+      statement.execute("flush");
+
+      statement.execute("delete from root.sg.d1.s1 where time >= 1 and time <= 2");
+      statement.execute("delete from root.sg.d1.s1 where time >= 3 and time <= 4");
+
+      int cnt = 0;
+      try (ResultSet resultSet =
+          statement.executeQuery(
+              "select count(s1) from root.sg.d1 where time >= 3 and time <= 4")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(count("root.sg.d1.s1"));
+          Assert.assertEquals(retArray1[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(retArray1.length, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void deleteTimeSeriesAndAutoDeleteDeviceTest() throws Exception {
+    String[] retArray1 = new String[] {"0,4,4,4,4"};
+
+    String insertSql = "insert into root.sg.d1(time, s1, s2, s3, s4) values(%d, %d, %d, %d, %d)";
+    for (int i = 1; i <= 4; i++) {
+      statement.execute(String.format(insertSql, i, i, i, i, i));
+    }
+
+    int cnt = 0;
+    try (ResultSet resultSet =
+        statement.executeQuery(
+            "select count(s1), count(s2), count(s3), count(s4) from root.sg.d1")) {
+      while (resultSet.next()) {
+        StringBuilder ans = new StringBuilder(resultSet.getString(TIMESTAMP_STR));
+        for (int i = 1; i <= 4; i++) {
+          ans.append(",").append(resultSet.getString(count("root.sg.d1.s" + i)));
+        }
+        Assert.assertEquals(retArray1[cnt], ans.toString());
+        cnt++;
+      }
+      Assert.assertEquals(retArray1.length, cnt);
+    }
+
+    statement.execute("delete timeseries root.sg.d1.*");
+    try (ResultSet resultSet = statement.executeQuery("select * from root.sg.d1")) {
+      Assert.assertFalse(resultSet.next());
+    }
+
+    try (ResultSet resultSet = statement.executeQuery("show timeseries root.sg.d1.*")) {
+      Assert.assertFalse(resultSet.next());
+    }
+
+    try (ResultSet resultSet = statement.executeQuery("show devices root.sg.d1")) {
+      Assert.assertFalse(resultSet.next());
+    }
+  }
+
+  @Test
+  public void deleteTimeSeriesCrossSchemaRegionTest() throws Exception {
+    String[] retArray1 = new String[] {"0,4,4,4,4"};
+
+    String insertSql = "insert into root.sg.d%d(time, s1, s2) values(%d, %d, %d)";
+    for (int i = 1; i <= 4; i++) {
+      for (int j = 1; j <= 4; j++) {
+        statement.execute(String.format(insertSql, j, i, i, i));
+      }
+    }
+
+    int cnt = 0;
+    try (ResultSet resultSet = statement.executeQuery("select count(s1) from root.sg.*")) {
+      while (resultSet.next()) {
+        StringBuilder ans = new StringBuilder(resultSet.getString(TIMESTAMP_STR));
+        for (int i = 1; i <= 4; i++) {
+          ans.append(",").append(resultSet.getString(count("root.sg.d" + i + ".s1")));
+        }
+        Assert.assertEquals(retArray1[cnt], ans.toString());
+        cnt++;
+      }
+      Assert.assertEquals(retArray1.length, cnt);
+    }
+
+    statement.execute("delete timeseries root.sg.*.s1");
+    try (ResultSet resultSet = statement.executeQuery("select s1 from root.sg.*")) {
+      Assert.assertFalse(resultSet.next());
+    }
+
+    try (ResultSet resultSet = statement.executeQuery("show timeseries root.sg.*.s1")) {
+      Assert.assertFalse(resultSet.next());
+    }
+
+    cnt = 0;
+    try (ResultSet resultSet = statement.executeQuery("select count(s2) from root.sg.*")) {
+      while (resultSet.next()) {
+        StringBuilder ans = new StringBuilder(resultSet.getString(TIMESTAMP_STR));
+        for (int i = 1; i <= 4; i++) {
+          ans.append(",").append(resultSet.getString(count("root.sg.d" + i + ".s2")));
+        }
+        Assert.assertEquals(retArray1[cnt], ans.toString());
+        cnt++;
+      }
+      Assert.assertEquals(retArray1.length, cnt);
+    }
+  }
+
+  @Test
+  public void deleteTimeSeriesCrossStorageGroupTest() throws Exception {
+    String[] retArray1 = new String[] {"0,4,4,4,4"};
+
+    String insertSql = "insert into root.sg%d.d1(time, s1, s2) values(%d, %d, %d)";
+    for (int i = 1; i <= 4; i++) {
+      for (int j = 1; j <= 4; j++) {
+        statement.execute(String.format(insertSql, j, i, i, i));
+      }
+    }
+
+    int cnt = 0;
+    try (ResultSet resultSet = statement.executeQuery("select count(s1) from root.*.d1")) {
+      while (resultSet.next()) {
+        StringBuilder ans = new StringBuilder(resultSet.getString(TIMESTAMP_STR));
+        for (int i = 1; i <= 4; i++) {
+          ans.append(",").append(resultSet.getString(count("root.sg" + i + ".d1.s1")));
+        }
+        Assert.assertEquals(retArray1[cnt], ans.toString());
+        cnt++;
+      }
+      Assert.assertEquals(retArray1.length, cnt);
+    }
+
+    statement.execute("delete timeseries root.*.d1.s1");
+    try (ResultSet resultSet = statement.executeQuery("select s1 from root.*.*")) {
+      Assert.assertFalse(resultSet.next());
+    }
+
+    try (ResultSet resultSet = statement.executeQuery("show timeseries root.*.*.s1")) {
+      Assert.assertFalse(resultSet.next());
+    }
+
+    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 = 1; 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
+  public void deleteTimeSeriesWithMultiPatternTest() throws Exception {
+    String[] retArray1 = new String[] {"0,4,4,4,4"};
+
+    String insertSql = "insert into root.sg%d.d1(time, s1, s2) values(%d, %d, %d)";
+    for (int i = 1; i <= 4; i++) {
+      for (int j = 1; j <= 4; j++) {
+        statement.execute(String.format(insertSql, j, i, i, i));
+      }
+    }
+
+    int cnt = 0;
+    try (ResultSet resultSet = statement.executeQuery("select count(s1) from root.*.d1")) {
+      while (resultSet.next()) {
+        StringBuilder ans = new StringBuilder(resultSet.getString(TIMESTAMP_STR));
+        for (int i = 1; i <= 4; i++) {
+          ans.append(",").append(resultSet.getString(count("root.sg" + i + ".d1.s1")));
+        }
+        Assert.assertEquals(retArray1[cnt], ans.toString());
+        cnt++;
+      }
+      Assert.assertEquals(retArray1.length, cnt);
+    }
+
+    statement.execute("delete timeseries root.*.d1.s1, root.*.d1.s2");
+    try (ResultSet resultSet = statement.executeQuery("select * from root.*.*")) {
+      Assert.assertFalse(resultSet.next());
+    }
+
+    try (ResultSet resultSet = statement.executeQuery("show timeseries root.*.*.*")) {
+      Assert.assertFalse(resultSet.next());
+    }
+  }
+
+  @Test
+  public void deleteTimeSeriesAndReturnPathNotExistsTest() throws Exception {
+    try {
+      statement.execute("delete timeseries root.**");
+    } catch (SQLException e) {
+      Assert.assertTrue(e.getMessage().contains("304: Path [root.**] does not exist"));
+    }
+
+    String[] retArray1 = new String[] {"0,4,4,4,4"};
+
+    String insertSql = "insert into root.sg%d.d1(time, s1, s2) values(%d, %d, %d)";
+    for (int i = 1; i <= 4; i++) {
+      for (int j = 1; j <= 4; j++) {
+        statement.execute(String.format(insertSql, j, i, i, i));
+      }
+    }
+
+    int cnt = 0;
+    try (ResultSet resultSet = statement.executeQuery("select count(s1) from root.*.d1")) {
+      while (resultSet.next()) {
+        StringBuilder ans = new StringBuilder(resultSet.getString(TIMESTAMP_STR));
+        for (int i = 1; i <= 4; i++) {
+          ans.append(",").append(resultSet.getString(count("root.sg" + i + ".d1.s1")));
+        }
+        Assert.assertEquals(retArray1[cnt], ans.toString());
+        cnt++;
+      }
+      Assert.assertEquals(retArray1.length, cnt);
+    }
+
+    try {
+      statement.execute("delete timeseries root.*.d1.s3");
+    } catch (SQLException e) {
+      Assert.assertTrue(e.getMessage().contains("304: Path [root.*.d1.s3] does not exist"));
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagIT.java
index 9bc20cbe71..4a373d92fd 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagIT.java
@@ -25,7 +25,6 @@ import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
@@ -45,7 +44,6 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 @RunWith(IoTDBTestRunner.class)
-@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBTagIT {
 
   @Before
@@ -59,6 +57,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void createOneTimeseriesTest() {
     List<String> ret =
         Collections.singletonList(
@@ -105,6 +104,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void createMultiTimeseriesTest() {
     List<String> ret =
         Arrays.asList(
@@ -159,6 +159,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void showTimeseriesTest() {
     List<String> ret =
         Arrays.asList(
@@ -212,6 +213,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void createDuplicateAliasTimeseriesTest1() {
     String sql1 =
         "create timeseries root.turbine.d3.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
@@ -239,6 +241,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void createDuplicateAliasTimeseriesTest2() {
     String sql1 =
         "create timeseries root.turbine.d4.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
@@ -264,6 +267,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void createDuplicateAliasTimeseriesTest3() {
     String sql1 =
         "create timeseries root.turbine.d5.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
@@ -290,6 +294,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void queryWithAliasTest() {
     List<String> ret =
         Collections.singletonList(
@@ -334,6 +339,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void queryWithLimitTest() {
     List<String> ret =
         Arrays.asList(
@@ -387,8 +393,8 @@ public class IoTDBTagIT {
     }
   }
 
-  @Ignore
   @Test
+  @Category({ClusterIT.class})
   public void deleteTest() {
     List<String> ret1 =
         Arrays.asList(
@@ -471,8 +477,8 @@ public class IoTDBTagIT {
     }
   }
 
-  @Ignore
   @Test
+  @Category({ClusterIT.class})
   public void deleteWithAliasTest() {
     List<String> ret1 =
         Arrays.asList(
@@ -556,6 +562,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void queryWithWhereTest1() {
     List<String> ret1 =
         Arrays.asList(
@@ -679,6 +686,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void queryWithWhereTest2() {
     Set<String> ret = new HashSet<>();
     ret.add(
@@ -798,8 +806,8 @@ public class IoTDBTagIT {
     }
   }
 
-  @Ignore
   @Test
+  @Category({ClusterIT.class})
   public void queryWithWhereAndDeleteTest() {
     Set<String> ret = new HashSet<>();
     ret.add(
@@ -882,6 +890,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void queryWithWhereContainsTest() {
     Set<String> ret = new HashSet<>();
     ret.add(
@@ -1001,6 +1010,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void queryWithWhereOnNoneTagTest() {
     String[] sqls = {
       "create timeseries root.turbine.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
@@ -1047,6 +1057,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void sameNameTest() {
     String sql =
         "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
@@ -1062,6 +1073,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void deleteStorageGroupTest() {
     List<String> ret =
         Collections.singletonList(
@@ -1111,6 +1123,7 @@ public class IoTDBTagIT {
   }
 
   @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void insertWithAliasTest() {
     List<String> ret = Collections.singletonList("1,36.5,36.5");
     String[] sqls = {
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCompleteIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCompleteIT.java
deleted file mode 100644
index f6f1a04170..0000000000
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCompleteIT.java
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * 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.integration;
-
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.constant.TestConstant;
-import org.apache.iotdb.integration.env.ConfigFactory;
-import org.apache.iotdb.integration.env.EnvFactory;
-import org.apache.iotdb.itbase.category.ClusterTest;
-import org.apache.iotdb.itbase.category.LocalStandaloneTest;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.Statement;
-
-/**
- * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
- * IoTDB server should be defined as integration test.
- */
-@Category({LocalStandaloneTest.class, ClusterTest.class})
-public class IoTDBCompleteIT {
-  private int prevDataRegionNum;
-
-  @Before
-  public void setUp() throws InterruptedException {
-    // test different partition
-    prevDataRegionNum = IoTDBDescriptor.getInstance().getConfig().getDataRegionNum();
-    ConfigFactory.getConfig().setDataRegionNum(16);
-    EnvFactory.getEnv().initBeforeClass();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    EnvFactory.getEnv().cleanAfterClass();
-    ConfigFactory.getConfig().setDataRegionNum(prevDataRegionNum);
-  }
-
-  @Test
-  public void test() {
-    String[] sqls = {"SET STORAGE GROUP TO root.vehicle"};
-    executeSQL(sqls);
-    // simpleTest();
-    //    insertTest();
-    // selectTest();
-    deleteTest();
-    //    groupByTest();
-    //    funcTest();
-
-    //    funcTestWithOutTimeGenerator();
-  }
-
-  public void simpleTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "SHOW TIMESERIES",
-      "===  Timeseries Tree  ===\n"
-          + "\n"
-          + "{\n"
-          + "\t\"root\":{\n"
-          + "\t\t\"vehicle\":{\n"
-          + "\t\t\t\"d0\":{\n"
-          + "\t\t\t\t\"s0\":{\n"
-          + "\t\t\t\t\t\"args\":\"{}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t}\n"
-          + "\t\t}\n"
-          + "\t}\n"
-          + "}",
-      "DELETE TIMESERIES root.vehicle.d0.s0",
-      "SHOW TIMESERIES",
-      "===  Timeseries Tree  ===\n"
-          + "\n"
-          + "{\n"
-          + "\t\"root\":{\n"
-          + "\t\t\"vehicle\":{}\n"
-          + "\t}\n"
-          + "}",
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=BOOLEAN,ENCODING=PLAIN",
-      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT64,ENCODING=TS_2DIFF",
-      "CREATE TIMESERIES root.vehicle.d0.s2 WITH DATATYPE=FLOAT,ENCODING=GORILLA",
-      "CREATE TIMESERIES root.vehicle.d0.s4 WITH DATATYPE=DOUBLE,ENCODING=RLE",
-      "CREATE TIMESERIES root.vehicle.d1.s5 WITH DATATYPE=TEXT,ENCODING=PLAIN",
-      "CREATE TIMESERIES root.vehicle.d2.s6 WITH DATATYPE=INT32,ENCODING=TS_2DIFF,compressor=UNCOMPRESSED",
-      "CREATE TIMESERIES root.vehicle.d3.s7 WITH DATATYPE=INT32,ENCODING=RLE,compressor=SNAPPY",
-      "CREATE TIMESERIES root.vehicle.d4.s8 WITH DATATYPE=INT32,ENCODING=RLE,MAX_POINT_NUMBER=100",
-      "CREATE TIMESERIES root.vehicle.d5.s9 WITH DATATYPE=FLOAT,ENCODING=PLAIN,compressor=SNAPPY,MAX_POINT_NUMBER=10",
-      "CREATE TIMESERIES root.vehicle.d6.s10 WITH DATATYPE=DOUBLE,ENCODING=RLE,compressor=UNCOMPRESSED,MAX_POINT_NUMBER=10",
-      "DELETE TIMESERIES root.vehicle.d0.**",
-      "SHOW TIMESERIES",
-      "===  Timeseries Tree  ===\n"
-          + "\n"
-          + "{\n"
-          + "\t\"root\":{\n"
-          + "\t\t\"vehicle\":{\n"
-          + "\t\t\t\"d4\":{\n"
-          + "\t\t\t\t\"s8\":{\n"
-          + "\t\t\t\t\t\"args\":\"{max_point_number=100}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d5\":{\n"
-          + "\t\t\t\t\"s9\":{\n"
-          + "\t\t\t\t\t\"args\":\"{max_point_number=10}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"FLOAT\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"SNAPPY\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"PLAIN\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d6\":{\n"
-          + "\t\t\t\t\"s10\":{\n"
-          + "\t\t\t\t\t\"args\":\"{max_point_number=10}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"DOUBLE\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d1\":{\n"
-          + "\t\t\t\t\"s5\":{\n"
-          + "\t\t\t\t\t\"args\":\"{}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"TEXT\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"PLAIN\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d2\":{\n"
-          + "\t\t\t\t\"s6\":{\n"
-          + "\t\t\t\t\t\"args\":\"{}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"TS_2DIFF\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t},\n"
-          + "\t\t\t\"d3\":{\n"
-          + "\t\t\t\t\"s7\":{\n"
-          + "\t\t\t\t\t\"args\":\"{}\",\n"
-          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
-          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
-          + "\t\t\t\t\t\"Compressor\":\"SNAPPY\",\n"
-          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
-          + "\t\t\t\t}\n"
-          + "\t\t\t}\n"
-          + "\t\t}\n"
-          + "\t}\n"
-          + "}",
-      "DELETE TIMESERIES root.vehicle.**",
-      "SHOW TIMESERIES",
-      "===  Timeseries Tree  ===\n"
-          + "\n"
-          + "{\n"
-          + "\t\"root\":{\n"
-          + "\t\t\"vehicle\":{}\n"
-          + "\t}\n"
-          + "}"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void insertTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,101)",
-      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0,s1) values(2,102,202)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2000-01-01T08:00:00+08:00,105)",
-      "SELECT * FROM root.vehicle.d0",
-      "1,101,null,\n" + "2,102,202,\n" + "946684800000,105,null,\n" + "NOW(),104,null,\n",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void deleteTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,101)",
-      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0,s1) values(2,102,202)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2000-01-01T08:00:00+08:00,105)",
-      "SELECT * FROM root.vehicle.d0",
-      "1,101,null,\n" + "2,102,202,\n" + "946684800000,105,null,\n" + "NOW(),104,null,\n",
-      "DELETE TIMESERIES root.vehicle.**",
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,1)",
-      "SELECT * FROM root.vehicle.d0",
-      "1,1,\n" + "2,1,\n" + "3,1,\n" + "4,1,\n" + "5,1,\n" + "6,1,\n" + "7,1,\n" + "8,1,\n"
-          + "9,1,\n" + "10,1,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time < 8",
-      "SELECT * FROM root.vehicle.d0",
-      "8,1,\n" + "9,1,\n" + "10,1,\n",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2000-01-01T08:00:00+08:00,1)",
-      "SELECT * FROM root.vehicle.d0",
-      "8,1,\n" + "9,1,\n" + "10,1,\n" + "946684800000,1,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time < 2000-01-02T08:00:00+08:00",
-      "SELECT * FROM root.vehicle.d0",
-      "",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),1)",
-      "SELECT * FROM root.vehicle.d0",
-      "NOW(),1,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= NOW()",
-      "SELECT * FROM root.vehicle.d0",
-      "",
-      "CREATE TIMESERIES root.vehicle.d1.s1 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,1)",
-      "INSERT INTO root.vehicle.d1(timestamp,s1) values(1,1)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,5)",
-      "INSERT INTO root.vehicle.d1(timestamp,s1) values(5,5)",
-      "SELECT * FROM root.vehicle.*",
-      "1,1,1,\n" + "5,5,5,\n",
-      "DELETE FROM root.vehicle.d0.s0,root.vehicle.d1.s1 WHERE time < 3",
-      "SELECT * FROM root.vehicle.*",
-      "5,5,5,\n",
-      "DELETE FROM root.vehicle.** WHERE time < 7",
-      "SELECT * FROM root.vehicle.*",
-      "",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void selectTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,101)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,110)",
-      "SELECT * FROM root.vehicle.d0 WHERE s0 < 104",
-      "1,101,\n" + "2,102,\n" + "3,103,\n",
-      "SELECT * FROM root.vehicle.d0 WHERE s0 > 105 and time < 8",
-      "6,106,\n" + "7,107,\n",
-      "SELECT * FROM root.vehicle.d0",
-      "1,101,\n"
-          + "2,102,\n"
-          + "3,103,\n"
-          + "4,104,\n"
-          + "5,105,\n"
-          + "6,106,\n"
-          + "7,107,\n"
-          + "8,108,\n"
-          + "9,109,\n"
-          + "10,110,\n",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void funcTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,110)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,101)",
-      "SELECT COUNT(s0) FROM root.vehicle.d0",
-      "0,10,\n",
-      "SELECT COUNT(s0) FROM root.vehicle.d0 WHERE root.vehicle.d0.s0 < 105",
-      "0,4,\n",
-      "SELECT MAX_TIME(s0) FROM root.vehicle.d0",
-      "0,10,\n",
-      "SELECT MAX_TIME(s0) FROM root.vehicle.d0 WHERE root.vehicle.d0.s0 > 105",
-      "0,5,\n",
-      "SELECT MIN_TIME(s0) FROM root.vehicle.d0",
-      "0,1,\n",
-      "SELECT MIN_TIME(s0) FROM root.vehicle.d0 WHERE root.vehicle.d0.s0 < 106",
-      "0,6,\n",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0",
-      "0,110,\n",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0 WHERE time > 4",
-      "0,106,\n",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0",
-      "0,101,\n",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0 WHERE time < 5",
-      "0,107,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= 10",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),5)",
-      "SELECT * FROM root.vehicle.d0",
-      "NOW(),5,\n",
-      "UPDATE root.vehicle.d0 SET s0 = 10 WHERE time <= NOW()",
-      "SELECT * FROM root.vehicle.d0",
-      "NOW(),10,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= NOW()",
-      "SELECT * FROM root.vehicle.d0",
-      "",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void funcTestWithOutTimeGenerator() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,110)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,101)",
-      "SELECT COUNT(s0) FROM root.vehicle.d0",
-      "0,10,\n",
-      "SELECT MAX_TIME(s0) FROM root.vehicle.d0",
-      "0,10,\n",
-      "SELECT MIN_TIME(s0) FROM root.vehicle.d0",
-      "0,1,\n",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0",
-      "0,110,\n",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0 WHERE time > 4",
-      "0,106,\n",
-      "SELECT SUM(s0) FROM root.vehicle.d0 WHERE time > 4",
-      "0,621.0,\n",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0",
-      "0,101,\n",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0 WHERE time < 5",
-      "0,107,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= 10",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),5)",
-      "SELECT * FROM root.vehicle.d0",
-      "NOW(),5,\n",
-      "DELETE FROM root.vehicle.d0.s0 WHERE time <= NOW()",
-      "SELECT * FROM root.vehicle.d0",
-      "",
-      "SELECT COUNT(s0) FROM root.vehicle.d0",
-      "0,0,\n",
-      "SELECT MAX_TIME(s0) FROM root.vehicle.d0",
-      "",
-      "SELECT MIN_TIME(s0) FROM root.vehicle.d0",
-      "",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0",
-      "",
-      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0 WHERE time > 4",
-      "",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0",
-      "",
-      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0 WHERE time < 5",
-      "",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  public void groupByTest() {
-    String[] sqlS = {
-      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,110)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,101)",
-      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT32,ENCODING=RLE",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(1,101)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(2,102)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(3,103)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(4,104)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(5,105)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(6,106)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(7,107)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(8,108)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(9,109)",
-      "INSERT INTO root.vehicle.d0(timestamp,s1) values(10,110)",
-      "SELECT COUNT(s0), COUNT(s1) FROM root.vehicle.d0 WHERE s1 < 109 GROUP BY(4ms,[1,10])",
-      "1,3,3,\n" + "4,4,4,\n" + "8,1,1,\n",
-      "SELECT COUNT(s0), MAX_VALUE(s1) FROM root.vehicle.d0 WHERE time < 7 GROUP BY(3ms,2,[1,5])",
-      "1,1,101,\n" + "2,3,104,\n" + "5,1,105,\n",
-      "SELECT MIN_VALUE(s0), MAX_TIME(s1) FROM root.vehicle.d0 WHERE s1 > 102 and time < 9 GROUP BY(3ms,1,[1,4],[6,9])",
-      "1,108,3,\n" + "4,105,6,\n" + "7,103,8,\n",
-      "DELETE TIMESERIES root.vehicle.**"
-    };
-    executeSQL(sqlS);
-  }
-
-  private void executeSQL(String[] sqls) {
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-      String result = "";
-      Long now_start = 0L;
-      boolean cmp = false;
-
-      for (String sql : sqls) {
-        if (cmp) {
-          Assert.assertEquals(sql, result);
-          cmp = false;
-        } else if (sql.equals("SHOW TIMESERIES")) {
-          DatabaseMetaData data = connection.getMetaData();
-          result = data.toString();
-          cmp = true;
-        } else {
-          if (sql.contains("NOW()") && now_start == 0L) {
-            now_start = System.currentTimeMillis();
-          }
-
-          statement.execute(sql);
-          if (sql.split(" ")[0].equals("SELECT")) {
-            ResultSet resultSet = statement.getResultSet();
-            ResultSetMetaData metaData = resultSet.getMetaData();
-            int count = metaData.getColumnCount();
-            String[] column = new String[count];
-            for (int i = 0; i < count; i++) {
-              column[i] = metaData.getColumnName(i + 1);
-            }
-            result = "";
-            while (resultSet.next()) {
-              for (int i = 1; i <= count; i++) {
-                if (now_start > 0L && column[i - 1] == TestConstant.TIMESTAMP_STR) {
-                  String timestr = resultSet.getString(i);
-                  Long tn = Long.valueOf(timestr);
-                  Long now = System.currentTimeMillis();
-                  if (tn >= now_start && tn <= now) {
-                    timestr = "NOW()";
-                  }
-                  result += timestr + ',';
-                } else {
-                  result += resultSet.getString(i) + ',';
-                }
-              }
-              result += '\n';
-            }
-            cmp = true;
-          }
-        }
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-}
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateAlignedTimeseriesIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateAlignedTimeseriesIT.java
deleted file mode 100644
index b5327716e8..0000000000
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateAlignedTimeseriesIT.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.integration;
-
-import org.apache.iotdb.db.utils.EnvironmentUtils;
-import org.apache.iotdb.itbase.category.LocalStandaloneTest;
-import org.apache.iotdb.jdbc.Config;
-import org.apache.iotdb.jdbc.IoTDBSQLException;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-/**
- * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
- * IoTDB server should be defined as integration test.
- */
-@Category({LocalStandaloneTest.class})
-public class IoTDBCreateAlignedTimeseriesIT {
-
-  private Statement statement;
-  private Connection connection;
-
-  @Before
-  public void setUp() throws Exception {
-    EnvironmentUtils.envSetUp();
-
-    Class.forName(Config.JDBC_DRIVER_NAME);
-    connection = DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
-    statement = connection.createStatement();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    statement.close();
-    connection.close();
-    EnvironmentUtils.cleanEnv();
-  }
-
-  @Test
-  public void testCreateAlignedTimeseriesWithDeletion() throws Exception {
-    String[] timeSeriesArray =
-        new String[] {
-          "root.sg1.d1.vector1.s1,DOUBLE,PLAIN,SNAPPY", "root.sg1.d1.vector1.s2,INT64,RLE,SNAPPY"
-        };
-
-    statement.execute("SET STORAGE GROUP TO root.sg1");
-    try {
-      statement.execute(
-          "CREATE ALIGNED TIMESERIES root.sg1.d1.vector1(s1 FLOAT encoding=PLAIN compressor=UNCOMPRESSED,s2 INT64 encoding=RLE)");
-      statement.execute("DELETE TIMESERIES root.sg1.d1.vector1.s1");
-      statement.execute(
-          "CREATE ALIGNED TIMESERIES root.sg1.d1.vector1(s1 DOUBLE encoding=PLAIN compressor=SNAPPY)");
-    } catch (IoTDBSQLException e) {
-      e.printStackTrace();
-    }
-
-    // ensure that current storage group in cache is right.
-    assertTimeseriesEquals(timeSeriesArray);
-
-    statement.close();
-    connection.close();
-    EnvironmentUtils.stopDaemon();
-    setUp();
-
-    // ensure storage group in cache is right after recovering.
-    assertTimeseriesEquals(timeSeriesArray);
-  }
-
-  private void assertTimeseriesEquals(String[] timeSeriesArray) throws SQLException {
-    boolean hasResult = statement.execute("SHOW TIMESERIES");
-    Assert.assertTrue(hasResult);
-
-    int count = 0;
-    try (ResultSet resultSet = statement.getResultSet()) {
-      while (resultSet.next()) {
-        String ActualResult =
-            resultSet.getString("timeseries")
-                + ","
-                + resultSet.getString("dataType")
-                + ","
-                + resultSet.getString("encoding")
-                + ","
-                + resultSet.getString("compression");
-        Assert.assertEquals(timeSeriesArray[count], ActualResult);
-        count++;
-      }
-    }
-    Assert.assertEquals(timeSeriesArray.length, count);
-  }
-}
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeleteTimeseriesIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeleteTimeseriesIT.java
deleted file mode 100644
index 8df643e9b4..0000000000
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeleteTimeseriesIT.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * 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.integration;
-
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.utils.EnvironmentUtils;
-import org.apache.iotdb.integration.env.ConfigFactory;
-import org.apache.iotdb.integration.env.EnvFactory;
-import org.apache.iotdb.itbase.category.LocalStandaloneTest;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.Statement;
-
-import static org.apache.iotdb.db.constant.TestConstant.TIMESTAMP_STR;
-import static org.apache.iotdb.db.constant.TestConstant.count;
-import static org.junit.Assert.fail;
-
-@Category({LocalStandaloneTest.class})
-public class IoTDBDeleteTimeseriesIT {
-
-  private long memtableSizeThreshold;
-
-  @Before
-  public void setUp() throws Exception {
-    memtableSizeThreshold = IoTDBDescriptor.getInstance().getConfig().getMemtableSizeThreshold();
-    ConfigFactory.getConfig().setMemtableSizeThreshold(16);
-    EnvFactory.getEnv().initBeforeTest();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    ConfigFactory.getConfig().setMemtableSizeThreshold(memtableSizeThreshold);
-    EnvFactory.getEnv().cleanAfterTest();
-  }
-
-  @Test
-  public void deleteTimeseriesAndCreateDifferentTypeTest() throws Exception {
-    String[] retArray = new String[] {"1,1,", "2,1.1,"};
-    int cnt = 0;
-
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-      statement.execute(
-          "create timeseries root.turbine1.d1.s1 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
-      statement.execute(
-          "create timeseries root.turbine1.d1.s2 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
-      statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1,s2) VALUES(1,1,2)");
-      boolean hasResult = statement.execute("SELECT s1 FROM root.turbine1.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-      statement.execute("DELETE timeseries root.turbine1.d1.s1");
-      statement.execute(
-          "create timeseries root.turbine1.d1.s1 with datatype=DOUBLE, encoding=PLAIN, compression=SNAPPY");
-      statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1) VALUES(2,1.1)");
-      statement.execute("FLUSH");
-
-      hasResult = statement.execute("SELECT s1 FROM root.turbine1.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-    }
-
-    EnvironmentUtils.restartDaemon();
-
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-      boolean hasResult = statement.execute("SELECT * FROM root.**");
-      Assert.assertTrue(hasResult);
-    }
-  }
-
-  @Test
-  public void deleteTimeseriesAndCreateSameTypeTest() throws Exception {
-    String[] retArray = new String[] {"1,1,", "2,5,"};
-    int cnt = 0;
-
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-      statement.execute(
-          "create timeseries root.turbine1.d1.s1 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
-      statement.execute(
-          "create timeseries root.turbine1.d1.s2 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
-      statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1,s2) VALUES(1,1,2)");
-      boolean hasResult = statement.execute("SELECT s1 FROM root.turbine1.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-      statement.execute("DELETE timeseries root.turbine1.d1.s1");
-      statement.execute(
-          "create timeseries root.turbine1.d1.s1 with datatype=INT64, encoding=PLAIN, compression=SNAPPY");
-      statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1) VALUES(2,5)");
-      statement.execute("FLUSH");
-
-      hasResult = statement.execute("SELECT s1 FROM root.turbine1.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-    }
-
-    EnvironmentUtils.restartDaemon();
-
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-      boolean hasResult = statement.execute("SELECT * FROM root.**");
-      Assert.assertTrue(hasResult);
-    }
-  }
-
-  @Test
-  public void deleteTimeSeriesMultiIntervalTest() {
-    String[] retArray1 = new String[] {"0,0"};
-
-    int preAvgSeriesPointNumberThreshold =
-        IoTDBDescriptor.getInstance().getConfig().getAvgSeriesPointNumberThreshold();
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-
-      IoTDBDescriptor.getInstance().getConfig().setAvgSeriesPointNumberThreshold(2);
-      String insertSql = "insert into root.sg.d1(time, s1) values(%d, %d)";
-      for (int i = 1; i <= 4; i++) {
-        statement.execute(String.format(insertSql, i, i));
-      }
-      statement.execute("flush");
-
-      statement.execute("delete from root.sg.d1.s1 where time >= 1 and time <= 2");
-      statement.execute("delete from root.sg.d1.s1 where time >= 3 and time <= 4");
-
-      boolean hasResultSet =
-          statement.execute("select count(s1) from root.sg.d1 where time >= 3 and time <= 4");
-
-      Assert.assertTrue(hasResultSet);
-      int cnt = 0;
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          String ans =
-              resultSet.getString(TIMESTAMP_STR)
-                  + ","
-                  + resultSet.getString(count("root.sg.d1.s1"));
-          Assert.assertEquals(retArray1[cnt], ans);
-          cnt++;
-        }
-        Assert.assertEquals(retArray1.length, cnt);
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-      fail(e.getMessage());
-    } finally {
-      IoTDBDescriptor.getInstance()
-          .getConfig()
-          .setAvgSeriesPointNumberThreshold(preAvgSeriesPointNumberThreshold);
-    }
-  }
-}
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBTagIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBTagIT.java
deleted file mode 100644
index eaac40ef72..0000000000
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBTagIT.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * 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.integration;
-
-import org.apache.iotdb.db.mpp.common.header.ColumnHeaderConstant;
-import org.apache.iotdb.integration.env.EnvFactory;
-import org.apache.iotdb.itbase.category.ClusterTest;
-import org.apache.iotdb.itbase.category.LocalStandaloneTest;
-import org.apache.iotdb.itbase.category.RemoteTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.Statement;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@Category({LocalStandaloneTest.class, ClusterTest.class, RemoteTest.class})
-public class IoTDBTagIT {
-
-  @Before
-  public void setUp() throws Exception {
-    EnvFactory.getEnv().initBeforeTest();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    EnvFactory.getEnv().cleanAfterTest();
-  }
-
-  @Test
-  public void deleteTest() {
-    List<String> ret1 =
-        Arrays.asList(
-            "root.turbine.d7.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
-                + "{\"tag1\":\"t1\",\"tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}",
-            "root.turbine.d7.s2,status,root.turbine,INT32,RLE,SNAPPY,{\"tag2\""
-                + ":\"t2\",\"tag3\":\"t3\"},{\"attr4\":\"a4\",\"attr3\":\"a3\"}");
-    List<String> ret2 =
-        Collections.singletonList(
-            "root.turbine.d7.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
-                + "{\"tag1\":\"t1\",\"tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}");
-
-    String sql1 =
-        "create timeseries root.turbine.d7.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
-            + "tags('tag1'='t1', 'tag2'='t2') "
-            + "attributes('attr1'='a1', 'attr2'='a2')";
-    String sql2 =
-        "create timeseries root.turbine.d7.s2(status) with datatype=INT32, encoding=RLE "
-            + "tags('tag2'='t2', 'tag3'='t3') "
-            + "attributes('attr3'='a3', 'attr4'='a4')";
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-      statement.execute(sql1);
-      statement.execute(sql2);
-      boolean hasResult = statement.execute("show timeseries");
-      assertTrue(hasResult);
-      int count = 0;
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          String ans =
-              resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ALIAS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_STORAGE_GROUP)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_DATATYPE)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ENCODING)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_COMPRESSION)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TAGS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_ATTRIBUTES);
-
-          assertTrue(ret1.contains(ans));
-          count++;
-        }
-      }
-      assertEquals(ret1.size(), count);
-
-      statement.execute("delete timeseries root.turbine.d7.s2");
-      hasResult = statement.execute("show timeseries");
-      assertTrue(hasResult);
-      count = 0;
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          String ans =
-              resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ALIAS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_STORAGE_GROUP)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_DATATYPE)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ENCODING)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_COMPRESSION)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TAGS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_ATTRIBUTES);
-
-          assertTrue(ret2.contains(ans));
-          count++;
-        }
-      }
-      assertEquals(ret2.size(), count);
-    } catch (Exception e) {
-      e.printStackTrace();
-      fail();
-    }
-  }
-
-  @Test
-  public void deleteWithAliasTest() {
-    List<String> ret1 =
-        Arrays.asList(
-            "root.turbine.d7.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
-                + "{\"tag1\":\"t1\",\"tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}",
-            "root.turbine.d7.s2,status,root.turbine,INT32,RLE,SNAPPY,"
-                + "{\"tag2\":\"t2\",\"tag3\":\"t3\"},{\"attr4\":\"a4\",\"attr3\":\"a3\"}");
-    List<String> ret2 =
-        Collections.singletonList(
-            "root.turbine.d7.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
-                + "{\"tag1\":\"t1\",\"tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}");
-
-    String sql1 =
-        "create timeseries root.turbine.d7.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
-            + "tags('tag1'='t1', 'tag2'='t2') "
-            + "attributes('attr1'='a1', 'attr2'='a2')";
-    String sql2 =
-        "create timeseries root.turbine.d7.s2(status) with datatype=INT32, encoding=RLE "
-            + "tags('tag2'='t2', 'tag3'='t3') "
-            + "attributes('attr3'='a3', 'attr4'='a4')";
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-      statement.execute(sql1);
-      statement.execute(sql2);
-      boolean hasResult = statement.execute("show timeseries");
-      assertTrue(hasResult);
-      int count = 0;
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          String ans =
-              resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ALIAS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_STORAGE_GROUP)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_DATATYPE)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ENCODING)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_COMPRESSION)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TAGS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_ATTRIBUTES);
-
-          assertTrue(ret1.contains(ans));
-          count++;
-        }
-      }
-      assertEquals(ret1.size(), count);
-
-      statement.execute("delete timeseries root.turbine.d7.status");
-      hasResult = statement.execute("show timeseries");
-      assertTrue(hasResult);
-      count = 0;
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          String ans =
-              resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ALIAS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_STORAGE_GROUP)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_DATATYPE)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ENCODING)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_COMPRESSION)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TAGS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_ATTRIBUTES);
-
-          assertTrue(ret2.contains(ans));
-          count++;
-        }
-      }
-      assertEquals(ret2.size(), count);
-    } catch (Exception e) {
-      e.printStackTrace();
-      fail();
-    }
-  }
-
-  @Test
-  public void queryWithWhereAndDeleteTest() {
-    Set<String> ret = new HashSet<>();
-    ret.add(
-        "root.turbine.d0.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\""
-            + "turbine this is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"100\",\"M_Alarm\":\"50\"}");
-    ret.add(
-        "root.ln.d0.s0,temperature,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this "
-            + "is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"1000\",\"M_Alarm\":\"500\"}");
-
-    String[] sqls = {
-      "create timeseries root.turbine.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
-          + "tags('unit'='f', 'description'='turbine this is a test1') "
-          + "attributes('H_Alarm'='100', 'M_Alarm'='50')",
-      "create timeseries root.turbine.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
-          + "tags('unit'='kw', 'description'='turbine this is a test2') "
-          + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
-      "create timeseries root.turbine.d1.s0(status) with datatype=INT32, encoding=RLE "
-          + "tags('description'='turbine this is a test3') "
-          + "attributes('H_Alarm'='9', 'M_Alarm'='5')",
-      "create timeseries root.turbine.d2.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
-          + "tags('unit'='f', 'description'='turbine d2 this is a test1') "
-          + "attributes('MaxValue'='100', 'MinValue'='1')",
-      "create timeseries root.turbine.d2.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
-          + "tags('unit'='kw', 'description'='turbine d2 this is a test2') "
-          + "attributes('MaxValue'='99.9', 'MinValue'='44.4')",
-      "create timeseries root.turbine.d2.s3(status) with datatype=INT32, encoding=RLE "
-          + "tags('description'='turbine d2 this is a test3') "
-          + "attributes('MaxValue'='9', 'MinValue'='5')",
-      "create timeseries root.ln.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
-          + "tags('unit'='f', 'description'='ln this is a test1') "
-          + "attributes('H_Alarm'='1000', 'M_Alarm'='500')",
-      "create timeseries root.ln.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
-          + "tags('unit'='w', 'description'='ln this is a test2') "
-          + "attributes('H_Alarm'='9.9', 'M_Alarm'='4.4')",
-      "create timeseries root.ln.d1.s0(status) with datatype=INT32, encoding=RLE "
-          + "tags('description'='ln this is a test3') "
-          + "attributes('H_Alarm'='90', 'M_Alarm'='50')",
-    };
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-      for (String sql : sqls) {
-        statement.execute(sql);
-      }
-
-      statement.execute("delete timeseries root.turbine.d2.s0");
-
-      // with *
-      boolean hasResult = statement.execute("show timeseries where 'unit'='f'");
-      assertTrue(hasResult);
-      int count = 0;
-      Set<String> res = new HashSet<>();
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          String ans =
-              resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ALIAS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_STORAGE_GROUP)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_DATATYPE)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_ENCODING)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TIMESERIES_COMPRESSION)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_TAGS)
-                  + ","
-                  + resultSet.getString(ColumnHeaderConstant.COLUMN_ATTRIBUTES);
-
-          res.add(ans);
-          count++;
-        }
-      }
-      assertEquals(ret, res);
-      assertEquals(ret.size(), count);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      fail();
-    }
-  }
-}
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeleteTimeseriesIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeleteTimeseriesIT.java
deleted file mode 100644
index a86b591b02..0000000000
--- a/integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeleteTimeseriesIT.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * 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.integration.aligned;
-
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.utils.EnvironmentUtils;
-import org.apache.iotdb.itbase.category.LocalStandaloneTest;
-import org.apache.iotdb.jdbc.Config;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.Statement;
-
-import static org.apache.iotdb.db.constant.TestConstant.TIMESTAMP_STR;
-import static org.apache.iotdb.db.constant.TestConstant.count;
-import static org.junit.Assert.fail;
-
-@Category({LocalStandaloneTest.class})
-public class IoTDBDeleteTimeseriesIT {
-
-  private long memtableSizeThreshold;
-
-  @Before
-  public void setUp() throws ClassNotFoundException {
-    Class.forName(Config.JDBC_DRIVER_NAME);
-    EnvironmentUtils.envSetUp();
-    memtableSizeThreshold = IoTDBDescriptor.getInstance().getConfig().getMemtableSizeThreshold();
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(16);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(memtableSizeThreshold);
-    EnvironmentUtils.cleanEnv();
-  }
-
-  @Test
-  public void deleteTimeseriesAndCreateDifferentTypeTest() throws Exception {
-    String[] retArray = new String[] {"1,1,", "2,1.1,"};
-    int cnt = 0;
-
-    try (Connection connection =
-            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
-        Statement statement = connection.createStatement()) {
-      statement.execute(
-          "create aligned timeseries root.turbine1.d1(s1 INT64 encoding=PLAIN compression=SNAPPY, "
-              + "s2 INT64 encoding=PLAIN compression=SNAPPY)");
-      statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1,s2) ALIGNED VALUES(1,1,2)");
-      boolean hasResult = statement.execute("SELECT s1 FROM root.turbine1.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-      statement.execute("DELETE timeseries root.turbine1.d1.s1");
-      statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1) ALIGNED VALUES(2,1.1)");
-      statement.execute("FLUSH");
-
-      hasResult = statement.execute("SELECT s1 FROM root.turbine1.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-    }
-
-    EnvironmentUtils.restartDaemon();
-
-    try (Connection connection =
-            DriverManager.getConnection(
-                Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
-        Statement statement = connection.createStatement()) {
-      boolean hasResult = statement.execute("SELECT * FROM root.**");
-      Assert.assertTrue(hasResult);
-    }
-  }
-
-  @Test
-  public void deleteTimeseriesAndCreateSameTypeTest() throws Exception {
-    String[] retArray = new String[] {"1,1.0,", "2,5.0,"};
-    int cnt = 0;
-
-    try (Connection connection =
-            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
-        Statement statement = connection.createStatement()) {
-      statement.execute(
-          "create aligned timeseries root.turbine1.d1(s1 FLOAT encoding=PLAIN compression=SNAPPY, "
-              + "s2 INT64 encoding=PLAIN compression=SNAPPY)");
-      statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1,s2) ALIGNED VALUES(1,1,2)");
-      boolean hasResult = statement.execute("SELECT s1 FROM root.turbine1.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-      statement.execute("DELETE timeseries root.turbine1.d1.s1");
-      statement.execute("INSERT INTO root.turbine1.d1(timestamp,s1) ALIGNED VALUES(2,5)");
-      statement.execute("FLUSH");
-
-      hasResult = statement.execute("SELECT s1 FROM root.turbine1.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-    }
-
-    EnvironmentUtils.restartDaemon();
-
-    try (Connection connection =
-            DriverManager.getConnection(
-                Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
-        Statement statement = connection.createStatement()) {
-      boolean hasResult = statement.execute("SELECT * FROM root.**");
-      Assert.assertTrue(hasResult);
-    }
-  }
-
-  @Test
-  public void deleteTimeseriesAndChangeDeviceAlignmentTest() throws Exception {
-    String[] retArray = new String[] {"1,1.0,2.0,"};
-    int cnt = 0;
-
-    try (Connection connection =
-            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
-        Statement statement = connection.createStatement()) {
-      statement.execute("INSERT INTO root.sg3.d1(timestamp,s1,s2) ALIGNED VALUES(1,1,2)");
-      statement.execute("SHOW DEVICES");
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          Assert.assertEquals("true", resultSet.getString("isAligned"));
-        }
-      }
-      cnt = 0;
-      statement.execute("DELETE timeseries root.sg3.d1.s1");
-      statement.execute("DELETE timeseries root.sg3.d1.s2");
-      statement.execute("INSERT INTO root.sg3.d1(timestamp,s1,s2) VALUES(1,1,2)");
-      statement.execute("SHOW DEVICES");
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          Assert.assertEquals("false", resultSet.getString("isAligned"));
-        }
-      }
-      boolean hasResult = statement.execute("SELECT * FROM root.sg3.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-      cnt = 0;
-      statement.execute("DELETE timeseries root.sg3.d1.s1");
-      statement.execute("DELETE timeseries root.sg3.d1.s2");
-      statement.execute("INSERT INTO root.sg3.d1(timestamp,s1,s2) ALIGNED VALUES(1,1,2)");
-      statement.execute("SHOW DEVICES");
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          Assert.assertEquals("true", resultSet.getString("isAligned"));
-        }
-      }
-      hasResult = statement.execute("SELECT * FROM root.sg3.d1");
-      Assert.assertTrue(hasResult);
-      try (ResultSet resultSet = statement.getResultSet()) {
-        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
-        while (resultSet.next()) {
-          StringBuilder builder = new StringBuilder();
-          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
-            builder.append(resultSet.getString(i)).append(",");
-          }
-          Assert.assertEquals(retArray[cnt], builder.toString());
-          cnt++;
-        }
-      }
-    }
-  }
-
-  @Test
-  public void deleteTimeSeriesMultiIntervalTest() {
-    String[] retArray1 = new String[] {"0,0"};
-
-    int preAvgSeriesPointNumberThreshold =
-        IoTDBDescriptor.getInstance().getConfig().getAvgSeriesPointNumberThreshold();
-    try (Connection connection =
-            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
-        Statement statement = connection.createStatement()) {
-
-      IoTDBDescriptor.getInstance().getConfig().setAvgSeriesPointNumberThreshold(2);
-      String insertSql = "insert into root.sg.d1(time, s1) aligned values(%d, %d)";
-      for (int i = 1; i <= 4; i++) {
-        statement.execute(String.format(insertSql, i, i));
-      }
-      statement.execute("flush");
-
-      statement.execute("delete from root.sg.d1.s1 where time >= 1 and time <= 2");
-      statement.execute("delete from root.sg.d1.s1 where time >= 3 and time <= 4");
-
-      boolean hasResultSet =
-          statement.execute("select count(s1) from root.sg.d1 where time >= 3 and time <= 4");
-
-      Assert.assertTrue(hasResultSet);
-      int cnt = 0;
-      try (ResultSet resultSet = statement.getResultSet()) {
-        while (resultSet.next()) {
-          String ans =
-              resultSet.getString(TIMESTAMP_STR)
-                  + ","
-                  + resultSet.getString(count("root.sg.d1.s1"));
-          Assert.assertEquals(retArray1[cnt], ans);
-          cnt++;
-        }
-        Assert.assertEquals(retArray1.length, cnt);
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-      fail(e.getMessage());
-    } finally {
-      IoTDBDescriptor.getInstance()
-          .getConfig()
-          .setAvgSeriesPointNumberThreshold(preAvgSeriesPointNumberThreshold);
-    }
-  }
-}
diff --git a/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/RSchemaRegion.java b/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/RSchemaRegion.java
index f82465708f..6aed5211f7 100644
--- a/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/RSchemaRegion.java
+++ b/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/RSchemaRegion.java
@@ -56,6 +56,7 @@ import org.apache.iotdb.db.metadata.schemaregion.rocksdb.mnode.RMeasurementMNode
 import org.apache.iotdb.db.metadata.template.Template;
 import org.apache.iotdb.db.metadata.utils.MetaFormatUtils;
 import org.apache.iotdb.db.mpp.common.schematree.DeviceSchemaInfo;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertTabletPlan;
@@ -681,6 +682,27 @@ public class RSchemaRegion implements ISchemaRegion {
     }
   }
 
+  @Override
+  public int constructSchemaBlackList(PathPatternTree patternTree) throws MetadataException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void rollbackSchemaBlackList(PathPatternTree patternTree) throws MetadataException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public List<PartialPath> fetchSchemaBlackList(PathPatternTree patternTree)
+      throws MetadataException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void deleteTimeseriesInBlackList(PathPatternTree patternTree) throws MetadataException {
+    throw new UnsupportedOperationException();
+  }
+
   private void traverseOutcomeBasins(
       String[] nodes,
       int maxLevel,
diff --git a/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/mnode/RMeasurementMNode.java b/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/mnode/RMeasurementMNode.java
index fe52cb7207..fc87ad1321 100644
--- a/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/mnode/RMeasurementMNode.java
+++ b/schema-engine-rocksdb/src/main/java/org/apache/iotdb/db/metadata/schemaregion/rocksdb/mnode/RMeasurementMNode.java
@@ -151,6 +151,14 @@ public class RMeasurementMNode extends RMNode implements IMeasurementMNode {
     throw new UnsupportedOperationException();
   }
 
+  @Override
+  public boolean isPreDeleted() {
+    return false;
+  }
+
+  @Override
+  public void setPreDeleted(boolean preDeleted) {}
+
   @Override
   public void serializeTo(MLogWriter logWriter) throws IOException {
     throw new UnsupportedOperationException();
diff --git a/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java b/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
index de2bc80f93..2dceb33ed5 100644
--- a/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
+++ b/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
@@ -51,6 +51,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TDataPartitionReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDataPartitionTableResp;
 import org.apache.iotdb.confignode.rpc.thrift.TDeleteStorageGroupReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDeleteStorageGroupsReq;
+import org.apache.iotdb.confignode.rpc.thrift.TDeleteTimeSeriesReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDropFunctionReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDropTriggerReq;
 import org.apache.iotdb.confignode.rpc.thrift.TGetAllTemplatesResp;
@@ -982,6 +983,22 @@ public class ConfigNodeClient
     throw new TException(MSG_RECONNECTION_FAIL);
   }
 
+  @Override
+  public TSStatus deleteTimeSeries(TDeleteTimeSeriesReq req) throws TException {
+    for (int i = 0; i < RETRY_NUM; i++) {
+      try {
+        TSStatus status = client.deleteTimeSeries(req);
+        if (!updateConfigNodeLeader(status)) {
+          return status;
+        }
+      } catch (TException e) {
+        configLeader = null;
+      }
+      reconnect();
+    }
+    throw new TException(MSG_RECONNECTION_FAIL);
+  }
+
   public static class Factory extends BaseClientFactory<PartitionRegionId, ConfigNodeClient> {
 
     public Factory(
diff --git a/server/src/main/java/org/apache/iotdb/db/client/DataNodeClientPoolFactory.java b/server/src/main/java/org/apache/iotdb/db/client/DataNodeClientPoolFactory.java
index 996e2372d5..09305eeeb3 100644
--- a/server/src/main/java/org/apache/iotdb/db/client/DataNodeClientPoolFactory.java
+++ b/server/src/main/java/org/apache/iotdb/db/client/DataNodeClientPoolFactory.java
@@ -158,4 +158,24 @@ public class DataNodeClientPoolFactory {
           new ClientPoolProperty.Builder<ConfigNodeClient>().build().getConfig());
     }
   }
+
+  public static class ClusterDeletionConfigNodeClientPoolFactory
+      implements IClientPoolFactory<PartitionRegionId, ConfigNodeClient> {
+    @Override
+    public KeyedObjectPool<PartitionRegionId, ConfigNodeClient> createClientPool(
+        ClientManager<PartitionRegionId, ConfigNodeClient> manager) {
+      return new GenericKeyedObjectPool<>(
+          new ConfigNodeClient.Factory(
+              manager,
+              new ClientFactoryProperty.Builder()
+                  .setConnectionTimeoutMs(conf.getConnectionTimeoutInMS() * 10)
+                  .setRpcThriftCompressionEnabled(conf.isRpcThriftCompressionEnable())
+                  .setSelectorNumOfAsyncClientManager(
+                      conf.getSelectorNumOfClientManager() / 10 > 0
+                          ? conf.getSelectorNumOfClientManager() / 10
+                          : 1)
+                  .build()),
+          new ClientPoolProperty.Builder<ConfigNodeClient>().build().getConfig());
+    }
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/DeleteTimeSeriesStatement.java b/server/src/main/java/org/apache/iotdb/db/exception/metadata/MeasurementInBlackListException.java
similarity index 58%
copy from server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/DeleteTimeSeriesStatement.java
copy to server/src/main/java/org/apache/iotdb/db/exception/metadata/MeasurementInBlackListException.java
index 99cb5b57ff..3aef42cec0 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/DeleteTimeSeriesStatement.java
+++ b/server/src/main/java/org/apache/iotdb/db/exception/metadata/MeasurementInBlackListException.java
@@ -15,31 +15,27 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
+ *
  */
 
-package org.apache.iotdb.db.mpp.plan.statement.metadata;
+package org.apache.iotdb.db.exception.metadata;
 
+import org.apache.iotdb.commons.exception.MetadataException;
 import org.apache.iotdb.commons.path.PartialPath;
-import org.apache.iotdb.db.mpp.plan.statement.Statement;
-import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
-
-import java.util.List;
+import org.apache.iotdb.rpc.TSStatusCode;
 
-public class DeleteTimeSeriesStatement extends Statement {
+public class MeasurementInBlackListException extends MetadataException {
 
-  List<PartialPath> partialPaths;
-
-  @Override
-  public List<PartialPath> getPaths() {
-    return partialPaths;
-  }
+  private final PartialPath path;
 
-  public void setPartialPaths(List<PartialPath> partialPaths) {
-    this.partialPaths = partialPaths;
+  public MeasurementInBlackListException(PartialPath path) {
+    super(
+        String.format("Some task is deleting timeseries [%s]", path),
+        TSStatusCode.MEASUREMENT_IN_BLACK_LIST.getStatusCode());
+    this.path = path;
   }
 
-  @Override
-  public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
-    return visitor.visitDeleteTimeseries(this, context);
+  public PartialPath getPath() {
+    return path;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/cache/DataNodeSchemaCache.java b/server/src/main/java/org/apache/iotdb/db/metadata/cache/DataNodeSchemaCache.java
index 6c88cbb870..bc8ae11d08 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/cache/DataNodeSchemaCache.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/cache/DataNodeSchemaCache.java
@@ -34,6 +34,8 @@ import com.github.benmanes.caffeine.cache.Caffeine;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
 /**
  * This class takes the responsibility of metadata cache management of all DataRegions under
  * StorageEngine
@@ -45,6 +47,9 @@ public class DataNodeSchemaCache {
 
   private final Cache<PartialPath, SchemaCacheEntry> cache;
 
+  // cache update or clean have higher priority than cache read
+  private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(false);
+
   private DataNodeSchemaCache() {
     cache =
         Caffeine.newBuilder()
@@ -69,6 +74,23 @@ public class DataNodeSchemaCache {
     private static final DataNodeSchemaCache INSTANCE = new DataNodeSchemaCache();
   }
 
+  public void takeReadLock() {
+    readWriteLock.readLock().lock();
+  }
+
+  public void releaseReadLock() {
+    readWriteLock.readLock().unlock();
+  }
+
+  public void takeWriteLock() {
+    readWriteLock.writeLock().lock();
+    ;
+  }
+
+  public void releaseWriteLock() {
+    readWriteLock.writeLock().unlock();
+  }
+
   /**
    * Get SchemaEntity info without auto create schema
    *
@@ -176,6 +198,17 @@ public class DataNodeSchemaCache {
     cache.invalidate(partialPath);
   }
 
+  public void invalidateMatchedSchema(PartialPath pathPattern) {
+    cache
+        .asMap()
+        .forEach(
+            (k, v) -> {
+              if (pathPattern.matchFullPath(k)) {
+                cache.invalidate(k);
+              }
+            });
+  }
+
   public long estimatedSize() {
     return cache.estimatedSize();
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/InsertMeasurementMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/InsertMeasurementMNode.java
index eb3b6e8e47..816de2d3eb 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/InsertMeasurementMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/InsertMeasurementMNode.java
@@ -98,6 +98,14 @@ public class InsertMeasurementMNode implements IMeasurementMNode {
   @Override
   public void setLastCacheContainer(ILastCacheContainer lastCacheContainer) {}
 
+  @Override
+  public boolean isPreDeleted() {
+    return false;
+  }
+
+  @Override
+  public void setPreDeleted(boolean preDeleted) {}
+
   @Override
   public IMeasurementSchema getSchema() {
     return schema;
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java
index fca21a9cbd..2ef5f09da7 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java
@@ -51,4 +51,8 @@ public interface IMeasurementMNode extends IMNode {
   ILastCacheContainer getLastCacheContainer();
 
   void setLastCacheContainer(ILastCacheContainer lastCacheContainer);
+
+  boolean isPreDeleted();
+
+  void setPreDeleted(boolean preDeleted);
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
index da8e92bffb..f15e71911d 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
@@ -46,6 +46,8 @@ public class MeasurementMNode extends MNode implements IMeasurementMNode {
   private long offset = -1;
   /** measurement's Schema for one timeseries represented by current leaf node */
   private IMeasurementSchema schema;
+  /** whether this measurement is pre deleted and considered in black list */
+  private boolean preDeleted = false;
   /** last value cache */
   private volatile ILastCacheContainer lastCacheContainer = null;
 
@@ -149,6 +151,16 @@ public class MeasurementMNode extends MNode implements IMeasurementMNode {
     this.lastCacheContainer = lastCacheContainer;
   }
 
+  @Override
+  public boolean isPreDeleted() {
+    return preDeleted;
+  }
+
+  @Override
+  public void setPreDeleted(boolean preDeleted) {
+    this.preDeleted = preDeleted;
+  }
+
   @Override
   public void serializeTo(MLogWriter logWriter) throws IOException {
     logWriter.serializeMeasurementMNode(this);
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGMemoryImpl.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGMemoryImpl.java
index 4151063116..4f7b87209b 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGMemoryImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTreeBelowSGMemoryImpl.java
@@ -28,6 +28,7 @@ import org.apache.iotdb.db.exception.metadata.AliasAlreadyExistException;
 import org.apache.iotdb.db.exception.metadata.AlignedTimeseriesException;
 import org.apache.iotdb.db.exception.metadata.MNodeTypeMismatchException;
 import org.apache.iotdb.db.exception.metadata.MeasurementAlreadyExistException;
+import org.apache.iotdb.db.exception.metadata.MeasurementInBlackListException;
 import org.apache.iotdb.db.exception.metadata.PathAlreadyExistException;
 import org.apache.iotdb.db.exception.metadata.PathNotExistException;
 import org.apache.iotdb.db.exception.metadata.template.TemplateImcompatibeException;
@@ -208,8 +209,12 @@ public class MTreeBelowSGMemoryImpl implements IMTreeBelowSG {
       if (device.hasChild(leafName)) {
         IMNode node = device.getChild(leafName);
         if (node.isMeasurement()) {
-          throw new MeasurementAlreadyExistException(
-              path.getFullPath(), node.getAsMeasurementMNode().getMeasurementPath());
+          if (node.getAsMeasurementMNode().isPreDeleted()) {
+            throw new MeasurementInBlackListException(path);
+          } else {
+            throw new MeasurementAlreadyExistException(
+                path.getFullPath(), node.getAsMeasurementMNode().getMeasurementPath());
+          }
         } else {
           throw new PathAlreadyExistException(path.getFullPath());
         }
@@ -284,9 +289,13 @@ public class MTreeBelowSGMemoryImpl implements IMTreeBelowSG {
         if (device.hasChild(measurements.get(i))) {
           IMNode node = device.getChild(measurements.get(i));
           if (node.isMeasurement()) {
-            throw new MeasurementAlreadyExistException(
-                devicePath.getFullPath() + "." + measurements.get(i),
-                node.getAsMeasurementMNode().getMeasurementPath());
+            if (node.getAsMeasurementMNode().isPreDeleted()) {
+              throw new MeasurementInBlackListException(devicePath.concatNode(measurements.get(i)));
+            } else {
+              throw new MeasurementAlreadyExistException(
+                  devicePath.getFullPath() + "." + measurements.get(i),
+                  node.getAsMeasurementMNode().getMeasurementPath());
+            }
           } else {
             throw new PathAlreadyExistException(
                 devicePath.getFullPath() + "." + measurements.get(i));
@@ -442,6 +451,23 @@ public class MTreeBelowSGMemoryImpl implements IMTreeBelowSG {
         && node.getChildren().isEmpty();
   }
 
+  public List<PartialPath> getPreDeleteTimeseries(PartialPath pathPattern)
+      throws MetadataException {
+    List<PartialPath> result = new LinkedList<>();
+    MeasurementCollector<List<PartialPath>> collector =
+        new MeasurementCollector<List<PartialPath>>(storageGroupMNode, pathPattern, store) {
+          @Override
+          protected void collectMeasurement(IMeasurementMNode node) throws MetadataException {
+            if (node.isPreDeleted()) {
+              result.add(getCurrentPartialPath(node));
+            }
+          }
+        };
+    collector.setResultSet(result);
+    collector.traverse();
+    return result;
+  }
+
   @Override
   public void setAlias(IMeasurementMNode measurementMNode, String alias) throws MetadataException {
     store.setAlias(measurementMNode, alias);
@@ -675,6 +701,9 @@ public class MTreeBelowSGMemoryImpl implements IMTreeBelowSG {
         new MeasurementCollector<List<PartialPath>>(storageGroupMNode, pathPattern, store) {
           @Override
           protected void collectMeasurement(IMeasurementMNode node) {
+            if (node.isPreDeleted()) {
+              return;
+            }
             MeasurementPath path = getCurrentMeasurementPathInTraverse(node);
             if (nodes[nodes.length - 1].equals(node.getAlias())) {
               // only when user query with alias, the alias in path will be set
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/snapshot/MemMTreeSnapshotUtil.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/snapshot/MemMTreeSnapshotUtil.java
index 6059872c20..a95af2a670 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/snapshot/MemMTreeSnapshotUtil.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/snapshot/MemMTreeSnapshotUtil.java
@@ -289,6 +289,7 @@ public class MemMTreeSnapshotUtil {
         node.getSchema().serializeTo(outputStream);
         ReadWriteIOUtils.write(node.getAlias(), outputStream);
         ReadWriteIOUtils.write(node.getOffset(), outputStream);
+        ReadWriteIOUtils.write(node.isPreDeleted(), outputStream);
         return true;
       } catch (IOException e) {
         logger.error(SERIALIZE_ERROR_INFO, e);
@@ -347,6 +348,7 @@ public class MemMTreeSnapshotUtil {
       long tagOffset = ReadWriteIOUtils.readLong(inputStream);
       MeasurementMNode node = new MeasurementMNode(null, name, schema, alias);
       node.setOffset(tagOffset);
+      node.setPreDeleted(ReadWriteIOUtils.readBool(inputStream));
       return node;
     }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/ISchemaRegion.java b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/ISchemaRegion.java
index 860d5b2005..e8b444a480 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/ISchemaRegion.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/ISchemaRegion.java
@@ -30,6 +30,7 @@ import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
 import org.apache.iotdb.db.metadata.path.MeasurementPath;
 import org.apache.iotdb.db.metadata.template.Template;
 import org.apache.iotdb.db.mpp.common.schematree.DeviceSchemaInfo;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.sys.ActivateTemplateInClusterPlan;
 import org.apache.iotdb.db.qp.physical.sys.ActivateTemplatePlan;
@@ -118,6 +119,32 @@ public interface ISchemaRegion {
    */
   Pair<Integer, Set<String>> deleteTimeseries(PartialPath pathPattern, boolean isPrefixMatch)
       throws MetadataException;
+
+  /**
+   * Construct schema black list via setting matched timeseries to pre deleted.
+   *
+   * @param patternTree
+   * @throws MetadataException
+   */
+  int constructSchemaBlackList(PathPatternTree patternTree) throws MetadataException;
+
+  /**
+   * Rollback schema black list via setting matched timeseries to not pre deleted.
+   *
+   * @param patternTree
+   * @throws MetadataException
+   */
+  void rollbackSchemaBlackList(PathPatternTree patternTree) throws MetadataException;
+
+  List<PartialPath> fetchSchemaBlackList(PathPatternTree patternTree) throws MetadataException;
+
+  /**
+   * Delete timeseries in schema black list.
+   *
+   * @param patternTree
+   * @throws MetadataException
+   */
+  void deleteTimeseriesInBlackList(PathPatternTree patternTree) throws MetadataException;
   // endregion
 
   // region Interfaces for auto create device
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionMemoryImpl.java b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionMemoryImpl.java
index 90394b6041..b52936f158 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionMemoryImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionMemoryImpl.java
@@ -59,6 +59,7 @@ import org.apache.iotdb.db.metadata.template.Template;
 import org.apache.iotdb.db.metadata.template.TemplateManager;
 import org.apache.iotdb.db.mpp.common.schematree.DeviceSchemaInfo;
 import org.apache.iotdb.db.mpp.common.schematree.MeasurementSchemaInfo;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
@@ -72,6 +73,8 @@ import org.apache.iotdb.db.qp.physical.sys.ChangeTagOffsetPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.PreDeleteTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.RollbackPreDeleteTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.SetTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.ShowDevicesPlan;
 import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
@@ -441,6 +444,15 @@ public class SchemaRegionMemoryImpl implements ISchemaRegion {
             (ActivateTemplateInClusterPlan) plan;
         recoverActivatingSchemaTemplate(activateTemplateInClusterPlan);
         break;
+      case PRE_DELETE_TIMESERIES_IN_CLUSTER:
+        PreDeleteTimeSeriesPlan preDeleteTimeSeriesPlan = (PreDeleteTimeSeriesPlan) plan;
+        recoverPreDeleteTimeseries(preDeleteTimeSeriesPlan.getPath());
+        break;
+      case ROLLBACK_PRE_DELETE_TIMESERIES:
+        RollbackPreDeleteTimeSeriesPlan rollbackPreDeleteTimeSeriesPlan =
+            (RollbackPreDeleteTimeSeriesPlan) plan;
+        recoverRollbackPreDeleteTimeseries(rollbackPreDeleteTimeSeriesPlan.getPath());
+        break;
       default:
         logger.error("Unrecognizable command {}", plan.getOperatorType());
     }
@@ -831,6 +843,97 @@ public class SchemaRegionMemoryImpl implements ISchemaRegion {
     }
   }
 
+  @Override
+  public int constructSchemaBlackList(PathPatternTree patternTree) throws MetadataException {
+    int preDeletedNum = 0;
+    for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+      for (PartialPath path : mtree.getMeasurementPaths(pathPattern)) {
+        IMeasurementMNode measurementMNode = mtree.getMeasurementMNode(path);
+        // Given pathPatterns may match one timeseries multi times, which may results in the
+        // preDeletedNum larger than the actual num of timeseries. It doesn't matter since the main
+        // purpose is to check whether there's timeseries to be deleted.
+        preDeletedNum++;
+        measurementMNode.setPreDeleted(true);
+        try {
+          writeToMLog(new PreDeleteTimeSeriesPlan(path));
+        } catch (IOException e) {
+          throw new MetadataException(e);
+        }
+      }
+    }
+    return preDeletedNum;
+  }
+
+  private void recoverPreDeleteTimeseries(PartialPath path) throws MetadataException {
+    IMeasurementMNode measurementMNode = mtree.getMeasurementMNode(path);
+    measurementMNode.setPreDeleted(true);
+  }
+
+  @Override
+  public void rollbackSchemaBlackList(PathPatternTree patternTree) throws MetadataException {
+    for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+      for (PartialPath path : mtree.getMeasurementPaths(pathPattern)) {
+        IMeasurementMNode measurementMNode = mtree.getMeasurementMNode(path);
+        measurementMNode.setPreDeleted(false);
+        try {
+          writeToMLog(new RollbackPreDeleteTimeSeriesPlan(path));
+        } catch (IOException e) {
+          throw new MetadataException(e);
+        }
+      }
+    }
+  }
+
+  @Override
+  public List<PartialPath> fetchSchemaBlackList(PathPatternTree patternTree)
+      throws MetadataException {
+    List<PartialPath> pathList = new ArrayList<>();
+    for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+      pathList.addAll(mtree.getPreDeleteTimeseries(pathPattern));
+    }
+    return pathList;
+  }
+
+  @Override
+  public void deleteTimeseriesInBlackList(PathPatternTree patternTree) throws MetadataException {
+    for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+      for (PartialPath path : mtree.getPreDeleteTimeseries(pathPattern)) {
+        try {
+          deleteSingleTimeseriesInBlackList(path);
+          writeToMLog(new DeleteTimeSeriesPlan(Collections.singletonList(path)));
+        } catch (IOException e) {
+          throw new MetadataException(e);
+        }
+      }
+    }
+  }
+
+  private void deleteSingleTimeseriesInBlackList(PartialPath path)
+      throws MetadataException, IOException {
+    Pair<PartialPath, IMeasurementMNode> pair =
+        mtree.deleteTimeseriesAndReturnEmptyStorageGroup(path);
+
+    IMeasurementMNode measurementMNode = pair.right;
+    removeFromTagInvertedIndex(measurementMNode);
+
+    IMNode node = measurementMNode.getParent();
+
+    if (node.isUseTemplate() && node.getSchemaTemplate().hasSchema(measurementMNode.getName())) {
+      // measurement represent by template doesn't affect the MTree structure and memory control
+      return;
+    }
+
+    mNodeCache.invalidate(node.getPartialPath());
+
+    schemaStatisticsManager.deleteTimeseries(1);
+    seriesNumerLimiter.deleteTimeSeries(1);
+  }
+
+  private void recoverRollbackPreDeleteTimeseries(PartialPath path) throws MetadataException {
+    IMeasurementMNode measurementMNode = mtree.getMeasurementMNode(path);
+    measurementMNode.setPreDeleted(false);
+  }
+
   /**
    * Delete all timeseries matching the given path pattern
    *
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionSchemaFileImpl.java b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionSchemaFileImpl.java
index 051f78898f..1ce7ecf550 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionSchemaFileImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaRegionSchemaFileImpl.java
@@ -56,6 +56,7 @@ import org.apache.iotdb.db.metadata.tag.TagManager;
 import org.apache.iotdb.db.metadata.template.Template;
 import org.apache.iotdb.db.metadata.template.TemplateManager;
 import org.apache.iotdb.db.mpp.common.schematree.DeviceSchemaInfo;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
@@ -753,6 +754,27 @@ public class SchemaRegionSchemaFileImpl implements ISchemaRegion {
     }
   }
 
+  @Override
+  public int constructSchemaBlackList(PathPatternTree patternTree) throws MetadataException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void rollbackSchemaBlackList(PathPatternTree patternTree) throws MetadataException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public List<PartialPath> fetchSchemaBlackList(PathPatternTree patternTree)
+      throws MetadataException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void deleteTimeseriesInBlackList(PathPatternTree patternTree) throws MetadataException {
+    throw new UnsupportedOperationException();
+  }
+
   /**
    * Delete all timeseries matching the given path pattern
    *
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/visitor/SchemaExecutionVisitor.java b/server/src/main/java/org/apache/iotdb/db/metadata/visitor/SchemaExecutionVisitor.java
index be37ccf002..d44af00add 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/visitor/SchemaExecutionVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/visitor/SchemaExecutionVisitor.java
@@ -32,11 +32,14 @@ import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanVisitor;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.ActivateTemplateNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.AlterTimeSeriesNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.ConstructSchemaBlackListNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.CreateAlignedTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.CreateMultiTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.CreateTimeSeriesNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.DeleteTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.InternalCreateTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.MeasurementGroup;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.RollbackSchemaBlackListNode;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.db.qp.physical.sys.ActivateTemplateInClusterPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
@@ -303,6 +306,41 @@ public class SchemaExecutionVisitor extends PlanVisitor<TSStatus, ISchemaRegion>
     }
   }
 
+  @Override
+  public TSStatus visitConstructSchemaBlackList(
+      ConstructSchemaBlackListNode node, ISchemaRegion schemaRegion) {
+    try {
+      int preDeletedNum = schemaRegion.constructSchemaBlackList(node.getPatternTree());
+      return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, String.valueOf(preDeletedNum));
+    } catch (MetadataException e) {
+      logger.error(e.getMessage(), e);
+      return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
+    }
+  }
+
+  @Override
+  public TSStatus visitRollbackSchemaBlackList(
+      RollbackSchemaBlackListNode node, ISchemaRegion schemaRegion) {
+    try {
+      schemaRegion.rollbackSchemaBlackList(node.getPatternTree());
+      return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS);
+    } catch (MetadataException e) {
+      logger.error(e.getMessage(), e);
+      return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
+    }
+  }
+
+  @Override
+  public TSStatus visitDeleteTimeseries(DeleteTimeSeriesNode node, ISchemaRegion schemaRegion) {
+    try {
+      schemaRegion.deleteTimeseriesInBlackList(node.getPatternTree());
+      return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS);
+    } catch (MetadataException e) {
+      logger.error(e.getMessage(), e);
+      return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
+    }
+  }
+
   @Override
   public TSStatus visitPlan(PlanNode node, ISchemaRegion context) {
     return null;
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/PathPatternTree.java b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/PathPatternTree.java
index df8b8f3b35..970e8715cc 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/PathPatternTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/PathPatternTree.java
@@ -218,6 +218,16 @@ public class PathPatternTree {
     return new PartialPath(nodeList.toArray(new String[0]));
   }
 
+  public boolean isOverlapWith(PathPatternTree patternTree) {
+    // todo improve this implementation
+    for (PartialPath pathPattern : getAllPathPatterns()) {
+      if (!patternTree.getOverlappedPathPatterns(pathPattern).isEmpty()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // serialize & deserialize
   /////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ClusterSchemaFetcher.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ClusterSchemaFetcher.java
index c3dbb79aea..49daadf555 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ClusterSchemaFetcher.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ClusterSchemaFetcher.java
@@ -176,42 +176,47 @@ public class ClusterSchemaFetcher implements ISchemaFetcher {
       String[] measurements,
       Function<Integer, TSDataType> getDataType,
       boolean isAligned) {
-    ClusterSchemaTree schemaTree = schemaCache.get(devicePath, measurements);
-    List<Integer> indexOfMissingMeasurements =
-        checkMissingMeasurements(schemaTree, devicePath, measurements);
+    schemaCache.takeReadLock();
+    try {
+      ClusterSchemaTree schemaTree = schemaCache.get(devicePath, measurements);
+      List<Integer> indexOfMissingMeasurements =
+          checkMissingMeasurements(schemaTree, devicePath, measurements);
 
-    if (indexOfMissingMeasurements.isEmpty()) {
-      return schemaTree;
-    }
+      if (indexOfMissingMeasurements.isEmpty()) {
+        return schemaTree;
+      }
 
-    PathPatternTree patternTree = new PathPatternTree();
-    for (int index : indexOfMissingMeasurements) {
-      patternTree.appendFullPath(devicePath, measurements[index]);
-    }
+      PathPatternTree patternTree = new PathPatternTree();
+      for (int index : indexOfMissingMeasurements) {
+        patternTree.appendFullPath(devicePath, measurements[index]);
+      }
 
-    ClusterSchemaTree remoteSchemaTree = fetchSchema(patternTree);
-    if (!remoteSchemaTree.isEmpty()) {
-      schemaTree.mergeSchemaTree(remoteSchemaTree);
-      schemaCache.put(remoteSchemaTree);
-    }
+      ClusterSchemaTree remoteSchemaTree = fetchSchema(patternTree);
+      if (!remoteSchemaTree.isEmpty()) {
+        schemaTree.mergeSchemaTree(remoteSchemaTree);
+        schemaCache.put(remoteSchemaTree);
+      }
 
-    if (!config.isAutoCreateSchemaEnabled()) {
-      return schemaTree;
-    }
+      if (!config.isAutoCreateSchemaEnabled()) {
+        return schemaTree;
+      }
 
-    ClusterSchemaTree missingSchemaTree =
-        checkAndAutoCreateMissingMeasurements(
-            remoteSchemaTree,
-            devicePath,
-            indexOfMissingMeasurements,
-            measurements,
-            getDataType,
-            isAligned);
+      ClusterSchemaTree missingSchemaTree =
+          checkAndAutoCreateMissingMeasurements(
+              remoteSchemaTree,
+              devicePath,
+              indexOfMissingMeasurements,
+              measurements,
+              getDataType,
+              isAligned);
 
-    schemaTree.mergeSchemaTree(missingSchemaTree);
-    schemaCache.put(missingSchemaTree);
+      schemaTree.mergeSchemaTree(missingSchemaTree);
+      schemaCache.put(missingSchemaTree);
 
-    return schemaTree;
+      return schemaTree;
+    } finally {
+      schemaCache.releaseReadLock();
+    }
   }
 
   @Override
@@ -220,49 +225,53 @@ public class ClusterSchemaFetcher implements ISchemaFetcher {
       List<String[]> measurementsList,
       List<TSDataType[]> tsDataTypesList,
       List<Boolean> isAlignedList) {
+    schemaCache.takeReadLock();
+    try {
+      ClusterSchemaTree schemaTree = new ClusterSchemaTree();
+      PathPatternTree patternTree = new PathPatternTree();
+      List<List<Integer>> indexOfMissingMeasurementsList = new ArrayList<>(devicePathList.size());
+      for (int i = 0; i < devicePathList.size(); i++) {
+        schemaTree.mergeSchemaTree(schemaCache.get(devicePathList.get(i), measurementsList.get(i)));
+        List<Integer> indexOfMissingMeasurements =
+            checkMissingMeasurements(schemaTree, devicePathList.get(i), measurementsList.get(i));
+        indexOfMissingMeasurementsList.add(indexOfMissingMeasurements);
+        for (int index : indexOfMissingMeasurements) {
+          patternTree.appendFullPath(devicePathList.get(i), measurementsList.get(i)[index]);
+        }
+      }
 
-    ClusterSchemaTree schemaTree = new ClusterSchemaTree();
-    PathPatternTree patternTree = new PathPatternTree();
-    List<List<Integer>> indexOfMissingMeasurementsList = new ArrayList<>(devicePathList.size());
-    for (int i = 0; i < devicePathList.size(); i++) {
-      schemaTree.mergeSchemaTree(schemaCache.get(devicePathList.get(i), measurementsList.get(i)));
-      List<Integer> indexOfMissingMeasurements =
-          checkMissingMeasurements(schemaTree, devicePathList.get(i), measurementsList.get(i));
-      indexOfMissingMeasurementsList.add(indexOfMissingMeasurements);
-      for (int index : indexOfMissingMeasurements) {
-        patternTree.appendFullPath(devicePathList.get(i), measurementsList.get(i)[index]);
+      if (patternTree.isEmpty()) {
+        return schemaTree;
       }
-    }
 
-    if (patternTree.isEmpty()) {
-      return schemaTree;
-    }
+      ClusterSchemaTree remoteSchemaTree = fetchSchema(patternTree);
+      if (!remoteSchemaTree.isEmpty()) {
+        schemaTree.mergeSchemaTree(remoteSchemaTree);
+        schemaCache.put(remoteSchemaTree);
+      }
 
-    ClusterSchemaTree remoteSchemaTree = fetchSchema(patternTree);
-    if (!remoteSchemaTree.isEmpty()) {
-      schemaTree.mergeSchemaTree(remoteSchemaTree);
-      schemaCache.put(remoteSchemaTree);
-    }
+      if (!config.isAutoCreateSchemaEnabled()) {
+        return schemaTree;
+      }
 
-    if (!config.isAutoCreateSchemaEnabled()) {
+      ClusterSchemaTree missingSchemaTree;
+      for (int i = 0; i < devicePathList.size(); i++) {
+        int finalI = i;
+        missingSchemaTree =
+            checkAndAutoCreateMissingMeasurements(
+                schemaTree,
+                devicePathList.get(i),
+                indexOfMissingMeasurementsList.get(i),
+                measurementsList.get(i),
+                index -> tsDataTypesList.get(finalI)[index],
+                isAlignedList.get(i));
+        schemaTree.mergeSchemaTree(missingSchemaTree);
+        schemaCache.put(missingSchemaTree);
+      }
       return schemaTree;
+    } finally {
+      schemaCache.releaseReadLock();
     }
-
-    ClusterSchemaTree missingSchemaTree;
-    for (int i = 0; i < devicePathList.size(); i++) {
-      int finalI = i;
-      missingSchemaTree =
-          checkAndAutoCreateMissingMeasurements(
-              schemaTree,
-              devicePathList.get(i),
-              indexOfMissingMeasurementsList.get(i),
-              measurementsList.get(i),
-              index -> tsDataTypesList.get(finalI)[index],
-              isAlignedList.get(i));
-      schemaTree.mergeSchemaTree(missingSchemaTree);
-      schemaCache.put(missingSchemaTree);
-    }
-    return schemaTree;
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigExecution.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigExecution.java
index 91260063a5..be8a4491f1 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigExecution.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigExecution.java
@@ -68,7 +68,10 @@ public class ConfigExecution implements IQueryExecution {
     this.executor = executor;
     this.stateMachine = new QueryStateMachine(context.getQueryId(), executor);
     this.taskFuture = SettableFuture.create();
-    this.task = statement.accept(new ConfigTaskVisitor(), new ConfigTaskVisitor.TaskContext());
+    this.task =
+        statement.accept(
+            new ConfigTaskVisitor(),
+            new ConfigTaskVisitor.TaskContext(context.getQueryId().getId()));
     this.resultSetConsumed = false;
     if (config.isClusterMode()) {
       configTaskExecutor = ClusterConfigTaskExecutor.getInstance();
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
index 931ea8a0d6..aee5e3fff9 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.mpp.plan.execution.config.metadata.CountStorageGroupT
 import org.apache.iotdb.db.mpp.plan.execution.config.metadata.CreateFunctionTask;
 import org.apache.iotdb.db.mpp.plan.execution.config.metadata.CreateTriggerTask;
 import org.apache.iotdb.db.mpp.plan.execution.config.metadata.DeleteStorageGroupTask;
+import org.apache.iotdb.db.mpp.plan.execution.config.metadata.DeleteTimeSeriesTask;
 import org.apache.iotdb.db.mpp.plan.execution.config.metadata.DropFunctionTask;
 import org.apache.iotdb.db.mpp.plan.execution.config.metadata.DropTriggerTask;
 import org.apache.iotdb.db.mpp.plan.execution.config.metadata.SetStorageGroupTask;
@@ -61,6 +62,7 @@ import org.apache.iotdb.db.mpp.plan.statement.metadata.CountStorageGroupStatemen
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateFunctionStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateTriggerStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteStorageGroupStatement;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteTimeSeriesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.DropFunctionStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.DropTriggerStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetStorageGroupStatement;
@@ -302,5 +304,22 @@ public class ConfigTaskVisitor
     return new StopPipeTask(stopPipeStatement);
   }
 
-  public static class TaskContext {}
+  @Override
+  public IConfigTask visitDeleteTimeseries(
+      DeleteTimeSeriesStatement deleteTimeSeriesStatement, TaskContext context) {
+    return new DeleteTimeSeriesTask(context.getQueryId(), deleteTimeSeriesStatement);
+  }
+
+  public static class TaskContext {
+
+    private final String queryId;
+
+    public TaskContext(String queryId) {
+      this.queryId = queryId;
+    }
+
+    public String getQueryId() {
+      return queryId;
+    }
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/ClusterConfigTaskExecutor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/ClusterConfigTaskExecutor.java
index cc1ee8e967..d4bd990140 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/ClusterConfigTaskExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/ClusterConfigTaskExecutor.java
@@ -32,6 +32,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TCountStorageGroupResp;
 import org.apache.iotdb.confignode.rpc.thrift.TCreateFunctionReq;
 import org.apache.iotdb.confignode.rpc.thrift.TCreateTriggerReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDeleteStorageGroupsReq;
+import org.apache.iotdb.confignode.rpc.thrift.TDeleteTimeSeriesReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDropFunctionReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDropTriggerReq;
 import org.apache.iotdb.confignode.rpc.thrift.TGetTemplateResp;
@@ -50,6 +51,7 @@ import org.apache.iotdb.db.client.DataNodeClientPoolFactory;
 import org.apache.iotdb.db.localconfignode.LocalConfigNode;
 import org.apache.iotdb.db.metadata.template.ClusterTemplateManager;
 import org.apache.iotdb.db.metadata.template.Template;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.db.mpp.plan.execution.config.ConfigTaskResult;
 import org.apache.iotdb.db.mpp.plan.execution.config.metadata.CountStorageGroupTask;
 import org.apache.iotdb.db.mpp.plan.execution.config.metadata.SetStorageGroupTask;
@@ -65,6 +67,7 @@ import org.apache.iotdb.db.mpp.plan.execution.config.metadata.template.ShowSchem
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CountStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateTriggerStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteStorageGroupStatement;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteTimeSeriesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetTTLStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowDataNodesStatement;
@@ -84,15 +87,21 @@ import org.apache.iotdb.db.mpp.plan.statement.sys.sync.ShowPipeSinkStatement;
 import org.apache.iotdb.db.mpp.plan.statement.sys.sync.ShowPipeStatement;
 import org.apache.iotdb.db.mpp.plan.statement.sys.sync.StartPipeStatement;
 import org.apache.iotdb.db.mpp.plan.statement.sys.sync.StopPipeStatement;
+import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.StatementExecutionException;
 import org.apache.iotdb.rpc.TSStatusCode;
 
 import com.google.common.util.concurrent.SettableFuture;
 import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransportException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
 import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -108,6 +117,12 @@ public class ClusterConfigTaskExecutor implements IConfigTaskExecutor {
           new IClientManager.Factory<PartitionRegionId, ConfigNodeClient>()
               .createClientManager(new DataNodeClientPoolFactory.ConfigNodeClientPoolFactory());
 
+  private static final IClientManager<PartitionRegionId, ConfigNodeClient>
+      CLUSTER_DELETION_CONFIG_NODE_CLIENT_MANAGER =
+          new IClientManager.Factory<PartitionRegionId, ConfigNodeClient>()
+              .createClientManager(
+                  new DataNodeClientPoolFactory.ClusterDeletionConfigNodeClientPoolFactory());
+
   private static final class ClusterConfigTaskExecutorHolder {
     private static final ClusterConfigTaskExecutor INSTANCE = new ClusterConfigTaskExecutor();
 
@@ -758,4 +773,56 @@ public class ClusterConfigTaskExecutor implements IConfigTaskExecutor {
             TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode()));
     return future;
   }
+
+  @Override
+  public SettableFuture<ConfigTaskResult> deleteTimeSeries(
+      String queryId, DeleteTimeSeriesStatement deleteTimeSeriesStatement) {
+    SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+    PathPatternTree patternTree = new PathPatternTree();
+    for (PartialPath pathPattern : deleteTimeSeriesStatement.getPathPatternList()) {
+      patternTree.appendPathPattern(pathPattern);
+    }
+    patternTree.constructTree();
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
+    try {
+      patternTree.serialize(dataOutputStream);
+    } catch (IOException ignored) {
+      // memory operation, won't happen
+    }
+    TDeleteTimeSeriesReq req =
+        new TDeleteTimeSeriesReq(queryId, ByteBuffer.wrap(byteArrayOutputStream.toByteArray()));
+    try (ConfigNodeClient client =
+        CLUSTER_DELETION_CONFIG_NODE_CLIENT_MANAGER.borrowClient(
+            ConfigNodeInfo.partitionRegionId)) {
+      TSStatus tsStatus = null;
+      do {
+        try {
+          tsStatus = client.deleteTimeSeries(req);
+        } catch (TTransportException e) {
+          if (e.getType() == TTransportException.TIMED_OUT
+              || e.getCause() instanceof SocketTimeoutException) {
+            // time out mainly caused by slow execution, wait until
+            tsStatus = RpcUtils.getStatus(TSStatusCode.STILL_EXECUTING_STATUS);
+          } else {
+            throw e;
+          }
+        }
+        // keep waiting until task ends
+      } while (TSStatusCode.STILL_EXECUTING_STATUS.getStatusCode() == tsStatus.getCode());
+
+      if (TSStatusCode.SUCCESS_STATUS.getStatusCode() != tsStatus.getCode()) {
+        LOGGER.error(
+            "Failed to execute delete timeseries {} in config node, status is {}.",
+            deleteTimeSeriesStatement.getPathPatternList(),
+            tsStatus);
+        future.setException(new IoTDBException(tsStatus.getMessage(), tsStatus.getCode()));
+      } else {
+        future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS));
+      }
+    } catch (TException | IOException e) {
+      future.setException(e);
+    }
+    return future;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/IConfigTaskExecutor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/IConfigTaskExecutor.java
index 90750c2526..d6b69f7a5d 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/IConfigTaskExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/IConfigTaskExecutor.java
@@ -25,6 +25,7 @@ import org.apache.iotdb.db.mpp.plan.execution.config.ConfigTaskResult;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CountStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateTriggerStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteStorageGroupStatement;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteTimeSeriesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetTTLStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowDataNodesStatement;
@@ -124,4 +125,7 @@ public interface IConfigTaskExecutor {
   SettableFuture<ConfigTaskResult> stopPipe(StopPipeStatement stopPipeStatement);
 
   SettableFuture<ConfigTaskResult> showPipe(ShowPipeStatement showPipeStatement);
+
+  SettableFuture<ConfigTaskResult> deleteTimeSeries(
+      String queryId, DeleteTimeSeriesStatement deleteTimeSeriesStatement);
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/StandaloneConfigTaskExecutor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/StandaloneConfigTaskExecutor.java
index acb6bda290..aca6198bd1 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/StandaloneConfigTaskExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/StandaloneConfigTaskExecutor.java
@@ -41,6 +41,7 @@ import org.apache.iotdb.db.mpp.plan.execution.config.sys.sync.ShowPipeTask;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CountStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateTriggerStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteStorageGroupStatement;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteTimeSeriesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetTTLStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowDataNodesStatement;
@@ -561,4 +562,15 @@ public class StandaloneConfigTaskExecutor implements IConfigTaskExecutor {
     ShowPipeTask.buildTSBlock(showPipeResp.getPipeInfoList(), future);
     return future;
   }
+
+  @Override
+  public SettableFuture<ConfigTaskResult> deleteTimeSeries(
+      String queryId, DeleteTimeSeriesStatement deleteTimeSeriesStatement) {
+    SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+    future.setException(
+        new IoTDBException(
+            "Executing delete timeseries is not supported",
+            TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode()));
+    return future;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/DeleteTimeSeriesTask.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/DeleteTimeSeriesTask.java
new file mode 100644
index 0000000000..530c1eb508
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/DeleteTimeSeriesTask.java
@@ -0,0 +1,45 @@
+/*
+ * 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.mpp.plan.execution.config.metadata;
+
+import org.apache.iotdb.db.mpp.plan.execution.config.ConfigTaskResult;
+import org.apache.iotdb.db.mpp.plan.execution.config.IConfigTask;
+import org.apache.iotdb.db.mpp.plan.execution.config.executor.IConfigTaskExecutor;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteTimeSeriesStatement;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class DeleteTimeSeriesTask implements IConfigTask {
+
+  private final String queryId;
+
+  private final DeleteTimeSeriesStatement deleteTimeSeriesStatement;
+
+  public DeleteTimeSeriesTask(String queryId, DeleteTimeSeriesStatement deleteTimeSeriesStatement) {
+    this.queryId = queryId;
+    this.deleteTimeSeriesStatement = deleteTimeSeriesStatement;
+  }
+
+  @Override
+  public ListenableFuture<ConfigTaskResult> execute(IConfigTaskExecutor configTaskExecutor)
+      throws InterruptedException {
+    return configTaskExecutor.deleteTimeSeries(queryId, deleteTimeSeriesStatement);
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index c766671e84..f6f5be5ee1 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -528,7 +528,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
     for (IoTDBSqlParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) {
       partialPaths.add(parsePrefixPath(prefixPathContext));
     }
-    deleteTimeSeriesStatement.setPartialPaths(partialPaths);
+    deleteTimeSeriesStatement.setPathPatternList(partialPaths);
     return deleteTimeSeriesStatement;
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/PlanNodeType.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/PlanNodeType.java
index d7f4c3cfb9..caa84ee5da 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/PlanNodeType.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/PlanNodeType.java
@@ -35,12 +35,14 @@ import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.read.TimeSeriesCo
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.read.TimeSeriesSchemaScanNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.ActivateTemplateNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.AlterTimeSeriesNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.ConstructSchemaBlackListNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.CreateAlignedTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.CreateMultiTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.CreateTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.DeleteTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.InternalCreateTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.InvalidateSchemaCacheNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.RollbackSchemaBlackListNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.AggregationNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.DeviceMergeNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.DeviceViewNode;
@@ -132,7 +134,9 @@ public enum PlanNodeType {
   NODE_PATHS_COUNT((short) 51),
   INTERNAL_CREATE_TIMESERIES((short) 52),
   ACTIVATE_TEMPLATE((short) 53),
-  PATHS_USING_TEMPLATE_SCAN((short) 54);
+  PATHS_USING_TEMPLATE_SCAN((short) 54),
+  CONSTRUCT_SCHEMA_BLACK_LIST_NODE((short) 55),
+  ROLLBACK_SCHEMA_BLACK_LIST_NODE((short) 56);
 
   public static final int BYTES = Short.BYTES;
 
@@ -291,6 +295,10 @@ public enum PlanNodeType {
         return ActivateTemplateNode.deserialize(buffer);
       case 54:
         return PathsUsingTemplateScanNode.deserialize(buffer);
+      case 55:
+        return ConstructSchemaBlackListNode.deserialize(buffer);
+      case 56:
+        return RollbackSchemaBlackListNode.deserialize(buffer);
       default:
         throw new IllegalArgumentException("Invalid node type: " + nodeType);
     }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/PlanVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/PlanVisitor.java
index 83fc883018..a8cea87284 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/PlanVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/PlanVisitor.java
@@ -35,11 +35,13 @@ import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.read.TimeSeriesCo
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.read.TimeSeriesSchemaScanNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.ActivateTemplateNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.AlterTimeSeriesNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.ConstructSchemaBlackListNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.CreateAlignedTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.CreateMultiTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.CreateTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.DeleteTimeSeriesNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.InternalCreateTimeSeriesNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.RollbackSchemaBlackListNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.AggregationNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.DeviceMergeNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.process.DeviceViewNode;
@@ -275,6 +277,14 @@ public abstract class PlanVisitor<R, C> {
     return visitPlan(node, context);
   }
 
+  public R visitConstructSchemaBlackList(ConstructSchemaBlackListNode node, C context) {
+    return visitPlan(node, context);
+  }
+
+  public R visitRollbackSchemaBlackList(RollbackSchemaBlackListNode node, C context) {
+    return visitPlan(node, context);
+  }
+
   public R visitDeleteData(DeleteDataNode node, C context) {
     return visitPlan(node, context);
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/ConstructSchemaBlackListNode.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/ConstructSchemaBlackListNode.java
new file mode 100644
index 0000000000..4d71b22096
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/ConstructSchemaBlackListNode.java
@@ -0,0 +1,91 @@
+/*
+ * 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.mpp.plan.planner.plan.node.metedata.write;
+
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeId;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeType;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanVisitor;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class ConstructSchemaBlackListNode extends PlanNode {
+
+  private final PathPatternTree patternTree;
+
+  public ConstructSchemaBlackListNode(PlanNodeId id, PathPatternTree patternTree) {
+    super(id);
+    this.patternTree = patternTree;
+  }
+
+  public PathPatternTree getPatternTree() {
+    return patternTree;
+  }
+
+  @Override
+  public List<PlanNode> getChildren() {
+    return null;
+  }
+
+  @Override
+  public void addChild(PlanNode child) {}
+
+  @Override
+  public PlanNode clone() {
+    return new ConstructSchemaBlackListNode(getPlanNodeId(), patternTree);
+  }
+
+  @Override
+  public int allowedChildCount() {
+    return 0;
+  }
+
+  @Override
+  public List<String> getOutputColumnNames() {
+    return null;
+  }
+
+  @Override
+  public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+    return visitor.visitConstructSchemaBlackList(this, context);
+  }
+
+  @Override
+  protected void serializeAttributes(ByteBuffer byteBuffer) {
+    PlanNodeType.CONSTRUCT_SCHEMA_BLACK_LIST_NODE.serialize(byteBuffer);
+    patternTree.serialize(byteBuffer);
+  }
+
+  @Override
+  protected void serializeAttributes(DataOutputStream stream) throws IOException {
+    PlanNodeType.CONSTRUCT_SCHEMA_BLACK_LIST_NODE.serialize(stream);
+    patternTree.serialize(stream);
+  }
+
+  public static ConstructSchemaBlackListNode deserialize(ByteBuffer buffer) {
+    PathPatternTree patternTree = PathPatternTree.deserialize(buffer);
+    PlanNodeId planNodeId = PlanNodeId.deserialize(buffer);
+    return new ConstructSchemaBlackListNode(planNodeId, patternTree);
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/DeleteTimeSeriesNode.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/DeleteTimeSeriesNode.java
index a1bf8ac56a..9e70f6100a 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/DeleteTimeSeriesNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/DeleteTimeSeriesNode.java
@@ -19,52 +19,41 @@
 
 package org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write;
 
-import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
-import org.apache.iotdb.commons.path.PartialPath;
-import org.apache.iotdb.db.metadata.path.PathDeserializeUtil;
-import org.apache.iotdb.db.mpp.plan.planner.plan.node.IPartitionRelatedNode;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeType;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanVisitor;
-import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.util.ArrayList;
 import java.util.List;
 
-public class DeleteTimeSeriesNode extends PlanNode implements IPartitionRelatedNode {
+public class DeleteTimeSeriesNode extends PlanNode {
 
-  private final List<PartialPath> pathList;
+  private final PathPatternTree patternTree;
 
-  private TRegionReplicaSet regionReplicaSet;
-  private List<PlanNode> children;
-
-  public DeleteTimeSeriesNode(PlanNodeId id, List<PartialPath> pathList) {
+  public DeleteTimeSeriesNode(PlanNodeId id, PathPatternTree patternTree) {
     super(id);
-    this.pathList = pathList;
-    this.children = new ArrayList<>();
+    this.patternTree = patternTree;
   }
 
-  public List<PartialPath> getPathList() {
-    return pathList;
+  public PathPatternTree getPatternTree() {
+    return patternTree;
   }
 
   @Override
   public List<PlanNode> getChildren() {
-    return children;
+    return null;
   }
 
   @Override
-  public void addChild(PlanNode child) {
-    children.add(child);
-  }
+  public void addChild(PlanNode child) {}
 
   @Override
   public PlanNode clone() {
-    return new DeleteTimeSeriesNode(getPlanNodeId(), pathList);
+    return new DeleteTimeSeriesNode(getPlanNodeId(), patternTree);
   }
 
   @Override
@@ -85,45 +74,23 @@ public class DeleteTimeSeriesNode extends PlanNode implements IPartitionRelatedN
   @Override
   protected void serializeAttributes(ByteBuffer byteBuffer) {
     PlanNodeType.DELETE_TIMESERIES.serialize(byteBuffer);
-    ReadWriteIOUtils.write(pathList.size(), byteBuffer);
-    for (PartialPath path : pathList) {
-      path.serialize(byteBuffer);
-    }
+    patternTree.serialize(byteBuffer);
   }
 
   @Override
   protected void serializeAttributes(DataOutputStream stream) throws IOException {
     PlanNodeType.DELETE_TIMESERIES.serialize(stream);
-    ReadWriteIOUtils.write(pathList.size(), stream);
-    for (PartialPath path : pathList) {
-      path.serialize(stream);
-    }
+    patternTree.serialize(stream);
   }
 
   public static DeleteTimeSeriesNode deserialize(ByteBuffer byteBuffer) {
-    int size = ReadWriteIOUtils.readInt(byteBuffer);
-    List<PartialPath> pathList = new ArrayList<>(size);
-    for (int i = 0; i < size; i++) {
-      pathList.add((PartialPath) PathDeserializeUtil.deserialize(byteBuffer));
-    }
+    PathPatternTree patternTree = PathPatternTree.deserialize(byteBuffer);
     PlanNodeId planNodeId = PlanNodeId.deserialize(byteBuffer);
-    return new DeleteTimeSeriesNode(planNodeId, pathList);
-  }
-
-  @Override
-  public TRegionReplicaSet getRegionReplicaSet() {
-    return regionReplicaSet;
-  }
-
-  public void setRegionReplicaSet(TRegionReplicaSet regionReplicaSet) {
-    this.regionReplicaSet = regionReplicaSet;
+    return new DeleteTimeSeriesNode(planNodeId, patternTree);
   }
 
   public String toString() {
     return String.format(
-        "DeleteTimeseriesNode-%s: %s. Region: %s",
-        getPlanNodeId(),
-        pathList,
-        regionReplicaSet == null ? "Not Assigned" : regionReplicaSet.getRegionId());
+        "DeleteTimeseriesNode-%s: %s. Region: %s", getPlanNodeId(), patternTree, "Not Assigned");
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/RollbackSchemaBlackListNode.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/RollbackSchemaBlackListNode.java
new file mode 100644
index 0000000000..f79b814bff
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/RollbackSchemaBlackListNode.java
@@ -0,0 +1,91 @@
+/*
+ * 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.mpp.plan.planner.plan.node.metedata.write;
+
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeId;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeType;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanVisitor;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class RollbackSchemaBlackListNode extends PlanNode {
+
+  private final PathPatternTree patternTree;
+
+  public RollbackSchemaBlackListNode(PlanNodeId id, PathPatternTree patternTree) {
+    super(id);
+    this.patternTree = patternTree;
+  }
+
+  public PathPatternTree getPatternTree() {
+    return patternTree;
+  }
+
+  @Override
+  public List<PlanNode> getChildren() {
+    return null;
+  }
+
+  @Override
+  public void addChild(PlanNode child) {}
+
+  @Override
+  public PlanNode clone() {
+    return new RollbackSchemaBlackListNode(getPlanNodeId(), patternTree);
+  }
+
+  @Override
+  public int allowedChildCount() {
+    return 0;
+  }
+
+  @Override
+  public List<String> getOutputColumnNames() {
+    return null;
+  }
+
+  @Override
+  public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+    return visitor.visitRollbackSchemaBlackList(this, context);
+  }
+
+  @Override
+  protected void serializeAttributes(ByteBuffer byteBuffer) {
+    PlanNodeType.ROLLBACK_SCHEMA_BLACK_LIST_NODE.serialize(byteBuffer);
+    patternTree.serialize(byteBuffer);
+  }
+
+  @Override
+  protected void serializeAttributes(DataOutputStream stream) throws IOException {
+    PlanNodeType.ROLLBACK_SCHEMA_BLACK_LIST_NODE.serialize(stream);
+    patternTree.serialize(stream);
+  }
+
+  public static RollbackSchemaBlackListNode deserialize(ByteBuffer buffer) {
+    PathPatternTree patternTree = PathPatternTree.deserialize(buffer);
+    PlanNodeId planNodeId = PlanNodeId.deserialize(buffer);
+    return new RollbackSchemaBlackListNode(planNodeId, patternTree);
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/DeleteTimeSeriesStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/DeleteTimeSeriesStatement.java
index 99cb5b57ff..ffc653f597 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/DeleteTimeSeriesStatement.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/DeleteTimeSeriesStatement.java
@@ -20,26 +20,43 @@
 package org.apache.iotdb.db.mpp.plan.statement.metadata;
 
 import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.mpp.plan.analyze.QueryType;
+import org.apache.iotdb.db.mpp.plan.constant.StatementType;
+import org.apache.iotdb.db.mpp.plan.statement.IConfigStatement;
 import org.apache.iotdb.db.mpp.plan.statement.Statement;
 import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
 
 import java.util.List;
 
-public class DeleteTimeSeriesStatement extends Statement {
+public class DeleteTimeSeriesStatement extends Statement implements IConfigStatement {
 
-  List<PartialPath> partialPaths;
+  List<PartialPath> pathPatternList;
+
+  public DeleteTimeSeriesStatement() {
+    super();
+    statementType = StatementType.DELETE_TIMESERIES;
+  }
 
   @Override
   public List<PartialPath> getPaths() {
-    return partialPaths;
+    return pathPatternList;
+  }
+
+  public List<PartialPath> getPathPatternList() {
+    return pathPatternList;
   }
 
-  public void setPartialPaths(List<PartialPath> partialPaths) {
-    this.partialPaths = partialPaths;
+  public void setPathPatternList(List<PartialPath> pathPatternList) {
+    this.pathPatternList = pathPatternList;
   }
 
   @Override
   public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
     return visitor.visitDeleteTimeseries(this, context);
   }
+
+  @Override
+  public QueryType getQueryType() {
+    return QueryType.WRITE;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
index 48fad9c0a0..32292b5b0d 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
@@ -206,6 +206,8 @@ public abstract class Operator {
     START_PIPE,
     DROP_PIPE,
 
-    ACTIVATE_TEMPLATE_IN_CLUSTER
+    ACTIVATE_TEMPLATE_IN_CLUSTER,
+    PRE_DELETE_TIMESERIES_IN_CLUSTER,
+    ROLLBACK_PRE_DELETE_TIMESERIES
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
index e49be4304e..070b198c35 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
@@ -63,7 +63,9 @@ import org.apache.iotdb.db.qp.physical.sys.LogPlan;
 import org.apache.iotdb.db.qp.physical.sys.MNodePlan;
 import org.apache.iotdb.db.qp.physical.sys.MeasurementMNodePlan;
 import org.apache.iotdb.db.qp.physical.sys.MergePlan;
+import org.apache.iotdb.db.qp.physical.sys.PreDeleteTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.PruneTemplatePlan;
+import org.apache.iotdb.db.qp.physical.sys.RollbackPreDeleteTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
 import org.apache.iotdb.db.qp.physical.sys.SetSystemModePlan;
 import org.apache.iotdb.db.qp.physical.sys.SetTTLPlan;
@@ -491,6 +493,12 @@ public abstract class PhysicalPlan implements IConsensusRequest {
         case ACTIVATE_TEMPLATE_IN_CLUSTER:
           plan = new ActivateTemplateInClusterPlan();
           break;
+        case PRE_DELETE_TIMESERIES_IN_CLUSTER:
+          plan = new PreDeleteTimeSeriesPlan();
+          break;
+        case ROLLBACK_PRE_DELETE_TIMESERIES:
+          plan = new RollbackPreDeleteTimeSeriesPlan();
+          break;
         default:
           throw new IOException("unrecognized log type " + type);
       }
@@ -563,7 +571,9 @@ public abstract class PhysicalPlan implements IConsensusRequest {
     START_PIPE_SERVER,
     STOP_PIPE_SERVER,
     DROP_TEMPLATE,
-    ACTIVATE_TEMPLATE_IN_CLUSTER
+    ACTIVATE_TEMPLATE_IN_CLUSTER,
+    PRE_DELETE_TIMESERIES_IN_CLUSTER,
+    ROLLBACK_PRE_DELETE_TIMESERIES
   }
 
   public long getIndex() {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/PreDeleteTimeSeriesPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/PreDeleteTimeSeriesPlan.java
new file mode 100644
index 0000000000..2c3e51952f
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/PreDeleteTimeSeriesPlan.java
@@ -0,0 +1,79 @@
+/*
+ * 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.qp.physical.sys;
+
+import org.apache.iotdb.commons.exception.IllegalPathException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.metadata.path.PathDeserializeUtil;
+import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+
+public class PreDeleteTimeSeriesPlan extends PhysicalPlan {
+
+  private PartialPath path;
+
+  public PreDeleteTimeSeriesPlan() {
+    super(Operator.OperatorType.PRE_DELETE_TIMESERIES_IN_CLUSTER);
+  }
+
+  public PreDeleteTimeSeriesPlan(PartialPath path) {
+    super(Operator.OperatorType.PRE_DELETE_TIMESERIES_IN_CLUSTER);
+    this.path = path;
+  }
+
+  public PartialPath getPath() {
+    return path;
+  }
+
+  public void setPath(PartialPath path) {
+    this.path = path;
+  }
+
+  @Override
+  public List<? extends PartialPath> getPaths() {
+    return Collections.singletonList(path);
+  }
+
+  @Override
+  public void serialize(DataOutputStream stream) throws IOException {
+    stream.write((byte) PhysicalPlanType.PRE_DELETE_TIMESERIES_IN_CLUSTER.ordinal());
+    path.serialize(stream);
+    stream.writeLong(index);
+  }
+
+  @Override
+  protected void serializeImpl(ByteBuffer buffer) {
+    buffer.put((byte) PhysicalPlanType.PRE_DELETE_TIMESERIES_IN_CLUSTER.ordinal());
+    path.serialize(buffer);
+    buffer.putLong(index);
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer) throws IllegalPathException, IOException {
+    path = (PartialPath) PathDeserializeUtil.deserialize(buffer);
+    index = buffer.getLong();
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/RollbackPreDeleteTimeSeriesPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/RollbackPreDeleteTimeSeriesPlan.java
new file mode 100644
index 0000000000..019472a254
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/RollbackPreDeleteTimeSeriesPlan.java
@@ -0,0 +1,79 @@
+/*
+ * 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.qp.physical.sys;
+
+import org.apache.iotdb.commons.exception.IllegalPathException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.metadata.path.PathDeserializeUtil;
+import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+
+public class RollbackPreDeleteTimeSeriesPlan extends PhysicalPlan {
+
+  private PartialPath path;
+
+  public RollbackPreDeleteTimeSeriesPlan() {
+    super(Operator.OperatorType.ROLLBACK_PRE_DELETE_TIMESERIES);
+  }
+
+  public RollbackPreDeleteTimeSeriesPlan(PartialPath path) {
+    super(Operator.OperatorType.ROLLBACK_PRE_DELETE_TIMESERIES);
+    this.path = path;
+  }
+
+  public PartialPath getPath() {
+    return path;
+  }
+
+  public void setPath(PartialPath path) {
+    this.path = path;
+  }
+
+  @Override
+  public List<? extends PartialPath> getPaths() {
+    return Collections.singletonList(path);
+  }
+
+  @Override
+  public void serialize(DataOutputStream stream) throws IOException {
+    stream.write((byte) PhysicalPlanType.ROLLBACK_PRE_DELETE_TIMESERIES.ordinal());
+    path.serialize(stream);
+    stream.writeLong(index);
+  }
+
+  @Override
+  protected void serializeImpl(ByteBuffer buffer) {
+    buffer.put((byte) PhysicalPlanType.ROLLBACK_PRE_DELETE_TIMESERIES.ordinal());
+    path.serialize(buffer);
+    buffer.putLong(index);
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer) throws IllegalPathException, IOException {
+    path = (PartialPath) PathDeserializeUtil.deserialize(buffer);
+    index = buffer.getLong();
+  }
+}
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 7b74027cef..bc487251b2 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
@@ -24,16 +24,13 @@ import org.apache.iotdb.common.rpc.thrift.TConsensusGroupId;
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
 import org.apache.iotdb.common.rpc.thrift.TEndPoint;
 import org.apache.iotdb.common.rpc.thrift.TFlushReq;
-import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.common.rpc.thrift.TSetTTLReq;
 import org.apache.iotdb.commons.cluster.NodeStatus;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
-import org.apache.iotdb.commons.conf.IoTDBConstant;
 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.trigger.TriggerInformation;
@@ -44,7 +41,6 @@ import org.apache.iotdb.confignode.rpc.thrift.TTriggerState;
 import org.apache.iotdb.consensus.common.Peer;
 import org.apache.iotdb.consensus.common.response.ConsensusGenericResponse;
 import org.apache.iotdb.consensus.common.response.ConsensusReadResponse;
-import org.apache.iotdb.consensus.common.response.ConsensusWriteResponse;
 import org.apache.iotdb.consensus.exception.PeerNotInConsensusGroupException;
 import org.apache.iotdb.db.auth.AuthorizerManager;
 import org.apache.iotdb.db.client.ConfigNodeInfo;
@@ -55,24 +51,26 @@ import org.apache.iotdb.db.engine.StorageEngineV2;
 import org.apache.iotdb.db.engine.cache.BloomFilterCache;
 import org.apache.iotdb.db.engine.cache.ChunkCache;
 import org.apache.iotdb.db.engine.cache.TimeSeriesMetadataCache;
-import org.apache.iotdb.db.exception.DataRegionException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
-import org.apache.iotdb.db.exception.sql.SemanticException;
 import org.apache.iotdb.db.metadata.cache.DataNodeSchemaCache;
 import org.apache.iotdb.db.metadata.schemaregion.SchemaEngine;
 import org.apache.iotdb.db.metadata.template.ClusterTemplateManager;
 import org.apache.iotdb.db.metadata.template.TemplateInternalRPCUpdateType;
 import org.apache.iotdb.db.mpp.common.FragmentInstanceId;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.db.mpp.execution.fragment.FragmentInstanceInfo;
 import org.apache.iotdb.db.mpp.execution.fragment.FragmentInstanceManager;
 import org.apache.iotdb.db.mpp.execution.fragment.FragmentInstanceState;
 import org.apache.iotdb.db.mpp.plan.analyze.ClusterPartitionFetcher;
-import org.apache.iotdb.db.mpp.plan.analyze.SchemaValidator;
 import org.apache.iotdb.db.mpp.plan.planner.plan.FragmentInstance;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeType;
-import org.apache.iotdb.db.mpp.plan.planner.plan.node.write.InsertNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.ConstructSchemaBlackListNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.DeleteTimeSeriesNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.metedata.write.RollbackSchemaBlackListNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.write.DeleteDataNode;
 import org.apache.iotdb.db.service.DataNode;
 import org.apache.iotdb.db.service.RegionMigrateService;
 import org.apache.iotdb.db.service.metrics.MetricService;
@@ -88,22 +86,29 @@ import org.apache.iotdb.mpp.rpc.thrift.TCancelFragmentInstanceReq;
 import org.apache.iotdb.mpp.rpc.thrift.TCancelPlanFragmentReq;
 import org.apache.iotdb.mpp.rpc.thrift.TCancelQueryReq;
 import org.apache.iotdb.mpp.rpc.thrift.TCancelResp;
+import org.apache.iotdb.mpp.rpc.thrift.TConstructSchemaBlackListReq;
 import org.apache.iotdb.mpp.rpc.thrift.TCreateDataRegionReq;
 import org.apache.iotdb.mpp.rpc.thrift.TCreateFunctionRequest;
 import org.apache.iotdb.mpp.rpc.thrift.TCreatePeerReq;
 import org.apache.iotdb.mpp.rpc.thrift.TCreateSchemaRegionReq;
+import org.apache.iotdb.mpp.rpc.thrift.TDeleteDataForDeleteTimeSeriesReq;
+import org.apache.iotdb.mpp.rpc.thrift.TDeleteTimeSeriesReq;
 import org.apache.iotdb.mpp.rpc.thrift.TDisableDataNodeReq;
 import org.apache.iotdb.mpp.rpc.thrift.TDropFunctionRequest;
 import org.apache.iotdb.mpp.rpc.thrift.TDropTriggerInstanceReq;
 import org.apache.iotdb.mpp.rpc.thrift.TFetchFragmentInstanceStateReq;
+import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListReq;
+import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListResp;
 import org.apache.iotdb.mpp.rpc.thrift.TFragmentInstanceStateResp;
 import org.apache.iotdb.mpp.rpc.thrift.THeartbeatReq;
 import org.apache.iotdb.mpp.rpc.thrift.THeartbeatResp;
 import org.apache.iotdb.mpp.rpc.thrift.TInvalidateCacheReq;
+import org.apache.iotdb.mpp.rpc.thrift.TInvalidateMatchedSchemaCacheReq;
 import org.apache.iotdb.mpp.rpc.thrift.TInvalidatePermissionCacheReq;
 import org.apache.iotdb.mpp.rpc.thrift.TMaintainPeerReq;
 import org.apache.iotdb.mpp.rpc.thrift.TRegionLeaderChangeReq;
 import org.apache.iotdb.mpp.rpc.thrift.TRegionRouteReq;
+import org.apache.iotdb.mpp.rpc.thrift.TRollbackSchemaBlackListReq;
 import org.apache.iotdb.mpp.rpc.thrift.TSchemaFetchRequest;
 import org.apache.iotdb.mpp.rpc.thrift.TSchemaFetchResponse;
 import org.apache.iotdb.mpp.rpc.thrift.TSendFragmentInstanceReq;
@@ -123,6 +128,10 @@ import org.apache.thrift.TException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -138,8 +147,11 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
   private final SchemaEngine schemaEngine = SchemaEngine.getInstance();
   private final StorageEngineV2 storageEngine = StorageEngineV2.getInstance();
 
+  private final DataNodeRegionManager regionManager;
+
   public DataNodeInternalRPCServiceImpl() {
     super();
+    regionManager = new DataNodeRegionManager(schemaEngine, storageEngine);
   }
 
   @Override
@@ -209,62 +221,8 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
     LOGGER.info("receive PlanNode to group[{}]", req.getConsensusGroupId());
     ConsensusGroupId groupId =
         ConsensusGroupId.Factory.createFromTConsensusGroupId(req.getConsensusGroupId());
-    TSendPlanNodeResp response = new TSendPlanNodeResp();
-    ConsensusWriteResponse writeResponse;
-
     PlanNode planNode = PlanNodeType.deserialize(req.planNode.body);
-    boolean hasFailedMeasurement = false;
-    String partialInsertMessage = null;
-    if (planNode instanceof InsertNode) {
-      InsertNode insertNode = (InsertNode) planNode;
-      try {
-        SchemaValidator.validate(insertNode);
-      } catch (SemanticException e) {
-        response.setAccepted(false);
-        response.setMessage(e.getMessage());
-        return response;
-      }
-      hasFailedMeasurement = insertNode.hasFailedMeasurements();
-      if (hasFailedMeasurement) {
-        partialInsertMessage =
-            String.format(
-                "Fail to insert measurements %s caused by %s",
-                insertNode.getFailedMeasurements(), insertNode.getFailedMessages());
-        LOGGER.warn(partialInsertMessage);
-      }
-    }
-    if (groupId instanceof DataRegionId) {
-
-      writeResponse = DataRegionConsensusImpl.getInstance().write(groupId, planNode);
-
-    } else {
-      writeResponse = SchemaRegionConsensusImpl.getInstance().write(groupId, planNode);
-    }
-    // TODO need consider more status
-    if (writeResponse.getStatus() != null) {
-      response.setAccepted(
-          !hasFailedMeasurement
-              && TSStatusCode.SUCCESS_STATUS.getStatusCode()
-                  == writeResponse.getStatus().getCode());
-      if (TSStatusCode.SUCCESS_STATUS.getStatusCode() != writeResponse.getStatus().getCode()) {
-        response.setMessage(writeResponse.getStatus().message);
-        response.setStatus(writeResponse.getStatus());
-      } else if (hasFailedMeasurement) {
-        response.setMessage(partialInsertMessage);
-        response.setStatus(
-            RpcUtils.getStatus(TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
-      } else {
-        response.setMessage(writeResponse.getStatus().message);
-      }
-    } else {
-      LOGGER.error(
-          "Something wrong happened while calling consensus layer's write API.",
-          writeResponse.getException());
-      response.setAccepted(false);
-      response.setMessage(writeResponse.getException().getMessage());
-    }
-
-    return response;
+    return regionManager.executePlanNode(groupId, planNode);
   }
 
   @Override
@@ -311,73 +269,13 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
 
   @Override
   public TSStatus createSchemaRegion(TCreateSchemaRegionReq req) {
-    TSStatus tsStatus;
-    try {
-      PartialPath storageGroupPartitionPath = new PartialPath(req.getStorageGroup());
-      TRegionReplicaSet regionReplicaSet = req.getRegionReplicaSet();
-      SchemaRegionId schemaRegionId = new SchemaRegionId(regionReplicaSet.getRegionId().getId());
-      schemaEngine.createSchemaRegion(storageGroupPartitionPath, schemaRegionId);
-      List<Peer> peers = new ArrayList<>();
-      for (TDataNodeLocation dataNodeLocation : regionReplicaSet.getDataNodeLocations()) {
-        TEndPoint endpoint =
-            new TEndPoint(
-                dataNodeLocation.getSchemaRegionConsensusEndPoint().getIp(),
-                dataNodeLocation.getSchemaRegionConsensusEndPoint().getPort());
-        peers.add(new Peer(schemaRegionId, endpoint));
-      }
-      ConsensusGenericResponse consensusGenericResponse =
-          SchemaRegionConsensusImpl.getInstance().createPeer(schemaRegionId, peers);
-      if (consensusGenericResponse.isSuccess()) {
-        tsStatus = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
-      } else {
-        tsStatus = new TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
-        tsStatus.setMessage(consensusGenericResponse.getException().getMessage());
-      }
-    } catch (IllegalPathException e1) {
-      LOGGER.error(
-          "Create Schema Region {} failed because path is illegal.", req.getStorageGroup());
-      tsStatus = new TSStatus(TSStatusCode.PATH_ILLEGAL.getStatusCode());
-      tsStatus.setMessage("Create Schema Region failed because storageGroup path is illegal.");
-    } catch (MetadataException e2) {
-      LOGGER.error(
-          "Create Schema Region {} failed because {}", req.getStorageGroup(), e2.getMessage());
-      tsStatus = new TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
-      tsStatus.setMessage(
-          String.format("Create Schema Region failed because of %s", e2.getMessage()));
-    }
-    return tsStatus;
+    return regionManager.createSchemaRegion(req.getRegionReplicaSet(), req.getStorageGroup());
   }
 
   @Override
   public TSStatus createDataRegion(TCreateDataRegionReq req) {
-    TSStatus tsStatus;
-    try {
-      TRegionReplicaSet regionReplicaSet = req.getRegionReplicaSet();
-      DataRegionId dataRegionId = new DataRegionId(regionReplicaSet.getRegionId().getId());
-      storageEngine.createDataRegion(dataRegionId, req.storageGroup, req.ttl);
-      List<Peer> peers = new ArrayList<>();
-      for (TDataNodeLocation dataNodeLocation : regionReplicaSet.getDataNodeLocations()) {
-        TEndPoint endpoint =
-            new TEndPoint(
-                dataNodeLocation.getDataRegionConsensusEndPoint().getIp(),
-                dataNodeLocation.getDataRegionConsensusEndPoint().getPort());
-        peers.add(new Peer(dataRegionId, endpoint));
-      }
-      ConsensusGenericResponse consensusGenericResponse =
-          DataRegionConsensusImpl.getInstance().createPeer(dataRegionId, peers);
-      if (consensusGenericResponse.isSuccess()) {
-        tsStatus = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
-      } else {
-        tsStatus = new TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
-        tsStatus.setMessage(consensusGenericResponse.getException().getMessage());
-      }
-    } catch (DataRegionException e) {
-      LOGGER.error(
-          "Create Data Region {} failed because {}", req.getStorageGroup(), e.getMessage());
-      tsStatus = new TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
-      tsStatus.setMessage(String.format("Create Data Region failed because of %s", e.getMessage()));
-    }
-    return tsStatus;
+    return regionManager.createDataRegion(
+        req.getRegionReplicaSet(), req.getStorageGroup(), req.getTtl());
   }
 
   @Override
@@ -392,6 +290,154 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
     return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
   }
 
+  @Override
+  public TSStatus constructSchemaBlackList(TConstructSchemaBlackListReq req) throws TException {
+    PathPatternTree patternTree =
+        PathPatternTree.deserialize(ByteBuffer.wrap(req.getPathPatternTree()));
+    List<TSStatus> failureList = new ArrayList<>();
+    TSStatus status;
+    int preDeletedNum = 0;
+    for (TConsensusGroupId consensusGroupId : req.getSchemaRegionIdList()) {
+      status =
+          regionManager.executeSchemaPlanNode(
+              new SchemaRegionId(consensusGroupId.getId()),
+              new ConstructSchemaBlackListNode(new PlanNodeId(""), patternTree));
+      if (status.code == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        preDeletedNum += Integer.parseInt(status.getMessage());
+      } else {
+        failureList.add(status);
+      }
+    }
+
+    if (!failureList.isEmpty()) {
+      return RpcUtils.getStatus(failureList);
+    }
+
+    return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, String.valueOf(preDeletedNum));
+  }
+
+  @Override
+  public TSStatus rollbackSchemaBlackList(TRollbackSchemaBlackListReq req) throws TException {
+    PathPatternTree patternTree =
+        PathPatternTree.deserialize(ByteBuffer.wrap(req.getPathPatternTree()));
+    List<TSStatus> failureList = new ArrayList<>();
+    TSStatus status;
+    for (TConsensusGroupId consensusGroupId : req.getSchemaRegionIdList()) {
+      status =
+          regionManager.executeSchemaPlanNode(
+              new SchemaRegionId(consensusGroupId.getId()),
+              new RollbackSchemaBlackListNode(new PlanNodeId(""), patternTree));
+      if (status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        failureList.add(status);
+      }
+    }
+
+    if (!failureList.isEmpty()) {
+      return RpcUtils.getStatus(failureList);
+    }
+
+    return RpcUtils.SUCCESS_STATUS;
+  }
+
+  @Override
+  public TSStatus invalidateMatchedSchemaCache(TInvalidateMatchedSchemaCacheReq req)
+      throws TException {
+    DataNodeSchemaCache cache = DataNodeSchemaCache.getInstance();
+    cache.takeWriteLock();
+    try {
+      for (PartialPath pathPattern :
+          PathPatternTree.deserialize(ByteBuffer.wrap(req.getPathPatternTree()))
+              .getAllPathPatterns()) {
+        cache.invalidateMatchedSchema(pathPattern);
+      }
+    } finally {
+      cache.releaseWriteLock();
+    }
+    return RpcUtils.SUCCESS_STATUS;
+  }
+
+  @Override
+  public TFetchSchemaBlackListResp fetchSchemaBlackList(TFetchSchemaBlackListReq req)
+      throws TException {
+    PathPatternTree patternTree = PathPatternTree.deserialize(req.pathPatternTree);
+    TFetchSchemaBlackListResp resp = new TFetchSchemaBlackListResp();
+    PathPatternTree result = new PathPatternTree();
+    for (TConsensusGroupId consensusGroupId : req.getSchemaRegionIdList()) {
+      // todo implement as consensus layer read request
+      try {
+        for (PartialPath path :
+            schemaEngine
+                .getSchemaRegion(new SchemaRegionId(consensusGroupId.getId()))
+                .fetchSchemaBlackList(patternTree)) {
+          result.appendFullPath(path);
+        }
+      } catch (MetadataException e) {
+        LOGGER.error(e.getMessage(), e);
+        resp.setStatus(RpcUtils.getStatus(e.getErrorCode(), e.getMessage()));
+        return resp;
+      }
+    }
+    resp.setStatus(RpcUtils.SUCCESS_STATUS);
+    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+    DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
+    result.constructTree();
+    try {
+      result.serialize(dataOutputStream);
+    } catch (IOException ignored) {
+      // won't reach here
+    }
+    resp.setPathPatternTree(outputStream.toByteArray());
+    return resp;
+  }
+
+  @Override
+  public TSStatus deleteDataForDeleteTimeSeries(TDeleteDataForDeleteTimeSeriesReq req)
+      throws TException {
+    PathPatternTree patternTree =
+        PathPatternTree.deserialize(ByteBuffer.wrap(req.getPathPatternTree()));
+    List<PartialPath> pathList = patternTree.getAllPathPatterns();
+    List<TSStatus> failureList = new ArrayList<>();
+    TSStatus status;
+    for (TConsensusGroupId consensusGroupId : req.getDataRegionIdList()) {
+      status =
+          regionManager.executeDeleteDataForDeleteTimeSeries(
+              new DataRegionId(consensusGroupId.getId()),
+              new DeleteDataNode(new PlanNodeId(""), pathList, Long.MIN_VALUE, Long.MAX_VALUE));
+      if (status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        failureList.add(status);
+      }
+    }
+
+    if (!failureList.isEmpty()) {
+      return RpcUtils.getStatus(failureList);
+    }
+
+    return RpcUtils.SUCCESS_STATUS;
+  }
+
+  @Override
+  public TSStatus deleteTimeSeries(TDeleteTimeSeriesReq req) throws TException {
+    PathPatternTree patternTree =
+        PathPatternTree.deserialize(ByteBuffer.wrap(req.getPathPatternTree()));
+    List<TSStatus> failureList = new ArrayList<>();
+    TSStatus status;
+    for (TConsensusGroupId consensusGroupId : req.getSchemaRegionIdList()) {
+      status =
+          regionManager.executeSchemaPlanNode(
+              new SchemaRegionId(consensusGroupId.getId()),
+              new DeleteTimeSeriesNode(new PlanNodeId(""), patternTree));
+      if (status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        failureList.add(status);
+      }
+    }
+
+    if (!failureList.isEmpty()) {
+      return RpcUtils.getStatus(failureList);
+    }
+
+    return RpcUtils.SUCCESS_STATUS;
+  }
+
   @Override
   public THeartbeatResp getDataNodeHeartBeat(THeartbeatReq req) throws TException {
     THeartbeatResp resp = new THeartbeatResp();
@@ -580,7 +626,7 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
         return RpcUtils.getStatus(
             TSStatusCode.DELETE_REGION_ERROR, response.getException().getMessage());
       }
-      StorageEngineV2.getInstance().deleteDataRegion((DataRegionId) consensusGroupId);
+      return regionManager.deleteDataRegion((DataRegionId) consensusGroupId);
     } else {
       ConsensusGenericResponse response =
           SchemaRegionConsensusImpl.getInstance().deletePeer(consensusGroupId);
@@ -589,14 +635,8 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
         return RpcUtils.getStatus(
             TSStatusCode.DELETE_REGION_ERROR, response.getException().getMessage());
       }
-      try {
-        SchemaEngine.getInstance().deleteSchemaRegion((SchemaRegionId) consensusGroupId);
-      } catch (MetadataException e) {
-        LOGGER.error("{}: MetaData error: ", IoTDBConstant.GLOBAL_DB_NAME, e);
-        return RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage());
-      }
+      return regionManager.deleteSchemaRegion((SchemaRegionId) consensusGroupId);
     }
-    return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, "Execute successfully");
   }
 
   public TSStatus changeRegionLeader(TRegionLeaderChangeReq req) throws TException {
@@ -716,23 +756,7 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
   }
 
   private TSStatus createNewRegion(ConsensusGroupId regionId, String storageGroup, long ttl) {
-    TSStatus status = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
-    LOGGER.info("start to create new region {}", regionId);
-    try {
-      if (regionId instanceof DataRegionId) {
-        storageEngine.createDataRegion((DataRegionId) regionId, storageGroup, ttl);
-      } else {
-        schemaEngine.createSchemaRegion(new PartialPath(storageGroup), (SchemaRegionId) regionId);
-      }
-    } catch (Exception e) {
-      LOGGER.error("create new region {} error", regionId, e);
-      status.setCode(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
-      status.setMessage("create new region " + regionId + "error,  exception:" + e.getMessage());
-      return status;
-    }
-    status.setMessage("create new region " + regionId + " succeed");
-    LOGGER.info("succeed to create new region {}", regionId);
-    return status;
+    return regionManager.createNewRegion(regionId, storageGroup, ttl);
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeRegionManager.java b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeRegionManager.java
new file mode 100644
index 0000000000..574ac8be54
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeRegionManager.java
@@ -0,0 +1,317 @@
+/*
+ * 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.service.thrift.impl;
+
+import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TEndPoint;
+import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.conf.IoTDBConstant;
+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.consensus.common.Peer;
+import org.apache.iotdb.consensus.common.response.ConsensusGenericResponse;
+import org.apache.iotdb.consensus.common.response.ConsensusWriteResponse;
+import org.apache.iotdb.db.consensus.DataRegionConsensusImpl;
+import org.apache.iotdb.db.consensus.SchemaRegionConsensusImpl;
+import org.apache.iotdb.db.engine.StorageEngineV2;
+import org.apache.iotdb.db.exception.DataRegionException;
+import org.apache.iotdb.db.exception.sql.SemanticException;
+import org.apache.iotdb.db.metadata.schemaregion.SchemaEngine;
+import org.apache.iotdb.db.mpp.plan.analyze.SchemaValidator;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNode;
+import org.apache.iotdb.db.mpp.plan.planner.plan.node.write.InsertNode;
+import org.apache.iotdb.mpp.rpc.thrift.TSendPlanNodeResp;
+import org.apache.iotdb.rpc.RpcUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * This class takes the responsibility of managing regions, executing PlanNode of write type on
+ * according regions and controlling the execution concurrency.
+ */
+public class DataNodeRegionManager {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeRegionManager.class);
+
+  private final SchemaEngine schemaEngine;
+  private final StorageEngineV2 storageEngine;
+
+  private final Map<SchemaRegionId, ReentrantReadWriteLock> schemaRegionLockMap =
+      new ConcurrentHashMap<>();
+  private final Map<DataRegionId, ReentrantReadWriteLock> dataRegionLockMap =
+      new ConcurrentHashMap<>();
+
+  public DataNodeRegionManager(SchemaEngine schemaEngine, StorageEngineV2 storageEngine) {
+    this.schemaEngine = schemaEngine;
+    this.storageEngine = storageEngine;
+    schemaEngine
+        .getAllSchemaRegions()
+        .forEach(
+            schemaRegion -> {
+              schemaRegionLockMap.put(
+                  schemaRegion.getSchemaRegionId(), new ReentrantReadWriteLock(false));
+            });
+
+    storageEngine
+        .getAllDataRegionIds()
+        .forEach(
+            dataRegionId -> dataRegionLockMap.put(dataRegionId, new ReentrantReadWriteLock(false)));
+  }
+
+  public TSendPlanNodeResp executePlanNode(ConsensusGroupId groupId, PlanNode planNode) {
+    if (planNode instanceof InsertNode) {
+      return executeDataInsert((DataRegionId) groupId, (InsertNode) planNode);
+    } else {
+      TSendPlanNodeResp response = new TSendPlanNodeResp();
+      ConsensusWriteResponse writeResponse = executePlanNodeInConsensusLayer(groupId, planNode);
+      // TODO need consider more status
+      if (writeResponse.getStatus() != null) {
+        response.setAccepted(
+            TSStatusCode.SUCCESS_STATUS.getStatusCode() == writeResponse.getStatus().getCode());
+        response.setMessage(writeResponse.getStatus().message);
+        response.setStatus(writeResponse.getStatus());
+      } else {
+        LOGGER.error(
+            "Something wrong happened while calling consensus layer's write API.",
+            writeResponse.getException());
+        response.setAccepted(false);
+        response.setMessage(writeResponse.getException().getMessage());
+      }
+      return response;
+    }
+  }
+
+  private ConsensusWriteResponse executePlanNodeInConsensusLayer(
+      ConsensusGroupId groupId, PlanNode planNode) {
+    if (groupId instanceof DataRegionId) {
+      return DataRegionConsensusImpl.getInstance().write(groupId, planNode);
+    } else {
+      return SchemaRegionConsensusImpl.getInstance().write(groupId, planNode);
+    }
+  }
+
+  private TSendPlanNodeResp executeDataInsert(DataRegionId dataRegionId, InsertNode insertNode) {
+    TSendPlanNodeResp response = new TSendPlanNodeResp();
+    dataRegionLockMap.get(dataRegionId).readLock().lock();
+    try {
+      try {
+        SchemaValidator.validate(insertNode);
+      } catch (SemanticException e) {
+        response.setAccepted(false);
+        response.setMessage(e.getMessage());
+        return response;
+      }
+      boolean hasFailedMeasurement = insertNode.hasFailedMeasurements();
+      String partialInsertMessage = null;
+      if (hasFailedMeasurement) {
+        partialInsertMessage =
+            String.format(
+                "Fail to insert measurements %s caused by %s",
+                insertNode.getFailedMeasurements(), insertNode.getFailedMessages());
+        LOGGER.warn(partialInsertMessage);
+      }
+
+      ConsensusWriteResponse writeResponse =
+          executePlanNodeInConsensusLayer(dataRegionId, insertNode);
+
+      // TODO need consider more status
+      if (writeResponse.getStatus() != null) {
+        response.setAccepted(
+            !hasFailedMeasurement
+                && TSStatusCode.SUCCESS_STATUS.getStatusCode()
+                    == writeResponse.getStatus().getCode());
+        if (TSStatusCode.SUCCESS_STATUS.getStatusCode() != writeResponse.getStatus().getCode()) {
+          response.setMessage(writeResponse.getStatus().message);
+          response.setStatus(writeResponse.getStatus());
+        } else if (hasFailedMeasurement) {
+          response.setMessage(partialInsertMessage);
+          response.setStatus(
+              RpcUtils.getStatus(
+                  TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
+        } else {
+          response.setMessage(writeResponse.getStatus().message);
+        }
+      } else {
+        LOGGER.error(
+            "Something wrong happened while calling consensus layer's write API.",
+            writeResponse.getException());
+        response.setAccepted(false);
+        response.setMessage(writeResponse.getException().getMessage());
+      }
+
+      return response;
+    } finally {
+      dataRegionLockMap.get(dataRegionId).readLock().unlock();
+    }
+  }
+
+  public TSStatus executeSchemaPlanNode(SchemaRegionId schemaRegionId, PlanNode planNode) {
+    ConsensusWriteResponse writeResponse =
+        executePlanNodeInConsensusLayer(schemaRegionId, planNode);
+    TSStatus status = writeResponse.getStatus();
+    if (status == null) {
+      LOGGER.error(
+          "Something wrong happened while calling consensus layer's write API.",
+          writeResponse.getException());
+      return RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR);
+    }
+    return status;
+  }
+
+  public TSStatus executeDeleteDataForDeleteTimeSeries(
+      DataRegionId dataRegionId, PlanNode planNode) {
+    dataRegionLockMap.get(dataRegionId).writeLock().lock();
+    try {
+      ConsensusWriteResponse writeResponse =
+          executePlanNodeInConsensusLayer(dataRegionId, planNode);
+      TSStatus status = writeResponse.getStatus();
+      if (status == null) {
+        LOGGER.error(
+            "Something wrong happened while calling consensus layer's write API.",
+            writeResponse.getException());
+        return RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR);
+      }
+      return status;
+    } finally {
+      dataRegionLockMap.get(dataRegionId).writeLock().unlock();
+    }
+  }
+
+  public TSStatus createSchemaRegion(TRegionReplicaSet regionReplicaSet, String storageGroup) {
+    TSStatus tsStatus;
+    try {
+      PartialPath storageGroupPartitionPath = new PartialPath(storageGroup);
+      SchemaRegionId schemaRegionId = new SchemaRegionId(regionReplicaSet.getRegionId().getId());
+      schemaEngine.createSchemaRegion(storageGroupPartitionPath, schemaRegionId);
+      schemaRegionLockMap.put(schemaRegionId, new ReentrantReadWriteLock(false));
+      List<Peer> peers = new ArrayList<>();
+      for (TDataNodeLocation dataNodeLocation : regionReplicaSet.getDataNodeLocations()) {
+        TEndPoint endpoint =
+            new TEndPoint(
+                dataNodeLocation.getSchemaRegionConsensusEndPoint().getIp(),
+                dataNodeLocation.getSchemaRegionConsensusEndPoint().getPort());
+        peers.add(new Peer(schemaRegionId, endpoint));
+      }
+      ConsensusGenericResponse consensusGenericResponse =
+          SchemaRegionConsensusImpl.getInstance().createPeer(schemaRegionId, peers);
+      if (consensusGenericResponse.isSuccess()) {
+        tsStatus = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
+      } else {
+        tsStatus = new TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
+        tsStatus.setMessage(consensusGenericResponse.getException().getMessage());
+      }
+    } catch (IllegalPathException e1) {
+      LOGGER.error("Create Schema Region {} failed because path is illegal.", storageGroup);
+      tsStatus = new TSStatus(TSStatusCode.PATH_ILLEGAL.getStatusCode());
+      tsStatus.setMessage("Create Schema Region failed because storageGroup path is illegal.");
+    } catch (MetadataException e2) {
+      LOGGER.error("Create Schema Region {} failed because {}", storageGroup, e2.getMessage());
+      tsStatus = new TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
+      tsStatus.setMessage(
+          String.format("Create Schema Region failed because of %s", e2.getMessage()));
+    }
+    return tsStatus;
+  }
+
+  public TSStatus createDataRegion(
+      TRegionReplicaSet regionReplicaSet, String storageGroup, long ttl) {
+    TSStatus tsStatus;
+    try {
+      DataRegionId dataRegionId = new DataRegionId(regionReplicaSet.getRegionId().getId());
+      storageEngine.createDataRegion(dataRegionId, storageGroup, ttl);
+      dataRegionLockMap.put(dataRegionId, new ReentrantReadWriteLock(false));
+      List<Peer> peers = new ArrayList<>();
+      for (TDataNodeLocation dataNodeLocation : regionReplicaSet.getDataNodeLocations()) {
+        TEndPoint endpoint =
+            new TEndPoint(
+                dataNodeLocation.getDataRegionConsensusEndPoint().getIp(),
+                dataNodeLocation.getDataRegionConsensusEndPoint().getPort());
+        peers.add(new Peer(dataRegionId, endpoint));
+      }
+      ConsensusGenericResponse consensusGenericResponse =
+          DataRegionConsensusImpl.getInstance().createPeer(dataRegionId, peers);
+      if (consensusGenericResponse.isSuccess()) {
+        tsStatus = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
+      } else {
+        tsStatus = new TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
+        tsStatus.setMessage(consensusGenericResponse.getException().getMessage());
+      }
+    } catch (DataRegionException e) {
+      LOGGER.error("Create Data Region {} failed because {}", storageGroup, e.getMessage());
+      tsStatus = new TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
+      tsStatus.setMessage(String.format("Create Data Region failed because of %s", e.getMessage()));
+    }
+    return tsStatus;
+  }
+
+  public TSStatus createNewRegion(ConsensusGroupId regionId, String storageGroup, long ttl) {
+    TSStatus status = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
+    LOGGER.info("start to create new region {}", regionId);
+    try {
+      if (regionId instanceof DataRegionId) {
+        DataRegionId dataRegionId = (DataRegionId) regionId;
+        storageEngine.createDataRegion(dataRegionId, storageGroup, ttl);
+        dataRegionLockMap.put(dataRegionId, new ReentrantReadWriteLock(false));
+      } else {
+        SchemaRegionId schemaRegionId = (SchemaRegionId) regionId;
+        schemaEngine.createSchemaRegion(new PartialPath(storageGroup), schemaRegionId);
+        schemaRegionLockMap.put(schemaRegionId, new ReentrantReadWriteLock(false));
+      }
+    } catch (Exception e) {
+      LOGGER.error("create new region {} error", regionId, e);
+      status.setCode(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
+      status.setMessage("create new region " + regionId + "error,  exception:" + e.getMessage());
+      return status;
+    }
+    status.setMessage("create new region " + regionId + " succeed");
+    LOGGER.info("succeed to create new region {}", regionId);
+    return status;
+  }
+
+  public TSStatus deleteDataRegion(DataRegionId dataRegionId) {
+    storageEngine.deleteDataRegion(dataRegionId);
+    dataRegionLockMap.remove(dataRegionId);
+    return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, "Execute successfully");
+  }
+
+  public TSStatus deleteSchemaRegion(SchemaRegionId schemaRegionId) {
+    try {
+      schemaEngine.deleteSchemaRegion(schemaRegionId);
+      schemaRegionLockMap.remove(schemaRegionId);
+      return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, "Execute successfully");
+    } catch (MetadataException e) {
+      LOGGER.error("{}: MetaData error: ", IoTDBConstant.GLOBAL_DB_NAME, e);
+      return RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage());
+    }
+  }
+}
diff --git a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/metadata/write/DeleteTimeSeriesNodeSerdeTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/metadata/write/DeleteTimeSeriesNodeSerdeTest.java
index 4cc69bd672..e2c17af9c7 100644
--- a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/metadata/write/DeleteTimeSeriesNodeSerdeTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/metadata/write/DeleteTimeSeriesNodeSerdeTest.java
@@ -21,6 +21,7 @@ package org.apache.iotdb.db.mpp.plan.plan.node.metadata.write;
 
 import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNodeType;
@@ -30,7 +31,6 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import java.nio.ByteBuffer;
-import java.util.ArrayList;
 import java.util.List;
 
 public class DeleteTimeSeriesNodeSerdeTest {
@@ -38,10 +38,11 @@ public class DeleteTimeSeriesNodeSerdeTest {
   @Test
   public void testSerializeAndDeserialize() throws IllegalPathException {
     PlanNodeId planNodeId = new PlanNodeId("DeleteTimeSeriesNode");
-    List<PartialPath> pathList = new ArrayList<>();
-    pathList.add(new PartialPath("root.sg.d1.s1"));
-    pathList.add(new PartialPath("root.sg.d2.*"));
-    DeleteTimeSeriesNode deleteTimeSeriesNode = new DeleteTimeSeriesNode(planNodeId, pathList);
+    PathPatternTree patternTree = new PathPatternTree();
+    patternTree.appendPathPattern(new PartialPath("root.sg.d1.s1"));
+    patternTree.appendPathPattern(new PartialPath("root.sg.d2.*"));
+    patternTree.constructTree();
+    DeleteTimeSeriesNode deleteTimeSeriesNode = new DeleteTimeSeriesNode(planNodeId, patternTree);
 
     ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
     deleteTimeSeriesNode.serialize(byteBuffer);
@@ -52,7 +53,9 @@ public class DeleteTimeSeriesNodeSerdeTest {
     Assert.assertEquals(planNodeId, deserializedNode.getPlanNodeId());
 
     deleteTimeSeriesNode = (DeleteTimeSeriesNode) deserializedNode;
-    List<PartialPath> deserializedPathList = deleteTimeSeriesNode.getPathList();
+    PathPatternTree deserializedPatternTree = deleteTimeSeriesNode.getPatternTree();
+    List<PartialPath> pathList = patternTree.getAllPathPatterns();
+    List<PartialPath> deserializedPathList = deserializedPatternTree.getAllPathPatterns();
     Assert.assertEquals(pathList.size(), deserializedPathList.size());
     for (int i = 0; i < pathList.size(); i++) {
       Assert.assertEquals(pathList.get(i), deserializedPathList.get(i));
diff --git a/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java b/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
index d611b32bd8..4c11f4b5df 100644
--- a/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
+++ b/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
@@ -72,6 +72,7 @@ public enum TSStatusCode {
   CREATE_TEMPLATE_ERROR(340),
   SYNC_FILE_REBASE(341),
   SYNC_FILE_ERROR(342),
+  MEASUREMENT_IN_BLACK_LIST(343),
 
   EXECUTE_STATEMENT_ERROR(400),
   SQL_PARSE_ERROR(401),
@@ -153,7 +154,8 @@ public enum TSStatusCode {
   LACK_REPLICATION(916),
   DATANODE_STOP_ERROR(917),
   REGION_LEADER_CHANGE_FAILED(918),
-  REMOVE_DATANODE_FAILED(919);
+  REMOVE_DATANODE_FAILED(919),
+  OVERLAP_WITH_EXISTING_DELETE_TIMESERIES_TASK(920);
 
   private int statusCode;
 
diff --git a/thrift-confignode/src/main/thrift/confignode.thrift b/thrift-confignode/src/main/thrift/confignode.thrift
index e4c12899c1..78de4b094f 100644
--- a/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/thrift-confignode/src/main/thrift/confignode.thrift
@@ -390,6 +390,11 @@ struct TShowPipeResp {
   2: optional list<TPipeInfo> pipeInfoList
 }
 
+struct TDeleteTimeSeriesReq{
+  1: required string queryId
+  2: required binary pathPatternTree
+}
+
 service IConfigNodeRPCService {
 
   // ======================================================
@@ -715,5 +720,14 @@ service IConfigNodeRPCService {
 
   TGetPathsSetTemplatesResp getPathsSetTemplate(string req)
 
+
+  /**
+   * Generate a set of DeleteTimeSeriesProcedure to delete some specific TimeSeries
+   *
+   * @return SUCCESS_STATUS if the DeleteTimeSeriesProcedure submitted and executed successfully
+   *         TIMESERIES_NOT_EXIST if the specific TimeSeries doesn't exist
+   *         EXECUTE_STATEMENT_ERROR if failed to submit or execute the DeleteTimeSeriesProcedure
+   */
+  common.TSStatus deleteTimeSeries(TDeleteTimeSeriesReq req)
 }
 
diff --git a/thrift/src/main/thrift/datanode.thrift b/thrift/src/main/thrift/datanode.thrift
index d62800c275..db8ebf20fb 100644
--- a/thrift/src/main/thrift/datanode.thrift
+++ b/thrift/src/main/thrift/datanode.thrift
@@ -216,6 +216,40 @@ struct TUpdateTemplateReq{
   2: required binary templateInfo
 }
 
+struct TConstructSchemaBlackListReq{
+  1: required list<common.TConsensusGroupId> schemaRegionIdList
+  2: required binary pathPatternTree
+}
+
+struct TRollbackSchemaBlackListReq{
+  1: required list<common.TConsensusGroupId> schemaRegionIdList
+  2: required binary pathPatternTree
+}
+
+struct TInvalidateMatchedSchemaCacheReq{
+  1: required binary pathPatternTree
+}
+
+struct TFetchSchemaBlackListReq{
+  1: required list<common.TConsensusGroupId> schemaRegionIdList
+  2: required binary pathPatternTree
+}
+
+struct TFetchSchemaBlackListResp{
+  1: required common.TSStatus status
+  2: required binary pathPatternTree
+}
+
+struct TDeleteDataForDeleteTimeSeriesReq{
+  1: required list<common.TConsensusGroupId> dataRegionIdList
+  2: required binary pathPatternTree
+}
+
+struct TDeleteTimeSeriesReq{
+  1: required list<common.TConsensusGroupId> schemaRegionIdList
+  2: required binary pathPatternTree
+}
+
 service IDataNodeRPCService {
 
   // -----------------------------------For Data Node-----------------------------------------------
@@ -404,7 +438,44 @@ service IDataNodeRPCService {
    */
   common.TSStatus updateConfigNodeGroup(TUpdateConfigNodeGroupReq req)
 
+  /**
+   * Update template cache when template info or template set info is updated
+   */
   common.TSStatus updateTemplate(TUpdateTemplateReq req)
+
+  /**
+   * Construct schema black list in target schemaRegion to block R/W on matched timeseries
+   */
+  common.TSStatus constructSchemaBlackList(TConstructSchemaBlackListReq req)
+
+  /**
+   * Remove the schema black list to recover R/W on matched timeseries
+   */
+  common.TSStatus rollbackSchemaBlackList(TRollbackSchemaBlackListReq req)
+
+  /**
+   * Config node will invalidate Schema Info cache, which matched by given pathPatternTree.
+   *
+   * @param binary: pathPatternTree
+   */
+  common.TSStatus invalidateMatchedSchemaCache(TInvalidateMatchedSchemaCacheReq req)
+
+  /**
+   * Config node will fetch the schema info in black list.
+   *
+   * @param binary: pathPatternTree
+   */
+  TFetchSchemaBlackListResp fetchSchemaBlackList(TFetchSchemaBlackListReq req)
+
+  /**
+   * Config node inform this dataNode to execute a distribution data deleion mpp task
+   */
+  common.TSStatus deleteDataForDeleteTimeSeries(TDeleteDataForDeleteTimeSeriesReq req)
+
+ /**
+  * Delete matched timeseries and remove according schema black list in target schemRegion
+  */
+  common.TSStatus deleteTimeSeries(TDeleteTimeSeriesReq req)
 }
 
 service MPPDataExchangeService {