3232import com .google .api .gax .rpc .TransportChannelProvider ;
3333import com .google .api .gax .rpc .UnaryCallSettings ;
3434import com .google .auth .Credentials ;
35+ import com .google .bigtable .v2 .FeatureFlags ;
3536import com .google .bigtable .v2 .PingAndWarmRequest ;
3637import com .google .cloud .bigtable .Version ;
3738import com .google .cloud .bigtable .data .v2 .models .ChangeStreamRecord ;
5051import com .google .common .collect .ImmutableList ;
5152import com .google .common .collect .ImmutableMap ;
5253import com .google .common .collect .ImmutableSet ;
54+ import java .io .ByteArrayOutputStream ;
5355import java .io .IOException ;
56+ import java .nio .charset .StandardCharsets ;
57+ import java .util .Base64 ;
5458import java .util .List ;
5559import java .util .Map ;
5660import java .util .Set ;
@@ -221,6 +225,8 @@ public class EnhancedBigtableStubSettings extends StubSettings<EnhancedBigtableS
221225 readChangeStreamSettings ;
222226 private final UnaryCallSettings <PingAndWarmRequest , Void > pingAndWarmSettings ;
223227
228+ private final FeatureFlags featureFlags ;
229+
224230 private EnhancedBigtableStubSettings (Builder builder ) {
225231 super (builder );
226232
@@ -259,6 +265,7 @@ private EnhancedBigtableStubSettings(Builder builder) {
259265 builder .generateInitialChangeStreamPartitionsSettings .build ();
260266 readChangeStreamSettings = builder .readChangeStreamSettings .build ();
261267 pingAndWarmSettings = builder .pingAndWarmSettings .build ();
268+ featureFlags = builder .featureFlags .build ();
262269 }
263270
264271 /** Create a new builder. */
@@ -598,6 +605,8 @@ public static class Builder extends StubSettings.Builder<EnhancedBigtableStubSet
598605 readChangeStreamSettings ;
599606 private final UnaryCallSettings .Builder <PingAndWarmRequest , Void > pingAndWarmSettings ;
600607
608+ private FeatureFlags .Builder featureFlags ;
609+
601610 /**
602611 * Initializes a new Builder with sane defaults for all settings.
603612 *
@@ -621,16 +630,6 @@ private Builder() {
621630 setStreamWatchdogCheckInterval (baseDefaults .getStreamWatchdogCheckInterval ());
622631 setStreamWatchdogProvider (baseDefaults .getStreamWatchdogProvider ());
623632
624- // Inject the UserAgent in addition to api-client header
625- Map <String , String > headers =
626- ImmutableMap .<String , String >builder ()
627- .putAll (
628- BigtableStubSettings .defaultApiClientHeaderProviderBuilder ().build ().getHeaders ())
629- // GrpcHeaderInterceptor treats the `user-agent` as a magic string
630- .put ("user-agent" , "bigtable-java/" + Version .VERSION )
631- .build ();
632- setInternalHeaderProvider (FixedHeaderProvider .create (headers ));
633-
634633 // Per-method settings using baseSettings for defaults.
635634 readRowsSettings = ServerStreamingCallSettings .newBuilder ();
636635
@@ -729,6 +728,8 @@ private Builder() {
729728 .setMaxRpcTimeout (PRIME_REQUEST_TIMEOUT )
730729 .setTotalTimeout (PRIME_REQUEST_TIMEOUT )
731730 .build ());
731+
732+ featureFlags = FeatureFlags .newBuilder ();
732733 }
733734
734735 private Builder (EnhancedBigtableStubSettings settings ) {
@@ -753,6 +754,7 @@ private Builder(EnhancedBigtableStubSettings settings) {
753754 settings .generateInitialChangeStreamPartitionsSettings .toBuilder ();
754755 readChangeStreamSettings = settings .readChangeStreamSettings .toBuilder ();
755756 pingAndWarmSettings = settings .pingAndWarmSettings .toBuilder ();
757+ featureFlags = settings .featureFlags .toBuilder ();
756758 }
757759 // <editor-fold desc="Private Helpers">
758760
@@ -970,6 +972,34 @@ public EnhancedBigtableStubSettings build() {
970972 BigtableChannelPrimer .create (credentials , projectId , instanceId , appProfileId ));
971973 this .setTransportChannelProvider (channelProviderBuilder .build ());
972974 }
975+
976+ if (this .bulkMutateRowsSettings ().isServerInitiatedFlowControlEnabled ()) {
977+ // only set mutate rows feature flag when this feature is enabled
978+ featureFlags .setMutateRowsRateLimit (true );
979+ }
980+
981+ // Serialize the web64 encode the bigtable feature flags
982+ ByteArrayOutputStream boas = new ByteArrayOutputStream ();
983+ try {
984+ featureFlags .build ().writeTo (boas );
985+ } catch (IOException e ) {
986+ throw new IllegalStateException (
987+ "Unexpected IOException while serializing feature flags" , e );
988+ }
989+ byte [] serializedFlags = boas .toByteArray ();
990+ byte [] encodedFlags = Base64 .getUrlEncoder ().encode (serializedFlags );
991+
992+ // Inject the UserAgent in addition to api-client header
993+ Map <String , String > headers =
994+ ImmutableMap .<String , String >builder ()
995+ .putAll (
996+ BigtableStubSettings .defaultApiClientHeaderProviderBuilder ().build ().getHeaders ())
997+ // GrpcHeaderInterceptor treats the `user-agent` as a magic string
998+ .put ("user-agent" , "bigtable-java/" + Version .VERSION )
999+ .put ("bigtable-features" , new String (encodedFlags , StandardCharsets .UTF_8 ))
1000+ .build ();
1001+ setInternalHeaderProvider (FixedHeaderProvider .create (headers ));
1002+
9731003 return new EnhancedBigtableStubSettings (this );
9741004 }
9751005 // </editor-fold>
0 commit comments