What is the problem?
CometShuffleExchangeExec decides whether columnar (JVM) shuffle can handle a RangePartitioning by asking whether Comet can serialize the sort orders to protobuf:
https://github.com/apache/datafusion-comet/blob/main/spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleExchangeExec.scala#L654-L659
case RangePartitioning(orderings, _) =>
for (o <- orderings) {
if (QueryPlanSerde.exprToProto(o, inputs).isEmpty) {
reasons += s"unsupported range partitioning sort order: $o"
}
}
But on the columnar path the range partitioning is performed entirely on the JVM by Spark's own RangePartitioner, over an UnsafeProjection of the sort keys and a LazilyGeneratedOrdering:
https://github.com/apache/datafusion-comet/blob/main/spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleExchangeExec.scala#L1002-L1022
case RangePartitioning(sortingExpressions, numPartitions) =>
val rddForSampling = rdd.mapPartitionsInternal { iter =>
val projection = UnsafeProjection.create(sortingExpressions.map(_.child), outputAttributes)
...
}
implicit val ordering = new LazilyGeneratedOrdering(orderingAttributes)
new RangePartitioner(numPartitions, rddForSampling, ascending = true, ...)
The serialized SortOrder produced by the check is never sent to native code on this path. So the gate rejects columnar shuffle for orderings that the JVM would have partitioned correctly, and the query falls back to Spark's shuffle for no compatibility reason.
Impact
Any ordering expression that Comet cannot serialize disables Comet's columnar shuffle for that exchange, even though nothing about the partitioning would have run natively. Examples:
- floating-point keys nested in arrays or structs while
spark.comet.exec.strictFloatingPoint=true
- any
ORDER BY / repartitionByRange expression Comet has no serde for
This is an unnecessary-fallback bug rather than a correctness bug.
History
Until #5506 this also fired for scalar float and double keys under spark.comet.exec.strictFloatingPoint=true, because CometSortOrder.getSupportLevel returned Incompatible for them and exprToProto therefore returned None. #5506 narrowed that verdict, so the scalar floating-point case no longer reaches this gate. The structural problem is unchanged.
Suggested fix
Drop the exprToProto probe from the columnar branch, keeping the collation check that follows it (collation genuinely affects JVM ordering semantics here).
Please verify before fixing — I have not confirmed this myself: that no part of the columnar shuffle write path consumes a serialized partitioning for RangePartitioning. If some writer does, the gate is load-bearing and the fix is instead to narrow it to whatever that writer actually needs.
Suggested test
Pick an ordering that Comet cannot serialize but the JVM can sort — a struct containing a float with spark.comet.exec.strictFloatingPoint=true is a ready-made one — and assert with spark.comet.exec.shuffle.mode=jvm that the exchange stays on Comet's columnar shuffle instead of falling back to Spark's.
What is the problem?
CometShuffleExchangeExecdecides whether columnar (JVM) shuffle can handle aRangePartitioningby asking whether Comet can serialize the sort orders to protobuf:https://github.com/apache/datafusion-comet/blob/main/spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleExchangeExec.scala#L654-L659
But on the columnar path the range partitioning is performed entirely on the JVM by Spark's own
RangePartitioner, over anUnsafeProjectionof the sort keys and aLazilyGeneratedOrdering:https://github.com/apache/datafusion-comet/blob/main/spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleExchangeExec.scala#L1002-L1022
The serialized
SortOrderproduced by the check is never sent to native code on this path. So the gate rejects columnar shuffle for orderings that the JVM would have partitioned correctly, and the query falls back to Spark's shuffle for no compatibility reason.Impact
Any ordering expression that Comet cannot serialize disables Comet's columnar shuffle for that exchange, even though nothing about the partitioning would have run natively. Examples:
spark.comet.exec.strictFloatingPoint=trueORDER BY/repartitionByRangeexpression Comet has no serde forThis is an unnecessary-fallback bug rather than a correctness bug.
History
Until #5506 this also fired for scalar float and double keys under
spark.comet.exec.strictFloatingPoint=true, becauseCometSortOrder.getSupportLevelreturnedIncompatiblefor them andexprToPrototherefore returnedNone. #5506 narrowed that verdict, so the scalar floating-point case no longer reaches this gate. The structural problem is unchanged.Suggested fix
Drop the
exprToProtoprobe from the columnar branch, keeping the collation check that follows it (collation genuinely affects JVM ordering semantics here).Please verify before fixing — I have not confirmed this myself: that no part of the columnar shuffle write path consumes a serialized partitioning for
RangePartitioning. If some writer does, the gate is load-bearing and the fix is instead to narrow it to whatever that writer actually needs.Suggested test
Pick an ordering that Comet cannot serialize but the JVM can sort — a struct containing a float with
spark.comet.exec.strictFloatingPoint=trueis a ready-made one — and assert withspark.comet.exec.shuffle.mode=jvmthat the exchange stays on Comet's columnar shuffle instead of falling back to Spark's.