@Override
  public SettableFuture<ConfigTaskResult> deleteDevice(
      final DeleteDevice deleteDevice, final String queryId, final SessionInfo sessionInfo) {
    final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
    if (!deleteDevice.isMayDeleteDevice()) {
      DeleteDeviceTask.buildTSBlock(0, future);
      return future;
    }

    try (final ConfigNodeClient client =
        CLUSTER_DELETION_CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {

      final ByteArrayOutputStream patternStream = new ByteArrayOutputStream();
      try (final DataOutputStream outputStream = new DataOutputStream(patternStream)) {
        deleteDevice.serializePatternInfo(outputStream);
      } catch (final IOException ignored) {
        // ByteArrayOutputStream won't throw IOException
      }

      final ByteArrayOutputStream filterStream = new ByteArrayOutputStream();
      try (final DataOutputStream outputStream = new DataOutputStream(filterStream)) {
        deleteDevice.serializeFilterInfo(outputStream, sessionInfo);
      } catch (final IOException ignored) {
        // ByteArrayOutputStream won't throw IOException
      }

      final ByteArrayOutputStream modStream = new ByteArrayOutputStream();
      try (final DataOutputStream outputStream = new DataOutputStream(modStream)) {
        deleteDevice.serializeModEntries(outputStream);
      } catch (final IOException ignored) {
        // ByteArrayOutputStream won't throw IOException
      }

      final TDeleteTableDeviceReq req =
          new TDeleteTableDeviceReq(
              deleteDevice.getDatabase(),
              deleteDevice.getTableName(),
              queryId,
              ByteBuffer.wrap(patternStream.toByteArray()),
              ByteBuffer.wrap(filterStream.toByteArray()),
              ByteBuffer.wrap(modStream.toByteArray()));

      TDeleteTableDeviceResp resp;
      do {
        try {
          resp = client.deleteDevice(req);
        } catch (final TTransportException e) {
          if (e.getType() == TTransportException.TIMED_OUT
              || e.getCause() instanceof SocketTimeoutException) {
            // time out mainly caused by slow execution, wait until
            resp =
                new TDeleteTableDeviceResp(
                    RpcUtils.getStatus(TSStatusCode.OVERLAP_WITH_EXISTING_TASK));
          } else {
            throw e;
          }
        }
        // keep waiting until task ends
      } while (TSStatusCode.OVERLAP_WITH_EXISTING_TASK.getStatusCode()
          == resp.getStatus().getCode());

      if (TSStatusCode.SUCCESS_STATUS.getStatusCode() == resp.getStatus().getCode()) {
        DeleteDeviceTask.buildTSBlock(resp.getDeletedNum(), future);
      } else {
        future.setException(
            new IoTDBException(
                getTableErrorMessage(resp.getStatus(), deleteDevice.getDatabase()),
                resp.getStatus().getCode()));
      }
    } catch (final ClientManagerException | TException e) {
      future.setException(e);
    }
    return future;
  }
FIXME Consolidate this clientManager with the upper one.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java