Skip to content

Commit c540cac

Browse files
committed
refactor(batch): structure Send and Recv as CompletableFutures
1 parent 1303422 commit c540cac

1 file changed

Lines changed: 39 additions & 35 deletions

File tree

src/main/java/io/weaviate/client6/v1/api/collections/batch/BatchContext.java

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@
1414
import java.util.concurrent.CompletableFuture;
1515
import java.util.concurrent.ConcurrentHashMap;
1616
import java.util.concurrent.ConcurrentMap;
17-
import java.util.concurrent.CountDownLatch;
1817
import java.util.concurrent.ExecutionException;
1918
import java.util.concurrent.ExecutorService;
2019
import java.util.concurrent.Executors;
21-
import java.util.concurrent.Future;
2220
import java.util.concurrent.ScheduledExecutorService;
2321
import java.util.concurrent.ScheduledFuture;
2422
import java.util.concurrent.TimeUnit;
@@ -64,8 +62,8 @@
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

Comments
 (0)