Skip to content

CometShuffleManager treats Spark's own shuffles differently from SortShuffleManager #7488

Open

Description

@andygrove

Describe the bug

CometShuffleManager handles shuffles that Comet does not replace differently from Spark's SortShuffleManager. These shuffles are RDD shuffles and Spark exchanges Comet leaves in place. They are not new, but they reach more applications once the plugin sets CometShuffleManager by default on Spark 4.0 and later (#7336). Found in review of that PR.

  1. Extra row copy in Spark exchanges. ShuffleExchangeExec.needToCopyObjectsBeforeShuffle returns true for any manager that is not a SortShuffleManager, so Spark's own exchanges copy every row before the shuffle.
  2. sortShuffleManager.getWriter entries are never released. For a Spark shuffle dependency, getWriter delegates to the inner sortShuffleManager, which records each map task in its own taskIdMapsForShuffle. unregisterShuffle clears only CometShuffleManager's map and never calls sortShuffleManager.unregisterShuffle, so those entries stay on the executor heap until the application ends.
  3. Blocks migrated in during decommissioning are never deleted. The IndexShuffleBlockResolver is built with a fresh ConcurrentHashMap instead of taskIdMapsForShuffle. The resolver records blocks migrated in during decommissioning in that map, so unregisterShuffle never deletes them.

All three are in spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleManager.scala.

Steps to reproduce

Read the code paths above. No reproduction has been run for any of them.

Expected behavior

A shuffle that Comet does not replace behaves as it does under SortShuffleManager: no extra row copy, and no state left behind after unregisterShuffle.

Activity

  1. added
    priority:mediumFunctional bugs, performance regressions, broken features
    area:shuffleShuffle (JVM and native)
    and removed on Nov 9, 2026
  2. rich7420 commented on Nov 10, 2026

    @rich7420
    Contributor

    Item 3 can be worse than a leak on Spark 4.x: the resolver can end up with no usable map at all.

    shuffleBlockResolver takes the first 2- or 3-parameter constructor that getDeclaredConstructors returns, and the JDK does not define that order. Spark 4.x has two 2-parameter constructors, and c.newInstance(conf, null) gives:

    • (SparkConf, Map) on 4.0, (SparkConf, ConcurrentHashMap) on 4.1+: taskIdMapsForShuffle is null
    • (SparkConf, BlockManager) on 4.0: Collections.emptyMap()
    • (SparkConf, BlockManager) on 4.1+: a fresh map, as item 3 describes

    When a shuffle block migrates in, onComplete in putShuffleBlockAsStream renames the file into place and then calls taskIdMapsForShuffle.computeIfAbsent (IndexShuffleBlockResolver.scala#L304-L319). That throws a NullPointerException on null and an UnsupportedOperationException on emptyMap, so the block is never reported. The sending executor then stops migrating to the receiving executor and queues the block for another one, giving up after 3 failures by default. The renamed file stays on the receiving executor, untracked.

    I loaded IndexShuffleBlockResolver in a standalone JVM (JDK 17) and printed its constructor order across 30 runs per version:

    Spark (SparkConf, Map) / (SparkConf, ConcurrentHashMap) first (SparkConf, BlockManager) first 3-parameter first
    4.0.4 13 16 1
    4.1.3 3 27 0
    4.2.0 2 28 0

    I haven't checked which constructor a real executor picks, or run decommissioning end to end. Spark 3.5 has a single constructor, so it isn't affected.

    Changing only case 3 to pass taskIdMapsForShuffle wouldn't fix this, because .head can still pick a 2-parameter constructor. Calling the 3-parameter constructor with taskIdMapsForShuffle should fix both. Is anyone working on this? If not, I can open a PR for item 3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:shuffleShuffle (JVM and native)bugSomething isn't workingpriority:mediumFunctional bugs, performance regressions, broken features

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions