Search in sources :

Example 1 with SubchannelPicker

use of io.grpc.LoadBalancer.SubchannelPicker 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);
}
Also used : SubchannelPicker(io.grpc.LoadBalancer.SubchannelPicker) EquivalentAddressGroup(io.grpc.EquivalentAddressGroup) Attributes(io.grpc.Attributes) PickResult(io.grpc.LoadBalancer.PickResult) PickSubchannelArgs(io.grpc.LoadBalancer.PickSubchannelArgs)

Example 2 with SubchannelPicker

use of io.grpc.LoadBalancer.SubchannelPicker in project grpc-java by grpc.

the class DelayedClientTransportTest method reprocessSemantics.

@Test
public void reprocessSemantics() {
    CallOptions failFastCallOptions = CallOptions.DEFAULT.withOption(SHARD_ID, 1);
    CallOptions waitForReadyCallOptions = CallOptions.DEFAULT.withOption(SHARD_ID, 2).withWaitForReady();
    AbstractSubchannel subchannel1 = mock(AbstractSubchannel.class);
    AbstractSubchannel subchannel2 = mock(AbstractSubchannel.class);
    AbstractSubchannel subchannel3 = mock(AbstractSubchannel.class);
    when(mockRealTransport.newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class), ArgumentMatchers.<ClientStreamTracer[]>any())).thenReturn(mockRealStream);
    when(mockRealTransport2.newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class), ArgumentMatchers.<ClientStreamTracer[]>any())).thenReturn(mockRealStream2);
    when(subchannel1.getInternalSubchannel()).thenReturn(newTransportProvider(mockRealTransport));
    when(subchannel2.getInternalSubchannel()).thenReturn(newTransportProvider(mockRealTransport2));
    when(subchannel3.getInternalSubchannel()).thenReturn(newTransportProvider(null));
    // Fail-fast streams
    DelayedStream ff1 = (DelayedStream) delayedTransport.newStream(method, headers, failFastCallOptions, tracers);
    ff1.start(mock(ClientStreamListener.class));
    ff1.halfClose();
    PickSubchannelArgsImpl ff1args = new PickSubchannelArgsImpl(method, headers, failFastCallOptions);
    verify(transportListener).transportInUse(true);
    DelayedStream ff2 = (DelayedStream) delayedTransport.newStream(method2, headers2, failFastCallOptions, tracers);
    PickSubchannelArgsImpl ff2args = new PickSubchannelArgsImpl(method2, headers2, failFastCallOptions);
    DelayedStream ff3 = (DelayedStream) delayedTransport.newStream(method, headers, failFastCallOptions, tracers);
    PickSubchannelArgsImpl ff3args = new PickSubchannelArgsImpl(method, headers, failFastCallOptions);
    DelayedStream ff4 = (DelayedStream) delayedTransport.newStream(method2, headers2, failFastCallOptions, tracers);
    PickSubchannelArgsImpl ff4args = new PickSubchannelArgsImpl(method2, headers2, failFastCallOptions);
    // Wait-for-ready streams
    FakeClock wfr3Executor = new FakeClock();
    DelayedStream wfr1 = (DelayedStream) delayedTransport.newStream(method, headers, waitForReadyCallOptions, tracers);
    PickSubchannelArgsImpl wfr1args = new PickSubchannelArgsImpl(method, headers, waitForReadyCallOptions);
    DelayedStream wfr2 = (DelayedStream) delayedTransport.newStream(method2, headers2, waitForReadyCallOptions, tracers);
    PickSubchannelArgsImpl wfr2args = new PickSubchannelArgsImpl(method2, headers2, waitForReadyCallOptions);
    CallOptions wfr3callOptions = waitForReadyCallOptions.withExecutor(wfr3Executor.getScheduledExecutorService());
    DelayedStream wfr3 = (DelayedStream) delayedTransport.newStream(method, headers, wfr3callOptions, tracers);
    wfr3.start(mock(ClientStreamListener.class));
    wfr3.halfClose();
    PickSubchannelArgsImpl wfr3args = new PickSubchannelArgsImpl(method, headers, wfr3callOptions);
    DelayedStream wfr4 = (DelayedStream) delayedTransport.newStream(method2, headers2, waitForReadyCallOptions, tracers);
    PickSubchannelArgsImpl wfr4args = new PickSubchannelArgsImpl(method2, headers2, waitForReadyCallOptions);
    assertEquals(8, delayedTransport.getPendingStreamsCount());
    // First reprocess(). Some will proceed, some will fail and the rest will stay buffered.
    SubchannelPicker picker = mock(SubchannelPicker.class);
    when(picker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(// ff1: proceed
    PickResult.withSubchannel(subchannel1), // ff2: fail
    PickResult.withError(Status.UNAVAILABLE), // ff3: stay
    PickResult.withSubchannel(subchannel3), // ff4: stay
    PickResult.withNoResult(), // wfr1: proceed
    PickResult.withSubchannel(subchannel2), // wfr2: stay
    PickResult.withError(Status.RESOURCE_EXHAUSTED), // wfr3: stay
    PickResult.withSubchannel(subchannel3));
    InOrder inOrder = inOrder(picker);
    delayedTransport.reprocess(picker);
    assertEquals(5, delayedTransport.getPendingStreamsCount());
    inOrder.verify(picker).pickSubchannel(ff1args);
    inOrder.verify(picker).pickSubchannel(ff2args);
    inOrder.verify(picker).pickSubchannel(ff3args);
    inOrder.verify(picker).pickSubchannel(ff4args);
    inOrder.verify(picker).pickSubchannel(wfr1args);
    inOrder.verify(picker).pickSubchannel(wfr2args);
    inOrder.verify(picker).pickSubchannel(wfr3args);
    inOrder.verify(picker).pickSubchannel(wfr4args);
    inOrder.verifyNoMoreInteractions();
    // Make sure that streams are created and started immediately, not in any executor. This is
    // necessary during shut down to guarantee that when DelayedClientTransport terminates, all
    // streams are now owned by a real transport (which should prevent the Channel from
    // terminating).
    // ff1 and wfr1 went through
    verify(mockRealTransport).newStream(method, headers, failFastCallOptions, tracers);
    verify(mockRealTransport2).newStream(method, headers, waitForReadyCallOptions, tracers);
    assertSame(mockRealStream, ff1.getRealStream());
    assertSame(mockRealStream2, wfr1.getRealStream());
    verify(mockRealStream).start(any(ClientStreamListener.class));
    // But also verify that non-start()-related calls are run within the Executor, since they may be
    // slow.
    verify(mockRealStream, never()).halfClose();
    fakeExecutor.runDueTasks();
    assertEquals(0, fakeExecutor.numPendingTasks());
    verify(mockRealStream).halfClose();
    // The ff2 has failed due to picker returning an error
    assertSame(Status.UNAVAILABLE, ((FailingClientStream) ff2.getRealStream()).getError());
    // Other streams are still buffered
    assertNull(ff3.getRealStream());
    assertNull(ff4.getRealStream());
    assertNull(wfr2.getRealStream());
    assertNull(wfr3.getRealStream());
    assertNull(wfr4.getRealStream());
    // Second reprocess(). All existing streams will proceed.
    picker = mock(SubchannelPicker.class);
    when(picker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(// ff3
    PickResult.withSubchannel(subchannel1), // ff4
    PickResult.withSubchannel(subchannel2), // wfr2
    PickResult.withSubchannel(subchannel2), // wfr3
    PickResult.withSubchannel(subchannel1), // wfr4
    PickResult.withSubchannel(subchannel2), // wfr5 (not yet created)
    PickResult.withNoResult());
    inOrder = inOrder(picker);
    assertEquals(0, wfr3Executor.numPendingTasks());
    verify(transportListener, never()).transportInUse(false);
    delayedTransport.reprocess(picker);
    assertEquals(0, delayedTransport.getPendingStreamsCount());
    verify(transportListener).transportInUse(false);
    // ff3
    inOrder.verify(picker).pickSubchannel(ff3args);
    // ff4
    inOrder.verify(picker).pickSubchannel(ff4args);
    // wfr2
    inOrder.verify(picker).pickSubchannel(wfr2args);
    // wfr3
    inOrder.verify(picker).pickSubchannel(wfr3args);
    // wfr4
    inOrder.verify(picker).pickSubchannel(wfr4args);
    inOrder.verifyNoMoreInteractions();
    fakeExecutor.runDueTasks();
    assertEquals(0, fakeExecutor.numPendingTasks());
    assertSame(mockRealStream, ff3.getRealStream());
    assertSame(mockRealStream2, ff4.getRealStream());
    assertSame(mockRealStream2, wfr2.getRealStream());
    assertSame(mockRealStream2, wfr4.getRealStream());
    assertSame(mockRealStream, wfr3.getRealStream());
    // If there is an executor in the CallOptions, it will be used to create the real stream.
    // 1 for ff1
    verify(mockRealStream, times(1)).halfClose();
    wfr3Executor.runDueTasks();
    verify(mockRealStream, times(2)).halfClose();
    // New streams will use the last picker
    DelayedStream wfr5 = (DelayedStream) delayedTransport.newStream(method, headers, waitForReadyCallOptions, tracers);
    assertNull(wfr5.getRealStream());
    inOrder.verify(picker).pickSubchannel(new PickSubchannelArgsImpl(method, headers, waitForReadyCallOptions));
    inOrder.verifyNoMoreInteractions();
    assertEquals(1, delayedTransport.getPendingStreamsCount());
    // wfr5 will stop delayed transport from terminating
    delayedTransport.shutdown(SHUTDOWN_STATUS);
    verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS));
    verify(transportListener, never()).transportTerminated();
    // ... until it's gone
    picker = mock(SubchannelPicker.class);
    when(picker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(PickResult.withSubchannel(subchannel1));
    delayedTransport.reprocess(picker);
    verify(picker).pickSubchannel(new PickSubchannelArgsImpl(method, headers, waitForReadyCallOptions));
    fakeExecutor.runDueTasks();
    assertSame(mockRealStream, wfr5.getRealStream());
    assertEquals(0, delayedTransport.getPendingStreamsCount());
    verify(transportListener).transportTerminated();
}
Also used : SubchannelPicker(io.grpc.LoadBalancer.SubchannelPicker) ClientStreamTracer(io.grpc.ClientStreamTracer) InOrder(org.mockito.InOrder) Metadata(io.grpc.Metadata) PickSubchannelArgs(io.grpc.LoadBalancer.PickSubchannelArgs) CallOptions(io.grpc.CallOptions) MethodDescriptor(io.grpc.MethodDescriptor) Test(org.junit.Test)

