- 
                Notifications
    You must be signed in to change notification settings 
- Fork 14.8k
KAFKA-19340: Move DelayedRemoteFetch to the storage module #19876
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
7ab02f4
              052f60a
              37aa96f
              e5d1abb
              46dd310
              1fac1e4
              52156c0
              20ec186
              de54d11
              67c3c18
              6aa0df8
              b403181
              544e04f
              941b2d3
              d222a5a
              ea5539d
              24df252
              11f7708
              57c4e9b
              fd4e3f9
              cdbdc00
              07db3cc
              5184d31
              ef1ce23
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -56,16 +56,16 @@ import org.apache.kafka.server.config.ReplicationConfigs | |
| import org.apache.kafka.server.log.remote.storage.RemoteLogManager | ||
| import org.apache.kafka.server.metrics.KafkaMetricsGroup | ||
| import org.apache.kafka.server.network.BrokerEndPoint | ||
| import org.apache.kafka.server.purgatory.{DelayedDeleteRecords, DelayedOperationPurgatory, DelayedRemoteListOffsets, DeleteRecordsPartitionStatus, ListOffsetsPartitionStatus, TopicPartitionOperationKey} | ||
| import org.apache.kafka.server.purgatory.{DelayedDeleteRecords, DelayedOperationPurgatory, DelayedRemoteFetch, DelayedRemoteListOffsets, DeleteRecordsPartitionStatus, ListOffsetsPartitionStatus, TopicPartitionOperationKey} | ||
| import org.apache.kafka.server.share.fetch.{DelayedShareFetchKey, DelayedShareFetchPartitionKey} | ||
| import org.apache.kafka.server.storage.log.{FetchParams, FetchPartitionData} | ||
| import org.apache.kafka.server.transaction.AddPartitionsToTxnManager | ||
| import org.apache.kafka.server.transaction.AddPartitionsToTxnManager.TransactionSupportedOperation | ||
| import org.apache.kafka.server.util.timer.{SystemTimer, TimerTask} | ||
| import org.apache.kafka.server.util.{Scheduler, ShutdownableThread} | ||
| import org.apache.kafka.server.{ActionQueue, DelayedActionQueue, LogReadResult, common} | ||
| import org.apache.kafka.server.{ActionQueue, DelayedActionQueue, common} | ||
| import org.apache.kafka.storage.internals.checkpoint.{LazyOffsetCheckpoints, OffsetCheckpointFile, OffsetCheckpoints} | ||
| import org.apache.kafka.storage.internals.log.{AppendOrigin, FetchDataInfo, LeaderHwChange, LogAppendInfo, LogConfig, LogDirFailureChannel, LogOffsetMetadata, LogReadInfo, OffsetResultHolder, RecordValidationException, RemoteLogReadResult, RemoteStorageFetchInfo, UnifiedLog, VerificationGuard} | ||
| import org.apache.kafka.storage.internals.log.{AppendOrigin, FetchDataInfo, FetchPartitionStatus, LeaderHwChange, LogAppendInfo, LogConfig, LogDirFailureChannel, LogOffsetMetadata, LogReadInfo, LogReadResult, OffsetResultHolder, RecordValidationException, RemoteLogReadResult, RemoteStorageFetchInfo, UnifiedLog, VerificationGuard} | ||
| import org.apache.kafka.storage.log.metrics.BrokerTopicStats | ||
|  | ||
| import java.io.File | ||
|  | @@ -188,19 +188,7 @@ object ReplicaManager { | |
| -1L, | ||
| -1L, | ||
| OptionalLong.empty(), | ||
| Optional.of(e)) | ||
| } | ||
|  | ||
| def createLogReadResult(e: Throwable): LogReadResult = { | ||
| new LogReadResult(new FetchDataInfo(LogOffsetMetadata.UNKNOWN_OFFSET_METADATA, MemoryRecords.EMPTY), | ||
| Optional.empty(), | ||
| UnifiedLog.UNKNOWN_OFFSET, | ||
| UnifiedLog.UNKNOWN_OFFSET, | ||
| UnifiedLog.UNKNOWN_OFFSET, | ||
| UnifiedLog.UNKNOWN_OFFSET, | ||
| -1L, | ||
| OptionalLong.empty(), | ||
| Optional.of(e)) | ||
| Errors.forException(e)); | ||
| } | ||
|  | ||
| private[server] def isListOffsetsTimestampUnsupported(timestamp: JLong, version: Short): Boolean = { | ||
|  | @@ -1639,7 +1627,7 @@ class ReplicaManager(val config: KafkaConfig, | |
| private def processRemoteFetches(remoteFetchInfos: util.LinkedHashMap[TopicIdPartition, RemoteStorageFetchInfo], | ||
| params: FetchParams, | ||
| responseCallback: Seq[(TopicIdPartition, FetchPartitionData)] => Unit, | ||
| logReadResults: Seq[(TopicIdPartition, LogReadResult)], | ||
| logReadResults: util.LinkedHashMap[TopicIdPartition, LogReadResult], | ||
| fetchPartitionStatus: Seq[(TopicIdPartition, FetchPartitionStatus)]): Unit = { | ||
| val remoteFetchTasks = new util.HashMap[TopicIdPartition, Future[Void]] | ||
| val remoteFetchResults = new util.HashMap[TopicIdPartition, CompletableFuture[RemoteLogReadResult]] | ||
|  | @@ -1651,8 +1639,15 @@ class ReplicaManager(val config: KafkaConfig, | |
| } | ||
|  | ||
| val remoteFetchMaxWaitMs = config.remoteLogManagerConfig.remoteFetchMaxWaitMs().toLong | ||
| val remoteFetch = new DelayedRemoteFetch(remoteFetchTasks, remoteFetchResults, remoteFetchInfos, remoteFetchMaxWaitMs, | ||
| fetchPartitionStatus, params, logReadResults, this, responseCallback) | ||
| val remoteFetch = new DelayedRemoteFetch(remoteFetchTasks, | ||
| remoteFetchResults, | ||
| remoteFetchInfos, | ||
| remoteFetchMaxWaitMs, | ||
| fetchPartitionStatus.toMap.asJava, | ||
| 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. We could initialize  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. Opened #20769 to address this comment. PTAL. 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. Didn't saw #20768 was also opened. We can merge either one. 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. Let's keep the FIFO policy and review #20768 together | ||
| params, | ||
| logReadResults, | ||
| tp => getPartitionOrException(tp), | ||
| response => responseCallback(response.asScala.toSeq)) | ||
|  | ||
| // create a list of (topic, partition) pairs to use as keys for this delayed fetch operation | ||
| val delayedFetchKeys = remoteFetchTasks.asScala.map { case (tp, _) => new TopicPartitionOperationKey(tp) }.toList | ||
|  | @@ -1681,7 +1676,7 @@ class ReplicaManager(val config: KafkaConfig, | |
|  | ||
| var hasDivergingEpoch = false | ||
| var hasPreferredReadReplica = false | ||
| val logReadResultMap = new mutable.HashMap[TopicIdPartition, LogReadResult] | ||
| val logReadResultMap = new util.LinkedHashMap[TopicIdPartition, LogReadResult] | ||
|  | ||
| logReadResults.foreach { case (topicIdPartition, logReadResult) => | ||
| brokerTopicStats.topicStats(topicIdPartition.topicPartition.topic).totalFetchRequestRate.mark() | ||
|  | @@ -1717,14 +1712,15 @@ class ReplicaManager(val config: KafkaConfig, | |
| // construct the fetch results from the read results | ||
| val fetchPartitionStatus = new mutable.ArrayBuffer[(TopicIdPartition, FetchPartitionStatus)] | ||
| fetchInfos.foreach { case (topicIdPartition, partitionData) => | ||
| logReadResultMap.get(topicIdPartition).foreach(logReadResult => { | ||
| val logReadResult = logReadResultMap.get(topicIdPartition) | ||
| if (logReadResult != null) { | ||
| val logOffsetMetadata = logReadResult.info.fetchOffsetMetadata | ||
| fetchPartitionStatus += (topicIdPartition -> FetchPartitionStatus(logOffsetMetadata, partitionData)) | ||
| }) | ||
| fetchPartitionStatus += (topicIdPartition -> new FetchPartitionStatus(logOffsetMetadata, partitionData)) | ||
| } | ||
| } | ||
|  | ||
| if (!remoteFetchInfos.isEmpty) { | ||
| processRemoteFetches(remoteFetchInfos, params, responseCallback, logReadResults, fetchPartitionStatus.toSeq) | ||
| processRemoteFetches(remoteFetchInfos, params, responseCallback, logReadResultMap, fetchPartitionStatus.toSeq) | ||
| } else { | ||
| // If there is not enough data to respond and there is no remote data, we will let the fetch request | ||
| // wait for new data. | ||
|  | @@ -1812,7 +1808,7 @@ class ReplicaManager(val config: KafkaConfig, | |
| -1L, | ||
| OptionalLong.of(offsetSnapshot.lastStableOffset.messageOffset), | ||
| if (preferredReadReplica.isDefined) OptionalInt.of(preferredReadReplica.get) else OptionalInt.empty(), | ||
| Optional.empty()) | ||
| Errors.NONE) | ||
| } else { | ||
| log = partition.localLogWithEpochOrThrow(fetchInfo.currentLeaderEpoch, params.fetchOnlyLeader()) | ||
|  | ||
|  | @@ -1836,7 +1832,7 @@ class ReplicaManager(val config: KafkaConfig, | |
| fetchTimeMs, | ||
| OptionalLong.of(readInfo.lastStableOffset), | ||
| if (preferredReadReplica.isDefined) OptionalInt.of(preferredReadReplica.get) else OptionalInt.empty(), | ||
| Optional.empty() | ||
| Errors.NONE | ||
| ) | ||
| } | ||
| } catch { | ||
|  | @@ -1849,7 +1845,7 @@ class ReplicaManager(val config: KafkaConfig, | |
| _: ReplicaNotAvailableException | | ||
| _: KafkaStorageException | | ||
| _: InconsistentTopicIdException) => | ||
| createLogReadResult(e) | ||
| new LogReadResult(Errors.forException(e)) | ||
| case e: OffsetOutOfRangeException => | ||
| handleOffsetOutOfRangeError(tp, params, fetchInfo, adjustedMaxBytes, minOneMessage, log, fetchTimeMs, e) | ||
| case e: Throwable => | ||
|  | @@ -1868,7 +1864,7 @@ class ReplicaManager(val config: KafkaConfig, | |
| UnifiedLog.UNKNOWN_OFFSET, | ||
| -1L, | ||
| OptionalLong.empty(), | ||
| Optional.of(e) | ||
| Errors.forException(e) | ||
| ) | ||
| } | ||
| } | ||
|  | @@ -1949,10 +1945,10 @@ class ReplicaManager(val config: KafkaConfig, | |
| fetchInfo.logStartOffset, | ||
| fetchTimeMs, | ||
| OptionalLong.of(log.lastStableOffset), | ||
| Optional.empty[Throwable]()) | ||
| Errors.NONE) | ||
| } | ||
| } else { | ||
| createLogReadResult(exception) | ||
| new LogReadResult(Errors.forException(exception)) | ||
| } | ||
| } | ||
|  | ||
|  | ||
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.
Did we check that we didn't lose a useful error message by doing this?
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.
Thanks for pointing this out. I checked the usage of
LogReadResultand only found calls toLogReadResult.error(), so in the previous implementation, no code would utilize the error message from the Exception.If anything is inappropriate, please feel free to correct me.