Search in sources :

Example 6 with ApiMessageAndVersion

use of org.apache.kafka.server.common.ApiMessageAndVersion in project kafka by apache.

the class ReplicationControlManager method processBrokerHeartbeat.

ControllerResult<BrokerHeartbeatReply> processBrokerHeartbeat(BrokerHeartbeatRequestData request, long lastCommittedOffset) {
    int brokerId = request.brokerId();
    long brokerEpoch = request.brokerEpoch();
    clusterControl.checkBrokerEpoch(brokerId, brokerEpoch);
    BrokerHeartbeatManager heartbeatManager = clusterControl.heartbeatManager();
    BrokerControlStates states = heartbeatManager.calculateNextBrokerState(brokerId, request, lastCommittedOffset, () -> brokersToIsrs.hasLeaderships(brokerId));
    List<ApiMessageAndVersion> records = new ArrayList<>();
    if (states.current() != states.next()) {
        switch(states.next()) {
            case FENCED:
                handleBrokerFenced(brokerId, records);
                break;
            case UNFENCED:
                handleBrokerUnfenced(brokerId, brokerEpoch, records);
                break;
            case CONTROLLED_SHUTDOWN:
                generateLeaderAndIsrUpdates("enterControlledShutdown[" + brokerId + "]", brokerId, NO_LEADER, records, brokersToIsrs.partitionsWithBrokerInIsr(brokerId));
                break;
            case SHUTDOWN_NOW:
                handleBrokerFenced(brokerId, records);
                break;
        }
    }
    heartbeatManager.touch(brokerId, states.next().fenced(), request.currentMetadataOffset());
    boolean isCaughtUp = request.currentMetadataOffset() >= lastCommittedOffset;
    BrokerHeartbeatReply reply = new BrokerHeartbeatReply(isCaughtUp, states.next().fenced(), states.next().inControlledShutdown(), states.next().shouldShutDown());
    return ControllerResult.of(records, reply);
}
Also used : BrokerHeartbeatReply(org.apache.kafka.metadata.BrokerHeartbeatReply) ApiMessageAndVersion(org.apache.kafka.server.common.ApiMessageAndVersion) ArrayList(java.util.ArrayList)

Example 7 with ApiMessageAndVersion

use of org.apache.kafka.server.common.ApiMessageAndVersion in project kafka by apache.

the class ReplicationControlManager method handleBrokerFenced.

/**
 * Generate the appropriate records to handle a broker being fenced.
 *
 * First, we remove this broker from any non-singleton ISR. Then we generate a
 * FenceBrokerRecord.
 *
 * @param brokerId      The broker id.
 * @param records       The record list to append to.
 */
void handleBrokerFenced(int brokerId, List<ApiMessageAndVersion> records) {
    BrokerRegistration brokerRegistration = clusterControl.brokerRegistrations().get(brokerId);
    if (brokerRegistration == null) {
        throw new RuntimeException("Can't find broker registration for broker " + brokerId);
    }
    generateLeaderAndIsrUpdates("handleBrokerFenced", brokerId, NO_LEADER, records, brokersToIsrs.partitionsWithBrokerInIsr(brokerId));
    records.add(new ApiMessageAndVersion(new FenceBrokerRecord().setId(brokerId).setEpoch(brokerRegistration.epoch()), FENCE_BROKER_RECORD.highestSupportedVersion()));
}
Also used : ApiMessageAndVersion(org.apache.kafka.server.common.ApiMessageAndVersion) FenceBrokerRecord(org.apache.kafka.common.metadata.FenceBrokerRecord) BrokerRegistration(org.apache.kafka.metadata.BrokerRegistration)

Example 8 with ApiMessageAndVersion

use of org.apache.kafka.server.common.ApiMessageAndVersion in project kafka by apache.

the class ReplicationControlManager method createPartitions.

