24
24
import java .util .Iterator ;
25
25
import java .util .List ;
26
26
import java .util .concurrent .Executor ;
27
+ import java .util .concurrent .atomic .AtomicBoolean ;
27
28
import java .util .concurrent .atomic .AtomicReference ;
28
29
import java .util .function .Supplier ;
29
30
import java .util .stream .Collectors ;
@@ -56,6 +57,10 @@ public class Driver implements Releasable, Describable {
56
57
57
58
private final AtomicReference <String > cancelReason = new AtomicReference <>();
58
59
private final AtomicReference <SubscribableListener <Void >> blocked = new AtomicReference <>();
60
+
61
+ private final AtomicBoolean started = new AtomicBoolean ();
62
+ private final SubscribableListener <Void > completionListener = new SubscribableListener <>();
63
+
59
64
/**
60
65
* Status reported to the tasks API. We write the status at most once every
61
66
* {@link #statusNanos}, as soon as loop has finished and after {@link #statusNanos}
@@ -149,7 +154,7 @@ private SubscribableListener<Void> run(TimeValue maxTime, int maxIterations) {
149
154
if (isFinished ()) {
150
155
status .set (updateStatus (DriverStatus .Status .DONE ));
151
156
driverContext .finish ();
152
- releasable .close ();
157
+ Releasables .close (releasable , driverContext . getSnapshot () );
153
158
} else {
154
159
status .set (updateStatus (DriverStatus .Status .WAITING ));
155
160
}
@@ -159,7 +164,7 @@ private SubscribableListener<Void> run(TimeValue maxTime, int maxIterations) {
159
164
/**
160
165
* Whether the driver has run the chain of operators to completion.
161
166
*/
162
- public boolean isFinished () {
167
+ private boolean isFinished () {
163
168
return activeOperators .isEmpty ();
164
169
}
165
170
@@ -168,6 +173,19 @@ public void close() {
168
173
drainAndCloseOperators (null );
169
174
}
170
175
176
+ /**
177
+ * Abort the driver and wait for it to finish
178
+ */
179
+ public void abort (Exception reason , ActionListener <Void > listener ) {
180
+ completionListener .addListener (listener );
181
+ if (started .compareAndSet (false , true )) {
182
+ drainAndCloseOperators (reason );
183
+ completionListener .onFailure (reason );
184
+ } else {
185
+ cancel (reason .getMessage ());
186
+ }
187
+ }
188
+
171
189
private SubscribableListener <Void > runSingleLoopIteration () {
172
190
ensureNotCancelled ();
173
191
boolean movedPage = false ;
@@ -261,8 +279,11 @@ public static void start(
261
279
int maxIterations ,
262
280
ActionListener <Void > listener
263
281
) {
264
- driver .status .set (driver .updateStatus (DriverStatus .Status .STARTING ));
265
- schedule (DEFAULT_TIME_BEFORE_YIELDING , maxIterations , threadContext , executor , driver , listener );
282
+ driver .completionListener .addListener (listener );
283
+ if (driver .started .compareAndSet (false , true )) {
284
+ driver .status .set (driver .updateStatus (DriverStatus .Status .STARTING ));
285
+ schedule (DEFAULT_TIME_BEFORE_YIELDING , maxIterations , threadContext , executor , driver , driver .completionListener );
286
+ }
266
287
}
267
288
268
289
// Drains all active operators and closes them.
@@ -279,7 +300,7 @@ private void drainAndCloseOperators(@Nullable Exception e) {
279
300
itr .remove ();
280
301
}
281
302
driverContext .finish ();
282
- Releasables .closeWhileHandlingException (releasable );
303
+ Releasables .closeWhileHandlingException (releasable , driverContext . getSnapshot () );
283
304
}
284
305
285
306
private static void schedule (
0 commit comments