andygrove commented on PR #5514:
URL: 
https://github.com/apache/datafusion-comet/pull/5514#issuecomment-5608172692

   Both remaining P2s are addressed in ac8e5a1c8, and the lint failure at 
`CometPlanOnlySuite.scala:272` is gone (an `s` prefix on a string with no 
substitution).
   
   ### Use the captured settings throughout conversion
   
   You are right that the three-flag snapshot only covered the gate, and I went 
looking for a way to make it govern the whole preview before concluding it 
cannot be done. `SparkPlan.conf` is:
   
   ```scala
   override def conf: SQLConf = {
     if (session != null) { session.sessionState.conf } else { super.conf }
   }
   ```
   
   with `@transient final val session = SparkSession.getActiveSession.orNull` 
captured at construction. So `op.conf` is the live conf of whichever session 
each node was built under. `SQLConf.withExistingConf` cannot redirect it, 
because it never consults the thread-local. A cloned session with the snapshot 
as its conf cannot either, because the nodes already exist and 
`withNewChildren` returns `this` when the children are unchanged, so most of 
the tree is never reconstructed. And `CometExecRule` reads `op.conf` in six 
places, including the per-operator gate at 
`handler.enabledConfig.forall(_.get(op.conf))`, the strict-fallback check and 
the shuffle checks. Injecting the snapshot would have covered `isCometLoaded` 
and the two rules and missed all of those, which is the partial fix you were 
objecting to, only harder to see.
   
   So the snapshot is now used as a check rather than an override. It records 
every SQL conf that was set, not just Comet's, and at report time anything that 
differs from the live session means the preview would describe a configuration 
the query never ran under. The report is skipped and the diagnostic names the 
keys that moved. Better nothing than coverage numbers for a configuration that 
never executed.
   
   The gate is deliberately excluded from that comparison, so the case the 
snapshot was added for still works: restoring 
`spark.comet.explain.planOnly.enabled` before the callback runs does not drop 
the report. That flag decides only whether to report, and the snapshot remains 
the authority for it.
   
   The gated test is now two tests sharing one helper, so the comparison you 
asked for is against a control rather than against nothing:
   
   ```
   - a report survives the setting being restored before the callback runs
   - a report is skipped when a conversion setting changed before the callback 
runs
   ```
   
   The first still asserts one report and now also asserts it carries `Comet 
accelerated` numbers. The second flips `spark.comet.exec.sort.enabled` instead 
of the gate, and asserts one line that says `settings changed since it was 
planned`, that it names the changed key, and that it carries no coverage 
numbers.
   
   ### Keep exchange identity restoration independent of projection support
   
   Fixed by not adding a node at all. The subtree's own attribute IDs are 
rewritten to the wrapper's, everywhere they appear beneath it, instead of being 
re-labelled by a `ProjectExec` of aliases. That reads no user setting and adds 
no eligible operator, so it also answers your abstraction point about identity 
bookkeeping moving the number the report exists to state.
   
   The reuse test is now parameterized on `spark.comet.exec.project.enabled`. 
Your prediction was exact; with the projection approach still in place and only 
that flag flipped:
   
   ```
   - a reused exchange keeps its output IDs so consumers still convert 
(project.enabled=true)
   - a reused exchange keeps its output IDs so consumers still convert 
(project.enabled=false) *** FAILED ***
     Comet accelerated 10 out of 14 eligible operators (71%) ... did not 
contain "CometHashJoin"
   ```
   
   Both pass with the rewrite. All 24 `CometPlanOnlySuite` tests pass on the 
default profile, spotless and scalastyle are clean.
   
   Two things about the rewrite worth stating, since it is more 
invasive-looking than an added node. It walks the whole subtree rather than 
just the root because almost every operator derives `output` from its children, 
so the producing leaf has to be rewritten for the root to present the new IDs; 
that is safe because attribute IDs are globally unique, so an ID in the root's 
output means the same attribute wherever it appears below, and intermediate 
attributes not in the root's output are untouched. And the direction is 
load-bearing: rewriting the consumers to reference the shared subtree's IDs 
instead would merge the two copies of a self-join onto one set of attributes, 
which is precisely what `ReusedExchangeExec`'s re-aliasing exists to prevent.
   


-- 
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