ControllerResult<List<CreatePartitionsTopicResult>> createPartitions(List<CreatePartitionsTopic> topics) {
    List<ApiMessageAndVersion> records = new ArrayList<>();
    List<CreatePartitionsTopicResult> results = new ArrayList<>();
    for (CreatePartitionsTopic topic : topics) {
        ApiError apiError = ApiError.NONE;
        try {
            createPartitions(topic, records);
        } catch (ApiException e) {
            apiError = ApiError.fromThrowable(e);
        } catch (Exception e) {
            log.error("Unexpected createPartitions error for {}", topic, e);
            apiError = ApiError.fromThrowable(e);
        }
        results.add(new CreatePartitionsTopicResult().setName(topic.name()).setErrorCode(apiError.error().code()).setErrorMessage(apiError.message()));
    }
    return new ControllerResult<>(records, results, true);
}
Also used : ApiMessageAndVersion(org.apache.kafka.server.common.ApiMessageAndVersion) ArrayList(java.util.ArrayList) ApiError(org.apache.kafka.common.requests.ApiError) CreatePartitionsTopicResult(org.apache.kafka.common.message.CreatePartitionsResponseData.CreatePartitionsTopicResult) CreatePartitionsTopic(org.apache.kafka.common.message.CreatePartitionsRequestData.CreatePartitionsTopic) InvalidReplicationFactorException(org.apache.kafka.common.errors.InvalidReplicationFactorException) NoReassignmentInProgressException(org.apache.kafka.common.errors.NoReassignmentInProgressException) InvalidTopicException(org.apache.kafka.common.errors.InvalidTopicException) InvalidPartitionsException(org.apache.kafka.common.errors.InvalidPartitionsException) UnknownTopicOrPartitionException(org.apache.kafka.common.errors.UnknownTopicOrPartitionException) UnknownTopicIdException(org.apache.kafka.common.errors.UnknownTopicIdException) BrokerIdNotRegisteredException(org.apache.kafka.common.errors.BrokerIdNotRegisteredException) UnknownServerException(org.apache.kafka.common.errors.UnknownServerException) PolicyViolationException(org.apache.kafka.common.errors.PolicyViolationException) NoSuchElementException(java.util.NoSuchElementException) InvalidReplicaAssignmentException(org.apache.kafka.common.errors.InvalidReplicaAssignmentException) InvalidRequestException(org.apache.kafka.common.errors.InvalidRequestException) ApiException(org.apache.kafka.common.errors.ApiException) ApiException(org.apache.kafka.common.errors.ApiException)

Example 9 with ApiMessageAndVersion

use of org.apache.kafka.server.common.ApiMessageAndVersion in project kafka by apache.

the class ReplicationControlManager method handleBrokerUnfenced.

/**
 * Generate the appropriate records to handle a broker becoming unfenced.
 *
 * First, we create an UnfenceBrokerRecord. Then, we check if if there are any
 * partitions that don't currently have a leader that should be led by the newly
 * unfenced broker.
 *
 * @param brokerId      The broker id.
 * @param brokerEpoch   The broker epoch.
 * @param records       The record list to append to.
 */
void handleBrokerUnfenced(int brokerId, long brokerEpoch, List<ApiMessageAndVersion> records) {
    records.add(new ApiMessageAndVersion(new UnfenceBrokerRecord().setId(brokerId).setEpoch(brokerEpoch), UNFENCE_BROKER_RECORD.highestSupportedVersion()));
    generateLeaderAndIsrUpdates("handleBrokerUnfenced", NO_LEADER, brokerId, records, brokersToIsrs.partitionsWithNoLeader());
}
Also used : ApiMessageAndVersion(org.apache.kafka.server.common.ApiMessageAndVersion) UnfenceBrokerRecord(org.apache.kafka.common.metadata.UnfenceBrokerRecord)

Example 10 with ApiMessageAndVersion

use of org.apache.kafka.server.common.ApiMessageAndVersion in project kafka by apache.

the class ReplicationControlManager method alterIsr.

