Skip to content

Commit 7ed116b

Browse files
authored
[improvement](decommission be) decommission check replica num #32748 (#34038)
1 parent cc1aabb commit 7ed116b

File tree

7 files changed

+183
-1
lines changed

7 files changed

+183
-1
lines changed

fe/fe-core/src/main/java/org/apache/doris/alter/SystemHandler.java

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,34 @@
3333
import org.apache.doris.analysis.ModifyFrontendHostNameClause;
3434
import org.apache.doris.catalog.Database;
3535
import org.apache.doris.catalog.Env;
36+
import org.apache.doris.catalog.MysqlCompatibleDatabase;
3637
import org.apache.doris.catalog.OlapTable;
38+
import org.apache.doris.catalog.Partition;
39+
import org.apache.doris.catalog.ReplicaAllocation;
40+
import org.apache.doris.catalog.Table;
3741
import org.apache.doris.catalog.TabletInvertedIndex;
3842
import org.apache.doris.common.Config;
3943
import org.apache.doris.common.DdlException;
4044
import org.apache.doris.common.UserException;
45+
import org.apache.doris.common.util.DebugPointUtil;
4146
import org.apache.doris.common.util.NetUtils;
4247
import org.apache.doris.ha.FrontendNodeType;
48+
import org.apache.doris.resource.Tag;
4349
import org.apache.doris.system.Backend;
4450
import org.apache.doris.system.SystemInfoService;
4551
import org.apache.doris.system.SystemInfoService.HostInfo;
4652

4753
import com.google.common.base.Preconditions;
4854
import com.google.common.collect.Lists;
55+
import com.google.common.collect.Maps;
4956
import org.apache.commons.lang3.NotImplementedException;
5057
import org.apache.logging.log4j.LogManager;
5158
import org.apache.logging.log4j.Logger;
5259

5360
import java.util.List;
61+
import java.util.Map;
62+
import java.util.Set;
63+
import java.util.stream.Collectors;
5464

