Copilot commented on code in PR #13033:
URL: https://github.com/apache/gluten/pull/13033#discussion_r4023408143


##########
backends-velox/src/main/scala/org/apache/gluten/extension/FlushableHashAggregateRule.scala:
##########
@@ -79,74 +72,30 @@ case class FlushableHashAggregateRule(session: 
SparkSession) extends Rule[SparkP
   }
 
   /**
-   * Walks the plan downward, applying func to each 
RegularHashAggregateExecTransformer or
-   * SortHashAggregateExecTransformer that is eligible for flushable 
conversion. An aggregate is
-   * eligible when all expressions are Partial/PartialMerge, it is not the 
final stage of a
-   * grouping-only aggregate, it is not the protected PartialMerge aggregate 
directly below a
-   * distinct-partial aggregate, and no aggregate function disallows flushing.
+   * An aggregate is eligible when all expressions are Partial/PartialMerge, 
it is not the final
+   * stage of a grouping-only aggregate, it is not the protected PartialMerge 
aggregate directly
+   * below a distinct-partial aggregate, and no aggregate function disallows 
flushing.
    */
-  private def replaceEligibleAggregates(
-      plan: SparkPlan,
-      protectedAggs: mutable.Map[Int, HashAggregateExecTransformer]): 
SparkPlan = {
-    def toFlushableAgg(agg: HashAggregateExecTransformer): 
FlushableHashAggregateExecTransformer = {
-      FlushableHashAggregateExecTransformer(
-        agg.requiredChildDistributionExpressions,
-        agg.groupingExpressions,
-        agg.aggregateExpressions,
-        agg.aggregateAttributes,
-        agg.initialInputBufferOffset,
-        agg.resultExpressions,
-        agg.child
-      )
-    }
-
-    def transformDown: SparkPlan => SparkPlan = {
-      case agg: RegularHashAggregateExecTransformer if 
isGroupingOnlyFinalAgg(agg) =>
-        // Final stage of a grouping-only aggregate. It must fully aggregate. 
Skip.
-        agg
-      case agg: RegularHashAggregateExecTransformer
-          if !agg.aggregateExpressions.forall(p => p.mode == Partial || p.mode 
== PartialMerge) =>
-        // Not an intermediate agg. Skip.
-        agg
-      case agg: RegularHashAggregateExecTransformer
-          if protectedAggs.contains(agg.id) =>
-        // This is the PartialMerge aggregate directly below a 
distinct-partial aggregate in
-        // Spark's one-distinct pipeline. Keep it non-flushable so the 
distinct step continues to
-        // see globally de-duplicated (grouping + distinct) keys.
-        agg
-      case agg: RegularHashAggregateExecTransformer
-          if aggregatesNotSupportFlush(agg.aggregateExpressions) =>
-        // Aggregate uses a function that is unsafe to flush. Skip.
-        agg
-      case agg: RegularHashAggregateExecTransformer =>
-        // All guards passed; replace with the flushable variant.
-        toFlushableAgg(agg)
-      case agg: SortHashAggregateExecTransformer if 
isGroupingOnlyFinalAgg(agg) =>
-        // See the RegularHashAggregateExecTransformer branch above.
-        agg
-      case agg: SortHashAggregateExecTransformer
-          if !agg.aggregateExpressions.forall(p => p.mode == Partial || p.mode 
== PartialMerge) =>
-        // Not an intermediate agg. Skip.
-        agg
-      case agg: SortHashAggregateExecTransformer if 
protectedAggs.contains(agg.id) =>
-        // See the RegularHashAggregateExecTransformer branch above.
-        agg
-      case agg: SortHashAggregateExecTransformer
-          if aggregatesNotSupportFlush(agg.aggregateExpressions) =>
-        // Aggregate uses a function that is unsafe to flush. Skip.
-        agg
-      case agg: SortHashAggregateExecTransformer =>
-        // All guards passed; replace with the flushable variant.
-        toFlushableAgg(agg)
-      case exchange: ShuffleExchangeLike =>
-        // Stop at the next exchange. This rule is applied from an exchange 
boundary and should not
-        // continue rewriting into a different shuffle region.
-        exchange
-      case other => other.withNewChildren(other.children.map(transformDown))
-    }
+  private def isEligible(
+      agg: HashAggregateExecTransformer,
+      protectedAggIds: Set[Int]): Boolean = {
+    !isGroupingOnlyFinalAgg(agg) &&
+    agg.aggregateExpressions.forall(p => p.mode == Partial || p.mode == 
PartialMerge) &&
+    !protectedAggIds.contains(agg.id) &&

Review Comment:
   `protectedAggIds` is collected from the original tree, but this is now a 
bottom-up transform. When the partial aggregate below the exchange is replaced, 
Spark rebuilds the protected `PartialMerge` parent through 
`withNewChildInternal`/`copy(child = ...)`, so that copied node gets a 
different `id`; `contains(agg.id)` then misses it and the protected node is 
converted as well. This breaks the one-distinct invariant that the surrounding 
tests are intended to preserve. Carry the protection through the traversal (or 
use a stable structural marker) rather than matching copied plan IDs.



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