Skip to content
5 changes: 3 additions & 2 deletions core/src/main/scala/kafka/log/Log.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1345,8 +1345,9 @@ class Log(@volatile private var _dir: File,
val latestTimestampSegment = segmentsCopy.maxBy(_.maxTimestampSoFar)
val latestEpochOpt = leaderEpochCache.flatMap(_.latestEpoch).map(_.asInstanceOf[Integer])
val epochOptional = Optional.ofNullable(latestEpochOpt.orNull)
Some(new TimestampAndOffset(latestTimestampSegment.maxTimestampSoFar,
latestTimestampSegment.offsetOfMaxTimestampSoFar,
val latestTimestampAndOffset = latestTimestampSegment.maxTimestampAndOffsetSoFar
Some(new TimestampAndOffset(latestTimestampAndOffset.timestamp,
latestTimestampAndOffset.offset,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this another instance of unnecessary copying? Are there others?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, this is a different type (TimestampAndOffset).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a check through and can't see any other copy instances

epochOptional))
} else {
// Cache to avoid race conditions. `toBuffer` is faster than most alternatives and provides
Expand Down
48 changes: 22 additions & 26 deletions core/src/main/scala/kafka/log/LogSegment.scala
Original file line number Diff line number Diff line change
Expand Up @@ -99,21 +99,21 @@ class LogSegment private[log] (val log: FileRecords,
// volatile for LogCleaner to see the update
@volatile private var rollingBasedTimestamp: Option[Long] = None

/* The maximum timestamp and offset we see so far */
@volatile private var _maxTimestampAndOffsetSoFar: TimestampOffset = TimestampOffset.Unknown
def maxTimestampAndOffsetSoFar: TimestampOffset = {
if (_maxTimestampAndOffsetSoFar == TimestampOffset.Unknown)
_maxTimestampAndOffsetSoFar = TimestampOffset(timeIndex.lastEntry.timestamp,timeIndex.lastEntry.offset)
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
_maxTimestampAndOffsetSoFar
}

/* The maximum timestamp we see so far */
@volatile private var _maxTimestampSoFar: Option[Long] = None
def maxTimestampSoFar_=(timestamp: Long): Unit = _maxTimestampSoFar = Some(timestamp)
def maxTimestampSoFar: Long = {
if (_maxTimestampSoFar.isEmpty)
_maxTimestampSoFar = Some(timeIndex.lastEntry.timestamp)
_maxTimestampSoFar.get
maxTimestampAndOffsetSoFar.timestamp
}

@volatile private var _offsetOfMaxTimestampSoFar: Option[Long] = None
def offsetOfMaxTimestampSoFar_=(offset: Long): Unit = _offsetOfMaxTimestampSoFar = Some(offset)
def offsetOfMaxTimestampSoFar: Long = {
if (_offsetOfMaxTimestampSoFar.isEmpty)
_offsetOfMaxTimestampSoFar = Some(timeIndex.lastEntry.offset)
_offsetOfMaxTimestampSoFar.get
maxTimestampAndOffsetSoFar.offset
}

/* Return the size in bytes of this log segment */
Expand Down Expand Up @@ -158,13 +158,12 @@ class LogSegment private[log] (val log: FileRecords,
trace(s"Appended $appendedBytes to ${log.file} at end offset $largestOffset")
// Update the in memory max timestamp and corresponding offset.
if (largestTimestamp > maxTimestampSoFar) {
maxTimestampSoFar = largestTimestamp
offsetOfMaxTimestampSoFar = shallowOffsetOfMaxTimestamp
_maxTimestampAndOffsetSoFar = TimestampOffset(largestTimestamp, shallowOffsetOfMaxTimestamp)
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
}
// append an entry to the index (if needed)
if (bytesSinceLastIndexEntry > indexIntervalBytes) {
offsetIndex.append(largestOffset, physicalPosition)
timeIndex.maybeAppend(maxTimestampSoFar, offsetOfMaxTimestampSoFar)
timeIndex.maybeAppend(maxTimestampAndOffsetSoFar.timestamp, maxTimestampAndOffsetSoFar.offset)
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
bytesSinceLastIndexEntry = 0
}
bytesSinceLastIndexEntry += records.sizeInBytes
Expand Down Expand Up @@ -338,22 +337,21 @@ class LogSegment private[log] (val log: FileRecords,
txnIndex.reset()
var validBytes = 0
var lastIndexEntry = 0
maxTimestampSoFar = RecordBatch.NO_TIMESTAMP
_maxTimestampAndOffsetSoFar = TimestampOffset.Unknown
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
try {
for (batch <- log.batches.asScala) {
batch.ensureValid()
ensureOffsetInRange(batch.lastOffset)

// The max timestamp is exposed at the batch level, so no need to iterate the records
if (batch.maxTimestamp > maxTimestampSoFar) {
maxTimestampSoFar = batch.maxTimestamp
offsetOfMaxTimestampSoFar = batch.lastOffset
_maxTimestampAndOffsetSoFar = TimestampOffset(batch.maxTimestamp, batch.lastOffset)
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
}

// Build offset index
if (validBytes - lastIndexEntry > indexIntervalBytes) {
offsetIndex.append(batch.lastOffset, validBytes)
timeIndex.maybeAppend(maxTimestampSoFar, offsetOfMaxTimestampSoFar)
timeIndex.maybeAppend(maxTimestampAndOffsetSoFar.timestamp, maxTimestampAndOffsetSoFar.offset)
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
lastIndexEntry = validBytes
}
validBytes += batch.sizeInBytes()
Expand All @@ -378,23 +376,21 @@ class LogSegment private[log] (val log: FileRecords,
log.truncateTo(validBytes)
offsetIndex.trimToValidSize()
// A normally closed segment always appends the biggest timestamp ever seen into log segment, we do this as well.
timeIndex.maybeAppend(maxTimestampSoFar, offsetOfMaxTimestampSoFar, skipFullCheck = true)
timeIndex.maybeAppend(maxTimestampAndOffsetSoFar.timestamp, maxTimestampAndOffsetSoFar.offset, skipFullCheck = true)
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
timeIndex.trimToValidSize()
truncated
}

private def loadLargestTimestamp(): Unit = {
// Get the last time index entry. If the time index is empty, it will return (-1, baseOffset)
val lastTimeIndexEntry = timeIndex.lastEntry
maxTimestampSoFar = lastTimeIndexEntry.timestamp
offsetOfMaxTimestampSoFar = lastTimeIndexEntry.offset
_maxTimestampAndOffsetSoFar = TimestampOffset(lastTimeIndexEntry.timestamp, lastTimeIndexEntry.offset)
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated

val offsetPosition = offsetIndex.lookup(lastTimeIndexEntry.offset)
// Scan the rest of the messages to see if there is a larger timestamp after the last time index entry.
val maxTimestampOffsetAfterLastEntry = log.largestTimestampAfter(offsetPosition.position)
if (maxTimestampOffsetAfterLastEntry.timestamp > lastTimeIndexEntry.timestamp) {
maxTimestampSoFar = maxTimestampOffsetAfterLastEntry.timestamp
offsetOfMaxTimestampSoFar = maxTimestampOffsetAfterLastEntry.offset
_maxTimestampAndOffsetSoFar = TimestampOffset(maxTimestampOffsetAfterLastEntry.timestamp, maxTimestampOffsetAfterLastEntry.offset)
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
}
}

Expand Down Expand Up @@ -503,7 +499,7 @@ class LogSegment private[log] (val log: FileRecords,
* The time index entry appended will be used to decide when to delete the segment.
*/
def onBecomeInactiveSegment(): Unit = {
timeIndex.maybeAppend(maxTimestampSoFar, offsetOfMaxTimestampSoFar, skipFullCheck = true)
timeIndex.maybeAppend(maxTimestampAndOffsetSoFar.timestamp, maxTimestampAndOffsetSoFar.offset, skipFullCheck = true)
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
offsetIndex.trimToValidSize()
timeIndex.trimToValidSize()
log.trim()
Expand Down Expand Up @@ -584,8 +580,8 @@ class LogSegment private[log] (val log: FileRecords,
* Close this log segment
*/
def close(): Unit = {
if (_maxTimestampSoFar.nonEmpty || _offsetOfMaxTimestampSoFar.nonEmpty)
CoreUtils.swallow(timeIndex.maybeAppend(maxTimestampSoFar, offsetOfMaxTimestampSoFar,
if (_maxTimestampAndOffsetSoFar != TimestampOffset.Unknown)
CoreUtils.swallow(timeIndex.maybeAppend(maxTimestampAndOffsetSoFar.timestamp, maxTimestampAndOffsetSoFar.offset,
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated
skipFullCheck = true), this)
CoreUtils.swallow(lazyOffsetIndex.close(), this)
CoreUtils.swallow(lazyTimeIndex.close(), this)
Expand Down Expand Up @@ -680,4 +676,4 @@ object LogSegment {

object LogFlushStats extends KafkaMetricsGroup {
val logFlushTimer = new KafkaTimer(newTimer("LogFlushRateAndTimeMs", TimeUnit.MILLISECONDS, TimeUnit.SECONDS))
}
}
Comment thread
thomaskwscott marked this conversation as resolved.
Outdated