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


##########
core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala:
##########
@@ -1489,6 +1489,28 @@ private[spark] class DAGScheduler(
     checkPipelinedStageCreation(finalRDD, partitions, jobId)
   }
 
+  /** Reject persistence that could bypass a native pipelined shuffle reader. 
*/
+  private def checkPipelinedCacheSupported(finalRDD: RDD[_]): Unit = {
+    val persisted = new HashSet[RDD[_]]
+    traverseRDDGraph(finalRDD) { (rdd, enqueue) =>
+      if (rdd.getStorageLevel != StorageLevel.NONE ||
+          
rdd.checkpointData.exists(_.isInstanceOf[LocalRDDCheckpointData[_]])) {
+        persisted += rdd
+      }
+      rdd.dependencies.foreach(dep => enqueue(dep.rdd))
+    }
+    // Cache locations cannot establish a stable cut: eviction can revive an 
upstream producer,
+    // and a partial cache hit skips a reader whose producer still needs its 
termination ACK.
+    // Check storage intent instead, including pending local checkpoints and 
narrow descendants.
+    val visited = new HashSet[RDD[_]]
+    if (persisted.exists(rdd => rddChainReadsPipelinedShuffle(rdd, visited))) {
+      throw pipelinedUnsupportedError(
+        "cache/persist/localCheckpoint in a pipelined consumer's within-stage 
chain; " +
+          "unpersist cached RDDs or rebuild locally checkpointed consumers 
without " +
+          "localCheckpoint before submitting the job; persist producer inputs 
instead")

Review Comment:
   **Nit (P3):** The last clause, `persist producer inputs instead`, is only 
true for a producer whose own stage reads no pipelined shuffle. Take an 
all-pipelined chain `A -PSD1-> B -PSD2-> C`. Every RDD in stage B is an input 
of the B->C producer, but it also reads PSD1 within its stage, so 
`rddChainReadsPipelinedShuffle` flags it. The new test `reject a persisted 
stage that consumes and produces shuffles` is exactly this case: `middle` is 
PSD2's producer root and is still rejected. A user who persisted `middle` is 
told to do what they already did, and the job fails the same way again.
   
   Could the clause name the placement the check actually allows? For example: 
only RDDs that do not read a pipelined shuffle within their stage (such as 
inputs of the first pipelined producer) can be persisted. No existing assertion 
pins this clause, so rewording it should not disturb the current tests.
   
   A smaller point: the template renders this as `uses an unsupported feature: 
<reason>. Pipelined ... shuffles ... incompatible with this feature in this 
version.` So the two imperative clauses read a bit oddly next to the 
noun-phrase reasons the sibling rejections use.
   
   **Verification:**
   - **Behavior:** Persisting an RDD in the middle stage of a pipelined chain 
that both consumes and produces pipelined shuffles is still rejected before any 
stage registration. The resulting reason describes the allowed placement as one 
outside any pipelined consumer's within-stage chain.
   - **Compatibility:** Existing rejection coverage for direct consumers, 
narrow descendants, pending and unpersisted local checkpoints, and real cached 
blocks still observes the same error condition, exception type, and unpersist 
and rebuild guidance.



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