[Enhancement] Force drop decommissioned backend if all the tablets in recycle bin (backport #62781) (#63156)
Signed-off-by: gengjun-git <gengjun@starrocks.com> Co-authored-by: gengjun-git <gengjun@starrocks.com>
This commit is contained in:
parent
c0e4a1337b
commit
631312127b
|
|
@ -37,11 +37,15 @@ package com.starrocks.alter;
|
|||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.starrocks.catalog.BrokerMgr;
|
||||
import com.starrocks.catalog.CatalogRecycleBin;
|
||||
import com.starrocks.catalog.Database;
|
||||
import com.starrocks.catalog.OlapTable;
|
||||
import com.starrocks.catalog.PartitionInfo;
|
||||
import com.starrocks.catalog.Replica;
|
||||
import com.starrocks.catalog.Replica.ReplicaState;
|
||||
import com.starrocks.catalog.Table;
|
||||
import com.starrocks.catalog.TabletInvertedIndex;
|
||||
import com.starrocks.catalog.TabletMeta;
|
||||
import com.starrocks.common.Config;
|
||||
import com.starrocks.common.DdlException;
|
||||
import com.starrocks.common.ErrorReport;
|
||||
|
|
@ -82,6 +86,7 @@ import org.apache.logging.log4j.Logger;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -93,6 +98,8 @@ import java.util.stream.Collectors;
|
|||
*/
|
||||
public class SystemHandler extends AlterHandler {
|
||||
private static final Logger LOG = LogManager.getLogger(SystemHandler.class);
|
||||
private static final long RECYCLE_BIN_CHECK_INTERVAL = 10 * 60 * 1000L; // 10 min
|
||||
private long lastRecycleBinCheckTime = 0L;
|
||||
|
||||
public SystemHandler() {
|
||||
super("cluster");
|
||||
|
|
@ -355,11 +362,15 @@ public class SystemHandler extends AlterHandler {
|
|||
}
|
||||
|
||||
List<Long> backendTabletIds = invertedIndex.getTabletIdsByBackendId(beId);
|
||||
if (backendTabletIds.isEmpty()) {
|
||||
if (canDropBackend(backendTabletIds)) {
|
||||
if (Config.drop_backend_after_decommission) {
|
||||
try {
|
||||
systemInfoService.dropBackend(beId);
|
||||
LOG.info("no tablet on decommission backend {}, drop it", beId);
|
||||
if (backendTabletIds.isEmpty()) {
|
||||
LOG.info("no tablet on decommission backend {}, drop it", beId);
|
||||
} else {
|
||||
LOG.info("force drop decommission backend {}, the tablets on it are all in recycle bin", beId);
|
||||
}
|
||||
} catch (DdlException e) {
|
||||
// does not matter, maybe backend not exists
|
||||
LOG.info("backend {} drop failed after decommission {}", beId, e.getMessage());
|
||||
|
|
@ -373,6 +384,75 @@ public class SystemHandler extends AlterHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the following conditions are met, it can be forced to drop the backend
|
||||
* 1. All the tablets are in recycle bin.
|
||||
* 2. All the replication number of tablets is bigger than the retained backend number
|
||||
* (which means there is no backend to migrate, so decommission is blocked),
|
||||
* and at least one healthy replica on retained backend.
|
||||
* 3. There are at least 1 available backend.
|
||||
*/
|
||||
protected boolean canDropBackend(List<Long> backendTabletIds) {
|
||||
if (backendTabletIds.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// There is only on replica for shared data mode, so tablets can be migrated to other backends.
|
||||
if (RunMode.isSharedDataMode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lastRecycleBinCheckTime + RECYCLE_BIN_CHECK_INTERVAL > System.currentTimeMillis()) {
|
||||
return false;
|
||||
}
|
||||
lastRecycleBinCheckTime = System.currentTimeMillis();
|
||||
|
||||
SystemInfoService systemInfoService = GlobalStateMgr.getCurrentState().getNodeMgr().getClusterInfo();
|
||||
int availableBECnt = systemInfoService.getAvailableBackends().size();
|
||||
if (availableBECnt < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TabletInvertedIndex invertedIndex = GlobalStateMgr.getCurrentState().getTabletInvertedIndex();
|
||||
CatalogRecycleBin recycleBin = GlobalStateMgr.getCurrentState().getRecycleBin();
|
||||
List<Backend> retainedBackends = systemInfoService.getRetainedBackends();
|
||||
int retainedHostCnt = (int) retainedBackends.stream().map(Backend::getHost).distinct().count();
|
||||
Set<Long> retainedBackendIds = retainedBackends.stream().map(Backend::getId).collect(Collectors.toSet());
|
||||
for (Long tabletId : backendTabletIds) {
|
||||
TabletMeta tabletMeta = invertedIndex.getTabletMeta(tabletId);
|
||||
if (tabletMeta == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!recycleBin.isTabletInRecycleBin(tabletMeta)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<Long, Replica> replicas = invertedIndex.getReplicas(tabletId);
|
||||
if (replicas == null) {
|
||||
continue;
|
||||
}
|
||||
// It means the replica can be migrated to retained backends.
|
||||
if (replicas.size() <= retainedHostCnt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure there is at least one normal replica on retained backends.
|
||||
boolean hasNormalReplica = false;
|
||||
for (Replica replica : replicas.values()) {
|
||||
if (replica.getState() == ReplicaState.NORMAL && retainedBackendIds.contains(replica.getBackendId())) {
|
||||
hasNormalReplica = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasNormalReplica) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void cancel(CancelStmt stmt) throws DdlException {
|
||||
CancelAlterSystemStmt cancelAlterSystemStmt = (CancelAlterSystemStmt) stmt;
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ public class CatalogRecycleBin extends FrontendDaemon implements Writable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public PhysicalPartition getPhysicalPartition(long physicalPartitionId) {
|
||||
public synchronized PhysicalPartition getPhysicalPartition(long physicalPartitionId) {
|
||||
for (Partition partition : idToPartition.values().stream()
|
||||
.map(RecyclePartitionInfo::getPartition)
|
||||
.collect(Collectors.toList())) {
|
||||
|
|
@ -1121,6 +1121,12 @@ public class CatalogRecycleBin extends FrontendDaemon implements Writable {
|
|||
return Stream.of(dbInfos, tableInfos, partitionInfos).flatMap(Collection::stream).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public synchronized boolean isTabletInRecycleBin(TabletMeta tabletMeta) {
|
||||
return idToDatabase.containsKey(tabletMeta.getDbId()) ||
|
||||
idToTableInfo.containsColumn(tabletMeta.getTableId()) ||
|
||||
getPhysicalPartition(tabletMeta.getPhysicalPartitionId()) != null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
synchronized boolean isContainedInidToRecycleTime(long id) {
|
||||
return idToRecycleTime.get(id) != null;
|
||||
|
|
|
|||
|
|
@ -421,6 +421,15 @@ public class TabletInvertedIndex implements MemoryTrackable {
|
|||
}
|
||||
}
|
||||
|
||||
public Map<Long, Replica> getReplicas(long tabletId) {
|
||||
readLock();
|
||||
try {
|
||||
return this.replicaMetaTable.get(tabletId);
|
||||
} finally {
|
||||
readUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
// The caller should hold readLock.
|
||||
public Map<Long, Replica> getReplicaMetaWithBackend(Long backendId) {
|
||||
return row(backingReplicaMetaTable, backendId);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,365 @@
|
|||
// Copyright 2021-present StarRocks, Inc. All rights reserved.
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 com.starrocks.alter;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.starrocks.catalog.CatalogRecycleBin;
|
||||
import com.starrocks.catalog.Replica;
|
||||
import com.starrocks.catalog.TabletInvertedIndex;
|
||||
import com.starrocks.catalog.TabletMeta;
|
||||
import com.starrocks.server.RunMode;
|
||||
import com.starrocks.system.Backend;
|
||||
import com.starrocks.system.SystemInfoService;
|
||||
import mockit.Mock;
|
||||
import mockit.MockUp;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Test class for SystemHandler.canForceDrop method
|
||||
*/
|
||||
public class SystemHandlerCanForceDropTest {
|
||||
|
||||
private SystemHandler systemHandler;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
systemHandler = new SystemHandler();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanForceDropEmptyTablets() {
|
||||
// Test case: empty tablet list should return true
|
||||
List<Long> emptyTabletIds = new ArrayList<>();
|
||||
boolean result = systemHandler.canDropBackend(emptyTabletIds);
|
||||
Assertions.assertTrue(result, "Empty tablet list should return true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanForceDropSharedDataMode() {
|
||||
// Test case: shared data mode should return false
|
||||
List<Long> tabletIds = Lists.newArrayList(1L, 2L, 3L);
|
||||
|
||||
// Mock RunMode to return shared data mode
|
||||
new MockUp<RunMode>() {
|
||||
@Mock
|
||||
public static boolean isSharedDataMode() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
boolean result = systemHandler.canDropBackend(tabletIds);
|
||||
Assertions.assertFalse(result, "Shared data mode should return false");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanForceDropRecycleBinInterval() throws Exception {
|
||||
// Test case: within recycle bin check interval should return false
|
||||
List<Long> tabletIds = Lists.newArrayList(1L, 2L, 3L);
|
||||
|
||||
// Mock RunMode to return shared nothing mode
|
||||
new MockUp<RunMode>() {
|
||||
@Mock
|
||||
public static boolean isSharedDataMode() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// First call to set lastRecycleBinCheckTime
|
||||
systemHandler.canDropBackend(tabletIds);
|
||||
|
||||
// Second call within interval should return false
|
||||
boolean result = systemHandler.canDropBackend(tabletIds);
|
||||
Assertions.assertFalse(result, "Within recycle bin check interval should return false");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanForceDropNoAvailableBackends() throws Exception {
|
||||
// Test case: no available backends should return false
|
||||
List<Long> tabletIds = Lists.newArrayList(1L, 2L, 3L);
|
||||
|
||||
// Mock RunMode to return shared nothing mode
|
||||
new MockUp<RunMode>() {
|
||||
@Mock
|
||||
public static boolean isSharedDataMode() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock SystemInfoService to return empty available backends
|
||||
new MockUp<SystemInfoService>() {
|
||||
@Mock
|
||||
public List<Backend> getAvailableBackends() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
};
|
||||
|
||||
boolean result = systemHandler.canDropBackend(tabletIds);
|
||||
Assertions.assertFalse(result, "No available backends should return false");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanForceDropTabletNotInRecycleBin() throws Exception {
|
||||
// Test case: tablet not in recycle bin should return false
|
||||
List<Long> tabletIds = Lists.newArrayList(1L, 2L, 3L);
|
||||
|
||||
// Mock RunMode to return shared nothing mode
|
||||
new MockUp<RunMode>() {
|
||||
@Mock
|
||||
public static boolean isSharedDataMode() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock SystemInfoService to return available backends
|
||||
List<Backend> availableBackends = Lists.newArrayList(
|
||||
new Backend(1L, "host1", 1000),
|
||||
new Backend(2L, "host2", 1000)
|
||||
);
|
||||
new MockUp<SystemInfoService>() {
|
||||
@Mock
|
||||
public List<Backend> getAvailableBackends() {
|
||||
return availableBackends;
|
||||
}
|
||||
|
||||
@Mock
|
||||
public List<Backend> getRetainedBackends() {
|
||||
return Lists.newArrayList(availableBackends.get(0));
|
||||
}
|
||||
};
|
||||
|
||||
// Mock CatalogRecycleBin to return false for isTabletInRecycleBin
|
||||
new MockUp<CatalogRecycleBin>() {
|
||||
@Mock
|
||||
public boolean isTabletInRecycleBin(TabletMeta tabletMeta) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock TabletInvertedIndex
|
||||
mockTabletInvertedIndex();
|
||||
|
||||
boolean result = systemHandler.canDropBackend(tabletIds);
|
||||
Assertions.assertFalse(result, "Tablet not in recycle bin should return false");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanForceDropInsufficientReplicas() throws Exception {
|
||||
// Test case: insufficient replicas should return false
|
||||
List<Long> tabletIds = Lists.newArrayList(1L, 2L, 3L);
|
||||
|
||||
// Mock RunMode to return shared nothing mode
|
||||
new MockUp<RunMode>() {
|
||||
@Mock
|
||||
public static boolean isSharedDataMode() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock SystemInfoService to return available backends
|
||||
List<Backend> availableBackends = Lists.newArrayList(
|
||||
new Backend(1L, "host1", 1000),
|
||||
new Backend(2L, "host2", 1000)
|
||||
);
|
||||
new MockUp<SystemInfoService>() {
|
||||
@Mock
|
||||
public List<Backend> getAvailableBackends() {
|
||||
return availableBackends;
|
||||
}
|
||||
|
||||
@Mock
|
||||
public List<Backend> getRetainedBackends() {
|
||||
return availableBackends;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock CatalogRecycleBin to return true for isTabletInRecycleBin
|
||||
new MockUp<CatalogRecycleBin>() {
|
||||
@Mock
|
||||
public boolean isTabletInRecycleBin(TabletMeta tabletMeta) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock TabletInvertedIndex with insufficient replicas
|
||||
mockTabletInvertedIndexWithInsufficientReplicas();
|
||||
|
||||
boolean result = systemHandler.canDropBackend(tabletIds);
|
||||
Assertions.assertFalse(result, "Insufficient replicas should return false");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanForceDropNoNormalReplica() throws Exception {
|
||||
// Test case: no normal replica on retained backends should return false
|
||||
List<Long> tabletIds = Lists.newArrayList(1L, 2L, 3L);
|
||||
|
||||
// Mock RunMode to return shared nothing mode
|
||||
new MockUp<RunMode>() {
|
||||
@Mock
|
||||
public static boolean isSharedDataMode() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock SystemInfoService to return available backends
|
||||
List<Backend> availableBackends = Lists.newArrayList(
|
||||
new Backend(1L, "host1", 1000),
|
||||
new Backend(2L, "host2", 1000)
|
||||
);
|
||||
new MockUp<SystemInfoService>() {
|
||||
@Mock
|
||||
public List<Backend> getAvailableBackends() {
|
||||
return availableBackends;
|
||||
}
|
||||
|
||||
@Mock
|
||||
public List<Backend> getRetainedBackends() {
|
||||
return Lists.newArrayList(availableBackends.get(0));
|
||||
}
|
||||
};
|
||||
|
||||
// Mock CatalogRecycleBin to return true for isTabletInRecycleBin
|
||||
new MockUp<CatalogRecycleBin>() {
|
||||
@Mock
|
||||
public boolean isTabletInRecycleBin(TabletMeta tabletMeta) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock TabletInvertedIndex with no normal replica on retained backends
|
||||
mockTabletInvertedIndexWithNoNormalReplica();
|
||||
|
||||
boolean result = systemHandler.canDropBackend(tabletIds);
|
||||
Assertions.assertFalse(result, "No normal replica on retained backends should return false");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanForceDropSuccess() throws Exception {
|
||||
// Test case: all conditions met should return true
|
||||
List<Long> tabletIds = Lists.newArrayList(1L, 2L, 3L);
|
||||
|
||||
// Mock RunMode to return shared nothing mode
|
||||
new MockUp<RunMode>() {
|
||||
@Mock
|
||||
public static boolean isSharedDataMode() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock SystemInfoService to return available backends
|
||||
List<Backend> availableBackends = Lists.newArrayList(
|
||||
new Backend(1L, "host1", 1000),
|
||||
new Backend(2L, "host2", 1000)
|
||||
);
|
||||
new MockUp<SystemInfoService>() {
|
||||
@Mock
|
||||
public List<Backend> getAvailableBackends() {
|
||||
return availableBackends;
|
||||
}
|
||||
|
||||
@Mock
|
||||
public List<Backend> getRetainedBackends() {
|
||||
return Lists.newArrayList(availableBackends.get(0));
|
||||
}
|
||||
};
|
||||
|
||||
// Mock CatalogRecycleBin to return true for isTabletInRecycleBin
|
||||
new MockUp<CatalogRecycleBin>() {
|
||||
@Mock
|
||||
public boolean isTabletInRecycleBin(TabletMeta tabletMeta) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Mock TabletInvertedIndex with sufficient replicas and normal replica on retained backends
|
||||
mockTabletInvertedIndexWithSuccess();
|
||||
|
||||
boolean result = systemHandler.canDropBackend(tabletIds);
|
||||
Assertions.assertTrue(result, "All conditions met should return true");
|
||||
}
|
||||
|
||||
private void mockTabletInvertedIndex() {
|
||||
new MockUp<TabletInvertedIndex>() {
|
||||
@Mock
|
||||
public TabletMeta getTabletMeta(long tabletId) {
|
||||
return new TabletMeta(1L, 1L, 1L, 1L, null, false);
|
||||
}
|
||||
|
||||
@Mock
|
||||
public Map<Long, Replica> getReplicas(long tabletId) {
|
||||
Map<Long, Replica> replicas = new HashMap<>();
|
||||
replicas.put(1L, new Replica(1L, 1L, 1L, 1, 0L, 0L, Replica.ReplicaState.NORMAL, -1L, 1L));
|
||||
return replicas;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void mockTabletInvertedIndexWithInsufficientReplicas() {
|
||||
new MockUp<TabletInvertedIndex>() {
|
||||
@Mock
|
||||
public TabletMeta getTabletMeta(long tabletId) {
|
||||
return new TabletMeta(1L, 1L, 1L, 1L, null, false);
|
||||
}
|
||||
|
||||
@Mock
|
||||
public Map<Long, Replica> getReplicas(long tabletId) {
|
||||
Map<Long, Replica> replicas = new HashMap<>();
|
||||
replicas.put(1L, new Replica(1L, 1L, 1L, 1, 0L, 0L, Replica.ReplicaState.NORMAL, -1L, 1L));
|
||||
return replicas;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void mockTabletInvertedIndexWithNoNormalReplica() {
|
||||
new MockUp<TabletInvertedIndex>() {
|
||||
@Mock
|
||||
public TabletMeta getTabletMeta(long tabletId) {
|
||||
return new TabletMeta(1L, 1L, 1L, 1L, null, false);
|
||||
}
|
||||
|
||||
@Mock
|
||||
public Map<Long, Replica> getReplicas(long tabletId) {
|
||||
Map<Long, Replica> replicas = new HashMap<>();
|
||||
// Create replica on non-retained backend (backendId = 2)
|
||||
replicas.put(1L, new Replica(1L, 2L, 1L, 1, 0L, 0L, Replica.ReplicaState.NORMAL, -1L, 1L));
|
||||
return replicas;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void mockTabletInvertedIndexWithSuccess() {
|
||||
new MockUp<TabletInvertedIndex>() {
|
||||
@Mock
|
||||
public TabletMeta getTabletMeta(long tabletId) {
|
||||
return new TabletMeta(1L, 1L, 1L, 1L, null, false);
|
||||
}
|
||||
|
||||
@Mock
|
||||
public Map<Long, Replica> getReplicas(long tabletId) {
|
||||
Map<Long, Replica> replicas = new HashMap<>();
|
||||
// Create replica on retained backend (backendId = 1)
|
||||
replicas.put(1L, new Replica(1L, 1L, 1L, 1, 0L, 0L, Replica.ReplicaState.NORMAL, -1L, 1L));
|
||||
replicas.put(2L, new Replica(2L, 2L, 1L, 1, 0L, 0L, Replica.ReplicaState.NORMAL, -1L, 1L));
|
||||
return replicas;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2021-present StarRocks, Inc. All rights reserved.
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 com.starrocks.catalog;
|
||||
|
||||
import com.starrocks.thrift.TStorageMedium;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for TabletInvertedIndex class
|
||||
*/
|
||||
public class TabletInvertedIndexTest {
|
||||
|
||||
private TabletInvertedIndex tabletInvertedIndex;
|
||||
private TabletMeta tabletMeta;
|
||||
private Replica replica1;
|
||||
private Replica replica2;
|
||||
private Replica replica3;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
tabletInvertedIndex = new TabletInvertedIndex();
|
||||
|
||||
// Create test tablet meta
|
||||
tabletMeta = new TabletMeta(1L, 2L, 3L, 4L, TStorageMedium.HDD);
|
||||
|
||||
// Create test replicas
|
||||
replica1 = new Replica(100L, 1000L, 1L, 123, 0L, 0L,
|
||||
Replica.ReplicaState.NORMAL, -1L, 1L);
|
||||
replica2 = new Replica(101L, 1001L, 1L, 123, 0L, 0L,
|
||||
Replica.ReplicaState.NORMAL, -1L, 1L);
|
||||
replica3 = new Replica(102L, 1002L, 1L, 123, 0L, 0L,
|
||||
Replica.ReplicaState.NORMAL, -1L, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetReplicas_WithReplicas() {
|
||||
// Given: Add tablet and replicas
|
||||
long tabletId = 1000L;
|
||||
tabletInvertedIndex.addTablet(tabletId, tabletMeta);
|
||||
tabletInvertedIndex.addReplica(tabletId, replica1);
|
||||
tabletInvertedIndex.addReplica(tabletId, replica2);
|
||||
tabletInvertedIndex.addReplica(tabletId, replica3);
|
||||
|
||||
// When: Get replicas for the tablet
|
||||
Map<Long, Replica> replicas = tabletInvertedIndex.getReplicas(tabletId);
|
||||
|
||||
// Then: Verify the result
|
||||
Assertions.assertNotNull(replicas, "Replicas map should not be null");
|
||||
Assertions.assertEquals(3, replicas.size(), "Should have 3 replicas");
|
||||
|
||||
// Verify each replica is present
|
||||
Assertions.assertTrue(replicas.containsKey(1000L), "Should contain replica on backend 1000");
|
||||
Assertions.assertTrue(replicas.containsKey(1001L), "Should contain replica on backend 1001");
|
||||
Assertions.assertTrue(replicas.containsKey(1002L), "Should contain replica on backend 1002");
|
||||
|
||||
// Verify replica details
|
||||
Assertions.assertEquals(replica1, replicas.get(1000L), "Replica on backend 1000 should match");
|
||||
Assertions.assertEquals(replica2, replicas.get(1001L), "Replica on backend 1001 should match");
|
||||
Assertions.assertEquals(replica3, replicas.get(1002L), "Replica on backend 1002 should match");
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue