@@ -78,8 +78,13 @@ trait ShuffleExchangeLike extends Exchange {
78
78
private [sql] // Exposed for testing
79
79
val futureAction = new AtomicReference [Option [FutureAction [MapOutputStatistics ]]](None )
80
80
81
+ @ volatile
81
82
@ transient
82
- private val isCancelled : AtomicReference [Boolean ] = new AtomicReference (false )
83
+ private var isCancelled : Boolean = false
84
+
85
+ @ volatile
86
+ @ transient
87
+ private var quietly : Boolean = false
83
88
84
89
@ transient
85
90
private lazy val triggerFuture : java.util.concurrent.Future [Any ] = {
@@ -90,7 +95,7 @@ trait ShuffleExchangeLike extends Exchange {
90
95
executeQuery(null )
91
96
// Submit shuffle job if not cancelled.
92
97
this .synchronized {
93
- if (isCancelled.get ) {
98
+ if (isCancelled && ! quietly ) {
94
99
promise.tryFailure(new SparkException (" Shuffle cancelled." ))
95
100
} else {
96
101
val shuffleJob = RDDOperationScope .withScope(sparkContext, nodeName, false , true ) {
@@ -125,15 +130,15 @@ trait ShuffleExchangeLike extends Exchange {
125
130
* Cancels the shuffle job with an optional reason.
126
131
*/
127
132
final def cancelShuffleJob (reason : Option [String ], quiet : Boolean ): Unit = this .synchronized {
128
- if (! isCancelled.get) {
129
- if (quiet) {
130
- // tryFailure before isCancelled.set(true) to avoid concurrent issue with triggerFuture
131
- promise.tryFailure(new SparkAQEStageCancelException ())
133
+ this .synchronized {
134
+ if (! isCancelled) {
135
+ isCancelled = true
136
+ if (quiet) {
137
+ quietly = quiet
138
+ promise.tryFailure(new SparkAQEStageCancelException )
139
+ }
140
+ futureAction.get().foreach(_.cancel(reason, quiet))
132
141
}
133
- isCancelled.set(true )
134
- // this may take no effect, if the job has already been submitted
135
- // but futureAction is not set yet, it's a best effort to cancel it
136
- futureAction.get().foreach(_.cancel(reason, quiet))
137
142
}
138
143
}
139
144
0 commit comments