Example 3 with SubchannelPicker

use of io.grpc.LoadBalancer.SubchannelPicker 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, ClientStreamTracer[] tracers) {
    try {
        PickSubchannelArgs args = new PickSubchannelArgsImpl(method, headers, callOptions);
        SubchannelPicker picker = null;
        long pickerVersion = -1;
        while (true) {
            synchronized (lock) {
                if (shutdownStatus != null) {
                    return new FailingClientStream(shutdownStatus, tracers);
                }
                if (lastPicker == null) {
                    return createPendingStream(args, tracers);
                }
                // Check for second time through the loop, and whether anything changed
                if (picker != null && pickerVersion == lastPickerVersion) {
                    return createPendingStream(args, tracers);
                }
                picker = lastPicker;
                pickerVersion = lastPickerVersion;
            }
            PickResult pickResult = picker.pickSubchannel(args);
            ClientTransport transport = GrpcUtil.getTransportFromPickResult(pickResult, callOptions.isWaitForReady());
            if (transport != null) {
                return transport.newStream(args.getMethodDescriptor(), args.getHeaders(), args.getCallOptions(), tracers);
            }
        // This picker's conclusion is "buffer".  If there hasn't been a newer picker set (possible
        // race with reprocess()), we will buffer it.  Otherwise, will try with the new picker.
        }
    } finally {
        syncContext.drain();
    }
}
Also used : SubchannelPicker(io.grpc.LoadBalancer.SubchannelPicker) PickResult(io.grpc.LoadBalancer.PickResult) PickSubchannelArgs(io.grpc.LoadBalancer.PickSubchannelArgs)