ControllerResult<AlterIsrResponseData> alterIsr(AlterIsrRequestData request) {
    clusterControl.checkBrokerEpoch(request.brokerId(), request.brokerEpoch());
    AlterIsrResponseData response = new AlterIsrResponseData();
    List<ApiMessageAndVersion> records = new ArrayList<>();
    for (AlterIsrRequestData.TopicData topicData : request.topics()) {
        AlterIsrResponseData.TopicData responseTopicData = new AlterIsrResponseData.TopicData().setName(topicData.name());
        response.topics().add(responseTopicData);
        Uuid topicId = topicsByName.get(topicData.name());
        if (topicId == null || !topics.containsKey(topicId)) {
            for (AlterIsrRequestData.PartitionData partitionData : topicData.partitions()) {
                responseTopicData.partitions().add(new AlterIsrResponseData.PartitionData().setPartitionIndex(partitionData.partitionIndex()).setErrorCode(UNKNOWN_TOPIC_OR_PARTITION.code()));
            }
            log.info("Rejecting alterIsr request for unknown topic ID {}.", topicId);
            continue;
        }
        TopicControlInfo topic = topics.get(topicId);
        for (AlterIsrRequestData.PartitionData partitionData : topicData.partitions()) {
            int partitionId = partitionData.partitionIndex();
            PartitionRegistration partition = topic.parts.get(partitionId);
            if (partition == null) {
                responseTopicData.partitions().add(new AlterIsrResponseData.PartitionData().setPartitionIndex(partitionId).setErrorCode(UNKNOWN_TOPIC_OR_PARTITION.code()));
                log.info("Rejecting alterIsr request for unknown partition {}-{}.", topic.name, partitionId);
                continue;
            }
            if (partitionData.leaderEpoch() != partition.leaderEpoch) {
                responseTopicData.partitions().add(new AlterIsrResponseData.PartitionData().setPartitionIndex(partitionId).setErrorCode(FENCED_LEADER_EPOCH.code()));
                log.debug("Rejecting alterIsr request from node {} for {}-{} because " + "the current leader epoch is {}, not {}.", request.brokerId(), topic.name, partitionId, partition.leaderEpoch, partitionData.leaderEpoch());
                continue;
            }
            if (request.brokerId() != partition.leader) {
                responseTopicData.partitions().add(new AlterIsrResponseData.PartitionData().setPartitionIndex(partitionId).setErrorCode(INVALID_REQUEST.code()));
                log.info("Rejecting alterIsr request from node {} for {}-{} because " + "the current leader is {}.", request.brokerId(), topic.name, partitionId, partition.leader);
                continue;
            }
            if (partitionData.currentIsrVersion() != partition.partitionEpoch) {
                responseTopicData.partitions().add(new AlterIsrResponseData.PartitionData().setPartitionIndex(partitionId).setErrorCode(INVALID_UPDATE_VERSION.code()));
                log.info("Rejecting alterIsr request from node {} for {}-{} because " + "the current partition epoch is {}, not {}.", request.brokerId(), topic.name, partitionId, partition.partitionEpoch, partitionData.currentIsrVersion());
                continue;
            }
            int[] newIsr = Replicas.toArray(partitionData.newIsr());
            if (!Replicas.validateIsr(partition.replicas, newIsr)) {
                responseTopicData.partitions().add(new AlterIsrResponseData.PartitionData().setPartitionIndex(partitionId).setErrorCode(INVALID_REQUEST.code()));
                log.error("Rejecting alterIsr request from node {} for {}-{} because " + "it specified an invalid ISR {}.", request.brokerId(), topic.name, partitionId, partitionData.newIsr());
                continue;
            }
            if (!Replicas.contains(newIsr, partition.leader)) {
                // An alterIsr request can't ask for the current leader to be removed.
                responseTopicData.partitions().add(new AlterIsrResponseData.PartitionData().setPartitionIndex(partitionId).setErrorCode(INVALID_REQUEST.code()));
                log.error("Rejecting alterIsr request from node {} for {}-{} because " + "it specified an invalid ISR {} that doesn't include itself.", request.brokerId(), topic.name, partitionId, partitionData.newIsr());
                continue;
            }
            // At this point, we have decided to perform the ISR change. We use
            // PartitionChangeBuilder to find out what its effect will be.
            PartitionChangeBuilder builder = new PartitionChangeBuilder(partition, topic.id, partitionId, r -> clusterControl.unfenced(r), () -> configurationControl.uncleanLeaderElectionEnabledForTopic(topicData.name()));
            builder.setTargetIsr(partitionData.newIsr());
            Optional<ApiMessageAndVersion> record = builder.build();
            Errors result = Errors.NONE;
            if (record.isPresent()) {
                records.add(record.get());
                PartitionChangeRecord change = (PartitionChangeRecord) record.get().message();
                partition = partition.merge(change);
                if (log.isDebugEnabled()) {
                    log.debug("Node {} has altered ISR for {}-{} to {}.", request.brokerId(), topic.name, partitionId, change.isr());
                }
                if (change.leader() != request.brokerId() && change.leader() != NO_LEADER_CHANGE) {
                    // Normally, an alterIsr request, which is made by the partition
                    // leader itself, is not allowed to modify the partition leader.
                    // However, if there is an ongoing partition reassignment and the
                    // ISR change completes it, then the leader may change as part of
                    // the changes made during reassignment cleanup.
                    // 
                    // In this case, we report back FENCED_LEADER_EPOCH to the leader
                    // which made the alterIsr request. This lets it know that it must
                    // fetch new metadata before trying again. This return code is
                    // unusual because we both return an error and generate a new
                    // metadata record. We usually only do one or the other.
                    log.info("AlterIsr request from node {} for {}-{} completed " + "the ongoing partition reassignment and triggered a " + "leadership change. Reutrning FENCED_LEADER_EPOCH.", request.brokerId(), topic.name, partitionId);
                    responseTopicData.partitions().add(new AlterIsrResponseData.PartitionData().setPartitionIndex(partitionId).setErrorCode(FENCED_LEADER_EPOCH.code()));
                    continue;
                } else if (change.removingReplicas() != null || change.addingReplicas() != null) {
                    log.info("AlterIsr request from node {} for {}-{} completed " + "the ongoing partition reassignment.", request.brokerId(), topic.name, partitionId);
                }
            }
            responseTopicData.partitions().add(new AlterIsrResponseData.PartitionData().setPartitionIndex(partitionId).setErrorCode(result.code()).setLeaderId(partition.leader).setLeaderEpoch(partition.leaderEpoch).setCurrentIsrVersion(partition.partitionEpoch).setIsr(Replicas.toList(partition.isr)));
        }
    }
    return ControllerResult.of(records, response);
}
Also used : PartitionRegistration(org.apache.kafka.metadata.PartitionRegistration) PartitionChangeRecord(org.apache.kafka.common.metadata.PartitionChangeRecord) ArrayList(java.util.ArrayList) AlterIsrRequestData(org.apache.kafka.common.message.AlterIsrRequestData) Errors(org.apache.kafka.common.protocol.Errors) Uuid(org.apache.kafka.common.Uuid) ApiMessageAndVersion(org.apache.kafka.server.common.ApiMessageAndVersion) AlterIsrResponseData(org.apache.kafka.common.message.AlterIsrResponseData)

Aggregations

ApiMessageAndVersion (org.apache.kafka.server.common.ApiMessageAndVersion)84 ArrayList (java.util.ArrayList)38 Test (org.junit.jupiter.api.Test)35 Uuid (org.apache.kafka.common.Uuid)23 ApiError (org.apache.kafka.common.requests.ApiError)20 LogContext (org.apache.kafka.common.utils.LogContext)17 HashMap (java.util.HashMap)16 SnapshotRegistry (org.apache.kafka.timeline.SnapshotRegistry)15 List (java.util.List)12 Map (java.util.Map)12 PartitionChangeRecord (org.apache.kafka.common.metadata.PartitionChangeRecord)12 PartitionRegistration (org.apache.kafka.metadata.PartitionRegistration)11 TopicRecord (org.apache.kafka.common.metadata.TopicRecord)8 UnknownTopicOrPartitionException (org.apache.kafka.common.errors.UnknownTopicOrPartitionException)7 AlterIsrRequestData (org.apache.kafka.common.message.AlterIsrRequestData)7 Collections (java.util.Collections)6 Iterator (java.util.Iterator)6 Entry (java.util.Map.Entry)6 NoSuchElementException (java.util.NoSuchElementException)6 Optional (java.util.Optional)6