Chao Sun created SPARK-59094:
--------------------------------
Summary: Ignore late successes from invalidated barrier shuffle
attempts
Key: SPARK-59094
URL: https://issues.apache.org/jira/browse/SPARK-59094
Project: Spark
Issue Type: Bug
Components: Spark Core
Affects Versions: 5.0.0
Reporter: Chao Sun
A deterministic barrier shuffle stage can accept a late successful task result
after failure recovery has invalidated the entire stage attempt. The old result
can remove a participant from the replacement barrier stage or mark a
replacement partition complete before it launches.
The [barrier execution
contract|https://spark.apache.org/docs/latest/api/java/org/apache/spark/rdd/RDD.html#barrier()]
requires all tasks in a barrier stage to be relaunched when one task fails.
Deterministic output does not make it safe to omit one of those participants.
Upstream draft PR:
[apache/spark#58402|https://github.com/apache/spark/pull/58402].
h3. Reproduction ordering
# Run a deterministic two-partition {{RDD.barrier().mapPartitions(...)}}
followed by a normal shuffle and {{collect()}}, using {{SortShuffleManager}}.
Both tasks call {{BarrierTaskContext.barrier()}}. Let partition 0 finish its
shuffle output, but delay delivery of its successful completion to the driver.
# Fail partition 1 once. Spark fails the barrier stage and unregisters all of
its map outputs so that both partitions should run in the next attempt.
# Deliver partition 0's old success either before resubmission, or after the
replacement task set is submitted but before its tasks launch.
A native local-mode reproducer uses an executor plugin's {{onTaskSucceeded}}
hook to hold only the completed task's success delivery. The peer failure,
scheduler recovery, shuffle files, and downstream read use normal Spark
execution; no constructed map statuses or scheduler-state writes are used. For
the second ordering, an unrelated one-task job temporarily occupies one of the
two execution slots.
h3. Reproduction results
Reproduced on a fresh public Spark {{5.0.0-SNAPSHOT}} build at upstream commit
{{024120dc960517021a887b51865220f544340362}}, using Scala {{2.13.18}}. The
native runs used Java {{21.0.12}} and {{SortShuffleManager}}; the RDD reports
{{DETERMINATE}} output. The probe configures a three-second barrier timeout.
|| Delivery ordering || Unpatched behavior ||
| After failure, before resubmission | The two-task attempt is retried with
only one task, whose context still expects two participants. Barrier
synchronization times out. A two-attempt limit aborts the job; a four-attempt
limit allows an additional complete retry and successful readback. |
| After resubmission, with one slot temporarily occupied | The replacement has
{{successful=[true,false]}} and no running tasks. It does not launch after the
slot is released and before the 20-second job watchdog explicitly cancels it. |
The watchdog deadline is measured from the main job's start, not from slot
release; the latter precedes cancellation by about 17 seconds in this run. This
is a bounded stall followed by probe cancellation, not an observed permanent
hang or a Spark-triggered abort.
Late success after resubmission without deliberately blocked slots, a no-delay
barrier control, and an ordinary non-barrier control all succeed. The unblocked
case releases success on stage submission; it does not force delivery to wait
until both replacement tasks have launched.
With [candidate fix
daef30b0e585|https://github.com/sunchao/spark/commit/daef30b0e585c80786c2cc1f9304ce81204a190f],
all six matched native scenarios succeed and assert {{Seq((0, 0), (1, 1))}}.
Every barrier retry contains both tasks; the blocked case retains
{{successful=[false,false]}} until both tasks launch after slot release. All
completed scenarios satisfy their probe preconditions.
Separately, direct ScalaTest runs on JDK 17 give six new regression failures
and 225 passes in the unpatched {{DAGSchedulerSuite}}, then 352 passes across
the patched {{DAGSchedulerSuite}} and {{TaskSchedulerImplSuite}}. This
validates the tested development snapshot, not a released version or a backport.
h3. Cause and proposed scope
In [DAGScheduler at upstream commit
024120dc960517021a887b51865220f544340362|https://github.com/apache/spark/blob/024120dc960517021a887b51865220f544340362/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala#L3334],
accepted old successes can notify the task scheduler that a partition is
complete and register its map output. A barrier task failure, including a fetch
failure within a barrier shuffle stage, clears that failed stage's outputs
without marking the invalidated attempt's results to be ignored. Before
resubmission, a late registration changes the missing-partition set; after
resubmission, the completion notification can suppress a required participant.
The proposed change is limited to the two paths that clear the outputs of a
barrier shuffle stage that has itself failed:
* An ordinary barrier task failure.
* A fetch failure within that barrier shuffle stage.
Use the existing stage-attempt rollback marker to invalidate successful
completions from that failed attempt, including the interval before a new
attempt exists. Preserve valid replacement-attempt results and Spark's existing
reuse of old deterministic results for ordinary non-barrier stages. Do not
change the separate upstream barrier-producer invalidation path: a fetch
failure reported by a downstream consumer must not invalidate an
already-running retry of its barrier producer merely because that producer's
outputs are cleared.
This is related to
[SPARK-45182|https://issues.apache.org/jira/browse/SPARK-45182],
[SPARK-54556|https://issues.apache.org/jira/browse/SPARK-54556], and
[SPARK-54956|https://issues.apache.org/jira/browse/SPARK-54956], which address
old results during indeterminate or checksum-driven rollback.
[SPARK-25161|https://issues.apache.org/jira/browse/SPARK-25161] covers barrier
failure handling, including old failure events. This report concerns successful
completions from a deterministic barrier attempt that has been invalidated.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]