[
https://issues.apache.org/jira/browse/KAFKA-21129?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
ChenXi updated KAFKA-21129:
---------------------------
Component/s: kraft
> KRaft controller failover caused by an off-by-one in non-atomic batch
> appending
> -------------------------------------------------------------------------------
>
> Key: KAFKA-21129
> URL: https://issues.apache.org/jira/browse/KAFKA-21129
> Project: Kafka
> Issue Type: Bug
> Components: controller, kraft
> Affects Versions: 4.3.1
> Reporter: ChenXi
> Priority: Major
>
> QuorumController.appendRecords
> (metadata/src/main/java/org/apache/kafka/controller/QuorumController.java:918-933)
> splits a non-atomic result into batches, but its
> boundary check is off by one. When records.size() is an exact multiple of
> maxRecordsPerBatch, the final iteration calls the appender with an empty
> subList(size, size).
> {code:java}
> int startIndex = 0, numBatches = 0;
> while (true) {
> numBatches++;
> int endIndex = startIndex + maxRecordsPerBatch;
> if (endIndex > records.size()) {
> long offset = appender.apply(records.subList(startIndex,
> records.size()));
> ...
> return offset;
> } else {
> appender.apply(records.subList(startIndex, endIndex));
> }
> startIndex += maxRecordsPerBatch;
> }{code}
> The production appender passes this empty list to RaftClient.prepareAppend,
> and KafkaRaftClient.append rejects empty batches with IllegalArgumentException
> ("Append failed because there are no records").
> Since appendRecords only converts ApiException, the exception escapes the
> event handler and is treated as an unexpected fault, so the active controller
> renounces leadership and the client receives UnknownServerException.
> The preceding full batches may already have been appended, so the change can
> take effect even though the client sees a failure.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)