Skip to content

CASSANDRA-21519: Return CorruptSSTableException if chunk metadata and file size are out of sync - #4937

Open
nivykani wants to merge 3 commits into
apache:trunkfrom
nivykani:fill-exception
Open

CASSANDRA-21519: Return CorruptSSTableException if chunk metadata and file size are out of sync#4937
nivykani wants to merge 3 commits into
apache:trunkfrom
nivykani:fill-exception

Conversation

@nivykani

Copy link
Copy Markdown

In ThreadLocalReadAheadBuffer, in the rare case that chunk metadata and file size are out of sync (e.g. bytes erased from the file after chunk metadata is calculated), we’d enter an infinite loop.

The proposed fix is to throw a CorruptSSTableException if we’re trying to read past the end of a file, rather than clamping the read.

The Cassandra Jira

long realPosition = Math.min(channelSize, position);
int blockNo = (int) (realPosition / bufferSize);
if (position >= channelSize)
throw new CorruptSSTableException(null, channel.filePath());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nice find and fix!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Would it help with triage to include some details in the exception
"chunk read past EOF: position=<> channelSize=<>"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good idea! Updated, now we see a message like Caused by: java.io.IOException: Chunk read past EOF: requested position 2272 must be less than file size 592

@tejalchak

Copy link
Copy Markdown

lgtm

@frankgh frankgh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good, but I have a few questions

Comment on lines +109 to +111
throw new CorruptSSTableException(new IOException(String.format("Chunk read past EOF: requested position %d must be less than file size %d",
position, channelSize)),
channel.filePath());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NIT : formatting is off

Suggested change
throw new CorruptSSTableException(new IOException(String.format("Chunk read past EOF: requested position %d must be less than file size %d",
position, channelSize)),
channel.filePath());
throw new CorruptSSTableException(new IOException(String.format("Chunk read past EOF: requested position %d must be less than file size %d",
position, channelSize)),
channel.filePath());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see that we have CorruptSSTableException which might be suitable here. But it may be worth more exploration:

            throw new CorruptSSTableException(new CorruptBlockException(channel.filePath(), position, bufferSize),
                                              channel.filePath());

I think IOException will be fine here, but maybe someone with more context can comment on throwing the CorruptBlockException exception

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I agree CorruptBlockException is also suitable, but IOException was chosen to wrap a custom error message for CorruptSSTableException, since this could be a confusing error to debug otherwise. CorruptBlockException returns the error "corruption detected, chunk at {offset} of length {length}" but the issue isn't isolated to one specific block.

Comment thread test/unit/org/apache/cassandra/io/util/StandardCompressedChunkReaderTest.java Outdated

// Sanity: read-ahead must actually engage for this test to exercise the scan path
Assert.assertTrue("read-ahead must be larger than chunk length for scanReader to be non-null",
DatabaseDescriptor.getCompressedReadAheadBufferSize() > metadata.chunkLength());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should we set the compressed read ahead buffer size in the test setup as well?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch, changed this to directly set the buffer size, which avoids having to do this check.

@nivykani
nivykani requested a review from frankgh July 28, 2026 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants