@@ -85,7 +85,7 @@ public class StreamWriter implements AutoCloseable {
8585
8686 private final BatchingSettings batchingSettings ;
8787 private final RetrySettings retrySettings ;
88- private final BigQueryWriteSettings stubSettings ;
88+ private BigQueryWriteSettings stubSettings ;
8989
9090 private final Lock messagesBatchLock ;
9191 private final MessagesBatch messagesBatch ;
@@ -142,13 +142,21 @@ private StreamWriter(Builder builder)
142142 messagesWaiter = new Waiter (this .batchingSettings .getFlowControlSettings ());
143143 responseObserver = new AppendResponseObserver (this );
144144
145- stubSettings =
146- BigQueryWriteSettings .newBuilder ()
147- .setCredentialsProvider (builder .credentialsProvider )
148- .setExecutorProvider (builder .executorProvider )
149- .setTransportChannelProvider (builder .channelProvider )
150- .setEndpoint (builder .endpoint )
151- .build ();
145+ if (builder .client == null ) {
146+ stubSettings =
147+ BigQueryWriteSettings .newBuilder ()
148+ .setCredentialsProvider (builder .credentialsProvider )
149+ .setExecutorProvider (builder .executorProvider )
150+ .setTransportChannelProvider (builder .channelProvider )
151+ .setEndpoint (builder .endpoint )
152+ .build ();
153+ stub = BigQueryWriteClient .create (stubSettings );
154+ backgroundResourceList .add (stub );
155+ } else {
156+ stub = builder .client ;
157+ }
158+ backgroundResources = new BackgroundResourceAggregation (backgroundResourceList );
159+
152160 shutdown = new AtomicBoolean (false );
153161 refreshAppend ();
154162 Stream .WriteStream stream =
@@ -240,15 +248,10 @@ public ApiFuture<AppendRowsResponse> append(AppendRowsRequest message) {
240248 public void refreshAppend () throws IOException , InterruptedException {
241249 synchronized (this ) {
242250 Preconditions .checkState (!shutdown .get (), "Cannot append on a shut-down writer." );
243- if (stub != null ) {
251+ // There could be a moment, stub is not yet initialized.
252+ if (clientStream != null ) {
244253 clientStream .closeSend ();
245- stub .shutdown ();
246- stub .awaitTermination (1 , TimeUnit .MINUTES );
247254 }
248- backgroundResourceList .remove (stub );
249- stub = BigQueryWriteClient .create (stubSettings );
250- backgroundResourceList .add (stub );
251- backgroundResources = new BackgroundResourceAggregation (backgroundResourceList );
252255 messagesBatch .resetAttachSchema ();
253256 bidiStreamingCallable = stub .appendRowsCallable ();
254257 clientStream = bidiStreamingCallable .splitCall (responseObserver );
@@ -314,14 +317,12 @@ public void writeAllOutstanding() {
314317 private void writeBatch (final InflightBatch inflightBatch ) {
315318 if (inflightBatch != null ) {
316319 AppendRowsRequest request = inflightBatch .getMergedRequest ();
317- messagesWaiter .waitOnElementCount ();
318- messagesWaiter .waitOnSizeLimit (inflightBatch .getByteSize ());
319- responseObserver .addInflightBatch (inflightBatch );
320- clientStream .send (request );
321-
322- synchronized (messagesWaiter ) {
323- messagesWaiter .incrementPendingCount (1 );
324- messagesWaiter .incrementPendingSize (inflightBatch .getByteSize ());
320+ try {
321+ messagesWaiter .acquire (inflightBatch .getByteSize ());
322+ responseObserver .addInflightBatch (inflightBatch );
323+ clientStream .send (request );
324+ } catch (FlowController .FlowControlException ex ) {
325+ inflightBatch .onFailure (ex );
325326 }
326327 }
327328 }
@@ -346,14 +347,14 @@ private static final class InflightBatch {
346347 final ArrayList <Long > offsetList ;
347348 final long creationTime ;
348349 int attempt ;
349- int batchSizeBytes ;
350+ long batchSizeBytes ;
350351 long expectedOffset ;
351352 Boolean attachSchema ;
352353 String streamName ;
353354
354355 InflightBatch (
355356 List <AppendRequestAndFutureResponse > inflightRequests ,
356- int batchSizeBytes ,
357+ long batchSizeBytes ,
357358 String streamName ,
358359 Boolean attachSchema ) {
359360 this .inflightRequests = inflightRequests ;
@@ -377,7 +378,7 @@ int count() {
377378 return inflightRequests .size ();
378379 }
379380
380- int getByteSize () {
381+ long getByteSize () {
381382 return this .batchSizeBytes ;
382383 }
383384
@@ -478,7 +479,9 @@ public void shutdown() {
478479 currentAlarmFuture .cancel (false );
479480 }
480481 writeAllOutstanding ();
481- messagesWaiter .waitComplete ();
482+ synchronized (messagesWaiter ) {
483+ messagesWaiter .waitComplete ();
484+ }
482485 if (clientStream .isSendReady ()) {
483486 clientStream .closeSend ();
484487 }
@@ -496,7 +499,7 @@ public boolean awaitTermination(long duration, TimeUnit unit) throws Interrupted
496499 }
497500
498501 /**
499- * Constructs a new {@link Builder} using the given topic .
502+ * Constructs a new {@link Builder} using the given stream .
500503 *
501504 * <p>Example of creating a {@code WriteStream}.
502505 *
@@ -514,7 +517,15 @@ public boolean awaitTermination(long duration, TimeUnit unit) throws Interrupted
514517 * }</pre>
515518 */
516519 public static Builder newBuilder (String streamName ) {
517- return new Builder (streamName );
520+ return new Builder (streamName , null );
521+ }
522+
523+ /**
524+ * Constructs a new {@link Builder} using the given stream and an existing BigQueryWriteClient.
525+ */
526+ public static Builder newBuilder (String streamName , BigQueryWriteClient client ) {
527+ Preconditions .checkArgument (client != null );
528+ return new Builder (streamName , client );
518529 }
519530
520531 /** A builder of {@link StreamWriter}s. */
@@ -523,9 +534,6 @@ public static final class Builder {
523534 static final Duration MIN_RPC_TIMEOUT = Duration .ofMillis (10 );
524535
525536 // Meaningful defaults.
526- static final long DEFAULT_ELEMENT_COUNT_THRESHOLD = 100L ;
527- static final long DEFAULT_REQUEST_BYTES_THRESHOLD = 100 * 1024L ; // 100 kB
528- static final Duration DEFAULT_DELAY_THRESHOLD = Duration .ofMillis (10 );
529537 static final FlowControlSettings DEFAULT_FLOW_CONTROL_SETTINGS =
530538 FlowControlSettings .newBuilder ()
531539 .setLimitExceededBehavior (FlowController .LimitExceededBehavior .Block )
@@ -534,9 +542,9 @@ public static final class Builder {
534542 .build ();
535543 public static final BatchingSettings DEFAULT_BATCHING_SETTINGS =
536544 BatchingSettings .newBuilder ()
537- .setDelayThreshold (DEFAULT_DELAY_THRESHOLD )
538- .setRequestByteThreshold (DEFAULT_REQUEST_BYTES_THRESHOLD )
539- .setElementCountThreshold (DEFAULT_ELEMENT_COUNT_THRESHOLD )
545+ .setDelayThreshold (Duration . ofMillis ( 10 ) )
546+ .setRequestByteThreshold (100 * 1024L ) // 100 kb
547+ .setElementCountThreshold (100L )
540548 .setFlowControlSettings (DEFAULT_FLOW_CONTROL_SETTINGS )
541549 .build ();
542550 public static final RetrySettings DEFAULT_RETRY_SETTINGS =
@@ -555,6 +563,8 @@ public static final class Builder {
555563 private String streamName ;
556564 private String endpoint = BigQueryWriteSettings .getDefaultEndpoint ();
557565
566+ private BigQueryWriteClient client = null ;
567+
558568 // Batching options
559569 BatchingSettings batchingSettings = DEFAULT_BATCHING_SETTINGS ;
560570
@@ -569,8 +579,9 @@ public static final class Builder {
569579 private CredentialsProvider credentialsProvider =
570580 BigQueryWriteSettings .defaultCredentialsProviderBuilder ().build ();
571581
572- private Builder (String stream ) {
582+ private Builder (String stream , BigQueryWriteClient client ) {
573583 this .streamName = Preconditions .checkNotNull (stream );
584+ this .client = client ;
574585 }
575586
576587 /**
@@ -771,11 +782,7 @@ public void onResponse(AppendRowsResponse response) {
771782 inflightBatch .onSuccess (response );
772783 }
773784 } finally {
774- synchronized (streamWriter .messagesWaiter ) {
775- streamWriter .messagesWaiter .incrementPendingCount (-1 );
776- streamWriter .messagesWaiter .incrementPendingSize (0 - inflightBatch .getByteSize ());
777- streamWriter .messagesWaiter .notifyAll ();
778- }
785+ streamWriter .messagesWaiter .release (inflightBatch .getByteSize ());
779786 }
780787 }
781788
@@ -805,11 +812,11 @@ public void onError(Throwable t) {
805812 && !streamWriter .shutdown .get ()) {
806813 streamWriter .refreshAppend ();
807814 // Currently there is a bug that it took reconnected stream 5 seconds to pick up
808- // stream count. So wait at least 5 seconds before sending a new request.
815+ // stream count. So wait at least 7 seconds before sending a new request.
809816 Thread .sleep (
810817 Math .min (
811818 streamWriter .getRetrySettings ().getInitialRetryDelay ().toMillis (),
812- Duration .ofSeconds (5 ).toMillis ()));
819+ Duration .ofSeconds (7 ).toMillis ()));
813820 streamWriter .writeBatch (inflightBatch );
814821 synchronized (streamWriter .currentRetries ) {
815822 streamWriter .currentRetries ++;
@@ -837,19 +844,15 @@ public void onError(Throwable t) {
837844 }
838845 }
839846 } finally {
840- synchronized (streamWriter .messagesWaiter ) {
841- streamWriter .messagesWaiter .incrementPendingCount (-1 );
842- streamWriter .messagesWaiter .incrementPendingSize (0 - inflightBatch .getByteSize ());
843- streamWriter .messagesWaiter .notifyAll ();
844- }
847+ streamWriter .messagesWaiter .release (inflightBatch .getByteSize ());
845848 }
846849 }
847850 };
848851
849852 // This class controls how many messages are going to be sent out in a batch.
850853 private static class MessagesBatch {
851854 private List <AppendRequestAndFutureResponse > messages ;
852- private int batchedBytes ;
855+ private long batchedBytes ;
853856 private final BatchingSettings batchingSettings ;
854857 private Boolean attachSchema = true ;
855858 private final String streamName ;
@@ -882,7 +885,7 @@ private boolean isEmpty() {
882885 return messages .isEmpty ();
883886 }
884887
885- private int getBatchedBytes () {
888+ private long getBatchedBytes () {
886889 return batchedBytes ;
887890 }
888891
0 commit comments