diff --git a/docs/en/docs/sql-manual/sql-reference/Cluster-Management-Statements/CANCEL-ALTER-SYSTEM.md b/docs/en/docs/sql-manual/sql-reference/Cluster-Management-Statements/CANCEL-ALTER-SYSTEM.md index 60bc080d8d..24ab0c71b5 100644 --- a/docs/en/docs/sql-manual/sql-reference/Cluster-Management-Statements/CANCEL-ALTER-SYSTEM.md +++ b/docs/en/docs/sql-manual/sql-reference/Cluster-Management-Statements/CANCEL-ALTER-SYSTEM.md @@ -36,10 +36,18 @@ This statement is used to undo a node offline operation. (Administrator only!) grammar: +- Find backend through host and port + ```sql CANCEL DECOMMISSION BACKEND "host:heartbeat_port"[,"host:heartbeat_port"...]; ```` +- Find backend through backend_id + +```sql +CANCEL DECOMMISSION BACKEND "id1","id2","id3..."; +```` + ### Example 1. Cancel the offline operation of both nodes: @@ -48,6 +56,12 @@ CANCEL DECOMMISSION BACKEND "host:heartbeat_port"[,"host:heartbeat_port"...]; CANCEL DECOMMISSION BACKEND "host1:port", "host2:port"; ```` + 2. Cancel the offline operation of the node with backend_id 1: + + ```sql + CANCEL DECOMMISSION BACKEND "1","2"; + ``` + ### Keywords CANCEL, DECOMMISSION, CANCEL ALTER diff --git a/docs/zh-CN/docs/sql-manual/sql-reference/Cluster-Management-Statements/CANCEL-ALTER-SYSTEM.md b/docs/zh-CN/docs/sql-manual/sql-reference/Cluster-Management-Statements/CANCEL-ALTER-SYSTEM.md index d01ea16a03..15ce5d1eea 100644 --- a/docs/zh-CN/docs/sql-manual/sql-reference/Cluster-Management-Statements/CANCEL-ALTER-SYSTEM.md +++ b/docs/zh-CN/docs/sql-manual/sql-reference/Cluster-Management-Statements/CANCEL-ALTER-SYSTEM.md @@ -36,10 +36,18 @@ CANCEL DECOMMISSION 语法: +- 通过 host 和 port 查找 backend + ```sql CANCEL DECOMMISSION BACKEND "host:heartbeat_port"[,"host:heartbeat_port"...]; ``` +- 通过 backend_id 查找 backend + +```sql +CANCEL DECOMMISSION BACKEND "id1","id2","id3..."; +``` + ### Example 1. 取消两个节点的下线操作: @@ -48,6 +56,12 @@ CANCEL DECOMMISSION BACKEND "host:heartbeat_port"[,"host:heartbeat_port"...]; CANCEL DECOMMISSION BACKEND "host1:port", "host2:port"; ``` + 2. 取消 backend_id 为 1 的节点的下线操作: + + ```sql + CANCEL DECOMMISSION BACKEND "1","2"; + ``` + ### Keywords CANCEL, DECOMMISSION, CANCEL ALTER diff --git a/fe/fe-core/src/main/java/org/apache/doris/alter/SystemHandler.java b/fe/fe-core/src/main/java/org/apache/doris/alter/SystemHandler.java index fbfbc9cc0e..a146a72869 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/alter/SystemHandler.java +++ b/fe/fe-core/src/main/java/org/apache/doris/alter/SystemHandler.java @@ -107,8 +107,8 @@ public class SystemHandler extends AlterHandler { @Override // add synchronized to avoid process 2 or more stmts at same time public synchronized void process(String rawSql, List alterClauses, String clusterName, - Database dummyDb, - OlapTable dummyTbl) throws UserException { + Database dummyDb, + OlapTable dummyTbl) throws UserException { Preconditions.checkArgument(alterClauses.size() == 1); AlterClause alterClause = alterClauses.get(0); @@ -263,31 +263,48 @@ public class SystemHandler extends AlterHandler { CancelAlterSystemStmt cancelAlterSystemStmt = (CancelAlterSystemStmt) stmt; SystemInfoService infoService = Env.getCurrentSystemInfo(); // check if backends is under decommission - List backends = Lists.newArrayList(); List hostInfos = cancelAlterSystemStmt.getHostInfos(); - for (HostInfo hostInfo : hostInfos) { - // check if exist - Backend backend = infoService.getBackendWithHeartbeatPort(hostInfo.getHost(), - hostInfo.getPort()); - if (backend == null) { - throw new DdlException("Backend does not exist[" - + NetUtils.getHostPortInAccessibleFormat(hostInfo.getHost(), hostInfo.getPort()) + "]"); + if (hostInfos.isEmpty()) { + List ids = cancelAlterSystemStmt.getIds(); + for (String id : ids) { + Backend backend = infoService.getBackend(Long.parseLong(id)); + if (backend == null) { + throw new DdlException("Backend does not exist[" + + id + "]"); + } + if (!backend.isDecommissioned()) { + // it's ok. just log + LOG.info("backend is not decommissioned[{}]", backend.getId()); + continue; + } + if (backend.setDecommissioned(false)) { + Env.getCurrentEnv().getEditLog().logBackendStateChange(backend); + } else { + LOG.info("backend is not decommissioned[{}]", backend.getHost()); + } } - if (!backend.isDecommissioned()) { - // it's ok. just log - LOG.info("backend is not decommissioned[{}]", backend.getId()); - continue; - } + } else { + for (HostInfo hostInfo : hostInfos) { + // check if exist + Backend backend = infoService.getBackendWithHeartbeatPort(hostInfo.getHost(), + hostInfo.getPort()); + if (backend == null) { + throw new DdlException("Backend does not exist[" + + NetUtils.getHostPortInAccessibleFormat(hostInfo.getHost(), hostInfo.getPort()) + "]"); + } - backends.add(backend); - } + if (!backend.isDecommissioned()) { + // it's ok. just log + LOG.info("backend is not decommissioned[{}]", backend.getId()); + continue; + } - for (Backend backend : backends) { - if (backend.setDecommissioned(false)) { - Env.getCurrentEnv().getEditLog().logBackendStateChange(backend); - } else { - LOG.info("backend is not decommissioned[{}]", backend.getHost()); + if (backend.setDecommissioned(false)) { + Env.getCurrentEnv().getEditLog().logBackendStateChange(backend); + } else { + LOG.info("backend is not decommissioned[{}]", backend.getHost()); + } } } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CancelAlterSystemStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CancelAlterSystemStmt.java index abb44cd54b..9b547a4de5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CancelAlterSystemStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CancelAlterSystemStmt.java @@ -23,43 +23,62 @@ import org.apache.doris.system.SystemInfoService.HostInfo; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import lombok.Getter; import java.util.List; public class CancelAlterSystemStmt extends CancelStmt { - protected List hostPorts; - private List hostInfos; + protected List params; + @Getter + private final List hostInfos; - public CancelAlterSystemStmt(List hostPorts) { - this.hostPorts = hostPorts; + @Getter + private final List ids; + + public CancelAlterSystemStmt(List params) { + this.params = params; this.hostInfos = Lists.newArrayList(); - } - - public List getHostInfos() { - return hostInfos; + this.ids = Lists.newArrayList(); } @Override public void analyze(Analyzer analyzer) throws AnalysisException { - for (String hostPort : hostPorts) { - HostInfo hostInfo = SystemInfoService.getHostAndPort(hostPort); - this.hostInfos.add(hostInfo); + for (String param : params) { + if (!param.contains(":")) { + ids.add(param); + } else { + HostInfo hostInfo = SystemInfoService.getHostAndPort(param); + this.hostInfos.add(hostInfo); + } + } - Preconditions.checkState(!this.hostInfos.isEmpty()); + Preconditions.checkState(!this.hostInfos.isEmpty() || !this.ids.isEmpty(), + "hostInfos or ids can not be empty"); + } @Override public String toSql() { StringBuilder sb = new StringBuilder(); sb.append("CANCEL DECOMMISSION BACKEND "); - for (int i = 0; i < hostPorts.size(); i++) { - sb.append("\"").append(hostPorts.get(i)).append("\""); - if (i != hostPorts.size() - 1) { - sb.append(", "); + if (!ids.isEmpty()) { + for (int i = 0; i < hostInfos.size(); i++) { + sb.append("\"").append(hostInfos.get(i)).append("\""); + if (i != hostInfos.size() - 1) { + sb.append(", "); + } + } + } else { + for (int i = 0; i < params.size(); i++) { + sb.append("\"").append(params.get(i)).append("\""); + if (i != params.size() - 1) { + sb.append(", "); + } } } + return sb.toString(); } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/clone/TabletRepairAndBalanceTest.java b/fe/fe-core/src/test/java/org/apache/doris/clone/TabletRepairAndBalanceTest.java index 9b43d34281..b520d73a8b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/clone/TabletRepairAndBalanceTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/clone/TabletRepairAndBalanceTest.java @@ -20,6 +20,7 @@ package org.apache.doris.clone; import org.apache.doris.analysis.AlterSystemStmt; import org.apache.doris.analysis.AlterTableStmt; import org.apache.doris.analysis.BackendClause; +import org.apache.doris.analysis.CancelAlterSystemStmt; import org.apache.doris.analysis.CreateDbStmt; import org.apache.doris.analysis.CreateTableStmt; import org.apache.doris.analysis.DropTableStmt; @@ -497,6 +498,20 @@ public class TabletRepairAndBalanceTest { // set one replica to bad, see if it can be repaired oneReplica.setBad(true); Assert.assertTrue(checkReplicaBad(oneTablet, oneReplica)); + + + //test cancel decommission backend by ids + + String stmtStr4 = "alter system decommission backend \"" + be.getHost() + ":" + be.getHeartbeatPort() + "\""; + stmt = (AlterSystemStmt) UtFrameUtils.parseAndAnalyzeStmt(stmtStr4, connectContext); + DdlExecutor.execute(Env.getCurrentEnv(), stmt); + + String stmtStr5 = "cancel decommission backend \"" + be.getId() + "\""; + CancelAlterSystemStmt cancelAlterSystemStmt = (CancelAlterSystemStmt) UtFrameUtils.parseAndAnalyzeStmt(stmtStr5, connectContext); + DdlExecutor.execute(Env.getCurrentEnv(), cancelAlterSystemStmt); + + Assert.assertFalse(be.isDecommissioned()); + } private static boolean checkReplicaState(Replica replica) throws Exception {