use of io.grpc.LoadBalancer.PickResult in project grpc-java by grpc.
the class OobChannel method setSubchannel.
// Must be called only once, right after the OobChannel is created.
void setSubchannel(final InternalSubchannel subchannel) {
log.log(Level.FINE, "[{0}] Created with [{1}]", new Object[] { this, subchannel });
subchannelImpl = new SubchannelImpl() {
@Override
public void shutdown() {
subchannel.shutdown();
}
@Override
ClientTransport obtainActiveTransport() {
return subchannel.obtainActiveTransport();
}
@Override
public void requestConnection() {
subchannel.obtainActiveTransport();
}
@Override
public EquivalentAddressGroup getAddresses() {
return subchannel.getAddressGroup();
}
@Override
public Attributes getAttributes() {
return Attributes.EMPTY;
}
};
subchannelPicker = new SubchannelPicker() {
final PickResult result = PickResult.withSubchannel(subchannelImpl);
@Override
public PickResult pickSubchannel(PickSubchannelArgs args) {
return result;
}
};
delayedTransport.reprocess(subchannelPicker);
}
use of io.grpc.LoadBalancer.PickResult in project grpc-java by grpc.
the class DelayedClientTransportTest method reprocess_newStreamRacesWithReprocess.
@Test
public void reprocess_newStreamRacesWithReprocess() throws Exception {
final CyclicBarrier barrier = new CyclicBarrier(2);
// In both phases, we only expect the first pickSubchannel() call to block on the barrier.
final AtomicBoolean nextPickShouldWait = new AtomicBoolean(true);
///////// Phase 1: reprocess() twice with the same picker
SubchannelPicker picker = mock(SubchannelPicker.class);
doAnswer(new Answer<PickResult>() {
@Override
public PickResult answer(InvocationOnMock invocation) throws Throwable {
if (nextPickShouldWait.compareAndSet(true, false)) {
try {
barrier.await();
return PickResult.withNoResult();
} catch (Exception e) {
e.printStackTrace();
}
}
return PickResult.withNoResult();
}
}).when(picker).pickSubchannel(any(PickSubchannelArgs.class));
// Because there is no pending stream yet, it will do nothing but save the picker.
delayedTransport.reprocess(picker);
verify(picker, never()).pickSubchannel(any(PickSubchannelArgs.class));
Thread sideThread = new Thread("sideThread") {
@Override
public void run() {
// Will call pickSubchannel and wait on barrier
delayedTransport.newStream(method, headers, callOptions, statsTraceCtx);
}
};
sideThread.start();
PickSubchannelArgsImpl args = new PickSubchannelArgsImpl(method, headers, callOptions);
PickSubchannelArgsImpl args2 = new PickSubchannelArgsImpl(method, headers2, callOptions);
// Is called from sideThread
verify(picker, timeout(5000)).pickSubchannel(args);
// Because stream has not been buffered (it's still stuck in newStream()), this will do nothing,
// but incrementing the picker version.
delayedTransport.reprocess(picker);
verify(picker).pickSubchannel(args);
// Now let the stuck newStream() through
barrier.await(5, TimeUnit.SECONDS);
sideThread.join(5000);
assertFalse("sideThread should've exited", sideThread.isAlive());
// newStream() detects that there has been a new picker while it's stuck, thus will pick again.
verify(picker, times(2)).pickSubchannel(args);
barrier.reset();
nextPickShouldWait.set(true);
////////// Phase 2: reprocess() with a different picker
// Create the second stream
Thread sideThread2 = new Thread("sideThread2") {
@Override
public void run() {
// Will call pickSubchannel and wait on barrier
delayedTransport.newStream(method, headers2, callOptions, statsTraceCtx);
}
};
sideThread2.start();
// The second stream will see the first picker
verify(picker, timeout(5000)).pickSubchannel(args2);
// While the first stream won't use the first picker any more.
verify(picker, times(2)).pickSubchannel(args);
// Now use a different picker
SubchannelPicker picker2 = mock(SubchannelPicker.class);
when(picker2.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(PickResult.withNoResult());
delayedTransport.reprocess(picker2);
// The pending first stream uses the new picker
verify(picker2).pickSubchannel(args);
// The second stream is still pending in creation, doesn't use the new picker.
verify(picker2, never()).pickSubchannel(args2);
// Now let the second stream finish creation
barrier.await(5, TimeUnit.SECONDS);
sideThread2.join(5000);
assertFalse("sideThread2 should've exited", sideThread2.isAlive());
// The second stream should see the new picker
verify(picker2, timeout(5000)).pickSubchannel(args2);
// Wrapping up
verify(picker, times(2)).pickSubchannel(args);
verify(picker).pickSubchannel(args2);
verify(picker2).pickSubchannel(args);
verify(picker2).pickSubchannel(args);
}
use of io.grpc.LoadBalancer.PickResult in project grpc-java by grpc.
the class PickFirstLoadBalancerTest method nameResolutionError.
@Test
public void nameResolutionError() throws Exception {
Status error = Status.NOT_FOUND.withDescription("nameResolutionError");
loadBalancer.handleNameResolutionError(error);
verify(mockHelper).updatePicker(pickerCaptor.capture());
PickResult pickResult = pickerCaptor.getValue().pickSubchannel(mockArgs);
assertEquals(null, pickResult.getSubchannel());
assertEquals(error, pickResult.getStatus());
verifyNoMoreInteractions(mockHelper);
}
use of io.grpc.LoadBalancer.PickResult in project grpc-java by grpc.
the class PickFirstLoadBalancerTest method nameResolutionErrorWithStateChanges.
@Test
public void nameResolutionErrorWithStateChanges() throws Exception {
InOrder inOrder = inOrder(mockHelper);
loadBalancer.handleSubchannelState(mockSubchannel, ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE));
Status error = Status.NOT_FOUND.withDescription("nameResolutionError");
loadBalancer.handleNameResolutionError(error);
inOrder.verify(mockHelper).updatePicker(pickerCaptor.capture());
PickResult pickResult = pickerCaptor.getValue().pickSubchannel(mockArgs);
assertEquals(null, pickResult.getSubchannel());
assertEquals(error, pickResult.getStatus());
loadBalancer.handleSubchannelState(mockSubchannel, ConnectivityStateInfo.forNonError(ConnectivityState.READY));
Status error2 = Status.NOT_FOUND.withDescription("nameResolutionError2");
loadBalancer.handleNameResolutionError(error2);
inOrder.verify(mockHelper).updatePicker(pickerCaptor.capture());
pickResult = pickerCaptor.getValue().pickSubchannel(mockArgs);
assertEquals(null, pickResult.getSubchannel());
assertEquals(error2, pickResult.getStatus());
verifyNoMoreInteractions(mockHelper);
}
use of io.grpc.LoadBalancer.PickResult in project grpc-java by grpc.
the class DelayedClientTransport method newStream.
/**
* If a {@link SubchannelPicker} is being, or has been provided via {@link #reprocess}, the last
* picker will be consulted.
*
* <p>Otherwise, if the delayed transport is not shutdown, then a {@link PendingStream} is
* returned; if the transport is shutdown, then a {@link FailingClientStream} is returned.
*/
@Override
public final ClientStream newStream(MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions, StatsTraceContext statsTraceCtx) {
try {
SubchannelPicker picker = null;
PickSubchannelArgs args = new PickSubchannelArgsImpl(method, headers, callOptions);
long pickerVersion = -1;
synchronized (lock) {
if (!shutdown) {
if (lastPicker == null) {
return createPendingStream(args, statsTraceCtx);
}
picker = lastPicker;
pickerVersion = lastPickerVersion;
}
}
if (picker != null) {
while (true) {
PickResult pickResult = picker.pickSubchannel(args);
ClientTransport transport = GrpcUtil.getTransportFromPickResult(pickResult, callOptions.isWaitForReady());
if (transport != null) {
return transport.newStream(args.getMethodDescriptor(), args.getHeaders(), args.getCallOptions(), statsTraceCtx);
}
// picker.
synchronized (lock) {
if (shutdown) {
break;
}
if (pickerVersion == lastPickerVersion) {
return createPendingStream(args, statsTraceCtx);
}
picker = lastPicker;
pickerVersion = lastPickerVersion;
}
}
}
return new FailingClientStream(Status.UNAVAILABLE.withDescription("Channel has shutdown (reported by delayed transport)"));
} finally {
channelExecutor.drain();
}
}
Aggregations