Commit d9ea38b
fix(physical-optimizer): make OutputRequirements idempotent (#22522)
## Which issue does this PR close?
Related to apache/datafusion-ballista#1359
## Rationale
Ballista's Adaptive Query Execution (AQE) planner re-invokes
DataFusion's full `PhysicalOptimizer` chain after every completed stage
(`AdaptivePlanner::replan_stages`). Rules that are not idempotent
(`rule(rule(x)) != rule(x)`) stack execution-plan nodes on each pass.
`OutputRequirements::new_add_mode()` wraps the plan root with
`OutputRequirementExec` to preserve global ordering/distribution
requirements. On a second pass the wrapper's `maintains_input_order() ==
[true]` and `required_input_ordering() == [None]` cause
`require_top_ordering_helper` to recurse through it and produce a
*second* wrapper, yielding
`OutputRequirementExec(OutputRequirementExec(...))`. Each AQE replan
adds another layer.
## What changes are included in this PR?
- **Guard in `require_top_ordering()`**: if the plan root is already an
`OutputRequirementExec`, return it unchanged. This makes the rule
idempotent with zero overhead for single-pass use.
- **Doc-comment update** on `new_add_mode()` and
`require_top_ordering()` documenting the idempotence guarantee.
- **Two tests** in `tests/physical_optimizer/output_requirements.rs`:
- `add_mode_is_idempotent_on_bare_scan` — bare `ParquetExec` (exercises
`is_changed = false` path).
- `add_mode_is_idempotent_on_sorted_plan` — `SortExec → ParquetExec`
(exercises `is_changed = true` path).
## Are these changes tested?
Yes. Two new tests run the rule twice on distinct fixtures and assert
structural equality via `get_plan_string`. Both fail without the fix
(double-wrapped `OutputRequirementExec`) and pass with it.
## Are there any user-facing changes?
No. `OutputRequirementExec` is an internal ancillary node stripped
before execution; the idempotence guard only affects re-optimization
scenarios (AQE).
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent fa724c1 commit d9ea38b
3 files changed
Lines changed: 77 additions & 1 deletion
File tree
- datafusion
- core/tests/physical_optimizer
- physical-optimizer/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| 33 | + | |
33 | 34 | | |
34 | 35 | | |
35 | 36 | | |
| |||
Lines changed: 65 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
64 | | - | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
65 | 67 | | |
66 | 68 | | |
67 | 69 | | |
| |||
325 | 327 | | |
326 | 328 | | |
327 | 329 | | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
328 | 335 | | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
329 | 339 | | |
330 | 340 | | |
331 | 341 | | |
| |||
0 commit comments