Example 4 with SubchannelPicker

use of io.grpc.LoadBalancer.SubchannelPicker in project grpc-java by grpc.

the class RoundRobinLoadBalancerTest method subchannelStateIsolation.

@Test
public void subchannelStateIsolation() throws Exception {
    Iterator<Subchannel> subchannelIterator = subchannels.values().iterator();
    Subchannel sc1 = subchannelIterator.next();
    Subchannel sc2 = subchannelIterator.next();
    Subchannel sc3 = subchannelIterator.next();
    loadBalancer.handleResolvedAddresses(ResolvedAddresses.newBuilder().setAddresses(servers).setAttributes(Attributes.EMPTY).build());
    verify(sc1, times(1)).requestConnection();
    verify(sc2, times(1)).requestConnection();
    verify(sc3, times(1)).requestConnection();
    deliverSubchannelState(sc1, ConnectivityStateInfo.forNonError(READY));
    deliverSubchannelState(sc2, ConnectivityStateInfo.forNonError(READY));
    deliverSubchannelState(sc3, ConnectivityStateInfo.forNonError(READY));
    deliverSubchannelState(sc2, ConnectivityStateInfo.forNonError(IDLE));
    deliverSubchannelState(sc3, ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE));
    verify(mockHelper, times(6)).updateBalancingState(stateCaptor.capture(), pickerCaptor.capture());
    Iterator<ConnectivityState> stateIterator = stateCaptor.getAllValues().iterator();
    Iterator<SubchannelPicker> pickers = pickerCaptor.getAllValues().iterator();
    // The picker is incrementally updated as subchannels become READY
    assertEquals(CONNECTING, stateIterator.next());
    assertThat(pickers.next()).isInstanceOf(EmptyPicker.class);
    assertEquals(READY, stateIterator.next());
    assertThat(getList(pickers.next())).containsExactly(sc1);
    assertEquals(READY, stateIterator.next());
    assertThat(getList(pickers.next())).containsExactly(sc1, sc2);
    assertEquals(READY, stateIterator.next());
    assertThat(getList(pickers.next())).containsExactly(sc1, sc2, sc3);
    // The IDLE subchannel is dropped from the picker, but a reconnection is requested
    assertEquals(READY, stateIterator.next());
    assertThat(getList(pickers.next())).containsExactly(sc1, sc3);
    verify(sc2, times(2)).requestConnection();
    // The failing subchannel is dropped from the picker, with no requested reconnect
    assertEquals(READY, stateIterator.next());
    assertThat(getList(pickers.next())).containsExactly(sc1);
    verify(sc3, times(1)).requestConnection();
    assertThat(stateIterator.hasNext()).isFalse();
    assertThat(pickers.hasNext()).isFalse();
}
Also used : SubchannelPicker(io.grpc.LoadBalancer.SubchannelPicker) ConnectivityState(io.grpc.ConnectivityState) Subchannel(io.grpc.LoadBalancer.Subchannel) Test(org.junit.Test)

