use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class ManagedChannelImplTest method subchannelConnectionBroken_ResolverRefreshedByLb.
@Test
public void subchannelConnectionBroken_ResolverRefreshedByLb() {
FakeNameResolverFactory nameResolverFactory = new FakeNameResolverFactory.Builder(expectedUri).setServers(Collections.singletonList(new EquivalentAddressGroup(socketAddress))).build();
channelBuilder.nameResolverFactory(nameResolverFactory);
createChannel();
FakeNameResolverFactory.FakeNameResolver resolver = Iterables.getOnlyElement(nameResolverFactory.resolvers);
assertThat(resolver.refreshCalled).isEqualTo(0);
ArgumentCaptor<Helper> helperCaptor = ArgumentCaptor.forClass(Helper.class);
verify(mockLoadBalancerProvider).newLoadBalancer(helperCaptor.capture());
helper = helperCaptor.getValue();
SubchannelStateListener listener = new SubchannelStateListener() {
@Override
public void onSubchannelState(ConnectivityStateInfo newState) {
// TRANSIENT_FAILURE or IDLE
if (newState.getState() == TRANSIENT_FAILURE || newState.getState() == IDLE) {
helper.refreshNameResolution();
}
}
};
Subchannel subchannel = createSubchannelSafely(helper, addressGroup, Attributes.EMPTY, listener);
InternalSubchannel internalSubchannel = (InternalSubchannel) subchannel.getInternalSubchannel();
internalSubchannel.obtainActiveTransport();
MockClientTransportInfo transportInfo = transports.poll();
// Break subchannel connection and simulate load balancer refreshing name resolution
transportInfo.listener.transportShutdown(Status.UNAVAILABLE.withDescription("unreachable"));
assertThat(logs).isEmpty();
assertThat(resolver.refreshCalled).isEqualTo(1);
}
use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class RingHashLoadBalancer method handleResolvedAddresses.
@Override
public void handleResolvedAddresses(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."));
return;
}
Map<EquivalentAddressGroup, EquivalentAddressGroup> latestAddrs = stripAttrs(addrList);
Set<EquivalentAddressGroup> removedAddrs = Sets.newHashSet(Sets.difference(subchannels.keySet(), latestAddrs.keySet()));
RingHashConfig config = (RingHashConfig) resolvedAddresses.getLoadBalancingPolicyConfig();
Map<EquivalentAddressGroup, Long> serverWeights = new HashMap<>();
long totalWeight = 0L;
for (EquivalentAddressGroup eag : addrList) {
Long weight = eag.getAttributes().get(InternalXdsAttributes.ATTR_SERVER_WEIGHT);
// each occurrence of the address will be counted a weight value of one.
if (weight == null) {
weight = 1L;
}
totalWeight += weight;
EquivalentAddressGroup addrKey = stripAttrs(eag);
if (serverWeights.containsKey(addrKey)) {
serverWeights.put(addrKey, serverWeights.get(addrKey) + weight);
} else {
serverWeights.put(addrKey, weight);
}
Subchannel existingSubchannel = subchannels.get(addrKey);
if (existingSubchannel != null) {
existingSubchannel.updateAddresses(Collections.singletonList(eag));
continue;
}
Attributes attr = Attributes.newBuilder().set(STATE_INFO, new Ref<>(ConnectivityStateInfo.forNonError(IDLE))).build();
final Subchannel subchannel = helper.createSubchannel(CreateSubchannelArgs.newBuilder().setAddresses(eag).setAttributes(attr).build());
subchannel.start(new SubchannelStateListener() {
@Override
public void onSubchannelState(ConnectivityStateInfo newState) {
processSubchannelState(subchannel, newState);
}
});
subchannels.put(addrKey, subchannel);
}
long minWeight = Collections.min(serverWeights.values());
double normalizedMinWeight = (double) minWeight / totalWeight;
// Scale up the number of hashes per host such that the least-weighted host gets a whole
// number of hashes on the the ring. Other hosts might not end up with whole numbers, and
// that's fine (the ring-building algorithm can handle this). This preserves the original
// implementation's behavior: when weights aren't provided, all hosts should get an equal
// number of hashes. In the case where this number exceeds the max_ring_size, it's scaled
// back down to fit.
double scale = Math.min(Math.ceil(normalizedMinWeight * config.minRingSize) / normalizedMinWeight, (double) config.maxRingSize);
ring = buildRing(serverWeights, totalWeight, scale);
// Shut down subchannels for delisted addresses.
List<Subchannel> removedSubchannels = new ArrayList<>();
for (EquivalentAddressGroup addr : removedAddrs) {
removedSubchannels.add(subchannels.remove(addr));
}
// Update the picker before shutting down the subchannels, to reduce the chance of race
// between picking a subchannel and shutting it down.
updateBalancingState();
for (Subchannel subchann : removedSubchannels) {
shutdownSubchannel(subchann);
}
}
use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class LeastRequestLoadBalancer method updateBalancingState.
/**
* Updates picker with the list of active subchannels (state == READY).
*/
@SuppressWarnings("ReferenceEquality")
private void updateBalancingState() {
List<Subchannel> activeList = filterNonFailingSubchannels(getSubchannels());
if (activeList.isEmpty()) {
// No READY subchannels, determine aggregate state and error status
boolean isConnecting = false;
Status aggStatus = EMPTY_OK;
for (Subchannel subchannel : getSubchannels()) {
ConnectivityStateInfo stateInfo = getSubchannelStateInfoRef(subchannel).value;
// LRLB will request connection immediately on subchannel IDLE.
if (stateInfo.getState() == CONNECTING || stateInfo.getState() == IDLE) {
isConnecting = true;
}
if (aggStatus == EMPTY_OK || !aggStatus.isOk()) {
aggStatus = stateInfo.getStatus();
}
}
updateBalancingState(isConnecting ? CONNECTING : TRANSIENT_FAILURE, // an arbitrary subchannel, otherwise return OK.
new EmptyPicker(aggStatus));
} else {
updateBalancingState(READY, new ReadyPicker(activeList, choiceCount, random));
}
}
use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class GrpclbLoadBalancer method makePicker.
/**
* Make a picker out of the current roundRobinList and the states of subchannels.
*/
private SubchannelPicker makePicker() {
List<RoundRobinEntry> resultList = new ArrayList<RoundRobinEntry>();
Status error = null;
for (RoundRobinEntry entry : roundRobinList) {
Subchannel subchannel = entry.result.getSubchannel();
if (subchannel != null) {
Attributes attrs = subchannel.getAttributes();
ConnectivityStateInfo stateInfo = attrs.get(STATE_INFO).get();
if (stateInfo.getState() == READY) {
resultList.add(entry);
} else if (stateInfo.getState() == TRANSIENT_FAILURE) {
error = stateInfo.getStatus();
}
} else {
// This is a drop entry.
resultList.add(entry);
}
}
if (resultList.isEmpty()) {
if (error != null) {
logger.log(Level.FINE, "[{0}] No ready Subchannel. Using error: {1}", new Object[] { logId, error });
return new ErrorPicker(error);
} else {
logger.log(Level.FINE, "[{0}] No ready Subchannel and no error", logId);
return BUFFER_PICKER;
}
} else {
logger.log(Level.FINE, "[{0}] Using list {1}", new Object[] { logId, resultList });
return new RoundRobinPicker(resultList);
}
}
use of io.grpc.ConnectivityStateInfo in project grpc-java by grpc.
the class LeastRequestLoadBalancer method handleResolvedAddresses.
@Override
public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) {
LeastRequestConfig config = (LeastRequestConfig) resolvedAddresses.getLoadBalancingPolicyConfig();
// Config may be null if least_request is used outside xDS
if (config != null) {
choiceCount = config.choiceCount;
}
List<EquivalentAddressGroup> servers = resolvedAddresses.getAddresses();
Set<EquivalentAddressGroup> currentAddrs = subchannels.keySet();
Map<EquivalentAddressGroup, EquivalentAddressGroup> latestAddrs = stripAttrs(servers);
Set<EquivalentAddressGroup> removedAddrs = setsDifference(currentAddrs, latestAddrs.keySet());
for (Map.Entry<EquivalentAddressGroup, EquivalentAddressGroup> latestEntry : latestAddrs.entrySet()) {
EquivalentAddressGroup strippedAddressGroup = latestEntry.getKey();
EquivalentAddressGroup originalAddressGroup = latestEntry.getValue();
Subchannel existingSubchannel = subchannels.get(strippedAddressGroup);
if (existingSubchannel != null) {
// EAG's Attributes may have changed.
existingSubchannel.updateAddresses(Collections.singletonList(originalAddressGroup));
continue;
}
// Create new subchannels for new addresses.
Attributes.Builder subchannelAttrs = Attributes.newBuilder().set(STATE_INFO, new Ref<>(ConnectivityStateInfo.forNonError(IDLE))).set(IN_FLIGHTS, new AtomicInteger(0));
final Subchannel subchannel = checkNotNull(helper.createSubchannel(CreateSubchannelArgs.newBuilder().setAddresses(originalAddressGroup).setAttributes(subchannelAttrs.build()).build()), "subchannel");
subchannel.start(new SubchannelStateListener() {
@Override
public void onSubchannelState(ConnectivityStateInfo state) {
processSubchannelState(subchannel, state);
}
});
subchannels.put(strippedAddressGroup, subchannel);
subchannel.requestConnection();
}
ArrayList<Subchannel> removedSubchannels = new ArrayList<>();
for (EquivalentAddressGroup addressGroup : removedAddrs) {
removedSubchannels.add(subchannels.remove(addressGroup));
}
// Update the picker before shutting down the subchannels, to reduce the chance of the race
// between picking a subchannel and shutting it down.
updateBalancingState();
// Shutdown removed subchannels
for (Subchannel removedSubchannel : removedSubchannels) {
shutdownSubchannel(removedSubchannel);
}
}
Aggregations