Search in sources :

Example 1 with ElectLeadersResult

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());
}
Also used : ElectLeadersResult(org.apache.kafka.clients.admin.ElectLeadersResult) AlterPartitionReassignmentsResult(org.apache.kafka.clients.admin.AlterPartitionReassignmentsResult) Node(org.apache.kafka.common.Node) ArrayList(java.util.ArrayList) TopicDescription(org.apache.kafka.clients.admin.TopicDescription) ReplicaPlacementInfo(com.linkedin.kafka.cruisecontrol.model.ReplicaPlacementInfo) AdminClient(org.apache.kafka.clients.admin.AdminClient) Test(org.junit.Test)

Example 2 with ElectLeadersResult

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);
}
Also used : ElectLeadersResult(org.apache.kafka.clients.admin.ElectLeadersResult) Optional(java.util.Optional) ElectionNotNeededException(org.apache.kafka.common.errors.ElectionNotNeededException) NotControllerException(org.apache.kafka.common.errors.NotControllerException) InvalidTopicException(org.apache.kafka.common.errors.InvalidTopicException) ExecutionException(java.util.concurrent.ExecutionException) UnknownTopicOrPartitionException(org.apache.kafka.common.errors.UnknownTopicOrPartitionException) PreferredLeaderNotAvailableException(org.apache.kafka.common.errors.PreferredLeaderNotAvailableException) TopicPartition(org.apache.kafka.common.TopicPartition) ExecutionException(java.util.concurrent.ExecutionException) HashMap(java.util.HashMap) Map(java.util.Map) HashSet(java.util.HashSet) Test(org.junit.Test)

Aggregations

ElectLeadersResult (org.apache.kafka.clients.admin.ElectLeadersResult)2 Test (org.junit.Test)2 ReplicaPlacementInfo (com.linkedin.kafka.cruisecontrol.model.ReplicaPlacementInfo)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 Optional (java.util.Optional)1 ExecutionException (java.util.concurrent.ExecutionException)1 AdminClient (org.apache.kafka.clients.admin.AdminClient)1 AlterPartitionReassignmentsResult (org.apache.kafka.clients.admin.AlterPartitionReassignmentsResult)1 TopicDescription (org.apache.kafka.clients.admin.TopicDescription)1 Node (org.apache.kafka.common.Node)1 TopicPartition (org.apache.kafka.common.TopicPartition)1 ElectionNotNeededException (org.apache.kafka.common.errors.ElectionNotNeededException)1 InvalidTopicException (org.apache.kafka.common.errors.InvalidTopicException)1 NotControllerException (org.apache.kafka.common.errors.NotControllerException)1 PreferredLeaderNotAvailableException (org.apache.kafka.common.errors.PreferredLeaderNotAvailableException)1 UnknownTopicOrPartitionException (org.apache.kafka.common.errors.UnknownTopicOrPartitionException)1