jerrypeng commented on code in PR #59318:
URL: https://github.com/apache/spark/pull/59318#discussion_r4277604415


##########
core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala:
##########
@@ -1457,25 +1471,93 @@ private[spark] class DAGScheduler(
     // Rooting the consumer check at each checkpointed RDD (rather than at the 
PSD-reading RDD) is
     // what makes it cover a checkpoint anywhere DOWNSTREAM in the consumer 
stage, not just on the
     // reading RDD itself.
-    def chainHasReliableCheckpoint(root: RDD[_]): Boolean =
-      !traverseParentRDDsWithinStage(root, (r: RDD[_]) =>
-        !r.checkpointData.exists(_.isInstanceOf[ReliableRDDCheckpointData[_]]))
-    val offending =
-      // CONSUMER side: a checkpointed RDD whose own within-stage chain reads 
a pipelined shuffle is
-      // inside a consumer member stage (covers a checkpoint anywhere in that 
stage, not just on the
-      // reading RDD). PRODUCER side: a producer root's within-stage chain 
carries a checkpoint.
-      reliablyCheckpointed.exists(rddChainReadsPipelinedShuffle) ||
-        producerRoots.exists(chainHasReliableCheckpoint)
+    val offending = reliablyCheckpointed.nonEmpty && {
+      // Shared ancestry is visited once per search, not once per root. The 
two searches need
+      // separate visited sets because they have different predicates, even 
when roots overlap.
+      val consumerVisited = new HashSet[RDD[_]]
+      val producerVisited = new HashSet[RDD[_]]
+      reliablyCheckpointed.exists(rdd => rddChainReadsPipelinedShuffle(rdd, 
consumerVisited)) ||
+        producerRoots.exists { root =>
+          !traverseParentRDDsWithinStage(
+            root, (r: RDD[_]) => !reliablyCheckpointed.contains(r), 
producerVisited)
+        }
+    }
     if (offending) {
       throw pipelinedUnsupportedError(
         "a reliable RDD checkpoint in a pipelined-group member's within-stage 
chain")
     }
+    checkPipelinedStageCreation(finalRDD, partitions, jobId)
+  }
+
+  /** Validate the stages a native result job would create, without 
registering them. */
+  private def checkPipelinedStageCreation(
+      finalRDD: RDD[_], partitions: Array[Int], jobId: Int): Unit = {
+    val checkedShuffleIds = new HashSet[Int]
+    val pending = new ListBuffer[() => Unit]
+
+    def isRegistered(shuffleId: Int): Boolean =
+      checkedShuffleIds.contains(shuffleId) || 
shuffleIdToMapStage.contains(shuffleId)
+
+    def checkStage(rdd: RDD[_], numTasks: => Int): 
HashSet[ShuffleDependency[_, _, _]] = {
+      val (parents, profiles) = getShuffleDependenciesAndResourceProfiles(rdd)
+      val profile = mergeResourceProfilesForStage(profiles)
+      checkBarrierStage(rdd, profile, numTasks)
+      parents
+    }
+
+    def enqueueParents(parents: HashSet[ShuffleDependency[_, _, _]]): Unit = {
+      parents.toSeq.reverseIterator.foreach { dep =>
+        pending.prepend(() => checkShuffle(dep))
+      }
+    }
+
+    def checkNewStage(dep: ShuffleDependency[_, _, _]): Unit = {
+      val parents = checkStage(dep.rdd, dep.rdd.getNumPartitions)
+      checkPipelinedProducerSupported(dep)
+      outputTrackerMaster(dep)
+      pending.prepend(() => {
+        // Warm regular ancestors too, so native determinism does not recurse 
through a cold
+        // materialized prefix. This must happen after the parents have been 
checked.
+        dep.rdd.outputDeterministicLevel
+        checkedShuffleIds += dep.shuffleId
+        ()
+      })
+      enqueueParents(parents)

Review Comment:
   Thanks, added in 21ce72d9f0a: pipelined preflight: an owned parent of a new 
stage is rejected before registration. A new frontier stage reads the 
foreign-owned pipelined stage and a fresh pipelined sibling. Construction 
builds a missing ancestor before the frontier stage looks up its parents, so 
the sibling is always built first and the test needs no ordering.  Over two 
submissions it asserts the cross-job error, that no stage is constructed or 
registered with a tracker, that the shuffle-to-stage map is unchanged, and that 
only the owner job is active. With enqueueParents(parents) removed from 
checkNewStage, it fails on the unexpected createShuffleMapStage.



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