Skip to content

Commit ca99a8c

Browse files
committed
Fix RLS regressions from XdsDepMan conversion
297ab05 converted CDS to XdsDependencyManager. This caused three regressions: * CdsLB2 as a RLS child would always fail with "Unable to find non-dynamic root cluster" because is_dynamic=true was missing in its service config * XdsNameResolver only propagated resolution updates when the clusters changed, so a CdsUpdate change would be ignored. This caused a hang for RLS even with is_dynamic=true. For non-RLS the lack config update broke the circuit breaking psm interop test. This would have been more severe if ClusterResolverLb had been converted to XdsDependenceManager, as it would have ignored EDS updates * RLS did not propagate resolution updates, so CdsLB2 even with is_dynamic=true the CdsUpdate for the new cluster would never arrive, causing a hang b/428120265 b/427912384
1 parent 2ee4f9b commit ca99a8c

File tree

5 files changed

+76
-25
lines changed

5 files changed

+76
-25
lines changed

rls/src/main/java/io/grpc/rls/CachingRlsLbClient.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ void init() {
255255
}
256256
}
257257

258+
Status acceptResolvedAddressFactory(ResolvedAddressFactory childLbResolvedAddressFactory) {
259+
synchronized (lock) {
260+
return refCountedChildPolicyWrapperFactory.acceptResolvedAddressFactory(
261+
childLbResolvedAddressFactory);
262+
}
263+
}
264+
258265
/**
259266
* Convert the status to UNAVAILABLE and enhance the error message.
260267
* @param status status as provided by server

rls/src/main/java/io/grpc/rls/LbPolicyConfiguration.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.grpc.LoadBalancerProvider;
3232
import io.grpc.LoadBalancerRegistry;
3333
import io.grpc.NameResolver.ConfigOrError;
34+
import io.grpc.Status;
3435
import io.grpc.internal.ObjectPool;
3536
import io.grpc.rls.ChildLoadBalancerHelper.ChildLoadBalancerHelperProvider;
3637
import io.grpc.rls.RlsProtoData.RouteLookupConfig;
@@ -211,7 +212,7 @@ static final class RefCountedChildPolicyWrapperFactory {
211212
private final ChildLoadBalancerHelperProvider childLbHelperProvider;
212213
private final ChildLbStatusListener childLbStatusListener;
213214
private final ChildLoadBalancingPolicy childPolicy;
214-
private final ResolvedAddressFactory childLbResolvedAddressFactory;
215+
private ResolvedAddressFactory childLbResolvedAddressFactory;
215216

216217
public RefCountedChildPolicyWrapperFactory(
217218
ChildLoadBalancingPolicy childPolicy,
@@ -229,6 +230,19 @@ void init() {
229230
childLbHelperProvider.init();
230231
}
231232

233+
Status acceptResolvedAddressFactory(ResolvedAddressFactory childLbResolvedAddressFactory) {
234+
this.childLbResolvedAddressFactory = childLbResolvedAddressFactory;
235+
Status status = Status.OK;
236+
for (RefCountedChildPolicyWrapper wrapper : childPolicyMap.values()) {
237+
Status newStatus =
238+
wrapper.childPolicyWrapper.acceptResolvedAddressFactory(childLbResolvedAddressFactory);
239+
if (!newStatus.isOk()) {
240+
status = newStatus;
241+
}
242+
}
243+
return status;
244+
}
245+
232246
ChildPolicyWrapper createOrGet(String target) {
233247
// TODO(creamsoup) check if the target is valid or not
234248
RefCountedChildPolicyWrapper pooledChildPolicyWrapper = childPolicyMap.get(target);
@@ -277,6 +291,7 @@ static final class ChildPolicyWrapper {
277291
private final String target;
278292
private final ChildPolicyReportingHelper helper;
279293
private final LoadBalancer lb;
294+
private final Object childLbConfig;
280295
private volatile SubchannelPicker picker;
281296
private ConnectivityState state;
282297

@@ -295,21 +310,26 @@ public ChildPolicyWrapper(
295310
.parseLoadBalancingPolicyConfig(
296311
childPolicy.getEffectiveChildPolicy(target));
297312
this.lb = lbProvider.newLoadBalancer(helper);
313+
this.childLbConfig = lbConfig.getConfig();
298314
helper.getChannelLogger().log(
299-
ChannelLogLevel.DEBUG, "RLS child lb created. config: {0}", lbConfig.getConfig());
315+
ChannelLogLevel.DEBUG, "RLS child lb created. config: {0}", childLbConfig);
300316
helper.getSynchronizationContext().execute(
301317
new Runnable() {
302318
@Override
303319
public void run() {
304-
if (!lb.acceptResolvedAddresses(
305-
childLbResolvedAddressFactory.create(lbConfig.getConfig())).isOk()) {
320+
if (!acceptResolvedAddressFactory(childLbResolvedAddressFactory).isOk()) {
306321
helper.refreshNameResolution();
307322
}
308323
lb.requestConnection();
309324
}
310325
});
311326
}
312327

328+
Status acceptResolvedAddressFactory(ResolvedAddressFactory childLbResolvedAddressFactory) {
329+
helper.getSynchronizationContext().throwIfNotInThisSynchronizationContext();
330+
return lb.acceptResolvedAddresses(childLbResolvedAddressFactory.create(childLbConfig));
331+
}
332+
313333
String getTarget() {
314334
return target;
315335
}

rls/src/main/java/io/grpc/rls/RlsLoadBalancer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) {
7979
// not required.
8080
this.lbPolicyConfiguration = lbPolicyConfiguration;
8181
}
82-
return Status.OK;
82+
return routeLookupClient.acceptResolvedAddressFactory(
83+
new ChildLbResolvedAddressFactory(
84+
resolvedAddresses.getAddresses(), resolvedAddresses.getAttributes()));
8385
}
8486

8587
@Override

xds/src/main/java/io/grpc/xds/XdsNameResolver.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,9 @@ private void updateRoutes(
823823
if (shouldUpdateResult && routingConfig != null) {
824824
updateResolutionResult(xdsConfig);
825825
shouldUpdateResult = false;
826+
} else {
827+
// Need to update at least once
828+
shouldUpdateResult = true;
826829
}
827830
// Make newly added clusters selectable by config selector and deleted clusters no longer
828831
// selectable.
@@ -993,7 +996,8 @@ private ClusterRefState(
993996
.put("routeLookupConfig", rlsPluginConfig.config())
994997
.put(
995998
"childPolicy",
996-
ImmutableList.of(ImmutableMap.of(XdsLbPolicies.CDS_POLICY_NAME, ImmutableMap.of())))
999+
ImmutableList.of(ImmutableMap.of(XdsLbPolicies.CDS_POLICY_NAME, ImmutableMap.of(
1000+
"is_dynamic", true))))
9971001
.put("childPolicyConfigTargetFieldName", "cluster")
9981002
.buildOrThrow();
9991003
return ImmutableMap.of("rls_experimental", rlsConfig);

xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static org.mockito.ArgumentMatchers.anyInt;
2929
import static org.mockito.ArgumentMatchers.anyLong;
3030
import static org.mockito.ArgumentMatchers.eq;
31+
import static org.mockito.Mockito.atLeast;
3132
import static org.mockito.Mockito.lenient;
3233
import static org.mockito.Mockito.mock;
3334
import static org.mockito.Mockito.never;
@@ -449,7 +450,7 @@ public void resolving_ldsResourceUpdateRdsName() {
449450
// Two new service config updates triggered:
450451
// - with load balancing config being able to select cluster1 and cluster2
451452
// - with load balancing config being able to select cluster2 only
452-
verify(mockListener, times(2)).onResult2(resultCaptor.capture());
453+
verify(mockListener, times(3)).onResult2(resultCaptor.capture());
453454
assertServiceConfigForLoadBalancingConfig(
454455
Arrays.asList(cluster1, cluster2),
455456
(Map<String, ?>) resultCaptor.getAllValues().get(0).getServiceConfig().getConfig());
@@ -1070,7 +1071,9 @@ public void resolved_resourceUpdateAfterCallStarted() {
10701071
assertCallSelectClusterResult(call1, configSelector, "another-cluster", 20.0);
10711072

10721073
firstCall.deliverErrorStatus(); // completes previous call
1073-
verify(mockListener, times(2)).onResult2(resolutionResultCaptor.capture());
1074+
// Two updates: one for XdsNameResolver releasing the cluster, and another for
1075+
// XdsDependencyManager updating the XdsConfig
1076+
verify(mockListener, times(3)).onResult2(resolutionResultCaptor.capture());
10741077
result = resolutionResultCaptor.getValue();
10751078
assertServiceConfigForLoadBalancingConfig(
10761079
Arrays.asList(cluster2, "another-cluster"),
@@ -1100,7 +1103,7 @@ public void resolved_resourceUpdatedBeforeCallStarted() {
11001103
ImmutableMap.of())));
11011104
// Two consecutive service config updates: one for removing clcuster1,
11021105
// one for adding "another=cluster".
1103-
verify(mockListener, times(2)).onResult2(resolutionResultCaptor.capture());
1106+
verify(mockListener, times(3)).onResult2(resolutionResultCaptor.capture());
11041107
ResolutionResult result = resolutionResultCaptor.getValue();
11051108
assertServiceConfigForLoadBalancingConfig(
11061109
Arrays.asList(cluster2, "another-cluster"),
@@ -1155,7 +1158,7 @@ public void resolved_raceBetweenCallAndRepeatedResourceUpdate() {
11551158
cluster2, Collections.emptyList(),
11561159
TimeUnit.SECONDS.toNanos(15L), null, false),
11571160
ImmutableMap.of())));
1158-
verifyNoMoreInteractions(mockListener); // no cluster added/deleted
1161+
verify(mockListener, times(2)).onResult2(resolutionResultCaptor.capture());
11591162
assertCallSelectClusterResult(call1, configSelector, "another-cluster", 15.0);
11601163
}
11611164

@@ -1187,7 +1190,13 @@ public void resolved_raceBetweenClusterReleasedAndResourceUpdateAddBackAgain() {
11871190
null, false),
11881191
ImmutableMap.of())));
11891192
testCall.deliverErrorStatus();
1190-
verifyNoMoreInteractions(mockListener);
1193+
verify(mockListener, times(3)).onResult2(resolutionResultCaptor.capture());
1194+
assertServiceConfigForLoadBalancingConfig(
1195+
Arrays.asList(cluster1, cluster2), resolutionResultCaptor.getAllValues().get(1));
1196+
assertServiceConfigForLoadBalancingConfig(
1197+
Arrays.asList(cluster1, cluster2), resolutionResultCaptor.getAllValues().get(2));
1198+
assertServiceConfigForLoadBalancingConfig(
1199+
Arrays.asList(cluster1, cluster2), resolutionResultCaptor.getAllValues().get(3));
11911200
}
11921201

11931202
@SuppressWarnings("unchecked")
@@ -1268,7 +1277,7 @@ public void resolved_simpleCallSucceeds_routeToRls() {
12681277
"routeLookupConfig",
12691278
ImmutableMap.of("lookupService", "rls-cbt.googleapis.com"),
12701279
"childPolicy",
1271-
ImmutableList.of(ImmutableMap.of("cds_experimental", ImmutableMap.of())),
1280+
ImmutableList.of(ImmutableMap.of("cds_experimental", ImmutableMap.of("is_dynamic", true))),
12721281
"childPolicyConfigTargetFieldName",
12731282
"cluster");
12741283
Map<String, ?> expectedClusterManagerLbConfig = ImmutableMap.of(
@@ -1315,7 +1324,7 @@ public void resolved_simpleCallSucceeds_routeToRls() {
13151324
"routeLookupConfig",
13161325
ImmutableMap.of("lookupService", "rls-cbt-2.googleapis.com"),
13171326
"childPolicy",
1318-
ImmutableList.of(ImmutableMap.of("cds_experimental", ImmutableMap.of())),
1327+
ImmutableList.of(ImmutableMap.of("cds_experimental", ImmutableMap.of("is_dynamic", true))),
13191328
"childPolicyConfigTargetFieldName",
13201329
"cluster");
13211330
Map<String, ?> expectedClusterManagerLbConfig2 = ImmutableMap.of(
@@ -1656,7 +1665,7 @@ private void assertEmptyResolutionResult(String resource) {
16561665
}
16571666

16581667
private void assertClusterResolutionResult(CallInfo call, String expectedCluster) {
1659-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
1668+
verify(mockListener, atLeast(1)).onResult2(resolutionResultCaptor.capture());
16601669
ResolutionResult result = resolutionResultCaptor.getValue();
16611670
InternalConfigSelector configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
16621671
assertCallSelectClusterResult(call, configSelector, expectedCluster, null);
@@ -1744,6 +1753,13 @@ private InternalConfigSelector resolveToClusters() {
17441753
return result.getAttributes().get(InternalConfigSelector.KEY);
17451754
}
17461755

1756+
private static void assertServiceConfigForLoadBalancingConfig(
1757+
List<String> clusters, ResolutionResult result) {
1758+
@SuppressWarnings("unchecked")
1759+
Map<String, ?> config = (Map<String, ?>) result.getServiceConfig().getConfig();
1760+
assertServiceConfigForLoadBalancingConfig(clusters, config);
1761+
}
1762+
17471763
/**
17481764
* Verifies the raw service config contains an xDS load balancing config for the given clusters.
17491765
*/
@@ -1847,7 +1863,9 @@ public void generateServiceConfig_forClusterManagerLoadBalancingConfig() throws
18471863
+ " \"lookupService\": \"rls.bigtable.google.com\"\n"
18481864
+ " },\n"
18491865
+ " \"childPolicy\": [\n"
1850-
+ " {\"cds_experimental\": {}}\n"
1866+
+ " {\"cds_experimental\": {\n"
1867+
+ " \"is_dynamic\": true\n"
1868+
+ " }}\n"
18511869
+ " ],\n"
18521870
+ " \"childPolicyConfigTargetFieldName\": \"cluster\"\n"
18531871
+ " }\n"
@@ -2035,7 +2053,7 @@ public void resolved_faultAbortInLdsUpdate() {
20352053
FaultAbort.forHeader(FaultConfig.FractionalPercent.perMillion(600_000)),
20362054
null);
20372055
xdsClient.deliverLdsUpdateWithFaultInjection(cluster1, httpFilterFaultConfig, null, null, null);
2038-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2056+
verify(mockListener, times(2)).onResult2(resolutionResultCaptor.capture());
20392057
result = resolutionResultCaptor.getValue();
20402058
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
20412059
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,
@@ -2051,7 +2069,7 @@ public void resolved_faultAbortInLdsUpdate() {
20512069
FaultAbort.forHeader(FaultConfig.FractionalPercent.perMillion(0)),
20522070
null);
20532071
xdsClient.deliverLdsUpdateWithFaultInjection(cluster1, httpFilterFaultConfig, null, null, null);
2054-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2072+
verify(mockListener, times(3)).onResult2(resolutionResultCaptor.capture());
20552073
result = resolutionResultCaptor.getValue();
20562074
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
20572075
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,
@@ -2066,7 +2084,7 @@ public void resolved_faultAbortInLdsUpdate() {
20662084
FaultConfig.FractionalPercent.perMillion(600_000)),
20672085
null);
20682086
xdsClient.deliverLdsUpdateWithFaultInjection(cluster1, httpFilterFaultConfig, null, null, null);
2069-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2087+
verify(mockListener, times(4)).onResult2(resolutionResultCaptor.capture());
20702088
result = resolutionResultCaptor.getValue();
20712089
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
20722090
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,
@@ -2084,7 +2102,7 @@ public void resolved_faultAbortInLdsUpdate() {
20842102
FaultConfig.FractionalPercent.perMillion(400_000)),
20852103
null);
20862104
xdsClient.deliverLdsUpdateWithFaultInjection(cluster1, httpFilterFaultConfig, null, null, null);
2087-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2105+
verify(mockListener, times(5)).onResult2(resolutionResultCaptor.capture());
20882106
result = resolutionResultCaptor.getValue();
20892107
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
20902108
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,
@@ -2119,7 +2137,7 @@ public void resolved_faultDelayInLdsUpdate() {
21192137
httpFilterFaultConfig = FaultConfig.create(
21202138
FaultDelay.forHeader(FaultConfig.FractionalPercent.perMillion(600_000)), null, null);
21212139
xdsClient.deliverLdsUpdateWithFaultInjection(cluster1, httpFilterFaultConfig, null, null, null);
2122-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2140+
verify(mockListener, times(2)).onResult2(resolutionResultCaptor.capture());
21232141
result = resolutionResultCaptor.getValue();
21242142
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
21252143
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,
@@ -2130,7 +2148,7 @@ public void resolved_faultDelayInLdsUpdate() {
21302148
httpFilterFaultConfig = FaultConfig.create(
21312149
FaultDelay.forHeader(FaultConfig.FractionalPercent.perMillion(0)), null, null);
21322150
xdsClient.deliverLdsUpdateWithFaultInjection(cluster1, httpFilterFaultConfig, null, null, null);
2133-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2151+
verify(mockListener, times(3)).onResult2(resolutionResultCaptor.capture());
21342152
result = resolutionResultCaptor.getValue();
21352153
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
21362154
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,
@@ -2143,7 +2161,7 @@ public void resolved_faultDelayInLdsUpdate() {
21432161
null,
21442162
null);
21452163
xdsClient.deliverLdsUpdateWithFaultInjection(cluster1, httpFilterFaultConfig, null, null, null);
2146-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2164+
verify(mockListener, times(4)).onResult2(resolutionResultCaptor.capture());
21472165
result = resolutionResultCaptor.getValue();
21482166
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
21492167
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,
@@ -2156,7 +2174,7 @@ public void resolved_faultDelayInLdsUpdate() {
21562174
null,
21572175
null);
21582176
xdsClient.deliverLdsUpdateWithFaultInjection(cluster1, httpFilterFaultConfig, null, null, null);
2159-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2177+
verify(mockListener, times(5)).onResult2(resolutionResultCaptor.capture());
21602178
result = resolutionResultCaptor.getValue();
21612179
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
21622180
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,
@@ -2281,7 +2299,7 @@ public void resolved_faultConfigOverrideInLdsUpdate() {
22812299
null);
22822300
xdsClient.deliverLdsUpdateWithFaultInjection(
22832301
cluster1, httpFilterFaultConfig, virtualHostFaultConfig, routeFaultConfig, null);
2284-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2302+
verify(mockListener, times(2)).onResult2(resolutionResultCaptor.capture());
22852303
result = resolutionResultCaptor.getValue();
22862304
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
22872305
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,
@@ -2298,7 +2316,7 @@ public void resolved_faultConfigOverrideInLdsUpdate() {
22982316
xdsClient.deliverLdsUpdateWithFaultInjection(
22992317
cluster1, httpFilterFaultConfig, virtualHostFaultConfig, routeFaultConfig,
23002318
weightedClusterFaultConfig);
2301-
verify(mockListener).onResult2(resolutionResultCaptor.capture());
2319+
verify(mockListener, times(3)).onResult2(resolutionResultCaptor.capture());
23022320
result = resolutionResultCaptor.getValue();
23032321
configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
23042322
observer = startNewCall(TestMethodDescriptors.voidMethod(), configSelector,

0 commit comments

Comments
 (0)