Example 5 with SubchannelPicker

use of io.grpc.LoadBalancer.SubchannelPicker in project grpc-java by grpc.

the class RoundRobinLoadBalancerTest method pickerEmptyList.

@Test
public void pickerEmptyList() throws Exception {
    SubchannelPicker picker = new EmptyPicker(Status.UNKNOWN);
    assertEquals(null, picker.pickSubchannel(mockArgs).getSubchannel());
    assertEquals(Status.UNKNOWN, picker.pickSubchannel(mockArgs).getStatus());
}
Also used : SubchannelPicker(io.grpc.LoadBalancer.SubchannelPicker) EmptyPicker(io.grpc.util.RoundRobinLoadBalancer.EmptyPicker) Test(org.junit.Test)

Aggregations

SubchannelPicker (io.grpc.LoadBalancer.SubchannelPicker)50 Test (org.junit.Test)44 PickSubchannelArgs (io.grpc.LoadBalancer.PickSubchannelArgs)21 Helper (io.grpc.LoadBalancer.Helper)19 Metadata (io.grpc.Metadata)17 Subchannel (io.grpc.LoadBalancer.Subchannel)15 LoadBalancer (io.grpc.LoadBalancer)13 EquivalentAddressGroup (io.grpc.EquivalentAddressGroup)12 PickResult (io.grpc.LoadBalancer.PickResult)11 InOrder (org.mockito.InOrder)11 CreateSubchannelArgs (io.grpc.LoadBalancer.CreateSubchannelArgs)8 MockClientTransportInfo (io.grpc.internal.TestUtils.MockClientTransportInfo)7 CallOptions (io.grpc.CallOptions)6 ClientStreamTracer (io.grpc.ClientStreamTracer)6 Status (io.grpc.Status)6 PickSubchannelArgsImpl (io.grpc.internal.PickSubchannelArgsImpl)6 Attributes (io.grpc.Attributes)4 UnsupportedClientTransportFactoryBuilder (io.grpc.internal.ManagedChannelImplBuilder.UnsupportedClientTransportFactoryBuilder)4 ForwardingSubchannel (io.grpc.util.ForwardingSubchannel)4 ChannelLogger (io.grpc.ChannelLogger)3