-
Notifications
You must be signed in to change notification settings - Fork 15.1k
KAFKA-10740; Replace OffsetsForLeaderEpochRequest.PartitionData with automated protocol #9689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,7 @@ import kafka.utils.CoreUtils.inLock | |
| import org.apache.kafka.common.protocol.Errors | ||
|
|
||
| import scala.collection.{Map, Set, mutable} | ||
| import scala.compat.java8.OptionConverters._ | ||
| import scala.jdk.CollectionConverters._ | ||
| import java.util.concurrent.TimeUnit | ||
| import java.util.concurrent.atomic.AtomicLong | ||
|
|
@@ -41,6 +42,7 @@ import kafka.server.AbstractFetcherThread.ReplicaFetch | |
| import kafka.server.AbstractFetcherThread.ResultWithPartitions | ||
| import org.apache.kafka.common.{InvalidRecordException, TopicPartition} | ||
| import org.apache.kafka.common.internals.PartitionStates | ||
| import org.apache.kafka.common.message.OffsetForLeaderEpochRequestData | ||
| import org.apache.kafka.common.message.OffsetForLeaderEpochResponseData.EpochEndOffset | ||
| import org.apache.kafka.common.record.{FileRecords, MemoryRecords, Records} | ||
| import org.apache.kafka.common.requests._ | ||
|
|
@@ -61,7 +63,7 @@ abstract class AbstractFetcherThread(name: String, | |
| extends ShutdownableThread(name, isInterruptible) { | ||
|
|
||
| type FetchData = FetchResponse.PartitionData[Records] | ||
| type EpochData = OffsetsForLeaderEpochRequest.PartitionData | ||
| type EpochData = OffsetForLeaderEpochRequestData.OffsetForLeaderPartition | ||
|
|
||
| private val partitionStates = new PartitionStates[PartitionFetchState] | ||
| protected val partitionMapLock = new ReentrantLock | ||
|
|
@@ -160,7 +162,10 @@ abstract class AbstractFetcherThread(name: String, | |
| if (state.isTruncating) { | ||
| latestEpoch(tp) match { | ||
| case Some(epoch) if isOffsetForLeaderEpochSupported => | ||
| partitionsWithEpochs += tp -> new EpochData(Optional.of(state.currentLeaderEpoch), epoch) | ||
| partitionsWithEpochs += tp -> new EpochData() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should it call
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! Let me fix this.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have updated tests to catch this. |
||
| .setPartition(tp.partition) | ||
| .setCurrentLeaderEpoch(state.currentLeaderEpoch) | ||
| .setLeaderEpoch(epoch) | ||
| case _ => | ||
| partitionsWithoutEpochs += tp | ||
| } | ||
|
|
@@ -218,7 +223,7 @@ abstract class AbstractFetcherThread(name: String, | |
| throw new IllegalStateException( | ||
| s"Leader replied with partition $tp not requested in OffsetsForLeaderEpoch request") | ||
| }) | ||
| val leaderEpochInRequest = partitionEpochRequest.currentLeaderEpoch.get | ||
| val leaderEpochInRequest = partitionEpochRequest.currentLeaderEpoch | ||
| curPartitionState != null && leaderEpochInRequest == curPartitionState.currentLeaderEpoch | ||
| } | ||
|
|
||
|
|
@@ -268,11 +273,10 @@ abstract class AbstractFetcherThread(name: String, | |
| fetchOffsets.put(tp, offsetTruncationState) | ||
|
|
||
| case Errors.FENCED_LEADER_EPOCH => | ||
| if (onPartitionFenced(tp, latestEpochsForPartitions.get(tp).flatMap { | ||
| p => | ||
| if (p.currentLeaderEpoch.isPresent) Some(p.currentLeaderEpoch.get()) | ||
| else None | ||
| })) partitionsWithError += tp | ||
| val currentLeaderEpoch = latestEpochsForPartitions.get(tp) | ||
| .map(epochEndOffset => Int.box(epochEndOffset.currentLeaderEpoch)).asJava | ||
| if (onPartitionFenced(tp, currentLeaderEpoch)) | ||
| partitionsWithError += tp | ||
|
|
||
| case error => | ||
| info(s"Retrying leaderEpoch request for partition $tp as the leader reported an error: $error") | ||
|
|
@@ -287,10 +291,10 @@ abstract class AbstractFetcherThread(name: String, | |
| * remove the partition if the partition state is NOT updated. Otherwise, keep the partition active. | ||
| * @return true if the epoch in this thread is updated. otherwise, false | ||
| */ | ||
| private def onPartitionFenced(tp: TopicPartition, requestEpoch: Option[Int]): Boolean = inLock(partitionMapLock) { | ||
| private def onPartitionFenced(tp: TopicPartition, requestEpoch: Optional[Integer]): Boolean = inLock(partitionMapLock) { | ||
| Option(partitionStates.stateValue(tp)).exists { currentFetchState => | ||
| val currentLeaderEpoch = currentFetchState.currentLeaderEpoch | ||
| if (requestEpoch.contains(currentLeaderEpoch)) { | ||
| if (requestEpoch.isPresent && requestEpoch.get == currentLeaderEpoch) { | ||
| info(s"Partition $tp has an older epoch ($currentLeaderEpoch) than the current leader. Will await " + | ||
| s"the new LeaderAndIsr state before resuming fetching.") | ||
| markPartitionFailed(tp) | ||
|
|
@@ -336,7 +340,6 @@ abstract class AbstractFetcherThread(name: String, | |
| // the current offset is the same as the offset requested. | ||
| val fetchPartitionData = sessionPartitions.get(topicPartition) | ||
| if (fetchPartitionData != null && fetchPartitionData.fetchOffset == currentFetchState.fetchOffset && currentFetchState.isReadyForFetch) { | ||
| val requestEpoch = if (fetchPartitionData.currentLeaderEpoch.isPresent) Some(fetchPartitionData.currentLeaderEpoch.get().toInt) else None | ||
| partitionData.error match { | ||
| case Errors.NONE => | ||
| try { | ||
|
|
@@ -390,7 +393,7 @@ abstract class AbstractFetcherThread(name: String, | |
| markPartitionFailed(topicPartition) | ||
| } | ||
| case Errors.OFFSET_OUT_OF_RANGE => | ||
| if (handleOutOfRangeError(topicPartition, currentFetchState, requestEpoch)) | ||
| if (handleOutOfRangeError(topicPartition, currentFetchState, fetchPartitionData.currentLeaderEpoch)) | ||
| partitionsWithError += topicPartition | ||
|
|
||
| case Errors.UNKNOWN_LEADER_EPOCH => | ||
|
|
@@ -399,7 +402,8 @@ abstract class AbstractFetcherThread(name: String, | |
| partitionsWithError += topicPartition | ||
|
|
||
| case Errors.FENCED_LEADER_EPOCH => | ||
| if (onPartitionFenced(topicPartition, requestEpoch)) partitionsWithError += topicPartition | ||
| if (onPartitionFenced(topicPartition, fetchPartitionData.currentLeaderEpoch)) | ||
| partitionsWithError += topicPartition | ||
|
|
||
| case Errors.NOT_LEADER_OR_FOLLOWER => | ||
| debug(s"Remote broker is not the leader for partition $topicPartition, which could indicate " + | ||
|
|
@@ -600,7 +604,7 @@ abstract class AbstractFetcherThread(name: String, | |
| */ | ||
| private def handleOutOfRangeError(topicPartition: TopicPartition, | ||
| fetchState: PartitionFetchState, | ||
| requestEpoch: Option[Int]): Boolean = { | ||
| requestEpoch: Optional[Integer]): Boolean = { | ||
| try { | ||
| val newFetchState = fetchOffsetAndTruncate(topicPartition, fetchState.currentLeaderEpoch) | ||
| partitionStates.updateAndMoveToEnd(topicPartition, newFetchState) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some duplicate code. Maybe we can unify them in this PR (or we can address it in follow-up) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chia7712 Thanks for pointing this out. I think that we should tackle this in follow-up PRs as this is not strictly related to this change. Ok for you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is ok to me :)