From 99b38ddca74f1cf7f50292db3f7dc924d546a700 Mon Sep 17 00:00:00 2001 From: walter Date: Sat, 9 Dec 2023 01:41:38 +0800 Subject: [PATCH] [improve](env) Ensure next majority is met before drop an alive follower (#28101) Here is an example: ``` mysql> ALTER SYSTEM DROP FOLLOWER "127.0.0.1:19017"; ERROR 1105 (HY000): errCode = 2, detailMessage = Unable to drop this alive follower, because the quorum requirements are not met after this command execution. Current num alive followers 2, num followers 3, majority after execution 2 ``` --- .../java/org/apache/doris/catalog/Env.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java index b1ecd46956..b498ccb6a6 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java @@ -2768,6 +2768,10 @@ public class Env { throw new DdlException(role.toString() + " does not exist[" + NetUtils .getHostPortInAccessibleFormat(host, port) + "]"); } + if (role == FrontendNodeType.FOLLOWER && fe.isAlive()) { + // Try drop an alive follower, check the quorum safety. + ensureSafeToDropAliveFollower(); + } int targetFollowerCount = getFollowerCount() - 1; if (fe.getRole() == FrontendNodeType.FOLLOWER || fe.getRole() == FrontendNodeType.REPLICA) { @@ -2796,6 +2800,30 @@ public class Env { helperNodes.removeIf(node -> node.getHost().equals(host) && node.getPort() == port); } + private void ensureSafeToDropAliveFollower() throws DdlException { + int numFollower = 0; + int numAliveFollower = 0; + for (Frontend fe : frontends.values()) { + if (fe.getRole() == FrontendNodeType.FOLLOWER) { + numFollower += 1; + if (fe.isAlive()) { + numAliveFollower += 1; + } + } + } + + int nextMajority = ((numFollower - 1) / 2) + 1; + if (nextMajority + 1 <= numAliveFollower) { + return; + } + + LOG.warn("Drop an alive follower is not safety. Current alive followers {}, followers {}, next majority: {}", + numAliveFollower, numFollower, nextMajority); + throw new DdlException("Unable to drop this alive follower, because the quorum requirements " + + "are not met after this command execution. Current num alive followers " + + numAliveFollower + ", num followers " + numFollower + ", majority after execution " + nextMajority); + } + public Frontend checkFeExist(String host, int port) { for (Frontend fe : frontends.values()) { if (fe.getEditLogPort() != port) {