andygrove commented on PR #2434:
URL: 
https://github.com/apache/datafusion-ballista/pull/2434#issuecomment-5647182869

   Thanks both. @milenkovicm for the approval, and @comphead for the second 
pass — I took essentially all of it. Net **−232 lines** (386 insertions, 618 
deletions) across the branch, and **410 passed / 0 failed**, clippy and rustfmt 
clean.
   
   The load-bearing check: the only snapshots insta accepted were the four in 
`stage_build_side.rs`, and their plan shapes and `plan_id`s are byte-identical 
to before the refactor. Nothing in `test/join_selection.rs` or the 
plan-stability files moved, which is the evidence that this round is 
behaviour-preserving.
   
   I verified your three structural claims rather than taking them on faith, 
and all three hold: `create_partitioning(self, ..)` does consume (so the clone 
in `join_key_partitioning` was genuinely dead), `partition_mode` is 
`Partitioned` only when `!null_aware`, and the local `selection_state` can only 
be `Unknown` when `self.selection_state` already is — so 
`with_selection_state(Unknown)` really was copying eleven fields to change 
nothing.
   
   ### Taken
   
   **Production.** Dropped the `join` payload (the arm rebuilds from the 
visited node); `build_side: JoinSide` → `build_is_right: bool`, which deletes 
the unreachable `JoinSide::None` arm, its error string and the `JoinSide` 
import from both files; collapsed the two `(Unknown, Partitioned)` arms into 
one with the join-type condition moved inside `requires_build_staging` (which 
retires the "caller is responsible for the fourth condition" paragraph); 
removed `with_selection_state` and restored `to_partitioned`'s inline body; 
`BuildStagingLimits` → plain params; `probe_stats` hoisted beside 
`build_stats`; `join_key_partitioning` returns a tuple by value over the owned 
`Vec`; `exchange_on` → `SelectJoinRule::ensure_exchange`.
   
   On the naming: agreed `exchange_on` read as "on the join keys". The receiver 
keeps the `fetch_add` laziness without the generic, as you suggested. I also 
took the doc line about `inputs_already_partitioned` — the structural 
comparison is deliberate, since the only exchange worth reusing is one this 
rule just placed, and that is now written down so nobody unifies them later.
   
   **Tests.** Six single-assert staging tests folded into two behind a 
`stages(build, probe, threshold)` predicate; the two hand-partitioned join-type 
lists merged into one loop over all ten with `collect_left_broadcast_safe` as 
the oracle (your point that a new DataFusion join type fails neither current 
list is exactly right, and the merged form does catch it); `q8_shaped_action*` 
un-forked from `run_to_actual_join`, which gained a `stage_build_side` param; 
the fourth `StatisticsExec` builder parameterised with the other three as 
wrappers; `mock_partitions_with_statistics_no_data` delegating to 
`mock_partitions_with_size`; `estimated_statistics` using 
`Statistics::to_inexact`.
   
   You were right that the fixtures in `stage_build_side.rs` were a straight 
copy — `ballista_ctx`, `narrow_schema`, `register_stats_table` and `MB` now 
live in `test/mod.rs` and both files import them, so "the shipped session 
config" means one thing.
   
   Dropped `does_not_stage_a_left_join` and 
`exchange_on_wraps_a_non_exchange_child`. On the first, your read was better 
than mine: `Left` is already a row of the merged loop with the same q8-shaped 
statistics, so the only unique content was a plan snapshot that needs 
re-blessing on every unrelated `plan_id` shift.
   
   Also fixed the shadowed `use datafusion::common::{ColumnStatistics, 
Statistics, stats::Precision};` — good catch, since as you say `-D warnings` 
never would have.
   
   ### Not taken
   
   **The exchange-guard depth**, deliberately. The fire-at-most-once bound is 
unaffected, because staging always produces a *direct* `ExchangeExec` child, 
which the guard does catch. In the `FilterExec(ExchangeExec(..))` shape the 
staged measurement is of the filter's output rather than the inner shuffle's, 
so it is an extra boundary but not redundant work, and a subtree-wide search 
would decline legitimately useful cases — a build side that is itself a join 
over an already-resolved broadcast exchange, for one. Noted as a follow-up; 
happy to tighten if you think the shape is likelier than I am reading it.
   
   **Threading one `StatisticsContext` through `to_actual_join`.** Agreed it is 
the natural moment, and agreed this PR adds no new statistics computation. But 
it is a change to a path five callers share, with no test that would catch a 
memo-sharing mistake, so I would rather it not ride along behind a 
behaviour-preserving cleanup. Separate PR.
   
   ### @milenkovicm
   
   Law of Demeter: taken, and it lines up with comphead's item — 
`requires_build_staging` now takes `min_probe_ratio` and 
`max_estimate_multiple` as plain params rather than reaching through 
`&BallistaConfig`, and `broadcast_threshold_bytes` is passed the same way, so 
the mix-and-match is gone.
   
   Config wording: also taken. All three `stage_build_side*` entries now say 
explicitly that staging applies only where the build side's size is an estimate 
rather than a measurement — an exact size over the budget is a fact no further 
measurement can change. Docs regenerated.
   
   And yes on #1916 and cardinality estimation as the follow-up. Better 
cardinalities would shrink the window this heuristic exists to cover, which is 
the right direction.
   
   ### Benchmarks and docs
   
   I reverted the `benchmarking.md` change entirely, per your point. It pinned 
a row to an unmerged PR commit behind an unowned TODO, and it was the only 
`{note}` admonition in `docs/source`. The deeper problem is the one you found 
in Q1 vs Q6: both are join-free, one improved 4% and the other regressed 7%, so 
a ±7% noise floor was being published as measured signal next to a claim that 
this PR accounts for almost all of the improvement.
   
   Those numbers also predate the join-type guard, so they are stale 
regardless. I will re-measure on the cluster and land the docs separately after 
merge, with the iteration count and the regression band stated rather than 
rounded away.
   
   ### CI
   
   The S3 failures look like the MinIO issue you linked (#2446) rather than 
anything here.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to