Skip to content

KAFKA-21234: Fix bug in KRaft where the metadata layer can receive records past the high watermark - #23737

Open
kevin-wu24 wants to merge 1 commit into
apache:trunkfrom
kevin-wu24:KAFKA-21234
Open

kevin-wu24 wants to merge 1 commit into
apache:trunkfrom
kevin-wu24:KAFKA-21234

Conversation

@kevin-wu24

@kevin-wu24 kevin-wu24 commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Issue Description

When the metadata layer (e.g. MetadataLoader) tries to read a slice of records from KRaft which is greater than KafkaRaftClient#MAX_BATCH_SIZE_BYTES, the RecordsIterator can return records which are past the HWM. As it iterates through this slice of records, FileRecords#readInto reads from disk the minimum of the bytes until end of the file and the remaining space in the associated buffer. In the case of the former, this can lead to a metadata error where the node tries to snapshot with records past the HWM.

For the metadata error to occur, the following three pre-conditions must be met:

  1. One committed read handed to a listener is larger than 8 MiB.
  2. The segment file has bytes after the HW, meaning records this node already appended but that aren't committed yet.
  3. For the error to actually show up, the snapshot generator emits a snapshot from the resulting image before the HW catches up.

What Changed

Add FileRecords#readUntil which reads from the underlying file to the minimum of:

  • the remaining space in the associated buffer, which in the case of RecordsIterator is the minimum of the FileRecords' record size and the batch size defined by KRaft.
  • the end byte position of the FileRecords object, rather than the end of the underlying file. This ensures when a caller constructs a FileRecords slice of [start position, HWM), no bytes past the HWM are read into memory.

Testing

Added unit tests in RecordsIteratorTest and FileRecordsTest

Alternatives

  • Limiting the buffer in RecordsIterator prior to calling FileRecords#readInto. The motivation behind this is that other callers may want to this functionality in the future, so the change belongs in FileRecords, not a caller of that class.
  • Changing the implementation of FileRecords#readInto. The main concern I had with this was that there are many other callers of this method outside of the raft layer, and it is not clear to me the impact of this change on them. Adding an additional method does not impact existing behavior. The other users of readInto are AbstractFetcherThread, LogSegment, Cleaner, CoordinatorLoaderImpl, and TransactionStateManager.

Reviewers: José Armando García Sancio jsancio@apache.org

@github-actions github-actions Bot added triage PRs from the community kraft clients labels Oct 6, 2026

@jsancio jsancio left a comment

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.

Thanks for the fix @kevin-wu24 . I just have one high-level comment.

* possible exceptions
* @throws IllegalArgumentException If the position is negative or greater than the size of this FileRecords object
*/
public void readUntil(ByteBuffer buffer, int position) throws IOException {

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.

Instead of introducing a new method (readUntil). I would like to understand if we should fix readInto to honor the limit of the FileRecords slice. What do you think @junrao

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 am not opposed to that approach. I mainly need to understand what each of the other users of FileRecords#readInto assumes/can handle. I thought it might be better to see if others already knew some of these things. I will look into them myself, but it just may take some time.

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.

Take a look at writeTo.

I would expect the read semantic of readInto to be similar to writeTo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clients kraft triage PRs from the community

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants