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
37 changes: 17 additions & 20 deletions core/src/main/scala/kafka/log/LogSegment.scala
Original file line number Diff line number Diff line change
Expand Up @@ -99,21 +99,22 @@ 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: TimestampOffset) : Unit = _maxTimestampAndOffsetSoFar = timestampOffset

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.

nit: There is an extra space before : Unit.

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.

fixed this one and found a couple more.

def maxTimestampAndOffsetSoFar: TimestampOffset = {
if (_maxTimestampAndOffsetSoFar == TimestampOffset.Unknown)
_maxTimestampAndOffsetSoFar = timeIndex.lastEntry
_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,8 +159,7 @@ 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)
}
// append an entry to the index (if needed)
if (bytesSinceLastIndexEntry > indexIntervalBytes) {
Expand Down Expand Up @@ -338,16 +338,15 @@ 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
Expand Down Expand Up @@ -386,15 +385,13 @@ class LogSegment private[log] (val log: FileRecords,
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 @@ -584,7 +581,7 @@ class LogSegment private[log] (val log: FileRecords,
* Close this log segment
*/
def close(): Unit = {
if (_maxTimestampSoFar.nonEmpty || _offsetOfMaxTimestampSoFar.nonEmpty)
if (_maxTimestampAndOffsetSoFar != TimestampOffset.Unknown)
CoreUtils.swallow(timeIndex.maybeAppend(maxTimestampSoFar, offsetOfMaxTimestampSoFar,
skipFullCheck = true), this)
CoreUtils.swallow(lazyOffsetIndex.close(), this)
Expand Down