Skip to content

CASSJAVA-130: Fix Result-Metadata Race Causing Corrupt SKIP_METADATA Row Decoding#2094

Open
yifan-c wants to merge 1 commit into
apache:4.xfrom
yifan-c:CASSJAVA-130/fix-result-metadata-race
Open

CASSJAVA-130: Fix Result-Metadata Race Causing Corrupt SKIP_METADATA Row Decoding#2094
yifan-c wants to merge 1 commit into
apache:4.xfrom
yifan-c:CASSJAVA-130/fix-result-metadata-race

Conversation

@yifan-c

@yifan-c yifan-c commented Jul 17, 2026

Copy link
Copy Markdown

Patch by Yifan Cai; Reviewed by TBD for CASSJAVA-130

…Row Decoding

Patch by Yifan Cai; Reviewed by TBD for CASSJAVA-130
@yifan-c
yifan-c requested a review from SiyaoIsHiding July 17, 2026 22:05

@tejalchak tejalchak left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Solid fix. One follow-up question inline around toMessage worth deciding whether to thread the snapshot there too before/after merge.

Comment on lines +304 to 306
logPrefixJoiner.join(this.sessionName, nodeRequestId, currentExecutionIndex),
resultMetadataSnapshot(statement));
Message message = Conversions.toMessage(statement, executionProfile, context);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I was looking at the race condition window here and wanted to get a second pair of eyes ...

While the callback now safely uses the snapshot, toMessage still reads the live metadata state. I'm wondering if a concurrent schema update between capturing the snapshot and the toMessage execution could cause a mismatch (where the request sends the new metadata ID, but the callback decodes using the old snapshot). Should toMessage accept the snapshot to close any chance of discrepancy?

Since ConversionsMetadataRaceTest calls getResultDefinitions directly rather than driving through toMessage, so it might not catch this without some change.

Comment on lines +223 to +238
static class ResultMetadata {
private final ByteBuffer resultMetadataId;
private final ColumnDefinitions resultSetDefinitions;

private ResultMetadata(ByteBuffer resultMetadataId, ColumnDefinitions resultSetDefinitions) {
this.resultMetadataId = resultMetadataId;
this.resultSetDefinitions = resultSetDefinitions;
}

ByteBuffer getResultMetadataId() {
return resultMetadataId;
}

ColumnDefinitions getResultSetDefinitions() {
return resultSetDefinitions;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A minor thought: if this branch is strictly Java 17+, we could consider using a record to avoid the boilerplate code
static record ResultMetadata(ByteBuffer resultMetadataId, ColumnDefinitions resultSetDefinitions) {}

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.

3 participants