-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Fix Partial AggregateExec correctness issue dropping rows #18712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| // Check if we should switch to skip aggregation mode | ||
| // It's important that we do this before we early emit since we've | ||
| // already updated the probe. | ||
| if let Some(new_state) = self.switch_to_skip_aggregation()? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unclear to me why we set update_skip_aggregation_probe here https://github.com/apache/datafusion/pull/18712/files#diff-69c8ecaca5e2c7005f2ed1facaa41f80b45bfd006f2357e53ff3072f535c287dL687 and not next to switch_to_skip_aggregation. I can't fully give an explanation yet but allowing the probe to be updated and then allowing the look to break before we get here seems dangerous? It's important that we emit everything before we move to the SkipAggregation state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@korowa does that make sense to you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read this new logic carefully and I think moving the set to switch aggregation state next to the check makes a lot of sense to me
b28fce0 to
353b11b
Compare
90d5a48 to
febdd78
Compare
|
|
||
| ExecutionState::Done => { | ||
| // Sanity check: all groups should have been emitted by now | ||
| if !self.group_values.is_empty() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding some protection here to try and avoid bugs like this happening in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather fail the query than return the wrong / incomplete results.
|
|
||
| // Create constrained memory to trigger early emission but not completely fail | ||
| let runtime = RuntimeEnvBuilder::default() | ||
| .with_memory_limit(1024, 1.0) // 100KB - enough to start but will trigger pressure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1024 bytes != 100KB
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, I was playing around with this to repro the bug
|
Thank you for this PR @xanderbailey -- I plan to review it tomorrow |
alamb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @xanderbailey -- this is an amazing find and a really well done PR. It was clear, and easy to read and makes sense to me.
Thank you
| // Check if we should switch to skip aggregation mode | ||
| // It's important that we do this before we early emit since we've | ||
| // already updated the probe. | ||
| if let Some(new_state) = self.switch_to_skip_aggregation()? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read this new logic carefully and I think moving the set to switch aggregation state next to the check makes a lot of sense to me
| use std::sync::Arc; | ||
|
|
||
| #[tokio::test] | ||
| async fn test_double_emission_race_condition_bug() -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I verified that this test covers the code in this PR as it fails without the code changes:
thread 'aggregates::row_hash::tests::test_double_emission_race_condition_bug' (41064140) panicked at datafusion/physical-plan/src/aggregates/row_hash.rs:1354:9:
assertion `left == right` failed: Unexpected number of groups
left: 100
right: 1124
stack backtrace:
|
I also added this ticket to the potential content of a datafusion 51.1.0 release: |
|
Thanks again @xanderbailey |
## Which issue does this PR close? More detail is in the issue. <!-- We generally require a GitHub issue to be filed for all bug fixes and enhancements and this helps us generate change logs for our releases. You can link an issue to this PR using the GitHub syntax. For example `Closes apache#123` indicates that this PR will close issue apache#123. --> - Closes apache#18701 ## Rationale for this change This is a pretty major correctness issue. <!-- Why are you proposing this change? If this is already explained clearly in the issue then this section is not needed. Explaining clearly why changes are proposed helps reviewers understand your changes and offer better suggestions for fixes. --> ## What changes are included in this PR? Fixes issue and reorders skip aggregate and emit early within partial aggregate execution <!-- There is no need to duplicate the description in the issue here but it is sometimes worth providing a summary of the individual changes in this PR. --> ## Are these changes tested? Yes, the unit test that's added here previously failed before this change. <!-- We typically require tests for all PRs in order to: 1. Prevent the code from being accidentally broken by subsequent changes 2. Serve as another way to document the expected behavior of the code If tests are not included in your PR, please explain why (for example, are they covered by existing tests)? --> ## Are there any user-facing changes? <!-- If there are user-facing changes then we may require documentation to be updated before approving the PR. --> <!-- If there are any breaking changes to public APIs, please add the `api change` label. -->
Which issue does this PR close?
More detail is in the issue.
Rationale for this change
This is a pretty major correctness issue.
What changes are included in this PR?
Fixes issue and reorders skip aggregate and emit early within partial aggregate execution
Are these changes tested?
Yes, the unit test that's added here previously failed before this change.
Are there any user-facing changes?