5565
/*
5666
* SystemHandler is for
@@ -220,12 +230,81 @@ public static List<Backend> checkDecommission(List<HostInfo> hostInfos)
220230
decommissionBackends.add(backend);
221231
}
222232

223-
// TODO(cmy): check if replication num can be met
233+
checkDecommissionWithReplicaAllocation(decommissionBackends);
234+
224235
// TODO(cmy): check remaining space
225236

226237
return decommissionBackends;
227238
}
228239

240+
private static void checkDecommissionWithReplicaAllocation(List<Backend> decommissionBackends)
241+
throws DdlException {
242+
if (decommissionBackends.isEmpty()
243+
|| DebugPointUtil.isEnable("SystemHandler.decommission_no_check_replica_num")) {
244+
return;
245+
}
246+
247+
Set<Tag> decommissionTags = decommissionBackends.stream().map(be -> be.getLocationTag())
248+
.collect(Collectors.toSet());
249+
Map<Tag, Integer> tagAvailBackendNums = Maps.newHashMap();
250+
for (Backend backend : Env.getCurrentSystemInfo().getAllBackends()) {
251+
long beId = backend.getId();
252+
if (!backend.isScheduleAvailable()
253+
|| decommissionBackends.stream().anyMatch(be -> be.getId() == beId)) {
254+
continue;
255+
}
256+
257+
Tag tag = backend.getLocationTag();
258+
if (tag != null) {
259+
tagAvailBackendNums.put(tag, tagAvailBackendNums.getOrDefault(tag, 0) + 1);
260+
}
261+
}
262+
263+
Env env = Env.getCurrentEnv();
264+
List<Long> dbIds = env.getInternalCatalog().getDbIds();
265+
for (Long dbId : dbIds) {
266+
Database db = env.getInternalCatalog().getDbNullable(dbId);
267+
if (db == null) {
268+
continue;
269+
}
270+
271+
if (db instanceof MysqlCompatibleDatabase) {
272+
continue;
273+
}
274+
275+
for (Table table : db.getTables()) {
276+
table.readLock();
277+
try {
278+
if (!table.isManagedTable()) {
279+
continue;
280+
}
281+
282+
OlapTable tbl = (OlapTable) table;
283+
for (Partition partition : tbl.getAllPartitions()) {
284+
ReplicaAllocation replicaAlloc = tbl.getPartitionInfo().getReplicaAllocation(partition.getId());
285+
for (Map.Entry<Tag, Short> entry : replicaAlloc.getAllocMap().entrySet()) {
286+
Tag tag = entry.getKey();
287+
if (!decommissionTags.contains(tag)) {
288+
continue;
289+
}
290+
int replicaNum = (int) entry.getValue();
291+
int backendNum = tagAvailBackendNums.getOrDefault(tag, 0);
292+
if (replicaNum > backendNum) {
293+
throw new DdlException("After decommission, partition " + partition.getName()
294+
+ " of table " + db.getFullName() + "." + tbl.getName()
295+
+ " 's replication allocation { " + replicaAlloc
296+
+ " } > available backend num " + backendNum + " on tag " + tag
297+
+ ", otherwise need to decrease the partition's replication num.");
298+
}
299+
}
300+
}
301+
} finally {
302+
table.readUnlock();
303+
}
304+
}
305+
}
306+
}
307+
229308
@Override
230309
public synchronized void cancel(CancelStmt stmt) throws DdlException {
231310
CancelAlterSystemStmt cancelAlterSystemStmt = (CancelAlterSystemStmt) stmt;

regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,9 @@ class Suite implements GroovyInterceptable {
570570
assert p.exitValue() == 0
571571
}
572572

573+
List<String> getFrontendIpHttpPort() {
574+
return sql_return_maparray("show frontends").collect { it.Host + ":" + it.HttpPort };
575+
}
573576

574577
void getBackendIpHttpPort(Map<String, String> backendId_to_backendIP, Map<String, String> backendId_to_backendHttpPort) {
575578
List<List<Object>> backends = sql("show backends");

regression-test/pipeline/p0/conf/fe.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ enable_map_type=true
7878
enable_struct_type=true
7979
enable_feature_binlog=true
8080

81+
enable_debug_points=true
82+
8183
# enable mtmv
8284
enable_mtmv = true
8385

regression-test/pipeline/p1/conf/be.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,4 @@ enable_set_in_bitmap_value=true
7171
enable_feature_binlog=true
7272
max_sys_mem_available_low_water_mark_bytes=69206016
7373
enable_merge_on_write_correctness_check=false
74+
enable_debug_points=true

regression-test/pipeline/p1/conf/fe.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ remote_fragment_exec_timeout_ms=60000
7575
fuzzy_test_type=p1
7676
use_fuzzy_session_variable=true
7777

78+
enable_debug_points=true
79+
7880
# enable mtmv
7981
enable_mtmv = true
8082

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
suite('test_decommission_with_replica_num_fail') {
19+
def tbl = 'test_decommission_with_replica_num_fail'
20+
def backends = sql_return_maparray('show backends')
21+
def replicaNum = 0
22+
def targetBackend = null
23+
for (def be : backends) {
24+
def alive = be.Alive.toBoolean()
25+
def decommissioned = be.SystemDecommissioned.toBoolean()
26+
if (alive && !decommissioned) {
27+
replicaNum++
28+
targetBackend = be
29+
}
30+
}
31+
assertTrue(replicaNum > 0)
32+
33+
sql "DROP TABLE IF EXISTS ${tbl} FORCE"
34+
sql """
35+
CREATE TABLE ${tbl}
36+
(
37+
k1 int,
38+
k2 int
39+
)
40+
DISTRIBUTED BY HASH(k1) BUCKETS 6
41+
PROPERTIES
42+
(
43+
"replication_num" = "${replicaNum}"
44+
);
45+
"""
46+
try {
47+
test {
48+
sql "ALTER SYSTEM DECOMMISSION BACKEND '${targetBackend.Host}:${targetBackend.HeartbeatPort}'"
49+
exception "otherwise need to decrease the partition's replication num"
50+
}
51+
} finally {
52+
sql "CANCEL DECOMMISSION BACKEND '${targetBackend.Host}:${targetBackend.HeartbeatPort}'"
53+
}
54+
sql "DROP TABLE IF EXISTS ${tbl} FORCE"
55+
}

regression-test/suites/node_p0/test_backend.groovy

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,44 @@ suite("test_backend") {
3939
result = sql """SHOW BACKENDS;"""
4040
logger.info("result:${result}")
4141
}
42+
43+
if (context.config.jdbcUser.equals("root")) {
44+
def decommissionBe = null
45+
try {
46+
GetDebugPoint().enableDebugPointForAllFEs("SystemHandler.decommission_no_check_replica_num");
47+
try_sql """admin set frontend config("drop_backend_after_decommission" = "false")"""
48+
def result = sql_return_maparray """SHOW BACKENDS;"""
49+
logger.info("show backends result:${result}")
50+
for (def res : result) {
51+
decommissionBe = res
52+
break
53+
}
54+
sql """CANCEL DECOMMISSION BACKEND "${decommissionBe.Host}:${decommissionBe.HeartbeatPort}" """
55+
result = sql """ALTER SYSTEM DECOMMISSION BACKEND "${decommissionBe.Host}:${decommissionBe.HeartbeatPort}" """
56+
logger.info("ALTER SYSTEM DECOMMISSION BACKEND ${result}")
57+
result = sql_return_maparray """SHOW BACKENDS;"""
58+
for (def res : result) {
59+
if (res.BackendId == "${decommissionBe.BackendId}") {
60+
assertTrue(res.SystemDecommissioned.toBoolean())
61+
}
62+
}
63+
} finally {
64+
try {
65+
if (decommissionBe != null) {
66+
def result = sql """CANCEL DECOMMISSION BACKEND "${decommissionBe.Host}:${decommissionBe.HeartbeatPort}" """
67+
logger.info("CANCEL DECOMMISSION BACKEND ${result}")
68+
69+
result = sql_return_maparray """SHOW BACKENDS;"""
70+
for (def res : result) {
71+
if (res.BackendId == "${decommissionBe.BackendId}") {
72+
assertFalse(res.SystemDecommissioned.toBoolean())
73+
}
74+
}
75+
}
76+
} finally {
77+
GetDebugPoint().disableDebugPointForAllFEs('SystemHandler.decommission_no_check_replica_num');
78+
try_sql """admin set frontend config("drop_backend_after_decommission" = "true")"""
79+
}
80+
}
81+
}
4282
}

0 commit comments

Comments
 (0)