Skip to content
2 changes: 2 additions & 0 deletions core/src/main/scala/kafka/api/ApiVersion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ object ApiVersion {

val latestVersion: ApiVersion = allVersions.last

def isTruncationOnFetchSupported(version: ApiVersion): Boolean = version >= KAFKA_2_7_IV1

/**
* Return the minimum `ApiVersion` that supports `RecordVersion`.
*/
Expand Down
16 changes: 12 additions & 4 deletions core/src/main/scala/kafka/log/Log.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import scala.collection.{Seq, Set, mutable}

object LogAppendInfo {
val UnknownLogAppendInfo = LogAppendInfo(None, -1, RecordBatch.NO_TIMESTAMP, -1L, RecordBatch.NO_TIMESTAMP, -1L,
val UnknownLogAppendInfo = LogAppendInfo(None, -1, None, RecordBatch.NO_TIMESTAMP, -1L, RecordBatch.NO_TIMESTAMP, -1L,
RecordConversionStats.EMPTY, NoCompressionCodec, NoCompressionCodec, -1, -1, offsetsMonotonic = false, -1L)

def unknownLogAppendInfoWithLogStartOffset(logStartOffset: Long): LogAppendInfo =
LogAppendInfo(None, -1, RecordBatch.NO_TIMESTAMP, -1L, RecordBatch.NO_TIMESTAMP, logStartOffset,
LogAppendInfo(None, -1, None, RecordBatch.NO_TIMESTAMP, -1L, RecordBatch.NO_TIMESTAMP, logStartOffset,
RecordConversionStats.EMPTY, NoCompressionCodec, NoCompressionCodec, -1, -1,
offsetsMonotonic = false, -1L)

Expand All @@ -64,7 +64,7 @@ object LogAppendInfo {
* in unknownLogAppendInfoWithLogStartOffset, but with additiona fields recordErrors and errorMessage
*/
def unknownLogAppendInfoWithAdditionalInfo(logStartOffset: Long, recordErrors: Seq[RecordError], errorMessage: String): LogAppendInfo =
LogAppendInfo(None, -1, RecordBatch.NO_TIMESTAMP, -1L, RecordBatch.NO_TIMESTAMP, logStartOffset,
LogAppendInfo(None, -1, None, RecordBatch.NO_TIMESTAMP, -1L, RecordBatch.NO_TIMESTAMP, logStartOffset,
RecordConversionStats.EMPTY, NoCompressionCodec, NoCompressionCodec, -1, -1,
offsetsMonotonic = false, -1L, recordErrors, errorMessage)
}
Expand All @@ -82,6 +82,7 @@ object LeaderHwChange {
* @param firstOffset The first offset in the message set unless the message format is less than V2 and we are appending
* to the follower.
* @param lastOffset The last offset in the message set
* @param lastLeaderEpoch The partition leader epoch corresponding to the last offset, if available.
* @param maxTimestamp The maximum timestamp of the message set.
* @param offsetOfMaxTimestamp The offset of the message with the maximum timestamp.
* @param logAppendTime The log append time (if used) of the message set, otherwise Message.NoTimestamp
Expand All @@ -99,6 +100,7 @@ object LeaderHwChange {
*/
case class LogAppendInfo(var firstOffset: Option[Long],
var lastOffset: Long,
var lastLeaderEpoch: Option[Int],
var maxTimestamp: Long,
var offsetOfMaxTimestamp: Long,
var logAppendTime: Long,
Expand Down Expand Up @@ -1383,6 +1385,7 @@ class Log(@volatile private var _dir: File,
var validBytesCount = 0
var firstOffset: Option[Long] = None
var lastOffset = -1L
var lastLeaderEpoch = RecordBatch.NO_PARTITION_LEADER_EPOCH
var sourceCodec: CompressionCodec = NoCompressionCodec
var monotonic = true
var maxTimestamp = RecordBatch.NO_TIMESTAMP
Expand Down Expand Up @@ -1415,6 +1418,7 @@ class Log(@volatile private var _dir: File,

// update the last offset seen
lastOffset = batch.lastOffset
lastLeaderEpoch = batch.partitionLeaderEpoch

// Check if the message sizes are valid.
val batchSize = batch.sizeInBytes
Expand Down Expand Up @@ -1446,7 +1450,11 @@ class Log(@volatile private var _dir: File,

// Apply broker-side compression if any
val targetCodec = BrokerCompressionCodec.getTargetCompressionCodec(config.compressionType, sourceCodec)
LogAppendInfo(firstOffset, lastOffset, maxTimestamp, offsetOfMaxTimestamp, RecordBatch.NO_TIMESTAMP, logStartOffset,
val lastLeaderEpochOpt: Option[Int] = if (lastLeaderEpoch != RecordBatch.NO_PARTITION_LEADER_EPOCH)
Some(lastLeaderEpoch)
else
None
LogAppendInfo(firstOffset, lastOffset, lastLeaderEpochOpt, maxTimestamp, offsetOfMaxTimestamp, RecordBatch.NO_TIMESTAMP, logStartOffset,
RecordConversionStats.EMPTY, sourceCodec, targetCodec, shallowMessageCount, validBytesCount, monotonic, lastOffsetOfFirstBatch)
}

Expand Down
32 changes: 17 additions & 15 deletions core/src/main/scala/kafka/server/AbstractFetcherManager.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@

package kafka.server

import kafka.utils.Implicits._
import kafka.utils.Logging
import kafka.cluster.BrokerEndPoint
import kafka.metrics.KafkaMetricsGroup
import kafka.utils.Implicits._
import kafka.utils.Logging
import org.apache.kafka.common.TopicPartition
import org.apache.kafka.common.utils.Utils

import scala.collection.mutable
import scala.collection.{Map, Set}
import scala.collection.{Map, Set, mutable}

abstract class AbstractFetcherManager[T <: AbstractFetcherThread](val name: String, clientId: String, numFetchers: Int)
extends Logging with KafkaMetricsGroup {
Expand Down Expand Up @@ -64,11 +63,16 @@ abstract class AbstractFetcherManager[T <: AbstractFetcherThread](val name: Stri
def resizeThreadPool(newSize: Int): Unit = {
def migratePartitions(newSize: Int): Unit = {
fetcherThreadMap.forKeyValue { (id, thread) =>
val removedPartitions = thread.partitionsAndOffsets
removeFetcherForPartitions(removedPartitions.keySet)
val partitionStates = removeFetcherForPartitions(thread.partitions)
if (id.fetcherId >= newSize)
thread.shutdown()
addFetcherForPartitions(removedPartitions)
val fetchStates = partitionStates.map { case (topicPartition, currentFetchState) =>
val initialFetchState = InitialFetchState(thread.sourceBroker,
currentLeaderEpoch = currentFetchState.currentLeaderEpoch,
initOffset = currentFetchState.fetchOffset)
topicPartition -> initialFetchState
}
addFetcherForPartitions(fetchStates)
}
}
lock synchronized {
Expand Down Expand Up @@ -142,29 +146,27 @@ abstract class AbstractFetcherManager[T <: AbstractFetcherThread](val name: Stri
addAndStartFetcherThread(brokerAndFetcherId, brokerIdAndFetcherId)
}

val initialOffsetAndEpochs = initialFetchOffsets.map { case (tp, brokerAndInitOffset) =>
tp -> OffsetAndEpoch(brokerAndInitOffset.initOffset, brokerAndInitOffset.currentLeaderEpoch)
}

addPartitionsToFetcherThread(fetcherThread, initialOffsetAndEpochs)
addPartitionsToFetcherThread(fetcherThread, initialFetchOffsets)
}
}
}

protected def addPartitionsToFetcherThread(fetcherThread: T,
initialOffsetAndEpochs: collection.Map[TopicPartition, OffsetAndEpoch]): Unit = {
initialOffsetAndEpochs: collection.Map[TopicPartition, InitialFetchState]): Unit = {
fetcherThread.addPartitions(initialOffsetAndEpochs)
info(s"Added fetcher to broker ${fetcherThread.sourceBroker.id} for partitions $initialOffsetAndEpochs")
}

def removeFetcherForPartitions(partitions: Set[TopicPartition]): Unit = {
def removeFetcherForPartitions(partitions: Set[TopicPartition]): Map[TopicPartition, PartitionFetchState] = {
val fetchStates = mutable.Map.empty[TopicPartition, PartitionFetchState]
lock synchronized {
for (fetcher <- fetcherThreadMap.values)
fetcher.removePartitions(partitions)
fetchStates ++= fetcher.removePartitions(partitions)
failedPartitions.removeAll(partitions)
}
if (partitions.nonEmpty)
info(s"Removed fetcher for partitions $partitions")
fetchStates
}

def shutdownIdleFetcherThreads(): Unit = {
Expand Down
Loading