use of io.grpc.EquivalentAddressGroup in project grpc-java by grpc.
the class GrpclbLoadBalancer method handleResolvedAddresses.
@Override
public void handleResolvedAddresses(List<ResolvedServerInfoGroup> updatedServers, Attributes attributes) {
LbPolicy newLbPolicy = attributes.get(GrpclbConstants.ATTR_LB_POLICY);
// LB addresses and backend addresses are treated separately
List<LbAddressGroup> newLbAddressGroups = new ArrayList<LbAddressGroup>();
List<ResolvedServerInfoGroup> newBackendServerInfoGroups = new ArrayList<ResolvedServerInfoGroup>();
for (ResolvedServerInfoGroup serverInfoGroup : updatedServers) {
String lbAddrAuthority = serverInfoGroup.getAttributes().get(GrpclbConstants.ATTR_LB_ADDR_AUTHORITY);
EquivalentAddressGroup eag = serverInfoGroup.toEquivalentAddressGroup();
if (lbAddrAuthority != null) {
newLbAddressGroups.add(new LbAddressGroup(eag, lbAddrAuthority));
} else {
newBackendServerInfoGroups.add(serverInfoGroup);
}
}
if (newBackendServerInfoGroups.isEmpty()) {
// handleResolvedAddresses()'s javadoc has guaranteed updatedServers is never empty.
checkState(!newLbAddressGroups.isEmpty(), "No backend address nor LB address. updatedServers=%s", updatedServers);
if (newLbPolicy != LbPolicy.GRPCLB) {
newLbPolicy = LbPolicy.GRPCLB;
logger.log(Level.FINE, "[{0}] Switching to GRPCLB because all addresses are balancers", logId);
}
}
if (newLbPolicy == null) {
logger.log(Level.FINE, "[{0}] New config missing policy. Using PICK_FIRST", logId);
newLbPolicy = LbPolicy.PICK_FIRST;
}
// Switch LB policy if requested
if (newLbPolicy != lbPolicy) {
shutdownDelegate();
shutdownLbComm();
lbAddressGroups = null;
currentLbIndex = 0;
switch(newLbPolicy) {
case PICK_FIRST:
delegate = checkNotNull(pickFirstBalancerFactory.newLoadBalancer(helper), "pickFirstBalancerFactory.newLoadBalancer()");
break;
case ROUND_ROBIN:
delegate = checkNotNull(roundRobinBalancerFactory.newLoadBalancer(helper), "roundRobinBalancerFactory.newLoadBalancer()");
break;
default:
}
}
lbPolicy = newLbPolicy;
// Consume the new addresses
switch(lbPolicy) {
case PICK_FIRST:
case ROUND_ROBIN:
checkNotNull(delegate, "delegate should not be null. newLbPolicy=" + newLbPolicy);
delegate.handleResolvedAddresses(newBackendServerInfoGroups, attributes);
break;
case GRPCLB:
if (newLbAddressGroups.isEmpty()) {
shutdownLbComm();
lbAddressGroups = null;
handleGrpclbError(Status.UNAVAILABLE.withDescription("NameResolver returned no LB address while asking for GRPCLB"));
} else {
// See if the currently used LB server is in the new list.
int newIndexOfCurrentLb = -1;
if (lbAddressGroups != null) {
LbAddressGroup currentLb = lbAddressGroups.get(currentLbIndex);
newIndexOfCurrentLb = newLbAddressGroups.indexOf(currentLb);
}
lbAddressGroups = newLbAddressGroups;
if (newIndexOfCurrentLb == -1) {
shutdownLbComm();
currentLbIndex = 0;
startLbComm();
} else {
// Current LB is still in the list, calibrate index.
currentLbIndex = newIndexOfCurrentLb;
}
}
break;
default:
}
}
use of io.grpc.EquivalentAddressGroup in project grpc-java by grpc.
the class GrpclbLoadBalancerTest method grpclbWorking.
@Test
public void grpclbWorking() {
InOrder inOrder = inOrder(helper);
List<ResolvedServerInfoGroup> grpclbResolutionList = createResolvedServerInfoGroupList(true, true);
Attributes grpclbResolutionAttrs = Attributes.newBuilder().set(GrpclbConstants.ATTR_LB_POLICY, LbPolicy.GRPCLB).build();
deliverResolvedAddresses(grpclbResolutionList, grpclbResolutionAttrs);
assertSame(LbPolicy.GRPCLB, balancer.getLbPolicy());
assertNull(balancer.getDelegate());
verify(helper).createOobChannel(eq(grpclbResolutionList.get(0).toEquivalentAddressGroup()), eq(lbAuthority(0)));
assertEquals(1, fakeOobChannels.size());
ManagedChannel oobChannel = fakeOobChannels.poll();
verify(mockLbService).balanceLoad(lbResponseObserverCaptor.capture());
StreamObserver<LoadBalanceResponse> lbResponseObserver = lbResponseObserverCaptor.getValue();
// Simulate receiving LB response
List<ServerEntry> backends1 = Arrays.asList(new ServerEntry("127.0.0.1", 2000, "token0001"), new ServerEntry("127.0.0.1", 2010, "token0002"));
inOrder.verify(helper, never()).updatePicker(any(SubchannelPicker.class));
lbResponseObserver.onNext(buildInitialResponse());
lbResponseObserver.onNext(buildLbResponse(backends1));
inOrder.verify(helper).createSubchannel(eq(new EquivalentAddressGroup(backends1.get(0).addr)), any(Attributes.class));
inOrder.verify(helper).createSubchannel(eq(new EquivalentAddressGroup(backends1.get(1).addr)), any(Attributes.class));
assertEquals(2, mockSubchannels.size());
Subchannel subchannel1 = mockSubchannels.poll();
Subchannel subchannel2 = mockSubchannels.poll();
verify(subchannel1).requestConnection();
verify(subchannel2).requestConnection();
assertEquals(new EquivalentAddressGroup(backends1.get(0).addr), subchannel1.getAddresses());
assertEquals(new EquivalentAddressGroup(backends1.get(1).addr), subchannel2.getAddresses());
// Before any subchannel is READY, a buffer picker will be provided
inOrder.verify(helper).updatePicker(same(GrpclbLoadBalancer.BUFFER_PICKER));
deliverSubchannelState(subchannel1, ConnectivityStateInfo.forNonError(CONNECTING));
deliverSubchannelState(subchannel2, ConnectivityStateInfo.forNonError(CONNECTING));
inOrder.verify(helper, times(2)).updatePicker(same(GrpclbLoadBalancer.BUFFER_PICKER));
// Let subchannels be connected
deliverSubchannelState(subchannel2, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(helper).updatePicker(pickerCaptor.capture());
RoundRobinPicker picker1 = (RoundRobinPicker) pickerCaptor.getValue();
assertThat(picker1.list).containsExactly(new RoundRobinEntry(subchannel2, "token0002"));
deliverSubchannelState(subchannel1, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(helper).updatePicker(pickerCaptor.capture());
RoundRobinPicker picker2 = (RoundRobinPicker) pickerCaptor.getValue();
assertThat(picker2.list).containsExactly(new RoundRobinEntry(subchannel1, "token0001"), new RoundRobinEntry(subchannel2, "token0002")).inOrder();
// Disconnected subchannels
verify(subchannel1).requestConnection();
deliverSubchannelState(subchannel1, ConnectivityStateInfo.forNonError(IDLE));
verify(subchannel1, times(2)).requestConnection();
inOrder.verify(helper).updatePicker(pickerCaptor.capture());
RoundRobinPicker picker3 = (RoundRobinPicker) pickerCaptor.getValue();
assertThat(picker3.list).containsExactly(new RoundRobinEntry(subchannel2, "token0002"));
deliverSubchannelState(subchannel1, ConnectivityStateInfo.forNonError(CONNECTING));
inOrder.verify(helper).updatePicker(pickerCaptor.capture());
RoundRobinPicker picker4 = (RoundRobinPicker) pickerCaptor.getValue();
assertThat(picker4.list).containsExactly(new RoundRobinEntry(subchannel2, "token0002"));
// As long as there is at least one READY subchannel, round robin will work.
Status error1 = Status.UNAVAILABLE.withDescription("error1");
deliverSubchannelState(subchannel1, ConnectivityStateInfo.forTransientFailure(error1));
inOrder.verify(helper).updatePicker(pickerCaptor.capture());
RoundRobinPicker picker5 = (RoundRobinPicker) pickerCaptor.getValue();
assertThat(picker5.list).containsExactly(new RoundRobinEntry(subchannel2, "token0002"));
// If no subchannel is READY, will propagate an error from an arbitrary subchannel (but here
// only subchannel1 has error).
verify(subchannel2).requestConnection();
deliverSubchannelState(subchannel2, ConnectivityStateInfo.forNonError(IDLE));
verify(subchannel2, times(2)).requestConnection();
inOrder.verify(helper).updatePicker(pickerCaptor.capture());
ErrorPicker picker6 = (ErrorPicker) pickerCaptor.getValue();
assertNull(picker6.result.getSubchannel());
assertSame(error1, picker6.result.getStatus());
// Update backends, with a drop entry
List<ServerEntry> backends2 = Arrays.asList(// New address
new ServerEntry("127.0.0.1", 2030, "token0003"), // drop
null, // Existing address with token changed
new ServerEntry("127.0.0.1", 2010, "token0004"), // New address appearing second time
new ServerEntry("127.0.0.1", 2030, "token0005"));
verify(subchannel1, never()).shutdown();
lbResponseObserver.onNext(buildLbResponse(backends2));
// not in backends2, closed
verify(subchannel1).shutdown();
// backends2[2], will be kept
verify(subchannel2, never()).shutdown();
inOrder.verify(helper, never()).createSubchannel(eq(new EquivalentAddressGroup(backends2.get(2).addr)), any(Attributes.class));
inOrder.verify(helper).createSubchannel(eq(new EquivalentAddressGroup(backends2.get(0).addr)), any(Attributes.class));
assertEquals(1, mockSubchannels.size());
Subchannel subchannel3 = mockSubchannels.poll();
verify(subchannel3).requestConnection();
assertEquals(new EquivalentAddressGroup(backends2.get(0).addr), subchannel3.getAddresses());
inOrder.verify(helper).updatePicker(pickerCaptor.capture());
RoundRobinPicker picker7 = (RoundRobinPicker) pickerCaptor.getValue();
assertThat(picker7.list).containsExactly(GrpclbLoadBalancer.DROP_ENTRY);
// State updates on obsolete subchannel1 will have no effect
deliverSubchannelState(subchannel1, ConnectivityStateInfo.forNonError(READY));
deliverSubchannelState(subchannel1, ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE));
deliverSubchannelState(subchannel1, ConnectivityStateInfo.forNonError(SHUTDOWN));
inOrder.verifyNoMoreInteractions();
deliverSubchannelState(subchannel3, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(helper).updatePicker(pickerCaptor.capture());
RoundRobinPicker picker8 = (RoundRobinPicker) pickerCaptor.getValue();
// subchannel2 is still IDLE, thus not in the active list
assertThat(picker8.list).containsExactly(new RoundRobinEntry(subchannel3, "token0003"), GrpclbLoadBalancer.DROP_ENTRY, new RoundRobinEntry(subchannel3, "token0005")).inOrder();
// subchannel2 becomes READY and makes it into the list
deliverSubchannelState(subchannel2, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(helper).updatePicker(pickerCaptor.capture());
RoundRobinPicker picker9 = (RoundRobinPicker) pickerCaptor.getValue();
assertThat(picker9.list).containsExactly(new RoundRobinEntry(subchannel3, "token0003"), GrpclbLoadBalancer.DROP_ENTRY, new RoundRobinEntry(subchannel2, "token0004"), new RoundRobinEntry(subchannel3, "token0005")).inOrder();
verify(subchannel3, never()).shutdown();
assertFalse(oobChannel.isShutdown());
assertEquals(1, lbRequestObservers.size());
verify(lbRequestObservers.peek(), never()).onCompleted();
verify(lbRequestObservers.peek(), never()).onError(any(Throwable.class));
}
use of io.grpc.EquivalentAddressGroup in project grpc-java by grpc.
the class RoundRobinLoadBalancerTest method pickAfterResolvedUpdatedHosts.
@Test
public void pickAfterResolvedUpdatedHosts() throws Exception {
Subchannel removedSubchannel = mock(Subchannel.class);
Subchannel oldSubchannel = mock(Subchannel.class);
Subchannel newSubchannel = mock(Subchannel.class);
for (Subchannel subchannel : Lists.newArrayList(removedSubchannel, oldSubchannel, newSubchannel)) {
when(subchannel.getAttributes()).thenReturn(Attributes.newBuilder().set(STATE_INFO, new AtomicReference<ConnectivityStateInfo>(ConnectivityStateInfo.forNonError(READY))).build());
}
FakeSocketAddress removedAddr = new FakeSocketAddress("removed");
FakeSocketAddress oldAddr = new FakeSocketAddress("old");
FakeSocketAddress newAddr = new FakeSocketAddress("new");
final Map<EquivalentAddressGroup, Subchannel> subchannels2 = Maps.newHashMap();
subchannels2.put(new EquivalentAddressGroup(removedAddr), removedSubchannel);
subchannels2.put(new EquivalentAddressGroup(oldAddr), oldSubchannel);
List<ResolvedServerInfoGroup> currentServers = Lists.newArrayList(ResolvedServerInfoGroup.builder().add(new ResolvedServerInfo(removedAddr)).add(new ResolvedServerInfo(oldAddr)).build());
doAnswer(new Answer<Subchannel>() {
@Override
public Subchannel answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return subchannels2.get(args[0]);
}
}).when(mockHelper).createSubchannel(any(EquivalentAddressGroup.class), any(Attributes.class));
loadBalancer.handleResolvedAddresses(currentServers, affinity);
InOrder inOrder = inOrder(mockHelper);
inOrder.verify(mockHelper).updatePicker(pickerCaptor.capture());
Picker picker = pickerCaptor.getValue();
assertNull(picker.getStatus());
assertThat(picker.getList()).containsExactly(removedSubchannel, oldSubchannel);
verify(removedSubchannel, times(1)).requestConnection();
verify(oldSubchannel, times(1)).requestConnection();
assertThat(loadBalancer.getSubchannels()).containsExactly(removedSubchannel, oldSubchannel);
subchannels2.clear();
subchannels2.put(new EquivalentAddressGroup(oldAddr), oldSubchannel);
subchannels2.put(new EquivalentAddressGroup(newAddr), newSubchannel);
List<ResolvedServerInfoGroup> latestServers = Lists.newArrayList(ResolvedServerInfoGroup.builder().add(new ResolvedServerInfo(oldAddr)).add(new ResolvedServerInfo(newAddr)).build());
loadBalancer.handleResolvedAddresses(latestServers, affinity);
verify(newSubchannel, times(1)).requestConnection();
verify(removedSubchannel, times(1)).shutdown();
assertThat(loadBalancer.getSubchannels()).containsExactly(oldSubchannel, newSubchannel);
verify(mockHelper, times(3)).createSubchannel(any(EquivalentAddressGroup.class), any(Attributes.class));
inOrder.verify(mockHelper).updatePicker(pickerCaptor.capture());
picker = pickerCaptor.getValue();
assertNull(picker.getStatus());
assertThat(picker.getList()).containsExactly(oldSubchannel, newSubchannel);
verifyNoMoreInteractions(mockHelper);
}
use of io.grpc.EquivalentAddressGroup in project grpc-java by grpc.
the class ManagedChannelImplIdlenessTest method realTransportsHoldsOffIdleness.
@Test
public void realTransportsHoldsOffIdleness() throws Exception {
final EquivalentAddressGroup addressGroup = addressGroupList.get(1);
// Start a call, which goes to delayed transport
ClientCall<String, Integer> call = channel.newCall(method, CallOptions.DEFAULT);
call.start(mockCallListener, new Metadata());
// Verify that we have exited the idle mode
ArgumentCaptor<Helper> helperCaptor = ArgumentCaptor.forClass(null);
verify(mockLoadBalancerFactory).newLoadBalancer(helperCaptor.capture());
Helper helper = helperCaptor.getValue();
assertTrue(channel.inUseStateAggregator.isInUse());
// Assume LoadBalancer has received an address, then create a subchannel.
Subchannel subchannel = helper.createSubchannel(addressGroup, Attributes.EMPTY);
subchannel.requestConnection();
MockClientTransportInfo t0 = newTransports.poll();
t0.listener.transportReady();
SubchannelPicker mockPicker = mock(SubchannelPicker.class);
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(PickResult.withSubchannel(subchannel));
helper.updatePicker(mockPicker);
// Delayed transport creates real streams in the app executor
executor.runDueTasks();
// Delayed transport exits in-use, while real transport has not entered in-use yet.
assertFalse(channel.inUseStateAggregator.isInUse());
// Now it's in-use
t0.listener.transportInUse(true);
assertTrue(channel.inUseStateAggregator.isInUse());
// As long as the transport is in-use, the channel won't go idle.
timer.forwardTime(IDLE_TIMEOUT_SECONDS * 2, TimeUnit.SECONDS);
assertTrue(channel.inUseStateAggregator.isInUse());
t0.listener.transportInUse(false);
assertFalse(channel.inUseStateAggregator.isInUse());
// And allow the channel to go idle.
timer.forwardTime(IDLE_TIMEOUT_SECONDS - 1, TimeUnit.SECONDS);
verify(mockLoadBalancer, never()).shutdown();
timer.forwardTime(1, TimeUnit.SECONDS);
verify(mockLoadBalancer).shutdown();
}
use of io.grpc.EquivalentAddressGroup in project grpc-java by grpc.
the class InternalSubchannelTest method createInternalSubchannel.
private void createInternalSubchannel(SocketAddress... addrs) {
addressGroup = new EquivalentAddressGroup(Arrays.asList(addrs));
internalSubchannel = new InternalSubchannel(addressGroup, AUTHORITY, USER_AGENT, mockBackoffPolicyProvider, mockTransportFactory, fakeClock.getScheduledExecutorService(), fakeClock.getStopwatchSupplier(), channelExecutor, mockInternalSubchannelCallback);
}
Aggregations