use of org.apache.kafka.clients.admin.ElectLeadersResult in project cruise-control by linkedin.
the class ExecutorTest method testSubmitPreferredLeaderElection.
@Test
public void testSubmitPreferredLeaderElection() throws InterruptedException, ExecutionException {
Map<String, TopicDescription> topicDescriptions = createTopics(0);
AdminClient adminClient = KafkaCruiseControlUtils.createAdminClient(Collections.singletonMap(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, broker(0).plaintextAddr()));
// Case 1: Handle the successful case.
ReplicaPlacementInfo oldLeader = new ReplicaPlacementInfo(topicDescriptions.get(TP1.topic()).partitions().get(PARTITION).leader().id());
List<ReplicaPlacementInfo> replicas = new ArrayList<>();
for (Node node : topicDescriptions.get(TP1.topic()).partitions().get(PARTITION).replicas()) {
replicas.add(new ReplicaPlacementInfo(node.id()));
}
List<ReplicaPlacementInfo> newReplicas = new ArrayList<>(replicas.size());
for (int i = replicas.size() - 1; i >= 0; i--) {
newReplicas.add(new ReplicaPlacementInfo(replicas.get(i).brokerId()));
}
// Reorder replicas before leadership election to change the preferred replica.
ExecutionTask swapTask = new ExecutionTask(0, new ExecutionProposal(TP1, 0, oldLeader, replicas, newReplicas), ExecutionTask.TaskType.INTER_BROKER_REPLICA_ACTION, EXECUTION_ALERTING_THRESHOLD_MS);
swapTask.inProgress(MOCK_CURRENT_TIME);
AlterPartitionReassignmentsResult swapResult = ExecutionUtils.submitReplicaReassignmentTasks(adminClient, Collections.singletonList(swapTask));
assertEquals(1, swapResult.values().size());
// Can retrieve the future if it is successful.
swapResult.values().get(TP1).get();
// Leadership task to transfer the leadership to the preferred replica.
ExecutionTask task = new ExecutionTask(0, new ExecutionProposal(TP1, 0, oldLeader, newReplicas, newReplicas), ExecutionTask.TaskType.LEADER_ACTION, EXECUTION_ALERTING_THRESHOLD_MS);
task.inProgress(MOCK_CURRENT_TIME);
ElectLeadersResult result = ExecutionUtils.submitPreferredLeaderElection(adminClient, Collections.singletonList(task));
assertTrue(result.partitions().get().get(TP1).isEmpty());
// Case 2: Handle "election not needed" -- i.e. the leader is already the preferred replica for TP0.
oldLeader = new ReplicaPlacementInfo(topicDescriptions.get(TP0.topic()).partitions().get(PARTITION).leader().id());
replicas.clear();
for (Node node : topicDescriptions.get(TP0.topic()).partitions().get(PARTITION).replicas()) {
replicas.add(new ReplicaPlacementInfo(node.id()));
}
task = new ExecutionTask(0, new ExecutionProposal(TP0, 0, oldLeader, replicas, replicas), ExecutionTask.TaskType.LEADER_ACTION, EXECUTION_ALERTING_THRESHOLD_MS);
task.inProgress(MOCK_CURRENT_TIME);
result = ExecutionUtils.submitPreferredLeaderElection(adminClient, Collections.singletonList(task));
assertTrue(result.partitions().get().get(TP0).isPresent());
assertEquals(Errors.ELECTION_NOT_NEEDED.exception().getClass(), result.partitions().get().get(TP0).get().getClass());
// Case 3: Handle "unknown topic or partition" -- i.e. the partition TP2 does not exist, maybe it existed at some point and then deleted
task = new ExecutionTask(0, new ExecutionProposal(TP2, 0, oldLeader, replicas, replicas), ExecutionTask.TaskType.LEADER_ACTION, EXECUTION_ALERTING_THRESHOLD_MS);
task.inProgress(MOCK_CURRENT_TIME);
result = ExecutionUtils.submitPreferredLeaderElection(adminClient, Collections.singletonList(task));
assertTrue(result.partitions().get().get(TP2).isPresent());
assertEquals(Errors.UNKNOWN_TOPIC_OR_PARTITION.exception().getClass(), result.partitions().get().get(TP2).get().getClass());
// Case 4: Handle the scenario, where we tried to elect the preferred leader but it is offline.
_brokers.get(0).shutdown();
task = new ExecutionTask(0, new ExecutionProposal(TP0, 0, oldLeader, replicas, replicas), ExecutionTask.TaskType.LEADER_ACTION, EXECUTION_ALERTING_THRESHOLD_MS);
task.inProgress(MOCK_CURRENT_TIME);
result = ExecutionUtils.submitPreferredLeaderElection(adminClient, Collections.singletonList(task));
assertTrue(result.partitions().get().get(TP0).isPresent());
assertEquals(Errors.PREFERRED_LEADER_NOT_AVAILABLE.exception().getClass(), result.partitions().get().get(TP0).get().getClass());
}
use of org.apache.kafka.clients.admin.ElectLeadersResult in project cruise-control by linkedin.
the class ExecutionUtilsTest method testProcessElectLeadersResult.
@Test
public void testProcessElectLeadersResult() throws Exception {
// Case 1: Handle null result input. Expect no side effect.
ExecutionUtils.processElectLeadersResult(null, Collections.emptySet());
KafkaFutureImpl<Map<TopicPartition, Optional<Throwable>>> partitions = EasyMock.mock(KafkaFutureImpl.class);
Constructor<ElectLeadersResult> constructor = ElectLeadersResult.class.getDeclaredConstructor(KafkaFutureImpl.class);
constructor.setAccessible(true);
ElectLeadersResult result;
// Case 5: Handle one partition successful, the other has NotControllerException
for (Map<TopicPartition, Optional<Throwable>> entry : Set.of(SUCCESSFUL_PARTITIONS, ONE_WITH_ENN, ONE_WITH_PLNA, ONE_WITH_NC)) {
result = constructor.newInstance(partitions);
EasyMock.expect(partitions.get()).andReturn(entry).once();
EasyMock.replay(partitions);
ExecutionUtils.processElectLeadersResult(result, Collections.emptySet());
EasyMock.verify(partitions);
EasyMock.reset(partitions);
}
// Case 7: Handle one partition successful, the other has InvalidTopicException
for (Map<TopicPartition, Optional<Throwable>> entry : Set.of(ONE_WITH_UTOP, ONE_WITH_IT)) {
result = constructor.newInstance(partitions);
EasyMock.expect(partitions.get()).andReturn(entry).once();
EasyMock.replay(partitions);
Set<TopicPartition> deletedTopicPartitions = new HashSet<>();
ExecutionUtils.processElectLeadersResult(result, deletedTopicPartitions);
Assert.assertEquals(1, deletedTopicPartitions.size());
Assert.assertEquals(P1, deletedTopicPartitions.iterator().next());
EasyMock.verify(partitions);
EasyMock.reset(partitions);
}
// Case 10: Handle unexpected execution exception (i.e. ControllerMovedException). Expect no side effect.
for (Throwable entry : Set.of(new org.apache.kafka.common.errors.TimeoutException(), new org.apache.kafka.common.errors.ClusterAuthorizationException(""), new org.apache.kafka.common.errors.ControllerMovedException(""))) {
result = constructor.newInstance(partitions);
EasyMock.expect(partitions.get()).andThrow(new ExecutionException(entry)).once();
EasyMock.replay(partitions);
ElectLeadersResult exceptionResult = result;
Exception thrownException = assertThrows(IllegalStateException.class, () -> ExecutionUtils.processElectLeadersResult(exceptionResult, Collections.emptySet()));
Assert.assertEquals(entry, thrownException.getCause());
EasyMock.verify(partitions);
EasyMock.reset(partitions);
}
// Case 11: Handle future wait interrupted exception
result = constructor.newInstance(partitions);
EasyMock.expect(partitions.get()).andThrow(new InterruptedException()).once();
EasyMock.replay(partitions);
ExecutionUtils.processElectLeadersResult(result, Collections.emptySet());
EasyMock.verify(partitions);
EasyMock.reset(partitions);
}
Aggregations