Skip to content

Commit 201e631

Browse files
authored
feat: add a flag to add / remove routing cookie from callable chain (#2032)
Test and rollback plan: [go/cbt-routing-cookie-rollback](http://goto.google.com/cbt-routing-cookie-rollback) Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [ ] Make sure to open an issue as a [bug/issue](https://togithub.com/googleapis/java-bigtable/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Ensure the tests and linter pass - [ ] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary) - [ ] Rollback plan is reviewed and LGTMed Fixes #<issue_number_goes_here> ☕️ If you write sample code, please follow the [samples format]( https://togithub.com/GoogleCloudPlatform/java-docs-samples/blob/main/SAMPLE_FORMAT.md).
1 parent ccc2764 commit 201e631

File tree

7 files changed

+351
-64
lines changed

7 files changed

+351
-64
lines changed

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/CookiesHolder.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,14 @@ Metadata injectCookiesInRequestHeaders(Metadata headers) {
5555
* COOKIE_KEY_PREFIX to cookies. Values in trailers will override the value set in initial
5656
* metadata for the same keys.
5757
*/
58-
void extractCookiesFromMetadata(@Nullable Metadata trailers) {
59-
if (trailers == null) {
58+
void extractCookiesFromMetadata(@Nullable Metadata metadata) {
59+
if (metadata == null) {
6060
return;
6161
}
62-
for (String key : trailers.keys()) {
62+
for (String key : metadata.keys()) {
6363
if (key.startsWith(COOKIE_KEY_PREFIX)) {
6464
Metadata.Key<String> metadataKey = Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER);
65-
String value = trailers.get(metadataKey);
65+
String value = metadata.get(metadataKey);
6666
cookies.put(metadataKey, value);
6767
}
6868
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStub.java

+51-39
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import com.google.api.gax.rpc.RequestParamsExtractor;
3838
import com.google.api.gax.rpc.ServerStreamingCallSettings;
3939
import com.google.api.gax.rpc.ServerStreamingCallable;
40+
import com.google.api.gax.rpc.UnaryCallSettings;
4041
import com.google.api.gax.rpc.UnaryCallable;
4142
import com.google.api.gax.tracing.OpencensusTracerFactory;
4243
import com.google.api.gax.tracing.SpanName;
@@ -185,11 +186,14 @@ public static EnhancedBigtableStubSettings finalizeSettings(
185186
// workaround JWT audience issues
186187
patchCredentials(builder);
187188

188-
// patch cookies interceptor
189-
InstantiatingGrpcChannelProvider.Builder transportProvider = null;
190-
if (builder.getTransportChannelProvider() instanceof InstantiatingGrpcChannelProvider) {
191-
transportProvider =
192-
((InstantiatingGrpcChannelProvider) builder.getTransportChannelProvider()).toBuilder();
189+
InstantiatingGrpcChannelProvider.Builder transportProvider =
190+
builder.getTransportChannelProvider() instanceof InstantiatingGrpcChannelProvider
191+
? ((InstantiatingGrpcChannelProvider) builder.getTransportChannelProvider()).toBuilder()
192+
: null;
193+
194+
if (builder.getEnableRoutingCookie() && transportProvider != null) {
195+
// TODO: this also need to be added to BigtableClientFactory
196+
// patch cookies interceptor
193197
transportProvider.setInterceptorProvider(() -> ImmutableList.of(new CookiesInterceptor()));
194198
}
195199

@@ -371,11 +375,7 @@ public <RowT> ServerStreamingCallable<Query, RowT> createReadRowsCallable(
371375
new TracedServerStreamingCallable<>(
372376
readRowsUserCallable, clientContext.getTracerFactory(), span);
373377

374-
// CookieHolder needs to be injected to the CallOptions outside of retries, otherwise retry
375-
// attempts won't see a CookieHolder.
376-
ServerStreamingCallable<Query, RowT> withCookie = new CookiesServerStreamingCallable<>(traced);
377-
378-
return withCookie.withDefaultCallContext(clientContext.getDefaultCallContext());
378+
return traced.withDefaultCallContext(clientContext.getDefaultCallContext());
379379
}
380380

381381
/**
@@ -411,9 +411,7 @@ public <RowT> UnaryCallable<Query, RowT> createReadRowCallable(RowAdapter<RowT>
411411
new TracedUnaryCallable<>(
412412
firstRow, clientContext.getTracerFactory(), getSpanName("ReadRow"));
413413

414-
UnaryCallable<Query, RowT> withCookie = new CookiesUnaryCallable<>(traced);
415-
416-
return withCookie.withDefaultCallContext(clientContext.getDefaultCallContext());
414+
return traced.withDefaultCallContext(clientContext.getDefaultCallContext());
417415
}
418416

419417
/**
@@ -485,7 +483,7 @@ public Map<String, String> extract(ReadRowsRequest readRowsRequest) {
485483
new ReadRowsRetryCompletedCallable<>(withBigtableTracer);
486484

487485
ServerStreamingCallable<ReadRowsRequest, RowT> retrying2 =
488-
Callables.retrying(retrying1, innerSettings, clientContext);
486+
withRetries(retrying1, innerSettings);
489487

490488
return new FilterMarkerRowsCallable<>(retrying2, rowAdapter);
491489
}
@@ -568,7 +566,7 @@ public Map<String, String> extract(
568566
new BigtableTracerUnaryCallable<>(withStatsHeaders);
569567

570568
UnaryCallable<SampleRowKeysRequest, List<SampleRowKeysResponse>> retryable =
571-
Callables.retrying(withBigtableTracer, settings.sampleRowKeysSettings(), clientContext);
569+
withRetries(withBigtableTracer, settings.sampleRowKeysSettings());
572570

573571
return createUserFacingUnaryCallable(
574572
methodName, new SampleRowKeysCallable(retryable, requestContext));
@@ -607,7 +605,7 @@ public Map<String, String> extract(MutateRowRequest mutateRowRequest) {
607605
new BigtableTracerUnaryCallable<>(withStatsHeaders);
608606

609607
UnaryCallable<MutateRowRequest, MutateRowResponse> retrying =
610-
Callables.retrying(withBigtableTracer, settings.mutateRowSettings(), clientContext);
608+
withRetries(withBigtableTracer, settings.mutateRowSettings());
611609

612610
return createUserFacingUnaryCallable(
613611
methodName, new MutateRowCallable(retrying, requestContext));
@@ -631,19 +629,25 @@ public Map<String, String> extract(MutateRowRequest mutateRowRequest) {
631629
private UnaryCallable<BulkMutation, Void> createBulkMutateRowsCallable() {
632630
UnaryCallable<MutateRowsRequest, Void> baseCallable = createMutateRowsBaseCallable();
633631

632+
UnaryCallable<MutateRowsRequest, Void> withCookie = baseCallable;
633+
634+
if (settings.getEnableRoutingCookie()) {
635+
withCookie = new CookiesUnaryCallable<>(baseCallable);
636+
}
637+
634638
UnaryCallable<MutateRowsRequest, Void> flowControlCallable = null;
635639
if (settings.bulkMutateRowsSettings().isLatencyBasedThrottlingEnabled()) {
636640
flowControlCallable =
637641
new DynamicFlowControlCallable(
638-
baseCallable,
642+
withCookie,
639643
bulkMutationFlowController,
640644
bulkMutationDynamicFlowControlStats,
641645
settings.bulkMutateRowsSettings().getTargetRpcLatencyMs(),
642646
FLOW_CONTROL_ADJUSTING_INTERVAL_MS);
643647
}
644648
UnaryCallable<BulkMutation, Void> userFacing =
645649
new BulkMutateRowsUserFacingCallable(
646-
flowControlCallable != null ? flowControlCallable : baseCallable, requestContext);
650+
flowControlCallable != null ? flowControlCallable : withCookie, requestContext);
647651

648652
SpanName spanName = getSpanName("MutateRows");
649653

@@ -654,9 +658,7 @@ private UnaryCallable<BulkMutation, Void> createBulkMutateRowsCallable() {
654658
new TracedUnaryCallable<>(
655659
tracedBatcherUnaryCallable, clientContext.getTracerFactory(), spanName);
656660

657-
UnaryCallable<BulkMutation, Void> withCookie = new CookiesUnaryCallable<>(traced);
658-
659-
return withCookie.withDefaultCallContext(clientContext.getDefaultCallContext());
661+
return traced.withDefaultCallContext(clientContext.getDefaultCallContext());
660662
}
661663

662664
/**
@@ -810,7 +812,7 @@ public Map<String, String> extract(
810812
new BigtableTracerUnaryCallable<>(withStatsHeaders);
811813

812814
UnaryCallable<CheckAndMutateRowRequest, CheckAndMutateRowResponse> retrying =
813-
Callables.retrying(withBigtableTracer, settings.checkAndMutateRowSettings(), clientContext);
815+
withRetries(withBigtableTracer, settings.checkAndMutateRowSettings());
814816

815817
return createUserFacingUnaryCallable(
816818
methodName, new CheckAndMutateRowCallable(retrying, requestContext));
@@ -851,8 +853,7 @@ public Map<String, String> extract(ReadModifyWriteRowRequest request) {
851853
new BigtableTracerUnaryCallable<>(withStatsHeaders);
852854

853855
UnaryCallable<ReadModifyWriteRowRequest, ReadModifyWriteRowResponse> retrying =
854-
Callables.retrying(
855-
withBigtableTracer, settings.readModifyWriteRowSettings(), clientContext);
856+
withRetries(withBigtableTracer, settings.readModifyWriteRowSettings());
856857

857858
return createUserFacingUnaryCallable(
858859
methodName, new ReadModifyWriteRowCallable(retrying, requestContext));
@@ -932,16 +933,13 @@ public Map<String, String> extract(
932933
new BigtableTracerStreamingCallable<>(watched);
933934

934935
ServerStreamingCallable<String, ByteStringRange> retrying =
935-
Callables.retrying(withBigtableTracer, innerSettings, clientContext);
936+
withRetries(withBigtableTracer, innerSettings);
936937

937938
SpanName span = getSpanName("GenerateInitialChangeStreamPartitions");
938939
ServerStreamingCallable<String, ByteStringRange> traced =
939940
new TracedServerStreamingCallable<>(retrying, clientContext.getTracerFactory(), span);
940941

941-
ServerStreamingCallable<String, ByteStringRange> withCookie =
942-
new CookiesServerStreamingCallable<>(traced);
943-
944-
return withCookie.withDefaultCallContext(clientContext.getDefaultCallContext());
942+
return traced.withDefaultCallContext(clientContext.getDefaultCallContext());
945943
}
946944

947945
/**
@@ -1010,7 +1008,7 @@ public Map<String, String> extract(
10101008
new BigtableTracerStreamingCallable<>(watched);
10111009

10121010
ServerStreamingCallable<ReadChangeStreamRequest, ChangeStreamRecordT> readChangeStreamCallable =
1013-
Callables.retrying(withBigtableTracer, innerSettings, clientContext);
1011+
withRetries(withBigtableTracer, innerSettings);
10141012

10151013
ServerStreamingCallable<ReadChangeStreamQuery, ChangeStreamRecordT>
10161014
readChangeStreamUserCallable =
@@ -1021,10 +1019,7 @@ public Map<String, String> extract(
10211019
new TracedServerStreamingCallable<>(
10221020
readChangeStreamUserCallable, clientContext.getTracerFactory(), span);
10231021

1024-
ServerStreamingCallable<ReadChangeStreamQuery, ChangeStreamRecordT> withCookie =
1025-
new CookiesServerStreamingCallable<>(traced);
1026-
1027-
return withCookie.withDefaultCallContext(clientContext.getDefaultCallContext());
1022+
return traced.withDefaultCallContext(clientContext.getDefaultCallContext());
10281023
}
10291024

10301025
/**
@@ -1037,11 +1032,7 @@ private <RequestT, ResponseT> UnaryCallable<RequestT, ResponseT> createUserFacin
10371032
UnaryCallable<RequestT, ResponseT> traced =
10381033
new TracedUnaryCallable<>(inner, clientContext.getTracerFactory(), getSpanName(methodName));
10391034

1040-
// CookieHolder needs to be injected to the CallOptions outside of retries, otherwise retry
1041-
// attempts won't see a CookieHolder.
1042-
UnaryCallable<RequestT, ResponseT> withCookie = new CookiesUnaryCallable<>(traced);
1043-
1044-
return withCookie.withDefaultCallContext(clientContext.getDefaultCallContext());
1035+
return traced.withDefaultCallContext(clientContext.getDefaultCallContext());
10451036
}
10461037

10471038
private UnaryCallable<PingAndWarmRequest, PingAndWarmResponse> createPingAndWarmCallable() {
@@ -1062,6 +1053,27 @@ public Map<String, String> extract(PingAndWarmRequest request) {
10621053
Collections.emptySet());
10631054
return pingAndWarm.withDefaultCallContext(clientContext.getDefaultCallContext());
10641055
}
1056+
1057+
private <RequestT, ResponseT> UnaryCallable<RequestT, ResponseT> withRetries(
1058+
UnaryCallable<RequestT, ResponseT> innerCallable, UnaryCallSettings<?, ?> unaryCallSettings) {
1059+
UnaryCallable<RequestT, ResponseT> retrying =
1060+
Callables.retrying(innerCallable, unaryCallSettings, clientContext);
1061+
if (settings.getEnableRoutingCookie()) {
1062+
return new CookiesUnaryCallable<>(retrying);
1063+
}
1064+
return retrying;
1065+
}
1066+
1067+
private <RequestT, ResponseT> ServerStreamingCallable<RequestT, ResponseT> withRetries(
1068+
ServerStreamingCallable<RequestT, ResponseT> innerCallable,
1069+
ServerStreamingCallSettings<RequestT, ResponseT> serverStreamingCallSettings) {
1070+
ServerStreamingCallable<RequestT, ResponseT> retrying =
1071+
Callables.retrying(innerCallable, serverStreamingCallSettings, clientContext);
1072+
if (settings.getEnableRoutingCookie()) {
1073+
return new CookiesServerStreamingCallable<>(retrying);
1074+
}
1075+
return retrying;
1076+
}
10651077
// </editor-fold>
10661078

10671079
// <editor-fold desc="Callable accessors">

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java

+35
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.google.cloud.bigtable.data.v2.stub;
1717

18+
import com.google.api.core.BetaApi;
1819
import com.google.api.core.InternalApi;
1920
import com.google.api.gax.batching.BatchingCallSettings;
2021
import com.google.api.gax.batching.BatchingSettings;
@@ -211,6 +212,7 @@ public class EnhancedBigtableStubSettings extends StubSettings<EnhancedBigtableS
211212
private final boolean isRefreshingChannel;
212213
private ImmutableList<String> primedTableIds;
213214
private final Map<String, String> jwtAudienceMapping;
215+
private final boolean enableRoutingCookie;
214216

215217
private final ServerStreamingCallSettings<Query, Row> readRowsSettings;
216218
private final UnaryCallSettings<Query, Row> readRowSettings;
@@ -252,6 +254,7 @@ private EnhancedBigtableStubSettings(Builder builder) {
252254
isRefreshingChannel = builder.isRefreshingChannel;
253255
primedTableIds = builder.primedTableIds;
254256
jwtAudienceMapping = builder.jwtAudienceMapping;
257+
enableRoutingCookie = builder.enableRoutingCookie;
255258

256259
// Per method settings.
257260
readRowsSettings = builder.readRowsSettings.build();
@@ -313,6 +316,15 @@ public Map<String, String> getJwtAudienceMapping() {
313316
return jwtAudienceMapping;
314317
}
315318

319+
/**
320+
* Gets if routing cookie is enabled. If true, client will retry a request with extra metadata
321+
* server sent back.
322+
*/
323+
@BetaApi("Routing cookie is not currently stable and may change in the future")
324+
public boolean getEnableRoutingCookie() {
325+
return enableRoutingCookie;
326+
}
327+
316328
/** Returns a builder for the default ChannelProvider for this service. */
317329
public static InstantiatingGrpcChannelProvider.Builder defaultGrpcTransportProviderBuilder() {
318330
return BigtableStubSettings.defaultGrpcTransportProviderBuilder()
@@ -595,6 +607,7 @@ public static class Builder extends StubSettings.Builder<EnhancedBigtableStubSet
595607
private boolean isRefreshingChannel;
596608
private ImmutableList<String> primedTableIds;
597609
private Map<String, String> jwtAudienceMapping;
610+
private boolean enableRoutingCookie;
598611

599612
private final ServerStreamingCallSettings.Builder<Query, Row> readRowsSettings;
600613
private final UnaryCallSettings.Builder<Query, Row> readRowSettings;
@@ -627,6 +640,7 @@ private Builder() {
627640
primedTableIds = ImmutableList.of();
628641
jwtAudienceMapping = DEFAULT_JWT_AUDIENCE_MAPPING;
629642
setCredentialsProvider(defaultCredentialsProviderBuilder().build());
643+
this.enableRoutingCookie = true;
630644

631645
// Defaults provider
632646
BigtableStubSettings.Builder baseDefaults = BigtableStubSettings.newBuilder();
@@ -745,6 +759,7 @@ private Builder(EnhancedBigtableStubSettings settings) {
745759
isRefreshingChannel = settings.isRefreshingChannel;
746760
primedTableIds = settings.primedTableIds;
747761
jwtAudienceMapping = settings.jwtAudienceMapping;
762+
enableRoutingCookie = settings.enableRoutingCookie;
748763

749764
// Per method settings.
750765
readRowsSettings = settings.readRowsSettings.toBuilder();
@@ -893,6 +908,25 @@ public Map<String, String> getJwtAudienceMapping() {
893908
return jwtAudienceMapping;
894909
}
895910

911+
/**
912+
* Sets if routing cookie is enabled. If true, client will retry a request with extra metadata
913+
* server sent back.
914+
*/
915+
@BetaApi("Routing cookie is not currently stable and may change in the future")
916+
public Builder setEnableRoutingCookie(boolean enableRoutingCookie) {
917+
this.enableRoutingCookie = enableRoutingCookie;
918+
return this;
919+
}
920+
921+
/**
922+
* Gets if routing cookie is enabled. If true, client will retry a request with extra metadata
923+
* server sent back.
924+
*/
925+
@BetaApi("Routing cookie is not currently stable and may change in the future")
926+
public boolean getEnableRoutingCookie() {
927+
return enableRoutingCookie;
928+
}
929+
896930
/** Returns the builder for the settings used for calls to readRows. */
897931
public ServerStreamingCallSettings.Builder<Query, Row> readRowsSettings() {
898932
return readRowsSettings;
@@ -1019,6 +1053,7 @@ public String toString() {
10191053
.add("isRefreshingChannel", isRefreshingChannel)
10201054
.add("primedTableIds", primedTableIds)
10211055
.add("jwtAudienceMapping", jwtAudienceMapping)
1056+
.add("enableRoutingCookie", enableRoutingCookie)
10221057
.add("readRowsSettings", readRowsSettings)
10231058
.add("readRowSettings", readRowSettings)
10241059
.add("sampleRowKeysSettings", sampleRowKeysSettings)

google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/ReadIT.java

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import java.util.concurrent.atomic.AtomicReference;
6262
import org.junit.Before;
6363
import org.junit.ClassRule;
64+
import org.junit.Ignore;
6465
import org.junit.Test;
6566
import org.junit.runner.RunWith;
6667
import org.junit.runners.JUnit4;
@@ -322,6 +323,7 @@ public void reversed() {
322323
}
323324

324325
@Test
326+
@Ignore("Test taking too long to run, ignore for now")
325327
public void reversedWithForcedResumption() throws IOException, InterruptedException {
326328
assume()
327329
.withMessage("reverse scans are not supported in the emulator")

0 commit comments

Comments
 (0)