This is an automated email from the ASF dual-hosted git repository.

chia7712 pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 937add834bc MINOR: Avoid eager readNextOffset() call in 
Cleaner.cleanSegments (#22200)
937add834bc is described below

commit 937add834bcddbc31f714159eab85cbb04ebccae
Author: KC.H <[email protected]>
AuthorDate: Mon May 4 17:50:12 2026 +0800

    MINOR: Avoid eager readNextOffset() call in Cleaner.cleanSegments (#22200)
    
    In Cleaner.cleanSegments, the upper bound offset for each LogSegment is
    computed as the next segment's baseOffset when available, falling back
    to the current segment's readNextOffset() for the last segment.
    
    This is intentional: readNextOffset() reads from disk and is documented
    as expensive, so the next segment's baseOffset (an O(1) field access) is
    preferred whenever possible.
    
    However, the previous code used:
    ```java
    long upperBoundOffset = nextSegmentOpt.map(LogSegment::baseOffset)
        .orElse(currentSegment.readNextOffset());
    ```
    
    Optional.orElse evaluates its argument eagerly, so readNextOffset() was
    invoked once per segment regardless of whether nextSegmentOpt was
    present, defeating the optimization.
    
    Replace orElse with a conditional expression so the fallback is only
    evaluated when needed. orElseGet cannot be used here because
    readNextOffset() declares IOException, which Supplier does not allow.
    
    Reviewers: PoAn Yang <[email protected]>, Chia-Ping Tsai
    <[email protected]>
---
 .../main/java/org/apache/kafka/storage/internals/log/Cleaner.java   | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git 
a/storage/src/main/java/org/apache/kafka/storage/internals/log/Cleaner.java 
b/storage/src/main/java/org/apache/kafka/storage/internals/log/Cleaner.java
index 5c111cc50f3..7dfb36ce915 100644
--- a/storage/src/main/java/org/apache/kafka/storage/internals/log/Cleaner.java
+++ b/storage/src/main/java/org/apache/kafka/storage/internals/log/Cleaner.java
@@ -253,7 +253,11 @@ public class Cleaner {
                 // Note that it is important to collect aborted transactions 
from the full log segment
                 // range since we need to rebuild the full transaction index 
for the new segment.
                 long startOffset = currentSegment.baseOffset();
-                long upperBoundOffset = 
nextSegmentOpt.map(LogSegment::baseOffset).orElse(currentSegment.readNextOffset());
+                // readNextOffset() is expensive — keep it lazy. orElse() 
evaluates eagerly,
+                // and orElseGet() can't be used because readNextOffset() 
throws IOException.
+                long upperBoundOffset = nextSegmentOpt.isPresent()
+                        ? nextSegmentOpt.get().baseOffset()
+                        : currentSegment.readNextOffset();
                 List<AbortedTxn> abortedTransactions = 
log.collectAbortedTransactions(startOffset, upperBoundOffset);
                 
transactionMetadata.addAbortedTransactions(abortedTransactions);
 

Reply via email to