@@ -119,7 +119,8 @@ use crate::execution::tracing::{
119119
120120use crate :: execution:: memory_pools:: logging_pool:: LoggingMemoryPool ;
121121use crate :: execution:: spark_config:: {
122- SparkConfig , COMET_DEBUG_ENABLED , COMET_DEBUG_MEMORY , COMET_EXPLAIN_NATIVE_ENABLED ,
122+ SparkConfig , COMET_DEBUG_ENABLED , COMET_DEBUG_MEMORY ,
123+ COMET_EXEC_AGGREGATE_SKIP_PARTIAL_ENABLED , COMET_EXPLAIN_NATIVE_ENABLED ,
123124 COMET_MAX_TEMP_DIRECTORY_SIZE , COMET_PARQUET_ROW_FILTER_PUSHDOWN_ENABLED ,
124125 COMET_TRACING_ENABLED , SPARK_EXECUTOR_CORES ,
125126} ;
@@ -806,10 +807,15 @@ pub extern "system" fn Java_org_apache_comet_Native_setShufflePartitionPusher(
806807 } )
807808}
808809
809- /// Only admit the validated native-shuffle path. A session belongs to one fused Spark plan,
810- /// so an unsafe partial aggregate disables skipping for the whole plan, including its children.
811- /// This deliberately gives up some opportunities rather than changing execution contexts per op.
812- fn configure_skip_partial_aggregation ( config : & mut SessionConfig , plan : & Operator ) {
810+ /// Skipping is opt-in (`spark.comet.exec.aggregate.skipPartial.enabled`): once DataFusion's probe
811+ /// decides to skip, it never aggregates again, so a task whose keys repeat after a mostly distinct
812+ /// start shuffles every later row (#6466).
813+ ///
814+ /// When enabled, only admit the validated native-shuffle path. A session belongs to one fused
815+ /// Spark plan, so an unsafe partial aggregate disables skipping for the whole plan, including its
816+ /// children. This deliberately gives up some opportunities rather than changing execution
817+ /// contexts per op.
818+ fn configure_skip_partial_aggregation ( config : & mut SessionConfig , plan : & Operator , enabled : bool ) {
813819 fn supported ( plan : & Operator ) -> bool {
814820 let supported_aggregate = match & plan. op_struct {
815821 Some ( OpStruct :: HashAgg ( agg) ) => match AggregateMode :: try_from ( agg. mode ) {
@@ -832,9 +838,12 @@ fn configure_skip_partial_aggregation(config: &mut SessionConfig, plan: &Operato
832838 supported_aggregate && plan. children . iter ( ) . all ( supported)
833839 }
834840
835- if !matches ! ( & plan. op_struct, Some ( OpStruct :: ShuffleWriter ( _) ) ) || !supported ( plan) {
836- // Enforce safety after config pass-through: a testing override cannot make unsupported
837- // accumulators convertible. DF 55 removed supports_convert_to_state().
841+ let eligible =
842+ enabled && matches ! ( & plan. op_struct, Some ( OpStruct :: ShuffleWriter ( _) ) ) && supported ( plan) ;
843+ if !eligible {
844+ // Enforce this after config pass-through: a testing override can neither turn skipping
845+ // on nor make unsupported accumulators convertible. DF 55 removed
846+ // supports_convert_to_state().
838847 config
839848 . options_mut ( )
840849 . execution
@@ -893,7 +902,11 @@ fn prepare_datafusion_session_context(
893902 }
894903 }
895904
896- configure_skip_partial_aggregation ( & mut session_config, spark_plan) ;
905+ configure_skip_partial_aggregation (
906+ & mut session_config,
907+ spark_plan,
908+ spark_config. get_bool ( COMET_EXEC_AGGREGATE_SKIP_PARTIAL_ENABLED ) ,
909+ ) ;
897910
898911 let runtime = rt_config. build ( ) ?;
899912
@@ -2041,7 +2054,7 @@ mod tests {
20412054 } ] ,
20422055 ..Default :: default ( )
20432056 } ;
2044- let ratio = |plan : & Operator , requested : f64 | {
2057+ let ratio = |plan : & Operator , requested : f64 , enabled : bool | {
20452058 let mut config = SessionConfig :: new ( ) ;
20462059 config
20472060 . options_mut ( )
@@ -2051,7 +2064,7 @@ mod tests {
20512064 . options_mut ( )
20522065 . execution
20532066 . skip_partial_aggregation_probe_ratio_threshold = requested;
2054- configure_skip_partial_aggregation ( & mut config, plan) ;
2067+ configure_skip_partial_aggregation ( & mut config, plan, enabled ) ;
20552068 assert_eq ! (
20562069 config
20572070 . options( )
@@ -2077,11 +2090,13 @@ mod tests {
20772090 } ,
20782091 ] {
20792092 let plan = writer ( agg) ;
2080- assert_eq ! ( ratio( & plan, 0.8 ) , 0.8 ) ;
2081- assert_eq ! ( ratio( & plan, 0.5 ) , 0.5 ) ;
2082- assert_eq ! ( ratio( & plan, 1.1 ) , 1.1 ) ;
2093+ assert_eq ! ( ratio( & plan, 0.8 , true ) , 0.8 ) ;
2094+ assert_eq ! ( ratio( & plan, 0.5 , true ) , 0.5 ) ;
2095+ assert_eq ! ( ratio( & plan, 1.1 , true ) , 1.1 ) ;
2096+ // Skipping is opt-in, and a DataFusion override cannot turn it on.
2097+ assert_eq ! ( ratio( & plan, 0.8 , false ) , 1.1 ) ;
20832098 // Non-native shuffle / standalone native blocks stay disabled.
2084- assert_eq ! ( ratio( & plan. children[ 0 ] , 0.8 ) , 1.1 ) ;
2099+ assert_eq ! ( ratio( & plan. children[ 0 ] , 0.8 , true ) , 1.1 ) ;
20852100 }
20862101
20872102 for agg in [
@@ -2116,14 +2131,14 @@ mod tests {
21162131 } ,
21172132 ] {
21182133 let plan = writer ( agg) ;
2119- assert_eq ! ( ratio( & plan, 0.8 ) , 1.1 ) ;
2134+ assert_eq ! ( ratio( & plan, 0.8 , true ) , 1.1 ) ;
21202135 // An eligible sibling or a Final parent must not hide the unsafe child.
21212136 let mut nested = writer ( HashAggregate {
21222137 mode : AggregateMode :: Final as i32 ,
21232138 ..partial. clone ( )
21242139 } ) ;
21252140 nested. children [ 0 ] . children = plan. children ;
2126- assert_eq ! ( ratio( & nested, 0.8 ) , 1.1 ) ;
2141+ assert_eq ! ( ratio( & nested, 0.8 , true ) , 1.1 ) ;
21272142 }
21282143 }
21292144
0 commit comments