Eds weight allowed between max signed and max unsigned int (#9765)

* Enforce individual weights and sum of weights not exceeding the max unsigned int value
This commit is contained in:
Larry Safran 2022-12-20 21:07:10 +00:00 committed by GitHub
parent 7c73baa450
commit fe19152108
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 3 deletions

View File

@ -27,6 +27,7 @@ import static io.grpc.ConnectivityState.TRANSIENT_FAILURE;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Sets;
import com.google.common.primitives.UnsignedInteger;
import io.grpc.Attributes;
import io.grpc.ConnectivityState;
import io.grpc.ConnectivityStateInfo;
@ -84,11 +85,10 @@ final class RingHashLoadBalancer extends LoadBalancer {
public boolean acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) {
logger.log(XdsLogLevel.DEBUG, "Received resolution result: {0}", resolvedAddresses);
List<EquivalentAddressGroup> addrList = resolvedAddresses.getAddresses();
if (addrList.isEmpty()) {
handleNameResolutionError(Status.UNAVAILABLE.withDescription("Ring hash lb error: EDS "
+ "resolution was successful, but returned server addresses are empty."));
if (!validateAddrList(addrList)) {
return false;
}
Map<EquivalentAddressGroup, EquivalentAddressGroup> latestAddrs = stripAttrs(addrList);
Set<EquivalentAddressGroup> removedAddrs =
Sets.newHashSet(Sets.difference(subchannels.keySet(), latestAddrs.keySet()));
@ -166,6 +166,47 @@ final class RingHashLoadBalancer extends LoadBalancer {
return true;
}
private boolean validateAddrList(List<EquivalentAddressGroup> addrList) {
if (addrList.isEmpty()) {
handleNameResolutionError(Status.UNAVAILABLE.withDescription("Ring hash lb error: EDS "
+ "resolution was successful, but returned server addresses are empty."));
return false;
}
long totalWeight = 0;
for (EquivalentAddressGroup eag : addrList) {
Long weight = eag.getAttributes().get(InternalXdsAttributes.ATTR_SERVER_WEIGHT);
if (weight == null) {
weight = 1L;
}
if (weight < 0) {
handleNameResolutionError(Status.UNAVAILABLE.withDescription(
String.format("Ring hash lb error: EDS resolution was successful, but returned a "
+ "negative weight for %s.", stripAttrs(eag))));
return false;
}
if (weight > UnsignedInteger.MAX_VALUE.longValue()) {
handleNameResolutionError(Status.UNAVAILABLE.withDescription(
String.format("Ring hash lb error: EDS resolution was successful, but returned a weight"
+ " too large to fit in an unsigned int for %s.", stripAttrs(eag))));
return false;
}
totalWeight += weight;
}
if (totalWeight > UnsignedInteger.MAX_VALUE.longValue()) {
handleNameResolutionError(Status.UNAVAILABLE.withDescription(
String.format(
"Ring hash lb error: EDS resolution was successful, but returned a sum of weights too"
+ " large to fit in an unsigned int (%d).", totalWeight)));
return false;
}
return true;
}
private static List<RingEntry> buildRing(
Map<EquivalentAddressGroup, Long> serverWeights, long totalWeight, double scale) {
List<RingEntry> ring = new ArrayList<>();

View File

@ -36,6 +36,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import com.google.common.collect.Iterables;
import com.google.common.primitives.UnsignedInteger;
import io.grpc.Attributes;
import io.grpc.CallOptions;
import io.grpc.ConnectivityStateInfo;
@ -961,6 +962,46 @@ public class RingHashLoadBalancerTest {
.requestConnection();
}
@Test
public void largeWeights() {
RingHashConfig config = new RingHashConfig(10000, 100000); // large ring
List<EquivalentAddressGroup> servers =
createWeightedServerAddrs(Integer.MAX_VALUE, 10, 100); // MAX:10:100
boolean addressesAccepted = loadBalancer.acceptResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(servers).setLoadBalancingPolicyConfig(config).build());
assertThat(addressesAccepted).isTrue();
// Try value between max signed and max unsigned int
servers = createWeightedServerAddrs(Integer.MAX_VALUE + 100L, 100); // (MAX+100):100
addressesAccepted = loadBalancer.acceptResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(servers).setLoadBalancingPolicyConfig(config).build());
assertThat(addressesAccepted).isTrue();
// Try a negative value
servers = createWeightedServerAddrs(10, -20, 100); // 10:-20:100
addressesAccepted = loadBalancer.acceptResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(servers).setLoadBalancingPolicyConfig(config).build());
assertThat(addressesAccepted).isFalse();
// Try an individual value larger than max unsigned int
long maxUnsigned = UnsignedInteger.MAX_VALUE.longValue();
servers = createWeightedServerAddrs(maxUnsigned + 10, 10, 100); // uMAX+10:10:100
addressesAccepted = loadBalancer.acceptResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(servers).setLoadBalancingPolicyConfig(config).build());
assertThat(addressesAccepted).isFalse();
// Try a sum of values larger than max unsigned int
servers = createWeightedServerAddrs(Integer.MAX_VALUE, Integer.MAX_VALUE, 100); // MAX:MAX:100
addressesAccepted = loadBalancer.acceptResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(servers).setLoadBalancingPolicyConfig(config).build());
assertThat(addressesAccepted).isFalse();
}
@Test
public void hostSelectionProportionalToWeights() {
RingHashConfig config = new RingHashConfig(10000, 100000); // large ring