Skip to content

Commit 5d03069

Browse files
authored
Revert "fix(spanner): Avoid blocking thread in AsyncResultSet (#3446)"
This reverts commit 7c82f1c.
1 parent 7c82f1c commit 5d03069

File tree

13 files changed

+67
-333
lines changed

13 files changed

+67
-333
lines changed

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -768,14 +768,9 @@ ResultSet executeQueryInternalWithOptions(
768768
rpc.getExecuteQueryRetrySettings(),
769769
rpc.getExecuteQueryRetryableCodes()) {
770770
@Override
771-
CloseableIterator<PartialResultSet> startStream(
772-
@Nullable ByteString resumeToken,
773-
AsyncResultSet.StreamMessageListener streamListener) {
771+
CloseableIterator<PartialResultSet> startStream(@Nullable ByteString resumeToken) {
774772
GrpcStreamIterator stream =
775773
new GrpcStreamIterator(statement, prefetchChunks, cancelQueryWhenClientIsClosed);
776-
if (streamListener != null) {
777-
stream.registerListener(streamListener);
778-
}
779774
if (partitionToken != null) {
780775
request.setPartitionToken(partitionToken);
781776
}
@@ -796,8 +791,8 @@ CloseableIterator<PartialResultSet> startStream(
796791
getTransactionChannelHint(),
797792
isRouteToLeader());
798793
session.markUsed(clock.instant());
799-
stream.setCall(call, request.getTransaction().hasBegin());
800794
call.request(prefetchChunks);
795+
stream.setCall(call, request.getTransaction().hasBegin());
801796
return stream;
802797
}
803798

@@ -964,14 +959,9 @@ ResultSet readInternalWithOptions(
964959
rpc.getReadRetrySettings(),
965960
rpc.getReadRetryableCodes()) {
966961
@Override
967-
CloseableIterator<PartialResultSet> startStream(
968-
@Nullable ByteString resumeToken,
969-
AsyncResultSet.StreamMessageListener streamListener) {
962+
CloseableIterator<PartialResultSet> startStream(@Nullable ByteString resumeToken) {
970963
GrpcStreamIterator stream =
971964
new GrpcStreamIterator(prefetchChunks, cancelQueryWhenClientIsClosed);
972-
if (streamListener != null) {
973-
stream.registerListener(streamListener);
974-
}
975965
TransactionSelector selector = null;
976966
if (resumeToken != null) {
977967
builder.setResumeToken(resumeToken);
@@ -990,8 +980,8 @@ CloseableIterator<PartialResultSet> startStream(
990980
getTransactionChannelHint(),
991981
isRouteToLeader());
992982
session.markUsed(clock.instant());
993-
stream.setCall(call, /* withBeginTransaction = */ builder.getTransaction().hasBegin());
994983
call.request(prefetchChunks);
984+
stream.setCall(call, /* withBeginTransaction = */ builder.getTransaction().hasBegin());
995985
return stream;
996986
}
997987

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,6 @@ interface CloseableIterator<T> extends Iterator<T> {
150150
void close(@Nullable String message);
151151

152152
boolean isWithBeginTransaction();
153-
154-
/**
155-
* @param streamMessageListener A class object which implements StreamMessageListener
156-
* @return true if streaming is supported by the iterator, otherwise false
157-
*/
158-
default boolean initiateStreaming(AsyncResultSet.StreamMessageListener streamMessageListener) {
159-
return false;
160-
}
161153
}
162154

163155
static double valueProtoToFloat64(com.google.protobuf.Value proto) {

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSet.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import com.google.api.core.ApiFuture;
2020
import com.google.common.base.Function;
21-
import com.google.spanner.v1.PartialResultSet;
2221
import java.util.List;
2322
import java.util.concurrent.ExecutionException;
2423
import java.util.concurrent.Executor;
@@ -224,12 +223,4 @@ interface ReadyCallback {
224223
* @param transformer function which will be used to transform the row. It should not return null.
225224
*/
226225
<T> List<T> toList(Function<StructReader, T> transformer) throws SpannerException;
227-
228-
/**
229-
* An interface to register the listener for streaming gRPC request. It will be called when a
230-
* chunk is received from gRPC streaming call.
231-
*/
232-
interface StreamMessageListener {
233-
void onStreamMessage(PartialResultSet partialResultSet, boolean bufferIsFull);
234-
}
235226
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java

Lines changed: 21 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.google.api.core.ApiFuture;
2020
import com.google.api.core.ApiFutures;
21+
import com.google.api.core.ListenableFutureToApiFuture;
2122
import com.google.api.core.SettableApiFuture;
2223
import com.google.api.gax.core.ExecutorProvider;
2324
import com.google.cloud.spanner.AbstractReadContext.ListenableAsyncResultSet;
@@ -28,13 +29,13 @@
2829
import com.google.common.collect.ImmutableList;
2930
import com.google.common.util.concurrent.ListeningScheduledExecutorService;
3031
import com.google.common.util.concurrent.MoreExecutors;
31-
import com.google.spanner.v1.PartialResultSet;
3232
import com.google.spanner.v1.ResultSetMetadata;
3333
import com.google.spanner.v1.ResultSetStats;
3434
import java.util.Collection;
3535
import java.util.LinkedList;
3636
import java.util.List;
3737
import java.util.concurrent.BlockingDeque;
38+
import java.util.concurrent.Callable;
3839
import java.util.concurrent.CountDownLatch;
3940
import java.util.concurrent.ExecutionException;
4041
import java.util.concurrent.Executor;
@@ -44,14 +45,12 @@
4445
import java.util.logging.Logger;
4546

4647
/** Default implementation for {@link AsyncResultSet}. */
47-
class AsyncResultSetImpl extends ForwardingStructReader
48-
implements ListenableAsyncResultSet, AsyncResultSet.StreamMessageListener {
48+
class AsyncResultSetImpl extends ForwardingStructReader implements ListenableAsyncResultSet {
4949
private static final Logger log = Logger.getLogger(AsyncResultSetImpl.class.getName());
5050

5151
/** State of an {@link AsyncResultSetImpl}. */
5252
private enum State {
5353
INITIALIZED,
54-
STREAMING_INITIALIZED,
5554
/** SYNC indicates that the {@link ResultSet} is used in sync pattern. */
5655
SYNC,
5756
CONSUMING,
@@ -116,15 +115,12 @@ private enum State {
116115

117116
private State state = State.INITIALIZED;
118117

119-
/** This variable indicates that produce rows thread is initiated */
120-
private volatile boolean produceRowsInitiated;
121-
122118
/**
123119
* This variable indicates whether all the results from the underlying result set have been read.
124120
*/
125121
private volatile boolean finished;
126122

127-
private volatile SettableApiFuture<Void> result;
123+
private volatile ApiFuture<Void> result;
128124

129125
/**
130126
* This variable indicates whether {@link #tryNext()} has returned {@link CursorState#DONE} or a
@@ -333,12 +329,12 @@ public void run() {
333329
private final CallbackRunnable callbackRunnable = new CallbackRunnable();
334330

335331
/**
336-
* {@link ProduceRowsRunnable} reads data from the underlying {@link ResultSet}, places these in
332+
* {@link ProduceRowsCallable} reads data from the underlying {@link ResultSet}, places these in
337333
* the buffer and dispatches the {@link CallbackRunnable} when data is ready to be consumed.
338334
*/
339-
private class ProduceRowsRunnable implements Runnable {
335+
private class ProduceRowsCallable implements Callable<Void> {
340336
@Override
341-
public void run() {
337+
public Void call() throws Exception {
342338
boolean stop = false;
343339
boolean hasNext = false;
344340
try {
@@ -397,17 +393,12 @@ public void run() {
397393
}
398394
// Call the callback if there are still rows in the buffer that need to be processed.
399395
while (!stop) {
400-
try {
401-
waitIfPaused();
402-
startCallbackIfNecessary();
403-
// Make sure we wait until the callback runner has actually finished.
404-
consumingLatch.await();
405-
synchronized (monitor) {
406-
stop = cursorReturnedDoneOrException;
407-
}
408-
} catch (Throwable e) {
409-
result.setException(e);
410-
return;
396+
waitIfPaused();
397+
startCallbackIfNecessary();
398+
// Make sure we wait until the callback runner has actually finished.
399+
consumingLatch.await();
400+
synchronized (monitor) {
401+
stop = cursorReturnedDoneOrException;
411402
}
412403
}
413404
} finally {
@@ -419,14 +410,14 @@ public void run() {
419410
}
420411
synchronized (monitor) {
421412
if (executionException != null) {
422-
result.setException(executionException);
423-
} else if (state == State.CANCELLED) {
424-
result.setException(CANCELLED_EXCEPTION);
425-
} else {
426-
result.set(null);
413+
throw executionException;
414+
}
415+
if (state == State.CANCELLED) {
416+
throw CANCELLED_EXCEPTION;
427417
}
428418
}
429419
}
420+
return null;
430421
}
431422

432423
private void waitIfPaused() throws InterruptedException {
@@ -458,26 +449,6 @@ private void startCallbackWithBufferLatchIfNecessary(int bufferLatch) {
458449
}
459450
}
460451

461-
private class InitiateStreamingRunnable implements Runnable {
462-
463-
@Override
464-
public void run() {
465-
try {
466-
// This method returns true if the underlying result set is a streaming result set (e.g. a
467-
// GrpcResultSet).
468-
// Those result sets will trigger initiateProduceRows() when the first results are received.
469-
// Non-streaming result sets do not trigger this callback, and for those result sets, we
470-
// need to eagerly start the ProduceRowsRunnable.
471-
if (!initiateStreaming(AsyncResultSetImpl.this)) {
472-
initiateProduceRows();
473-
}
474-
} catch (Throwable exception) {
475-
executionException = SpannerExceptionFactory.asSpannerException(exception);
476-
initiateProduceRows();
477-
}
478-
}
479-
}
480-
481452
/** Sets the callback for this {@link AsyncResultSet}. */
482453
@Override
483454
public ApiFuture<Void> setCallback(Executor exec, ReadyCallback cb) {
@@ -487,24 +458,16 @@ public ApiFuture<Void> setCallback(Executor exec, ReadyCallback cb) {
487458
this.state == State.INITIALIZED, "callback may not be set multiple times");
488459

489460
// Start to fetch data and buffer these.
490-
this.result = SettableApiFuture.create();
491-
this.state = State.STREAMING_INITIALIZED;
492-
this.service.execute(new InitiateStreamingRunnable());
461+
this.result =
462+
new ListenableFutureToApiFuture<>(this.service.submit(new ProduceRowsCallable()));
493463
this.executor = MoreExecutors.newSequentialExecutor(Preconditions.checkNotNull(exec));
494464
this.callback = Preconditions.checkNotNull(cb);
465+
this.state = State.RUNNING;
495466
pausedLatch.countDown();
496467
return result;
497468
}
498469
}
499470

500-
private void initiateProduceRows() {
501-
if (this.state == State.STREAMING_INITIALIZED) {
502-
this.state = State.RUNNING;
503-
}
504-
produceRowsInitiated = true;
505-
this.service.execute(new ProduceRowsRunnable());
506-
}
507-
508471
Future<Void> getResult() {
509472
return result;
510473
}
@@ -615,10 +578,6 @@ public ResultSetMetadata getMetadata() {
615578
return delegateResultSet.get().getMetadata();
616579
}
617580

618-
boolean initiateStreaming(StreamMessageListener streamMessageListener) {
619-
return StreamingUtil.initiateStreaming(delegateResultSet.get(), streamMessageListener);
620-
}
621-
622581
@Override
623582
protected void checkValidState() {
624583
synchronized (monitor) {
@@ -634,22 +593,4 @@ public Struct getCurrentRowAsStruct() {
634593
checkValidState();
635594
return currentRow;
636595
}
637-
638-
@Override
639-
public void onStreamMessage(PartialResultSet partialResultSet, boolean bufferIsFull) {
640-
synchronized (monitor) {
641-
if (produceRowsInitiated) {
642-
return;
643-
}
644-
// if PartialResultSet contains a resume token or buffer size is full, or
645-
// we have reached the end of the stream, we can start the thread.
646-
boolean startJobThread =
647-
!partialResultSet.getResumeToken().isEmpty()
648-
|| bufferIsFull
649-
|| partialResultSet == GrpcStreamIterator.END_OF_STREAM;
650-
if (startJobThread || state != State.STREAMING_INITIALIZED) {
651-
initiateProduceRows();
652-
}
653-
}
654-
}
655596
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,14 @@
1616

1717
package com.google.cloud.spanner;
1818

19-
import com.google.api.core.InternalApi;
2019
import com.google.common.base.Preconditions;
2120
import com.google.common.base.Supplier;
2221
import com.google.common.base.Suppliers;
2322
import com.google.spanner.v1.ResultSetMetadata;
2423
import com.google.spanner.v1.ResultSetStats;
2524

2625
/** Forwarding implementation of ResultSet that forwards all calls to a delegate. */
27-
public class ForwardingResultSet extends ForwardingStructReader
28-
implements ProtobufResultSet, StreamingResultSet {
26+
public class ForwardingResultSet extends ForwardingStructReader implements ProtobufResultSet {
2927

3028
private Supplier<? extends ResultSet> delegate;
3129

@@ -104,10 +102,4 @@ public ResultSetStats getStats() {
104102
public ResultSetMetadata getMetadata() {
105103
return delegate.get().getMetadata();
106104
}
107-
108-
@Override
109-
@InternalApi
110-
public boolean initiateStreaming(AsyncResultSet.StreamMessageListener streamMessageListener) {
111-
return StreamingUtil.initiateStreaming(delegate.get(), streamMessageListener);
112-
}
113105
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/GrpcResultSet.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import static com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException;
2020
import static com.google.common.base.Preconditions.checkState;
2121

22-
import com.google.api.core.InternalApi;
2322
import com.google.common.annotations.VisibleForTesting;
2423
import com.google.protobuf.Value;
2524
import com.google.spanner.v1.PartialResultSet;
@@ -31,8 +30,7 @@
3130
import javax.annotation.Nullable;
3231

3332
@VisibleForTesting
34-
class GrpcResultSet extends AbstractResultSet<List<Object>>
35-
implements ProtobufResultSet, StreamingResultSet {
33+
class GrpcResultSet extends AbstractResultSet<List<Object>> implements ProtobufResultSet {
3634
private final GrpcValueIterator iterator;
3735
private final Listener listener;
3836
private final DecodeMode decodeMode;
@@ -125,12 +123,6 @@ public ResultSetMetadata getMetadata() {
125123
return metadata;
126124
}
127125

128-
@Override
129-
@InternalApi
130-
public boolean initiateStreaming(AsyncResultSet.StreamMessageListener streamMessageListener) {
131-
return iterator.initiateStreaming(streamMessageListener);
132-
}
133-
134126
@Override
135127
public void close() {
136128
synchronized (this) {

0 commit comments

Comments
 (0)