cloud-fan commented on code in PR #57286:
URL: https://github.com/apache/spark/pull/57286#discussion_r3597592245


##########
core/src/main/scala/org/apache/spark/storage/BlockManagerMasterEndpoint.scala:
##########
@@ -421,8 +417,12 @@ class BlockManagerMasterEndpoint(
           mapStatuses.filter(_ != null).foreach { mapStatus =>
             // Check if the executor has been deallocated
             if 
(!blockManagerIdByExecutor.contains(mapStatus.location.executorId)) {
-              val blocksToDel =
-                
shuffleManager.shuffleBlockResolver.getBlocksForShuffle(shuffleId, 
mapStatus.mapId)
+              // Only a BlockingShuffleManager serves block-manager blocks; a 
pipelined shuffle is
+              // served out-of-band and is not in the MapOutputTracker this 
loop iterates, so this
+              // resolves only regular shuffles (None when the default manager 
is not blocking).
+              val blocksToDel = SparkEnv.get.shuffleBlockResolver

Review Comment:
   This answers your own question at the `_shuffleManager` param above: with 
this call the param is now unused (its only consumer, the old `shuffleManager` 
lazy val, is gone). It can be removed from the constructor — that also touches 
`SparkEnv.scala:656` (`_shuffleManager = null`) and the two 
`BlockManagerReplicationSuite` call sites. Non-blocking.



##########
core/src/main/scala/org/apache/spark/SparkEnv.scala:
##########
@@ -80,12 +80,88 @@ class SparkEnv (
   // user jars to define custom ShuffleManagers.
   @volatile private var _shuffleManager: ShuffleManager = _
 
+  // The manager for pipelined (incrementally-readable) shuffle dependencies, 
configured by
+  // spark.shuffle.manager.incremental. Present only when that config is set. 
It is a peer of
+  // _shuffleManager, not a wrapper around it: a shuffle is routed to one or 
the other by its
+  // dependency type via `shuffleManagerFor`, so neither is ever installed 
"behind" the other.
+  @volatile private var _incrementalShuffleManager: Option[ShuffleManager] = 
None
+
   // Latch to signal when the ShuffleManager has been initialized.
   // Used to allow callers to wait for initialization.
   private val shuffleManagerInitLatch = new CountDownLatch(1)
 
+  /**
+   * The default [[ShuffleManager]] (configured by spark.shuffle.manager), 
which serves all regular
+   * shuffle dependencies. Use this only when the intent is specifically the 
default manager -- e.g.
+   * inspecting its concrete type, or resolving a shuffle block by id (a 
pipelined shuffle is served
+   * out-of-band by the incremental manager and produces no block-manager 
blocks). To serve a
+   * specific shuffle's reads/writes, use `shuffleManagerFor`, which routes by 
dependency type.
+   */
+  def defaultShuffleManager: ShuffleManager = _shuffleManager

Review Comment:
   There isn't really a "default" manager to name here: block-resolution paths 
always want the blocking manager, pipelined reads always want the pipelined 
manager, and routing picks by dependency type. Modeling one slot as the default 
(and sourcing the resolver from it at `shuffleBlockResolver`, line 112) hides 
exactly the blocking-vs-pipelined distinction the design relies on. Suggest 
holding both a blocking and a pipelined manager instance in `SparkEnv` and 
having each call site pick explicitly — always-blocking, always-pipelined, or 
by-dependency-type. That also removes the sharp edge where 
`spark.shuffle.manager.incremental` is set to a blocking manager (the routing 
suite sets it to `"sort"`) whose blocks are then unreachable through this 
accessor.



##########
core/src/main/scala/org/apache/spark/shuffle/ShuffleManager.scala:
##########
@@ -28,14 +28,19 @@ import org.apache.spark.util.Utils
  * and on each executor, based on the spark.shuffle.manager setting. The 
driver registers shuffles
  * with it, and executors (or tasks running locally in the driver) can ask to 
read and write data.
  *
+ * This trait is sealed and is not meant to be implemented directly. A shuffle 
manager declares its
+ * kind by extending one of its two subtypes: [[BlockingShuffleManager]] 
(output is materialized as
+ * block-manager-addressed blocks served through a [[ShuffleBlockResolver]]) or
+ * [[PipelinedShuffleManager]] (output is read incrementally and served 
out-of-band).
+ *
  * NOTE:
  * 1. This will be instantiated by SparkEnv so its constructor can take a 
SparkConf and
  * boolean isDriver as parameters.
- * 2. This contains a method ShuffleBlockResolver which interacts with 
External Shuffle Service
- * when it is enabled. Need to pay attention to that, if implementing a custom 
ShuffleManager, to
- * make sure the custom ShuffleManager could co-exist with External Shuffle 
Service.
+ * 2. A [[BlockingShuffleManager]] exposes a ShuffleBlockResolver which 
interacts with the External
+ * Shuffle Service when it is enabled. Need to pay attention to that, if 
implementing a custom
+ * shuffle manager, to make sure it could co-exist with the External Shuffle 
Service.
  */
-private[spark] trait ShuffleManager {
+private[spark] sealed trait ShuffleManager {

Review Comment:
   Please don't `seal` this. Breaking changes to the interface are fine — 
moving `shuffleBlockResolver` onto `BlockingShuffleManager` is a good change — 
but `sealed` fully stops third-party `ShuffleManager` implementations, which 
SPARK-45762 deliberately enabled. We should keep that extension point. 
(Consequence: the SPARK-45762 test in `SparkSubmitSuite` should be updated to 
implement `BlockingShuffleManager` rather than removed — see review summary.)



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