1414import java .util .concurrent .CompletableFuture ;
1515import java .util .concurrent .ConcurrentHashMap ;
1616import java .util .concurrent .ConcurrentMap ;
17- import java .util .concurrent .CountDownLatch ;
1817import java .util .concurrent .ExecutionException ;
1918import java .util .concurrent .ExecutorService ;
2019import java .util .concurrent .Executors ;
21- import java .util .concurrent .Future ;
2220import java .util .concurrent .ScheduledExecutorService ;
2321import java .util .concurrent .ScheduledFuture ;
2422import java .util .concurrent .TimeUnit ;
6462 * of the operations to its parent BatchContext.
6563 *
6664 * <p>
67- * Collectively, "sender" and " recv" are referred to as "workers".
68- * After both "workers" exit the {@link #workers} count is expected to be 0 .
65+ * {@link #send} and {@link # recv} futures track completion of the "sender"
66+ * and "recv" routines .
6967 *
7068 * <h2>State</h2>
7169 *
@@ -206,15 +204,19 @@ public final class BatchContext<PropertiesT> implements Closeable {
206204 */
207205 private volatile StreamObserver <Message > messages ;
208206
209- /** Handle for the "send" thread. Use {@link Future#cancel} to interrupt it. */
210- private volatile Future <?> send ;
207+ /**
208+ * Handle for the "sender" routine.
209+ * Cancel this future to interrupt the "sender".
210+ *
211+ * @see Send#cancel
212+ */
213+ private final Send send = new Send ();
211214
212215 /**
213- * Latch reaches zero once both "send" (client side) and "recv" (server side)
214- * parts of the stream have closed. After a {@link #reconnect}, the latch is
215- * reset.
216+ * Indicates completion of the "recv" routine.
217+ * Canceling this future will have no effect.
216218 */
217- private volatile CountDownLatch workers ;
219+ private volatile Recv recv ;
218220
219221 /** closing completes the stream. */
220222 private final CompletableFuture <Void > closing = new CompletableFuture <>();
@@ -274,18 +276,16 @@ void start() {
274276 throw new IllegalStateException ("context is closed" );
275277 }
276278
277- workers = new CountDownLatch (2 );
278-
279- messages = streamFactory .createStream (new Recv ());
279+ messages = streamFactory .createStream (recv = new Recv ());
280280 messages .onNext (Message .start (collectionHandleDefaults .consistencyLevel ()));
281281
282282 // "send" routine must start after the nextState has been set.
283283 setState (AWAIT_STARTED );
284- send = sendService .submit ( new Send () );
284+ sendService .execute (( Runnable ) send );
285285 }
286286
287287 /**
288- * Reconnect resets {@link #workers} latch and re-creates the stream .
288+ * Reconnect re-creates the stream and renews the {@link #recv} future .
289289 *
290290 * <p>
291291 * Unlike {@link #start} it does not trigger a state transition, and
@@ -294,16 +294,14 @@ void start() {
294294 * is reached.
295295 */
296296 void reconnect () throws InterruptedException , ExecutionException {
297- // We do not need to wait for the current latch to be "opened".
298297 // The "sender" survives reconnects and will not call countDown
299298 // until it's interrupted or the context is closed.
300299 // The "recv" thread is guaranteed to have already exited, because
301300 // the context can only transition into the Reconnecting state
302301 // after the server half of the stream is closed (EOF or hangup).
303- assert workers .getCount () == 1 : "recv must exit before reconnect" ;
304- workers = new CountDownLatch (2 );
302+ recv .get ();
305303
306- messages = streamFactory .createStream (new Recv ());
304+ messages = streamFactory .createStream (recv = new Recv ());
307305 messages .onNext (Message .start (collectionHandleDefaults .consistencyLevel ()));
308306 }
309307
@@ -363,15 +361,8 @@ private void shutdown() {
363361 // Luckily, shutdownNow resolves the `closing` future as well.
364362 queue .put (TaskHandle .POISON );
365363
366- // Wait for the send to exit before closing our end of the stream.
367- try {
368- send .get ();
369- } catch (CancellationException ignored ) {
370- // "sender" can be cancelled due to a reconnect or an internal error.
371- }
372-
373364 // Wait for both "send" and "recv" to exit.
374- workers . await ();
365+ CompletableFuture . allOf ( send , recv ). get ();
375366 closing .complete (null );
376367 } catch (Exception e ) {
377368 closing .completeExceptionally (e );
@@ -490,7 +481,7 @@ private TaskHandle add(final TaskHandle taskHandle) throws InterruptedException
490481 return taskHandle ;
491482 }
492483
493- private final class Send implements Runnable {
484+ private final class Send extends CompletableFuture < Void > implements Runnable {
494485
495486 @ Override
496487 public void run () {
@@ -499,10 +490,17 @@ public void run() {
499490 try {
500491 trySend ();
501492 } finally {
502- System .out .println ("sender countDown" );
503- workers .countDown ();
504493 Thread .currentThread ().setName (threadName );
494+ complete (null );
495+ }
496+ }
497+
498+ @ Override
499+ public boolean cancel (boolean mayInterruptIfRunning ) {
500+ if (mayInterruptIfRunning ) {
501+ Thread .currentThread ().interrupt ();
505502 }
503+ return mayInterruptIfRunning ;
506504 }
507505
508506 /**
@@ -620,7 +618,7 @@ private void awaitCanPrepareNext() throws InterruptedException {
620618 }
621619 }
622620
623- private final class Recv implements StreamObserver <Event > {
621+ private final class Recv extends CompletableFuture < Void > implements StreamObserver <Event > {
624622
625623 @ Override
626624 public void onNext (Event event ) {
@@ -634,15 +632,21 @@ public void onNext(Event event) {
634632 */
635633 @ Override
636634 public void onCompleted () {
637- workers .countDown ();
638- onEvent (Event .EOF );
635+ try {
636+ onEvent (Event .EOF );
637+ } finally {
638+ complete (null );
639+ }
639640 }
640641
641642 /** An exception occurred either on our end or in the channel internals. */
642643 @ Override
643644 public void onError (Throwable t ) {
644- workers .countDown ();
645- onEvent (Event .StreamHangup .fromThrowable (t ));
645+ try {
646+ onEvent (Event .StreamHangup .fromThrowable (t ));
647+ } finally {
648+ complete (null );
649+ }
646650 }
647651 }
648652
0 commit comments