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);
}
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()));
}
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);
}
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());
}
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);
}
Aggregations