core: promote LBv2 classes.

This commit is contained in:
Kun Zhang 2017-02-21 17:11:03 -08:00 committed by Kun Zhang
parent a6b1d8981a
commit a9bd94781c
25 changed files with 623 additions and 594 deletions

View File

@ -41,7 +41,7 @@ import java.lang.annotation.Target;
* Annotates a program element (class, method, package etc) which is internal to gRPC, not part of
* the public API, and should not be used by users of gRPC.
*
* <p>However, if you want to implement a custom {@link LoadBalancer2}, an alternative transport, or
* <p>However, if you want to implement a custom {@link LoadBalancer}, an alternative transport, or
* anything else that will be wired into gRPC library, you may use the internal parts. Please
* consult the gRPC team first, because internal APIs don't have the same API stability guarantee as
* the public APIs do.

View File

@ -0,0 +1,414 @@
/*
* Copyright 2016, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package io.grpc;
import com.google.common.base.Preconditions;
import java.util.List;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;
import javax.annotation.concurrent.ThreadSafe;
/**
* A pluggable component that receives resolved addresses from {@link NameResolver} and provides the
* channel a usable subchannel when asked.
*
* <h3>Overview</h3>
*
* <p>A LoadBalancer typically implements three interfaces:
* <ol>
* <li>{@link LoadBalancer} is the main interface. All methods on it are invoked sequentially
* from the Channel Executor. It receives the results from the {@link NameResolver}, updates
* of subchannels' connectivity states, and the channel's request for the LoadBalancer to
* shutdown.</li>
* <li>{@link SubchannelPicker SubchannelPicker} does the actual load-balancing work. It selects
* a {@link Subchannel Subchannel} for each new RPC.</li>
* <li>{@link Factory Factory} creates a new {@link LoadBalancer} instance.
* </ol>
*
* <p>{@link Helper Helper} is implemented by gRPC library and provided to {@link Factory
* Factory}. It provides functionalities that a {@code LoadBalancer} implementation would typically
* need.
*
* <h3>Channel Executor</h3>
*
* <p>Channel Executor is an internal executor of the channel, which is used to serialize all the
* callback methods on the {@link LoadBalancer} interface, thus the balancer implementation doesn't
* need to worry about synchronization among them. However, the actual thread of the Channel
* Executor is typically the network thread, thus the following rules must be followed to prevent
* blocking or even dead-locking in a network
*
* <ol>
*
* <li><strong>Never block in Channel Executor</strong>. The callback methods must return
* quickly. Examples or work that must be avoided: CPU-intensive calculation, waiting on
* synchronization primitives, blocking I/O, blocking RPCs, etc.</li>
*
* <li><strong>Avoid calling into other components with lock held</strong>. Channel Executor may
* run callbacks under a lock, e.g., the transport lock of OkHttp. If your LoadBalancer has a
* lock, holds the lock in a callback method (e.g., {@link #handleSubchannelState
* handleSubchannelState()}) while calling into another class that may involve locks, be cautious
* of deadlock. Generally you wouldn't need any locking in the LoadBalancer.</li>
*
* </ol>
*
* <p>{@link Helper#runSerialized Helper.runSerialized()} allows you to schedule a task to be run in
* the Channel Executor.
*
* <h3>The canonical implementation pattern</h3>
*
* <p>A {@link LoadBalancer} keeps states like the latest addresses from NameResolver, the
* Subchannel(s) and their latest connectivity states. These states are mutated within the Channel
* Executor.
*
* <p>A typical {@link SubchannelPicker SubchannelPicker} holds a snapshot of these states. It may
* have its own states, e.g., a picker from a round-robin load-balancer may keep a pointer to the
* next Subchannel, which are typically mutated by multiple threads. The picker should only mutate
* its own state, and should not mutate or re-acquire the states of the LoadBalancer. This way the
* picker only needs to synchronize its own states, which is typically trivial to implement.
*
* <p>When the LoadBalancer states changes, e.g., Subchannels has become or stopped being READY, and
* we want subsequent RPCs to use the latest list of READY Subchannels, LoadBalancer would create
* a new picker, which holds a snapshot of the latest Subchannel list. Refer to the javadoc of
* {@link #handleSubchannelState handleSubchannelState()} how to do this properly.
*
* <p>No synchronization should be necessary between LoadBalancer and its pickers if you follow
* the pattern above. It may be possible to implement in a different way, but that would usually
* result in more complicated threading.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771")
@NotThreadSafe
public abstract class LoadBalancer {
/**
* Handles newly resolved server groups and metadata attributes from name resolution system.
* {@code servers} contained in {@link ResolvedServerInfoGroup} should be considered equivalent
* but may be flattened into a single list if needed.
*
* <p>Implementations should not modify the given {@code servers}.
*
* @param servers the resolved server addresses, never empty.
* @param attributes extra metadata from naming system.
*/
public abstract void handleResolvedAddresses(
List<ResolvedServerInfoGroup> servers, Attributes attributes);
/**
* Handles an error from the name resolution system.
*
* @param error a non-OK status
*/
public abstract void handleNameResolutionError(Status error);
/**
* Handles a state change on a Subchannel.
*
* <p>The initial state of a Subchannel is IDLE. You won't get a notification for the initial IDLE
* state.
*
* <p>If the new state is not SHUTDOWN, this method should create a new picker and call {@link
* Helper#updatePicker Helper.updatePicker()}. Failing to do so may result in unnecessary delays
* of RPCs. Please refer to {@link PickResult#withSubchannel PickResult.withSubchannel()}'s
* javadoc for more information.
*
* <p>SHUTDOWN can only happen in two cases. One is that LoadBalancer called {@link
* Subchannel#shutdown} earlier, thus it should have already discarded this Subchannel. The other
* is that Channel is doing a {@link ManagedChannel#shutdownNow forced shutdown} or has already
* terminated, thus there won't be further requests to LoadBalancer. Therefore, SHUTDOWN can be
* safely ignored.
*
* @param subchannel the involved Subchannel
* @param stateInfo the new state
*/
public abstract void handleSubchannelState(
Subchannel subchannel, ConnectivityStateInfo stateInfo);
/**
* The channel asks the load-balancer to shutdown. No more callbacks will be called after this
* method. The implementation should shutdown all Subchannels and OOB channels, and do any other
* cleanup as necessary.
*/
public abstract void shutdown();
/**
* The main balancing logic. It <strong>must be thread-safe</strong>. Typically it should only
* synchronize on its own state, and avoid synchronizing with the LoadBalancer's state.
*/
@ThreadSafe
public abstract static class SubchannelPicker {
/**
* Make a balancing decision for a new RPC.
*
* @param affinity the affinity attributes provided via {@link CallOptions#withAffinity}
* @param headers the headers container of the RPC. It can be mutated within this method.
*/
public abstract PickResult pickSubchannel(Attributes affinity, Metadata headers);
}
/**
* A balancing decision made by {@link SubchannelPicker SubchannelPicker} for an RPC.
*
* <p>The outcome of the decision will be one of the following:
* <ul>
* <li>Proceed: if a Subchannel is provided via {@link #withSubchannel withSubchannel()}, and is
* in READY state when the RPC tries to start on it, the RPC will proceed on that
* Subchannel.</li>
* <li>Error: if an error is provided via {@link #withError withError()}, and the RPC is not
* wait-for-ready (i.e., {@link CallOptions#withWaitForReady} was not called), the RPC will
* fail immediately with the given error.</li>
* <li>Buffer: in all other cases, the RPC will be buffered in the Channel, until the next
* picker is provided via {@link Helper#updatePicker Helper.updatePicker()}, when the RPC
* will go through the same picking process again.</li>
* </ul>
*/
@Immutable
public static final class PickResult {
private static final PickResult NO_RESULT = new PickResult(null, Status.OK);
@Nullable private final Subchannel subchannel;
// An error to be propagated to the application if subchannel == null
// Or OK if there is no error.
// subchannel being null and error being OK means RPC needs to wait
private final Status status;
private PickResult(Subchannel subchannel, Status status) {
this.subchannel = subchannel;
this.status = Preconditions.checkNotNull(status, "status");
}
/**
* A decision to proceed the RPC on a Subchannel.
*
* <p>Only Subchannels returned by {@link Helper#createSubchannel Helper.createSubchannel()}
* will work. DO NOT try to use your own implementations of Subchannels, as they won't work.
*
* <p>When the RPC tries to use the return Subchannel, which is briefly after this method
* returns, the state of the Subchannel will decide where the RPC would go:
*
* <ul>
* <li>READY: the RPC will proceed on this Subchannel.</li>
* <li>IDLE: the RPC will be buffered. Subchannel will attempt to create connection.</li>
* <li>All other states: the RPC will be buffered.</li>
* </ul>
*
* <p><strong>All buffered RPCs will stay buffered</strong> until the next call of {@link
* Helper#updatePicker Helper.updatePicker()}, which will trigger a new picking process.
*
* <p>Note that Subchannel's state may change at the same time the picker is making the
* decision, which means the decision may be made with (to-be) outdated information. For
* example, a picker may return a Subchannel known to be READY, but it has become IDLE when is
* about to be used by the RPC, which makes the RPC to be buffered. The LoadBalancer will soon
* learn about the Subchannels' transition from READY to IDLE, create a new picker and allow the
* RPC to use another READY transport if there is any.
*
* <p>You will want to avoid running into a situation where there are READY Subchannels out
* there but some RPCs are still buffered for longer than a brief time.
* <ul>
* <li>This can happen if you return Subchannels with states other than READY and IDLE. For
* example, suppose you round-robin on 2 Subchannels, in READY and CONNECTING states
* respectively. If the picker ignores the state and pick them equally, 50% of RPCs will
* be stuck in buffered state until both Subchannels are READY.</li>
* <li>This can also happen if you don't create a new picker at key state changes of
* Subchannels. Take the above round-robin example again. Suppose you do pick only READY
* and IDLE Subchannels, and initially both Subchannels are READY. Now one becomes IDLE,
* then CONNECTING and stays CONNECTING for a long time. If you don't create a new picker
* in response to the CONNECTING state to exclude that Subchannel, 50% of RPCs will hit it
* and be buffered even though the other Subchannel is READY.</li>
* </ul>
*
* <p>In order to prevent unnecessary delay of RPCs, the rules of thumb are:
* <ol>
* <li>The picker should only pick Subchannels that are known as READY or IDLE. Whether to
* pick IDLE Subchannels depends on whether you want Subchannels to connect on-demand or
* actively:
* <ul>
* <li>If you want connect-on-demand, include IDLE Subchannels in your pick results,
* because when an RPC tries to use an IDLE Subchannel, the Subchannel will try to
* connect.</li>
* <li>If you want Subchannels to be always connected even when there is no RPC, you
* would call {@link Subchannel#requestConnection Subchannel.requestConnection()}
* whenever the Subchannel has transitioned to IDLE, then you don't need to include
* IDLE Subchannels in your pick results.</li>
* </ul></li>
* <li>Always create a new picker and call {@link Helper#updatePicker Helper.updatePicker()}
* whenever {@link #handleSubchannelState handleSubchannelState()} is called, unless the
* new state is SHUTDOWN. See {@code handleSubchannelState}'s javadoc for more
* details.</li>
* </ol>
*/
public static PickResult withSubchannel(Subchannel subchannel) {
return new PickResult(Preconditions.checkNotNull(subchannel, "subchannel"), Status.OK);
}
/**
* A decision to report a connectivity error to the RPC. If the RPC is {@link
* CallOptions#withWaitForReady wait-for-ready}, it will stay buffered. Otherwise, it will fail
* with the given error.
*
* @param error the error status. Must not be OK.
*/
public static PickResult withError(Status error) {
Preconditions.checkArgument(!error.isOk(), "error status shouldn't be OK");
return new PickResult(null, error);
}
/**
* No decision could be made. The RPC will stay buffered.
*/
public static PickResult withNoResult() {
return NO_RESULT;
}
/**
* The Subchannel if this result was created by {@link #withSubchannel withSubchannel()}, or
* null otherwise.
*/
@Nullable
public Subchannel getSubchannel() {
return subchannel;
}
/**
* The status associated with this result. Non-{@code OK} if created with {@link #withError
* withError}, or {@code OK} otherwise.
*/
public Status getStatus() {
return status;
}
@Override
public String toString() {
return "[subchannel=" + subchannel + " status=" + status + "]";
}
}
/**
* Provides essentials for LoadBalancer implementations.
*/
@ThreadSafe
public abstract static class Helper {
/**
* Creates a Subchannel, which is a logical connection to the given group of addresses which are
* considered equivalent. The {@code attrs} are custom attributes associated with this
* Subchannel, and can be accessed later through {@link Subchannel#getAttributes
* Subchannel.getAttributes()}.
*
* <p>The LoadBalancer is responsible for closing unused Subchannels, and closing all
* Subchannels within {@link #shutdown}.
*/
public abstract Subchannel createSubchannel(EquivalentAddressGroup addrs, Attributes attrs);
/**
* Out-of-band channel for LoadBalancers own RPC needs, e.g., talking to an external
* load-balancer service.
*
* <p>The LoadBalancer is responsible for closing unused OOB channels, and closing all OOB
* channels within {@link #shutdown}.
*/
public abstract ManagedChannel createOobChannel(
EquivalentAddressGroup eag, String authority);
/**
* Set a new picker to the channel.
*
* <p>When a new picker is provided via {@code updatePicker()}, the channel will apply the
* picker on all buffered RPCs, by calling {@link SubchannelPicker#pickSubchannel
* SubchannelPicker.pickSubchannel()}.
*
* <p>The channel will hold the picker and use it for all RPCs, until {@code updatePicker()} is
* called again and a new picker replaces the old one. If {@code updatePicker()} has never been
* called, the channel will buffer all RPCs until a picker is provided.
*/
public abstract void updatePicker(SubchannelPicker picker);
/**
* Schedule a task to be run in the Channel Executor, which serializes the task with the
* callback methods on the {@link LoadBalancer} interface.
*/
public abstract void runSerialized(Runnable task);
/**
* Returns the NameResolver of the channel.
*/
public abstract NameResolver.Factory getNameResolverFactory();
/**
* Returns the authority string of the channel, which is derived from the DNS-style target name.
*/
public abstract String getAuthority();
}
/**
* A logical connection to a server, or a group of equivalent servers represented by an {@link
* EquivalentAddressGroup}.
*
* <p>It maintains at most one physical connection (aka transport) for sending new RPCs, while
* also keeps track of previous transports that has been shut down but not terminated yet.
*
* <p>If there isn't an active transport yet, and an RPC is assigned to the Subchannel, it will
* create a new transport. It won't actively create transports otherwise. {@link
* #requestConnection requestConnection()} can be used to ask Subchannel to create a transport if
* there isn't any.
*/
@ThreadSafe
public abstract static class Subchannel {
/**
* Shuts down the Subchannel. After this method is called, this Subchannel should no longer
* be returned by the latest {@link SubchannelPicker picker}, and can be safely discarded.
*/
public abstract void shutdown();
/**
* Asks the Subchannel to create a connection (aka transport), if there isn't an active one.
*/
public abstract void requestConnection();
/**
* Returns the addresses that this Subchannel is bound to.
*/
public abstract EquivalentAddressGroup getAddresses();
/**
* The same attributes passed to {@link Helper#createSubchannel Helper.createSubchannel()}.
* LoadBalancer can use it to attach additional information here, e.g., the shard this
* Subchannel belongs to.
*/
public abstract Attributes getAttributes();
}
@ThreadSafe
public abstract static class Factory {
/**
* Creates a {@link LoadBalancer} that will be used inside a channel.
*/
public abstract LoadBalancer newLoadBalancer(Helper helper);
}
}

View File

@ -31,390 +31,13 @@
package io.grpc;
import com.google.common.base.Preconditions;
import java.util.List;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;
import javax.annotation.concurrent.ThreadSafe;
/**
* A pluggable component that receives resolved addresses from {@link NameResolver} and provides the
* channel a usable subchannel when asked. This is the new interface that will replace {@link
* LoadBalancer2}.
* An alias for {@link LoadBalancer}.
*
* <p><strong>IMPORTANT NOTICE FOR IMPLEMENTORS: </strong>The name of this class is temporary. It
* will be renamed to {@code LoadBalancer} eventually. Make sure you have read through <a
* href="https://github.com/grpc/grpc-java/issues/2656" target="_blank">#2656</a> to understand the
* transition path.
*
* <h3>Overview</h3>
*
* <p>A LoadBalancer typically implements three interfaces:
* <ol>
* <li>{@link LoadBalancer2} is the main interface. All methods on it are invoked sequentially
* from the Channel Executor. It receives the results from the {@link NameResolver}, updates
* of subchannels' connectivity states, and the channel's request for the LoadBalancer to
* shutdown.</li>
* <li>{@link SubchannelPicker SubchannelPicker} does the actual load-balancing work. It selects
* a {@link Subchannel Subchannel} for each new RPC.</li>
* <li>{@link Factory Factory} creates a new {@link LoadBalancer2} instance.
* </ol>
*
* <p>{@link Helper Helper} is implemented by gRPC library and provided to {@link Factory
* Factory}. It provides functionalities that a {@code LoadBalancer2} implementation would typically
* need.
*
* <h3>Channel Executor</h3>
*
* <p>Channel Executor is an internal executor of the channel, which is used to serialize all the
* callback methods on the {@link LoadBalancer2} interface, thus the balancer implementation doesn't
* need to worry about synchronization among them. However, the actual thread of the Channel
* Executor is typically the network thread, thus the following rules must be followed to prevent
* blocking or even dead-locking in a network
*
* <ol>
*
* <li><strong>Never block in Channel Executor</strong>. The callback methods must return
* quickly. Examples or work that must be avoided: CPU-intensive calculation, waiting on
* synchronization primitives, blocking I/O, blocking RPCs, etc.</li>
*
* <li><strong>Avoid calling into other components with lock held</strong>. Channel Executor may
* run callbacks under a lock, e.g., the transport lock of OkHttp. If your LoadBalancer has a
* lock, holds the lock in a callback method (e.g., {@link #handleSubchannelState
* handleSubchannelState()}) while calling into another class that may involve locks, be cautious
* of deadlock. Generally you wouldn't need any locking in the LoadBalancer.</li>
*
* </ol>
*
* <p>{@link Helper#runSerialized Helper.runSerialized()} allows you to schedule a task to be run in
* the Channel Executor.
*
* <h3>The canonical implementation pattern</h3>
*
* <p>A {@link LoadBalancer2} keeps states like the latest addresses from NameResolver, the
* Subchannel(s) and their latest connectivity states. These states are mutated within the Channel
* Executor.
*
* <p>A typical {@link SubchannelPicker SubchannelPicker} holds a snapshot of these states. It may
* have its own states, e.g., a picker from a round-robin load-balancer may keep a pointer to the
* next Subchannel, which are typically mutated by multiple threads. The picker should only mutate
* its own state, and should not mutate or re-acquire the states of the LoadBalancer. This way the
* picker only needs to synchronize its own states, which is typically trivial to implement.
*
* <p>When the LoadBalancer states changes, e.g., Subchannels has become or stopped being READY, and
* we want subsequent RPCs to use the latest list of READY Subchannels, LoadBalancer would create
* a new picker, which holds a snapshot of the latest Subchannel list. Refer to the javadoc of
* {@link #handleSubchannelState handleSubchannelState()} how to do this properly.
*
* <p>No synchronization should be necessary between LoadBalancer and its pickers if you follow
* the pattern above. It may be possible to implement in a different way, but that would usually
* result in more complicated threading.
* @deprecated this is going to be deleted in the next minor release. Use {@link LoadBalancer}
* instead.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771")
@NotThreadSafe
public abstract class LoadBalancer2 {
/**
* Handles newly resolved server groups and metadata attributes from name resolution system.
* {@code servers} contained in {@link ResolvedServerInfoGroup} should be considered equivalent
* but may be flattened into a single list if needed.
*
* <p>Implementations should not modify the given {@code servers}.
*
* @param servers the resolved server addresses, never empty.
* @param attributes extra metadata from naming system.
*/
public abstract void handleResolvedAddresses(
List<ResolvedServerInfoGroup> servers, Attributes attributes);
/**
* Handles an error from the name resolution system.
*
* @param error a non-OK status
*/
public abstract void handleNameResolutionError(Status error);
/**
* Handles a state change on a Subchannel.
*
* <p>The initial state of a Subchannel is IDLE. You won't get a notification for the initial IDLE
* state.
*
* <p>If the new state is not SHUTDOWN, this method should create a new picker and call {@link
* Helper#updatePicker Helper.updatePicker()}. Failing to do so may result in unnecessary delays
* of RPCs. Please refer to {@link PickResult#withSubchannel PickResult.withSubchannel()}'s
* javadoc for more information.
*
* <p>SHUTDOWN can only happen in two cases. One is that LoadBalancer called {@link
* Subchannel#shutdown} earlier, thus it should have already discarded this Subchannel. The other
* is that Channel is doing a {@link ManagedChannel#shutdownNow forced shutdown} or has already
* terminated, thus there won't be further requests to LoadBalancer. Therefore, SHUTDOWN can be
* safely ignored.
*
* @param subchannel the involved Subchannel
* @param stateInfo the new state
*/
public abstract void handleSubchannelState(
Subchannel subchannel, ConnectivityStateInfo stateInfo);
/**
* The channel asks the load-balancer to shutdown. No more callbacks will be called after this
* method. The implementation should shutdown all Subchannels and OOB channels, and do any other
* cleanup as necessary.
*/
public abstract void shutdown();
/**
* The main balancing logic. It <strong>must be thread-safe</strong>. Typically it should only
* synchronize on its own state, and avoid synchronizing with the LoadBalancer's state.
*/
@ThreadSafe
public abstract static class SubchannelPicker {
/**
* Make a balancing decision for a new RPC.
*
* @param affinity the affinity attributes provided via {@link CallOptions#withAffinity}
* @param headers the headers container of the RPC. It can be mutated within this method.
*/
public abstract PickResult pickSubchannel(Attributes affinity, Metadata headers);
}
/**
* A balancing decision made by {@link SubchannelPicker SubchannelPicker} for an RPC.
*
* <p>The outcome of the decision will be one of the following:
* <ul>
* <li>Proceed: if a Subchannel is provided via {@link #withSubchannel withSubchannel()}, and is
* in READY state when the RPC tries to start on it, the RPC will proceed on that
* Subchannel.</li>
* <li>Error: if an error is provided via {@link #withError withError()}, and the RPC is not
* wait-for-ready (i.e., {@link CallOptions#withWaitForReady} was not called), the RPC will
* fail immediately with the given error.</li>
* <li>Buffer: in all other cases, the RPC will be buffered in the Channel, until the next
* picker is provided via {@link Helper#updatePicker Helper.updatePicker()}, when the RPC
* will go through the same picking process again.</li>
* </ul>
*/
@Immutable
public static final class PickResult {
private static final PickResult NO_RESULT = new PickResult(null, Status.OK);
@Nullable private final Subchannel subchannel;
// An error to be propagated to the application if subchannel == null
// Or OK if there is no error.
// subchannel being null and error being OK means RPC needs to wait
private final Status status;
private PickResult(Subchannel subchannel, Status status) {
this.subchannel = subchannel;
this.status = Preconditions.checkNotNull(status, "status");
}
/**
* A decision to proceed the RPC on a Subchannel.
*
* <p>Only Subchannels returned by {@link Helper#createSubchannel Helper.createSubchannel()}
* will work. DO NOT try to use your own implementations of Subchannels, as they won't work.
*
* <p>When the RPC tries to use the return Subchannel, which is briefly after this method
* returns, the state of the Subchannel will decide where the RPC would go:
*
* <ul>
* <li>READY: the RPC will proceed on this Subchannel.</li>
* <li>IDLE: the RPC will be buffered. Subchannel will attempt to create connection.</li>
* <li>All other states: the RPC will be buffered.</li>
* </ul>
*
* <p><strong>All buffered RPCs will stay buffered</strong> until the next call of {@link
* Helper#updatePicker Helper.updatePicker()}, which will trigger a new picking process.
*
* <p>Note that Subchannel's state may change at the same time the picker is making the
* decision, which means the decision may be made with (to-be) outdated information. For
* example, a picker may return a Subchannel known to be READY, but it has become IDLE when is
* about to be used by the RPC, which makes the RPC to be buffered. The LoadBalancer will soon
* learn about the Subchannels' transition from READY to IDLE, create a new picker and allow the
* RPC to use another READY transport if there is any.
*
* <p>You will want to avoid running into a situation where there are READY Subchannels out
* there but some RPCs are still buffered for longer than a brief time.
* <ul>
* <li>This can happen if you return Subchannels with states other than READY and IDLE. For
* example, suppose you round-robin on 2 Subchannels, in READY and CONNECTING states
* respectively. If the picker ignores the state and pick them equally, 50% of RPCs will
* be stuck in buffered state until both Subchannels are READY.</li>
* <li>This can also happen if you don't create a new picker at key state changes of
* Subchannels. Take the above round-robin example again. Suppose you do pick only READY
* and IDLE Subchannels, and initially both Subchannels are READY. Now one becomes IDLE,
* then CONNECTING and stays CONNECTING for a long time. If you don't create a new picker
* in response to the CONNECTING state to exclude that Subchannel, 50% of RPCs will hit it
* and be buffered even though the other Subchannel is READY.</li>
* </ul>
*
* <p>In order to prevent unnecessary delay of RPCs, the rules of thumb are:
* <ol>
* <li>The picker should only pick Subchannels that are known as READY or IDLE. Whether to
* pick IDLE Subchannels depends on whether you want Subchannels to connect on-demand or
* actively:
* <ul>
* <li>If you want connect-on-demand, include IDLE Subchannels in your pick results,
* because when an RPC tries to use an IDLE Subchannel, the Subchannel will try to
* connect.</li>
* <li>If you want Subchannels to be always connected even when there is no RPC, you
* would call {@link Subchannel#requestConnection Subchannel.requestConnection()}
* whenever the Subchannel has transitioned to IDLE, then you don't need to include
* IDLE Subchannels in your pick results.</li>
* </ul></li>
* <li>Always create a new picker and call {@link Helper#updatePicker Helper.updatePicker()}
* whenever {@link #handleSubchannelState handleSubchannelState()} is called, unless the
* new state is SHUTDOWN. See {@code handleSubchannelState}'s javadoc for more
* details.</li>
* </ol>
*/
public static PickResult withSubchannel(Subchannel subchannel) {
return new PickResult(Preconditions.checkNotNull(subchannel, "subchannel"), Status.OK);
}
/**
* A decision to report a connectivity error to the RPC. If the RPC is {@link
* CallOptions#withWaitForReady wait-for-ready}, it will stay buffered. Otherwise, it will fail
* with the given error.
*
* @param error the error status. Must not be OK.
*/
public static PickResult withError(Status error) {
Preconditions.checkArgument(!error.isOk(), "error status shouldn't be OK");
return new PickResult(null, error);
}
/**
* No decision could be made. The RPC will stay buffered.
*/
public static PickResult withNoResult() {
return NO_RESULT;
}
/**
* The Subchannel if this result was created by {@link #withSubchannel withSubchannel()}, or
* null otherwise.
*/
@Nullable
public Subchannel getSubchannel() {
return subchannel;
}
/**
* The status associated with this result. Non-{@code OK} if created with {@link #withError
* withError}, or {@code OK} otherwise.
*/
public Status getStatus() {
return status;
}
@Override
public String toString() {
return "[subchannel=" + subchannel + " status=" + status + "]";
}
}
/**
* Provides essentials for LoadBalancer implementations.
*/
@ThreadSafe
public abstract static class Helper {
/**
* Creates a Subchannel, which is a logical connection to the given group of addresses which are
* considered equivalent. The {@code attrs} are custom attributes associated with this
* Subchannel, and can be accessed later through {@link Subchannel#getAttributes
* Subchannel.getAttributes()}.
*
* <p>The LoadBalancer is responsible for closing unused Subchannels, and closing all
* Subchannels within {@link #shutdown}.
*/
public abstract Subchannel createSubchannel(EquivalentAddressGroup addrs, Attributes attrs);
/**
* Out-of-band channel for LoadBalancers own RPC needs, e.g., talking to an external
* load-balancer service.
*
* <p>The LoadBalancer is responsible for closing unused OOB channels, and closing all OOB
* channels within {@link #shutdown}.
*/
public abstract ManagedChannel createOobChannel(
EquivalentAddressGroup eag, String authority);
/**
* Set a new picker to the channel.
*
* <p>When a new picker is provided via {@code updatePicker()}, the channel will apply the
* picker on all buffered RPCs, by calling {@link SubchannelPicker#pickSubchannel
* SubchannelPicker.pickSubchannel()}.
*
* <p>The channel will hold the picker and use it for all RPCs, until {@code updatePicker()} is
* called again and a new picker replaces the old one. If {@code updatePicker()} has never been
* called, the channel will buffer all RPCs until a picker is provided.
*/
public abstract void updatePicker(SubchannelPicker picker);
/**
* Schedule a task to be run in the Channel Executor, which serializes the task with the
* callback methods on the {@link LoadBalancer2} interface.
*/
public abstract void runSerialized(Runnable task);
/**
* Returns the NameResolver of the channel.
*/
public abstract NameResolver.Factory getNameResolverFactory();
/**
* Returns the authority string of the channel, which is derived from the DNS-style target name.
*/
public abstract String getAuthority();
}
/**
* A logical connection to a server, or a group of equivalent servers represented by an {@link
* EquivalentAddressGroup}.
*
* <p>It maintains at most one physical connection (aka transport) for sending new RPCs, while
* also keeps track of previous transports that has been shut down but not terminated yet.
*
* <p>If there isn't an active transport yet, and an RPC is assigned to the Subchannel, it will
* create a new transport. It won't actively create transports otherwise. {@link
* #requestConnection requestConnection()} can be used to ask Subchannel to create a transport if
* there isn't any.
*/
@ThreadSafe
public abstract static class Subchannel {
/**
* Shuts down the Subchannel. After this method is called, this Subchannel should no longer
* be returned by the latest {@link SubchannelPicker picker}, and can be safely discarded.
*/
public abstract void shutdown();
/**
* Asks the Subchannel to create a connection (aka transport), if there isn't an active one.
*/
public abstract void requestConnection();
/**
* Returns the addresses that this Subchannel is bound to.
*/
public abstract EquivalentAddressGroup getAddresses();
/**
* The same attributes passed to {@link Helper#createSubchannel Helper.createSubchannel()}.
* LoadBalancer can use it to attach additional information here, e.g., the shard this
* Subchannel belongs to.
*/
public abstract Attributes getAttributes();
}
@ThreadSafe
public abstract static class Factory {
/**
* Creates a {@link LoadBalancer2} that will be used inside a channel.
*/
public abstract LoadBalancer2 newLoadBalancer(Helper helper);
}
@Deprecated
public abstract class LoadBalancer2 extends LoadBalancer {
}

View File

@ -155,9 +155,9 @@ public abstract class ManagedChannelBuilder<T extends ManagedChannelBuilder<T>>
public abstract T nameResolverFactory(NameResolver.Factory resolverFactory);
/**
* Provides a custom {@link LoadBalancer2.Factory} for the channel.
* Provides a custom {@link LoadBalancer.Factory} for the channel.
*
* <p>If this method is not called, the builder will use {@link PickFirstBalancerFactory2}
* <p>If this method is not called, the builder will use {@link PickFirstBalancerFactory}
* for the channel.
*
* <p>Calling this will make the channel to run the LBv2 code path. See <a
@ -169,9 +169,7 @@ public abstract class ManagedChannelBuilder<T extends ManagedChannelBuilder<T>>
* this method will throw.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771")
public T loadBalancerFactory(LoadBalancer2.Factory loadBalancerFactory) {
throw new UnsupportedOperationException("Not implemented by " + this.getClass().getName());
}
public abstract T loadBalancerFactory(LoadBalancer.Factory loadBalancerFactory);
/**
* Set the decompression registry for use in the channel. This is an advanced API call and

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016, Google Inc. All rights reserved.
* Copyright 2015, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -31,6 +31,7 @@
package io.grpc;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.grpc.ConnectivityState.SHUTDOWN;
import com.google.common.annotations.VisibleForTesting;
@ -39,44 +40,39 @@ import java.util.ArrayList;
import java.util.List;
/**
* A {@link LoadBalancer2} that provides no load balancing mechanism over the
* A {@link LoadBalancer} that provides no load balancing mechanism over the
* addresses from the {@link NameResolver}. The channel's default behavior
* (currently pick-first) is used for all addresses found.
*
* <p><strong>TECHNICAL PREVIEW: </strong>The name of this class is temporary. It will be renamed to
* {@code PickFirstBalancerFactory} during <a href="https://github.com/grpc/grpc-java/issues/2656"
* target="_blank">the transition to LBv2</a>. You should use it only if you want to experiment the
* LBv2 code path.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771")
public final class PickFirstBalancerFactory2 extends LoadBalancer2.Factory {
public final class PickFirstBalancerFactory extends LoadBalancer.Factory {
private static final PickFirstBalancerFactory2 INSTANCE = new PickFirstBalancerFactory2();
private static final PickFirstBalancerFactory INSTANCE = new PickFirstBalancerFactory();
private PickFirstBalancerFactory2() {
private PickFirstBalancerFactory() {
}
public static PickFirstBalancerFactory2 getInstance() {
public static PickFirstBalancerFactory getInstance() {
return INSTANCE;
}
@Override
public LoadBalancer2 newLoadBalancer(LoadBalancer2.Helper helper) {
public LoadBalancer newLoadBalancer(LoadBalancer.Helper helper) {
return new PickFirstBalancer(helper);
}
@VisibleForTesting
static class PickFirstBalancer extends LoadBalancer2 {
static final class PickFirstBalancer extends LoadBalancer {
private final Helper helper;
private Subchannel subchannel;
public PickFirstBalancer(Helper helper) {
this.helper = helper;
PickFirstBalancer(Helper helper) {
this.helper = checkNotNull(helper, "helper");
}
@Override
public void handleResolvedAddresses(List<ResolvedServerInfoGroup> servers,
Attributes attributes) {
public void handleResolvedAddresses(
List<ResolvedServerInfoGroup> servers, Attributes attributes) {
// Flatten servers list received from name resolver into single address group. This means that
// as far as load balancer is concerned, there's virtually one single server with multiple
// addresses so the connection will be created only for the first address (pick first).
@ -123,7 +119,7 @@ public final class PickFirstBalancerFactory2 extends LoadBalancer2.Factory {
pickResult = PickResult.withError(stateInfo.getStatus());
break;
default:
throw new IllegalStateException();
throw new IllegalArgumentException("Unsupported state:" + currentState);
}
helper.updatePicker(new Picker(pickResult));
@ -157,15 +153,15 @@ public final class PickFirstBalancerFactory2 extends LoadBalancer2.Factory {
* received in constructor.
*/
@VisibleForTesting
static class Picker extends LoadBalancer2.SubchannelPicker {
private final LoadBalancer2.PickResult result;
static final class Picker extends LoadBalancer.SubchannelPicker {
private final LoadBalancer.PickResult result;
Picker(LoadBalancer2.PickResult result) {
this.result = result;
Picker(LoadBalancer.PickResult result) {
this.result = checkNotNull(result, "result");
}
@Override
public LoadBalancer2.PickResult pickSubchannel(Attributes affinity, Metadata headers) {
public LoadBalancer.PickResult pickSubchannel(Attributes affinity, Metadata headers) {
return result;
}
}

View File

@ -43,12 +43,12 @@ import io.grpc.Attributes;
import io.grpc.ClientInterceptor;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.NameResolver;
import io.grpc.NameResolverProvider;
import io.grpc.PickFirstBalancerFactory2;
import io.grpc.PickFirstBalancerFactory;
import io.grpc.ResolvedServerInfo;
import io.grpc.ResolvedServerInfoGroup;
import java.net.SocketAddress;
@ -108,7 +108,7 @@ public abstract class AbstractManagedChannelImplBuilder
@Nullable
private NameResolver.Factory nameResolverFactory;
private LoadBalancer2.Factory loadBalancerFactory;
private LoadBalancer.Factory loadBalancerFactory;
@Nullable
private DecompressorRegistry decompressorRegistry;
@ -193,9 +193,9 @@ public abstract class AbstractManagedChannelImplBuilder
}
@Override
public final T loadBalancerFactory(LoadBalancer2.Factory loadBalancerFactory) {
public final T loadBalancerFactory(LoadBalancer.Factory loadBalancerFactory) {
Preconditions.checkState(directServerAddress == null,
"directServerAddress is set (%s), which forbids the use of LoadBalancerFactory",
"directServerAddress is set (%s), which forbids the use of LoadBalancer.Factory",
directServerAddress);
this.loadBalancerFactory = loadBalancerFactory;
return thisT();
@ -231,7 +231,7 @@ public abstract class AbstractManagedChannelImplBuilder
// We convert to the largest unit to avoid overflow
if (unit.toDays(value) >= IDLE_MODE_MAX_TIMEOUT_DAYS) {
// This disables idle mode
this.idleTimeoutMillis = ManagedChannelImpl2.IDLE_TIMEOUT_MILLIS_DISABLE;
this.idleTimeoutMillis = ManagedChannelImpl.IDLE_TIMEOUT_MILLIS_DISABLE;
} else {
this.idleTimeoutMillis = Math.max(unit.toMillis(value), IDLE_MODE_MIN_TIMEOUT_MILLIS);
}
@ -275,21 +275,25 @@ public abstract class AbstractManagedChannelImplBuilder
// getResource(), then this shouldn't be a problem unless called on the UI thread.
nameResolverFactory = NameResolverProvider.asFactory();
}
return new ManagedChannelImpl2(
return new ManagedChannelImpl(
target,
// TODO(carl-mastrangelo): Allow clients to pass this in
new ExponentialBackoffPolicy.Provider(),
nameResolverFactory,
getNameResolverParams(),
firstNonNull(loadBalancerFactory, PickFirstBalancerFactory2.getInstance()),
firstNonNull(loadBalancerFactory, PickFirstBalancerFactory.getInstance()),
transportFactory,
firstNonNull(decompressorRegistry, DecompressorRegistry.getDefaultInstance()),
firstNonNull(compressorRegistry, CompressorRegistry.getDefaultInstance()),
SharedResourcePool.forResource(GrpcUtil.TIMER_SERVICE),
getExecutorPool(executor),
SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR),
GrpcUtil.STOPWATCH_SUPPLIER, idleTimeoutMillis,
userAgent, interceptors, firstNonNull(statsFactory,
GrpcUtil.STOPWATCH_SUPPLIER,
idleTimeoutMillis,
userAgent,
interceptors,
firstNonNull(
statsFactory,
firstNonNull(Stats.getStatsContextFactory(), NoopStatsContextFactory.INSTANCE)));
}

View File

@ -42,7 +42,7 @@ import javax.annotation.concurrent.ThreadSafe;
/**
* The thread-less Channel Executor used to run the state mutation logic in {@link
* ManagedChannelImpl}, {@link InternalSubchannel} and {@link io.grpc.LoadBalancer2}s.
* ManagedChannelImpl}, {@link InternalSubchannel} and {@link io.grpc.LoadBalancer}s.
*
* <p>Tasks are queued until {@link #drain} is called. Tasks are guaranteed to be run in the same
* order as they are submitted.

View File

@ -34,8 +34,8 @@ package io.grpc.internal;
import com.google.common.annotations.VisibleForTesting;
import io.grpc.CallOptions;
import io.grpc.Context;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.SubchannelPicker;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.SubchannelPicker;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.Status;
@ -55,7 +55,7 @@ import javax.annotation.concurrent.GuardedBy;
* for that stream, at which point the ownership of the stream is transferred to the real transport,
* thus the delayed transport stops owning the stream.
*/
final class DelayedClientTransport2 implements ManagedClientTransport {
final class DelayedClientTransport implements ManagedClientTransport {
private final LogId lodId = LogId.allocate(getClass().getName());
private final Object lock = new Object();
@ -96,7 +96,7 @@ final class DelayedClientTransport2 implements ManagedClientTransport {
* @param channelExecutor all listener callbacks of the delayed transport will be run from this
* ChannelExecutor.
*/
DelayedClientTransport2(Executor defaultAppExecutor, ChannelExecutor channelExecutor) {
DelayedClientTransport(Executor defaultAppExecutor, ChannelExecutor channelExecutor) {
this.defaultAppExecutor = defaultAppExecutor;
this.channelExecutor = channelExecutor;
}
@ -188,13 +188,16 @@ final class DelayedClientTransport2 implements ManagedClientTransport {
return newStream(method, headers, CallOptions.DEFAULT, StatsTraceContext.NOOP);
}
// Caller must call channelExecutor.drain() outside of lock because this method may schedule
// tasks on channelExecutor
/**
* Caller must call {@code channelExecutor.drain()} outside of lock because this method may
* schedule tasks on channelExecutor.
*/
@GuardedBy("lock")
private PendingStream createPendingStream(MethodDescriptor<?, ?> method, Metadata headers,
CallOptions callOptions, StatsTraceContext statsTraceCtx) {
PendingStream pendingStream = new PendingStream(method, headers, callOptions,
statsTraceCtx);
private PendingStream createPendingStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
StatsTraceContext statsTraceCtx) {
PendingStream pendingStream =
new PendingStream(method, headers, callOptions, statsTraceCtx);
pendingStreams.add(pendingStream);
if (pendingStreams.size() == 1) {
channelExecutor.executeLater(reportTransportInUse);

View File

@ -40,8 +40,8 @@ import com.google.common.base.Stopwatch;
import com.google.common.base.Supplier;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.Subchannel;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.Subchannel;
import io.grpc.Metadata;
import io.grpc.Status;
import io.grpc.internal.SharedResourceHolder.Resource;

View File

@ -38,7 +38,7 @@ import javax.annotation.concurrent.NotThreadSafe;
* Aggregates the in-use state of a set of objects.
*/
@NotThreadSafe
abstract class InUseStateAggregator2<T> {
abstract class InUseStateAggregator<T> {
private final HashSet<T> inUseObjects = new HashSet<T>();

View File

@ -118,8 +118,8 @@ final class InternalSubchannel implements WithLogId {
new ArrayList<ConnectionClientTransport>();
// Must only be used from channelExecutor
private final InUseStateAggregator2<ConnectionClientTransport> inUseStateAggregator =
new InUseStateAggregator2<ConnectionClientTransport>() {
private final InUseStateAggregator<ConnectionClientTransport> inUseStateAggregator =
new InUseStateAggregator<ConnectionClientTransport>() {
@Override
void handleInUse() {
callback.onInUse(InternalSubchannel.this);

View File

@ -51,9 +51,9 @@ import io.grpc.CompressorRegistry;
import io.grpc.ConnectivityStateInfo;
import io.grpc.DecompressorRegistry;
import io.grpc.EquivalentAddressGroup;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.SubchannelPicker;
import io.grpc.LoadBalancer;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.SubchannelPicker;
import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
@ -81,8 +81,8 @@ import javax.annotation.concurrent.ThreadSafe;
/** A communication channel for making outgoing RPCs. */
@ThreadSafe
public final class ManagedChannelImpl2 extends ManagedChannel implements WithLogId {
private static final Logger log = Logger.getLogger(ManagedChannelImpl2.class.getName());
public final class ManagedChannelImpl extends ManagedChannel implements WithLogId {
private static final Logger log = Logger.getLogger(ManagedChannelImpl.class.getName());
// Matching this pattern means the target string is a URI target or at least intended to be one.
// A URI target must be an absolute hierarchical URI.
@ -102,7 +102,7 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
private final String target;
private final NameResolver.Factory nameResolverFactory;
private final Attributes nameResolverParams;
private final LoadBalancer2.Factory loadBalancerFactory;
private final LoadBalancer.Factory loadBalancerFactory;
private final ClientTransportFactory transportFactory;
private final Executor executor;
private final ObjectPool<? extends Executor> executorPool;
@ -140,7 +140,7 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
// null when channel is in idle mode. Must be assigned from channelExecutor.
@Nullable
private LoadBalancer2 loadBalancer;
private LoadBalancer loadBalancer;
// Must be assigned from channelExecutor. null if channel is in idle mode.
@Nullable
@ -155,7 +155,7 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
private final Set<InternalSubchannel> oobChannels = new HashSet<InternalSubchannel>(1, .75f);
// reprocess() must be run from channelExecutor
private final DelayedClientTransport2 delayedTransport;
private final DelayedClientTransport delayedTransport;
// Shutdown states.
//
@ -234,8 +234,8 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
// Must be accessed from channelExecutor
@VisibleForTesting
final InUseStateAggregator2<Object> inUseStateAggregator =
new InUseStateAggregator2<Object>() {
final InUseStateAggregator<Object> inUseStateAggregator =
new InUseStateAggregator<Object>() {
@Override
void handleInUse() {
exitIdleMode();
@ -381,9 +381,9 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
}
};
ManagedChannelImpl2(String target, BackoffPolicy.Provider backoffPolicyProvider,
ManagedChannelImpl(String target, BackoffPolicy.Provider backoffPolicyProvider,
NameResolver.Factory nameResolverFactory, Attributes nameResolverParams,
LoadBalancer2.Factory loadBalancerFactory, ClientTransportFactory transportFactory,
LoadBalancer.Factory loadBalancerFactory, ClientTransportFactory transportFactory,
DecompressorRegistry decompressorRegistry, CompressorRegistry compressorRegistry,
ObjectPool<ScheduledExecutorService> timerServicePool,
ObjectPool<? extends Executor> executorPool, ObjectPool<? extends Executor> oobExecutorPool,
@ -398,7 +398,7 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
this.executorPool = checkNotNull(executorPool, "executorPool");
this.oobExecutorPool = checkNotNull(oobExecutorPool, "oobExecutorPool");
this.executor = checkNotNull(executorPool.getObject(), "executor");
this.delayedTransport = new DelayedClientTransport2(this.executor, this.channelExecutor);
this.delayedTransport = new DelayedClientTransport(this.executor, this.channelExecutor);
this.delayedTransport.start(delayedTransportListener);
this.backoffPolicyProvider = backoffPolicyProvider;
this.transportFactory =
@ -473,7 +473,7 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
* cancelled.
*/
@Override
public ManagedChannelImpl2 shutdown() {
public ManagedChannelImpl shutdown() {
log.log(Level.FINE, "[{0}] shutdown() called", getLogId());
if (!shutdown.compareAndSet(false, true)) {
return this;
@ -495,7 +495,7 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
* return {@code false} immediately after this method returns.
*/
@Override
public ManagedChannelImpl2 shutdownNow() {
public ManagedChannelImpl shutdownNow() {
log.log(Level.FINE, "[{0}] shutdownNow() called", getLogId());
shutdown();
delayedTransport.shutdownNow(SHUTDOWN_NOW_STATUS);
@ -547,7 +547,7 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
CallOptions callOptions) {
Executor executor = callOptions.getExecutor();
if (executor == null) {
executor = ManagedChannelImpl2.this.executor;
executor = ManagedChannelImpl.this.executor;
}
StatsTraceContext statsTraceCtx = StatsTraceContext.newClientContext(
method.getFullMethodName(), statsFactory, stopwatchSupplier);
@ -588,8 +588,8 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
}
}
private class LbHelperImpl extends LoadBalancer2.Helper {
LoadBalancer2 lb;
private class LbHelperImpl extends LoadBalancer.Helper {
LoadBalancer lb;
final NameResolver nr;
LbHelperImpl(NameResolver nr) {
@ -702,7 +702,7 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
@Override
public String getAuthority() {
return ManagedChannelImpl2.this.authority();
return ManagedChannelImpl.this.authority();
}
@Override
@ -733,8 +733,8 @@ public final class ManagedChannelImpl2 extends ManagedChannel implements WithLog
}
private class NameResolverListenerImpl implements NameResolver.Listener {
final LoadBalancer2 balancer;
final LoadBalancer2.Helper helper;
final LoadBalancer balancer;
final LoadBalancer.Helper helper;
NameResolverListenerImpl(LbHelperImpl helperImpl) {
this.balancer = helperImpl.lb;

View File

@ -41,9 +41,9 @@ import io.grpc.CallOptions;
import io.grpc.ClientCall;
import io.grpc.ConnectivityStateInfo;
import io.grpc.EquivalentAddressGroup;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.SubchannelPicker;
import io.grpc.LoadBalancer;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.SubchannelPicker;
import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
@ -58,7 +58,7 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.ThreadSafe;
/**
* A ManagedChannel backed by a single {@link InternalSubchannel} and used for {@link LoadBalancer2}
* A ManagedChannel backed by a single {@link InternalSubchannel} and used for {@link LoadBalancer}
* to its own RPC needs.
*/
@ThreadSafe
@ -71,7 +71,7 @@ final class OobChannel extends ManagedChannel implements WithLogId {
private final LogId logId = LogId.allocate(getClass().getName());
private final StatsContextFactory statsFactory;
private final String authority;
private final DelayedClientTransport2 delayedTransport;
private final DelayedClientTransport delayedTransport;
private final ObjectPool<? extends Executor> executorPool;
private final Executor executor;
private final ScheduledExecutorService deadlineCancellationExecutor;
@ -100,7 +100,7 @@ final class OobChannel extends ManagedChannel implements WithLogId {
this.deadlineCancellationExecutor = checkNotNull(
deadlineCancellationExecutor, "deadlineCancellationExecutor");
this.stopwatchSupplier = checkNotNull(stopwatchSupplier, "stopwatchSupplier");
this.delayedTransport = new DelayedClientTransport2(executor, channelExecutor);
this.delayedTransport = new DelayedClientTransport(executor, channelExecutor);
this.delayedTransport.start(new ManagedClientTransport.Listener() {
@Override
public void transportShutdown(Status s) {

View File

@ -31,14 +31,14 @@
package io.grpc.internal;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer;
import javax.annotation.Nullable;
/**
* The base interface of the Subchannels returned by {@link
* io.grpc.LoadBalancer2.Helper#createSubchannel}.
* io.grpc.LoadBalancer.Helper#createSubchannel}.
*/
abstract class SubchannelImpl extends LoadBalancer2.Subchannel {
abstract class SubchannelImpl extends LoadBalancer.Subchannel {
/**
* Same as {@link InternalSubchannel#obtainActiveTransport}.
*/

View File

@ -41,10 +41,10 @@ import io.grpc.Attributes;
import io.grpc.ConnectivityStateInfo;
import io.grpc.EquivalentAddressGroup;
import io.grpc.ExperimentalApi;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.Subchannel;
import io.grpc.LoadBalancer2.SubchannelPicker;
import io.grpc.LoadBalancer;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.Subchannel;
import io.grpc.LoadBalancer.SubchannelPicker;
import io.grpc.Metadata;
import io.grpc.NameResolver;
import io.grpc.ResolvedServerInfo;
@ -64,35 +64,30 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
/**
* A {@link LoadBalancer2} that provides round-robin load balancing mechanism over the
* A {@link LoadBalancer} that provides round-robin load balancing mechanism over the
* addresses from the {@link NameResolver}. The sub-lists received from the name resolver
* are considered to be an {@link EquivalentAddressGroup} and each of these sub-lists is
* what is then balanced across.
*
* <p><strong>TECHNICAL PREVIEW: </strong>The name of this class is temporary. It will be renamed to
* {@code RoundRobinLoadBalancerFactory} during the
* <a href="https://github.com/grpc/grpc-java/issues/2656" target="_blank">transition to LBv2</a>.
* You should use it only if you want to experiment the LBv2 code path.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771")
public class RoundRobinLoadBalancerFactory2 extends LoadBalancer2.Factory {
private static final RoundRobinLoadBalancerFactory2 INSTANCE =
new RoundRobinLoadBalancerFactory2();
public class RoundRobinLoadBalancerFactory extends LoadBalancer.Factory {
private static final RoundRobinLoadBalancerFactory INSTANCE =
new RoundRobinLoadBalancerFactory();
private RoundRobinLoadBalancerFactory2() {
private RoundRobinLoadBalancerFactory() {
}
public static RoundRobinLoadBalancerFactory2 getInstance() {
public static RoundRobinLoadBalancerFactory getInstance() {
return INSTANCE;
}
@Override
public LoadBalancer2 newLoadBalancer(LoadBalancer2.Helper helper) {
public LoadBalancer newLoadBalancer(LoadBalancer.Helper helper) {
return new RoundRobinLoadBalancer(helper);
}
@VisibleForTesting
static class RoundRobinLoadBalancer extends LoadBalancer2 {
static class RoundRobinLoadBalancer extends LoadBalancer {
private final Helper helper;
private final Map<EquivalentAddressGroup, Subchannel> subchannels =
new HashMap<EquivalentAddressGroup, Subchannel>();
@ -101,13 +96,13 @@ public class RoundRobinLoadBalancerFactory2 extends LoadBalancer2.Factory {
static final Attributes.Key<AtomicReference<ConnectivityStateInfo>> STATE_INFO =
Attributes.Key.of("state-info");
public RoundRobinLoadBalancer(Helper helper) {
this.helper = helper;
RoundRobinLoadBalancer(Helper helper) {
this.helper = checkNotNull(helper, "helper");
}
@Override
public void handleResolvedAddresses(List<ResolvedServerInfoGroup> servers,
Attributes attributes) {
public void handleResolvedAddresses(
List<ResolvedServerInfoGroup> servers, Attributes attributes) {
Set<EquivalentAddressGroup> currentAddrs = subchannels.keySet();
Set<EquivalentAddressGroup> latestAddrs =
resolvedServerInfoGroupToEquivalentAddressGroup(servers);
@ -237,7 +232,7 @@ public class RoundRobinLoadBalancerFactory2 extends LoadBalancer2.Factory {
}
@VisibleForTesting
static class Picker extends SubchannelPicker {
static final class Picker extends SubchannelPicker {
@Nullable
private final Status status;
private final List<Subchannel> list;

View File

@ -44,11 +44,11 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import com.google.common.collect.Lists;
import io.grpc.LoadBalancer2.Helper;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.Subchannel;
import io.grpc.PickFirstBalancerFactory2.PickFirstBalancer;
import io.grpc.PickFirstBalancerFactory2.Picker;
import io.grpc.LoadBalancer.Helper;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.Subchannel;
import io.grpc.PickFirstBalancerFactory.PickFirstBalancer;
import io.grpc.PickFirstBalancerFactory.Picker;
import java.net.SocketAddress;
import java.util.List;
import org.junit.Before;
@ -62,9 +62,9 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/** Unit test for {@link PickFirstBalancerFactory2}. */
/** Unit test for {@link PickFirstBalancerFactory}. */
@RunWith(JUnit4.class)
public class PickFirstLoadBalancer2Test {
public class PickFirstLoadBalancerTest {
private PickFirstBalancer loadBalancer;
private List<ResolvedServerInfoGroup> servers = Lists.newArrayList();
private List<SocketAddress> socketAddresses = Lists.newArrayList();
@ -96,7 +96,7 @@ public class PickFirstLoadBalancer2Test {
when(mockHelper.createSubchannel(any(EquivalentAddressGroup.class), any(Attributes.class)))
.thenReturn(mockSubchannel);
loadBalancer = (PickFirstBalancer) PickFirstBalancerFactory2.getInstance().newLoadBalancer(
loadBalancer = (PickFirstBalancer) PickFirstBalancerFactory.getInstance().newLoadBalancer(
mockHelper);
}

View File

@ -78,11 +78,11 @@ public class AbstractManagedChannelImplBuilderTest {
builder.getIdleTimeoutMillis());
builder.idleTimeout(Long.MAX_VALUE, TimeUnit.DAYS);
assertEquals(ManagedChannelImpl2.IDLE_TIMEOUT_MILLIS_DISABLE, builder.getIdleTimeoutMillis());
assertEquals(ManagedChannelImpl.IDLE_TIMEOUT_MILLIS_DISABLE, builder.getIdleTimeoutMillis());
builder.idleTimeout(AbstractManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS,
TimeUnit.DAYS);
assertEquals(ManagedChannelImpl2.IDLE_TIMEOUT_MILLIS_DISABLE, builder.getIdleTimeoutMillis());
assertEquals(ManagedChannelImpl.IDLE_TIMEOUT_MILLIS_DISABLE, builder.getIdleTimeoutMillis());
try {
builder.idleTimeout(0, TimeUnit.SECONDS);

View File

@ -51,8 +51,8 @@ import static org.mockito.Mockito.when;
import io.grpc.Attributes;
import io.grpc.CallOptions;
import io.grpc.IntegerMarshaller;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.SubchannelPicker;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.SubchannelPicker;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.MethodDescriptor.MethodType;
@ -76,10 +76,10 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/**
* Unit tests for {@link DelayedClientTransport2}.
* Unit tests for {@link DelayedClientTransport}.
*/
@RunWith(JUnit4.class)
public class DelayedClientTransport2Test {
public class DelayedClientTransportTest {
@Mock private ManagedClientTransport.Listener transportListener;
@Mock private SubchannelPicker mockPicker;
@Mock private SubchannelImpl mockSubchannel;
@ -117,7 +117,7 @@ public class DelayedClientTransport2Test {
private final FakeClock fakeExecutor = new FakeClock();
private final DelayedClientTransport2 delayedTransport = new DelayedClientTransport2(
private final DelayedClientTransport delayedTransport = new DelayedClientTransport(
fakeExecutor.getScheduledExecutorService(), new ChannelExecutor());
@Before public void setUp() {

View File

@ -43,7 +43,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link ManagedChannelImpl2#getNameResolver}. */
/** Unit tests for {@link ManagedChannelImpl#getNameResolver}. */
@RunWith(JUnit4.class)
public class ManagedChannelImplGetNameResolverTest {
private static final Attributes NAME_RESOLVER_PARAMS =
@ -121,7 +121,7 @@ public class ManagedChannelImplGetNameResolverTest {
}
};
try {
ManagedChannelImpl2.getNameResolver(
ManagedChannelImpl.getNameResolver(
"foo.googleapis.com:8080", nameResolverFactory, NAME_RESOLVER_PARAMS);
fail("Should fail");
} catch (IllegalArgumentException e) {
@ -131,7 +131,7 @@ public class ManagedChannelImplGetNameResolverTest {
private void testValidTarget(String target, String expectedUriString, URI expectedUri) {
Factory nameResolverFactory = new FakeNameResolverFactory(expectedUri.getScheme());
FakeNameResolver nameResolver = (FakeNameResolver) ManagedChannelImpl2.getNameResolver(
FakeNameResolver nameResolver = (FakeNameResolver) ManagedChannelImpl.getNameResolver(
target, nameResolverFactory, NAME_RESOLVER_PARAMS);
assertNotNull(nameResolver);
assertEquals(expectedUri, nameResolver.uri);
@ -142,7 +142,7 @@ public class ManagedChannelImplGetNameResolverTest {
Factory nameResolverFactory = new FakeNameResolverFactory("dns");
try {
FakeNameResolver nameResolver = (FakeNameResolver) ManagedChannelImpl2.getNameResolver(
FakeNameResolver nameResolver = (FakeNameResolver) ManagedChannelImpl.getNameResolver(
target, nameResolverFactory, NAME_RESOLVER_PARAMS);
fail("Should have failed, but got resolver with " + nameResolver.uri);
} catch (IllegalArgumentException e) {

View File

@ -52,11 +52,11 @@ import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.EquivalentAddressGroup;
import io.grpc.IntegerMarshaller;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer2.Helper;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.Subchannel;
import io.grpc.LoadBalancer2.SubchannelPicker;
import io.grpc.LoadBalancer;
import io.grpc.LoadBalancer.Helper;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.Subchannel;
import io.grpc.LoadBalancer.SubchannelPicker;
import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
@ -90,14 +90,14 @@ import org.mockito.MockitoAnnotations;
* Unit tests for {@link ManagedChannelImpl}'s idle mode.
*/
@RunWith(JUnit4.class)
public class ManagedChannelImpl2IdlenessTest {
public class ManagedChannelImplIdlenessTest {
private final FakeClock timer = new FakeClock();
private final FakeClock executor = new FakeClock();
private final FakeClock oobExecutor = new FakeClock();
private static final String AUTHORITY = "fakeauthority";
private static final String USER_AGENT = "fakeagent";
private static final long IDLE_TIMEOUT_SECONDS = 30;
private ManagedChannelImpl2 channel;
private ManagedChannelImpl channel;
private final MethodDescriptor<String, Integer> method =
MethodDescriptor.<String, Integer>newBuilder()
@ -115,8 +115,8 @@ public class ManagedChannelImpl2IdlenessTest {
@Mock private ObjectPool<Executor> executorPool;
@Mock private ObjectPool<Executor> oobExecutorPool;
@Mock private ClientTransportFactory mockTransportFactory;
@Mock private LoadBalancer2 mockLoadBalancer;
@Mock private LoadBalancer2.Factory mockLoadBalancerFactory;
@Mock private LoadBalancer mockLoadBalancer;
@Mock private LoadBalancer.Factory mockLoadBalancerFactory;
@Mock private NameResolver mockNameResolver;
@Mock private NameResolver.Factory mockNameResolverFactory;
@Mock private ClientCall.Listener<Integer> mockCallListener;
@ -136,7 +136,7 @@ public class ManagedChannelImpl2IdlenessTest {
.newNameResolver(any(URI.class), any(Attributes.class)))
.thenReturn(mockNameResolver);
channel = new ManagedChannelImpl2("fake://target", new FakeBackoffPolicyProvider(),
channel = new ManagedChannelImpl("fake://target", new FakeBackoffPolicyProvider(),
mockNameResolverFactory, Attributes.EMPTY, mockLoadBalancerFactory,
mockTransportFactory, DecompressorRegistry.getDefaultInstance(),
CompressorRegistry.getDefaultInstance(), timerServicePool, executorPool, oobExecutorPool,

View File

@ -71,11 +71,11 @@ import io.grpc.Context;
import io.grpc.DecompressorRegistry;
import io.grpc.EquivalentAddressGroup;
import io.grpc.IntegerMarshaller;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer2.Helper;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.Subchannel;
import io.grpc.LoadBalancer2.SubchannelPicker;
import io.grpc.LoadBalancer;
import io.grpc.LoadBalancer.Helper;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.Subchannel;
import io.grpc.LoadBalancer.SubchannelPicker;
import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
@ -116,9 +116,9 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/** Unit tests for {@link ManagedChannelImpl2}. */
/** Unit tests for {@link ManagedChannelImpl}. */
@RunWith(JUnit4.class)
public class ManagedChannelImpl2Test {
public class ManagedChannelImplTest {
private static final List<ClientInterceptor> NO_INTERCEPTOR =
Collections.<ClientInterceptor>emptyList();
private static final Attributes NAME_RESOLVER_PARAMS =
@ -147,16 +147,16 @@ public class ManagedChannelImpl2Test {
@Rule public final ExpectedException thrown = ExpectedException.none();
private ManagedChannelImpl2 channel;
private ManagedChannelImpl channel;
private Helper helper;
@Captor
private ArgumentCaptor<Status> statusCaptor;
@Captor
private ArgumentCaptor<StatsTraceContext> statsTraceCtxCaptor;
@Mock
private LoadBalancer2.Factory mockLoadBalancerFactory;
private LoadBalancer.Factory mockLoadBalancerFactory;
@Mock
private LoadBalancer2 mockLoadBalancer;
private LoadBalancer mockLoadBalancer;
@Captor
private ArgumentCaptor<ConnectivityStateInfo> stateInfoCaptor;
@Mock
@ -188,11 +188,11 @@ public class ManagedChannelImpl2Test {
private void createChannel(
NameResolver.Factory nameResolverFactory, List<ClientInterceptor> interceptors) {
channel = new ManagedChannelImpl2(target, new FakeBackoffPolicyProvider(),
channel = new ManagedChannelImpl(target, new FakeBackoffPolicyProvider(),
nameResolverFactory, NAME_RESOLVER_PARAMS, mockLoadBalancerFactory,
mockTransportFactory, DecompressorRegistry.getDefaultInstance(),
CompressorRegistry.getDefaultInstance(), timerServicePool, executorPool, oobExecutorPool,
timer.getStopwatchSupplier(), ManagedChannelImpl2.IDLE_TIMEOUT_MILLIS_DISABLE, userAgent,
timer.getStopwatchSupplier(), ManagedChannelImpl.IDLE_TIMEOUT_MILLIS_DISABLE, userAgent,
interceptors, statsCtxFactory);
// Force-exit the initial idle-mode
channel.exitIdleMode();
@ -365,7 +365,7 @@ public class ManagedChannelImpl2Test {
assertTrue(nameResolverFactory.resolvers.get(0).shutdown);
// call should have been aborted by delayed transport
executor.runDueTasks();
verify(mockCallListener).onClose(same(ManagedChannelImpl2.SHUTDOWN_NOW_STATUS),
verify(mockCallListener).onClose(same(ManagedChannelImpl.SHUTDOWN_NOW_STATUS),
any(Metadata.class));
} else {
// LoadBalancer and NameResolver are still running.
@ -389,7 +389,7 @@ public class ManagedChannelImpl2Test {
if (shutdownNow) {
// Channel shutdownNow() all subchannels after shutting down LoadBalancer
verify(mockTransport).shutdownNow(ManagedChannelImpl2.SHUTDOWN_NOW_STATUS);
verify(mockTransport).shutdownNow(ManagedChannelImpl.SHUTDOWN_NOW_STATUS);
} else {
verify(mockTransport, never()).shutdownNow(any(Status.class));
}
@ -755,7 +755,7 @@ public class ManagedChannelImpl2Test {
// shutdown() has a delay
sub1.shutdown();
timer.forwardTime(ManagedChannelImpl2.SUBCHANNEL_SHUTDOWN_DELAY_SECONDS - 1, TimeUnit.SECONDS);
timer.forwardTime(ManagedChannelImpl.SUBCHANNEL_SHUTDOWN_DELAY_SECONDS - 1, TimeUnit.SECONDS);
sub1.shutdown();
verify(transportInfo1.transport, never()).shutdown();
timer.forwardTime(1, TimeUnit.SECONDS);
@ -991,12 +991,12 @@ public class ManagedChannelImpl2Test {
@Test
public void uriPattern() {
assertTrue(ManagedChannelImpl2.URI_PATTERN.matcher("a:/").matches());
assertTrue(ManagedChannelImpl2.URI_PATTERN.matcher("Z019+-.:/!@ #~ ").matches());
assertFalse(ManagedChannelImpl2.URI_PATTERN.matcher("a/:").matches()); // "/:" not matched
assertFalse(ManagedChannelImpl2.URI_PATTERN.matcher("0a:/").matches()); // '0' not matched
assertFalse(ManagedChannelImpl2.URI_PATTERN.matcher("a,:/").matches()); // ',' not matched
assertFalse(ManagedChannelImpl2.URI_PATTERN.matcher(" a:/").matches()); // space not matched
assertTrue(ManagedChannelImpl.URI_PATTERN.matcher("a:/").matches());
assertTrue(ManagedChannelImpl.URI_PATTERN.matcher("Z019+-.:/!@ #~ ").matches());
assertFalse(ManagedChannelImpl.URI_PATTERN.matcher("a/:").matches()); // "/:" not matched
assertFalse(ManagedChannelImpl.URI_PATTERN.matcher("0a:/").matches()); // '0' not matched
assertFalse(ManagedChannelImpl.URI_PATTERN.matcher("a,:/").matches()); // ',' not matched
assertFalse(ManagedChannelImpl.URI_PATTERN.matcher(" a:/").matches()); // space not matched
}
/**

View File

@ -34,7 +34,7 @@ package io.grpc.util;
import static com.google.common.truth.Truth.assertThat;
import static io.grpc.ConnectivityState.IDLE;
import static io.grpc.ConnectivityState.READY;
import static io.grpc.util.RoundRobinLoadBalancerFactory2.RoundRobinLoadBalancer.STATE_INFO;
import static io.grpc.util.RoundRobinLoadBalancerFactory.RoundRobinLoadBalancer.STATE_INFO;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
@ -53,15 +53,15 @@ import io.grpc.Attributes;
import io.grpc.ConnectivityState;
import io.grpc.ConnectivityStateInfo;
import io.grpc.EquivalentAddressGroup;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer2.Helper;
import io.grpc.LoadBalancer2.Subchannel;
import io.grpc.LoadBalancer;
import io.grpc.LoadBalancer.Helper;
import io.grpc.LoadBalancer.Subchannel;
import io.grpc.Metadata;
import io.grpc.ResolvedServerInfo;
import io.grpc.ResolvedServerInfoGroup;
import io.grpc.Status;
import io.grpc.util.RoundRobinLoadBalancerFactory2.Picker;
import io.grpc.util.RoundRobinLoadBalancerFactory2.RoundRobinLoadBalancer;
import io.grpc.util.RoundRobinLoadBalancerFactory.Picker;
import io.grpc.util.RoundRobinLoadBalancerFactory.RoundRobinLoadBalancer;
import java.net.SocketAddress;
import java.util.Collections;
import java.util.List;
@ -79,9 +79,9 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/** Unit test for {@link RoundRobinLoadBalancerFactory2}. */
/** Unit test for {@link RoundRobinLoadBalancerFactory}. */
@RunWith(JUnit4.class)
public class RoundRobinLoadBalancer2Test {
public class RoundRobinLoadBalancerTest {
private RoundRobinLoadBalancer loadBalancer;
private Map<ResolvedServerInfoGroup, EquivalentAddressGroup> servers = Maps.newHashMap();
private Map<EquivalentAddressGroup, Subchannel> subchannels = Maps.newLinkedHashMap();
@ -117,7 +117,7 @@ public class RoundRobinLoadBalancer2Test {
}
});
loadBalancer = (RoundRobinLoadBalancer) RoundRobinLoadBalancerFactory2.getInstance()
loadBalancer = (RoundRobinLoadBalancer) RoundRobinLoadBalancerFactory.getInstance()
.newLoadBalancer(mockHelper);
}
@ -323,7 +323,7 @@ public class RoundRobinLoadBalancer2Test {
Status error = Status.NOT_FOUND.withDescription("nameResolutionError");
loadBalancer.handleNameResolutionError(error);
verify(mockHelper).updatePicker(pickerCaptor.capture());
LoadBalancer2.PickResult pickResult = pickerCaptor.getValue().pickSubchannel(Attributes.EMPTY,
LoadBalancer.PickResult pickResult = pickerCaptor.getValue().pickSubchannel(Attributes.EMPTY,
new Metadata());
assertNull(pickResult.getSubchannel());
assertEquals(error, pickResult.getStatus());
@ -341,12 +341,12 @@ public class RoundRobinLoadBalancer2Test {
any(Attributes.class));
verify(mockHelper, times(2)).updatePicker(pickerCaptor.capture());
LoadBalancer2.PickResult pickResult = pickerCaptor.getValue().pickSubchannel(Attributes.EMPTY,
LoadBalancer.PickResult pickResult = pickerCaptor.getValue().pickSubchannel(Attributes.EMPTY,
new Metadata());
assertEquals(readySubchannel, pickResult.getSubchannel());
assertEquals(Status.OK.getCode(), pickResult.getStatus().getCode());
LoadBalancer2.PickResult pickResult2 = pickerCaptor.getValue().pickSubchannel(Attributes.EMPTY,
LoadBalancer.PickResult pickResult2 = pickerCaptor.getValue().pickSubchannel(Attributes.EMPTY,
new Metadata());
assertEquals(readySubchannel, pickResult2.getSubchannel());
verifyNoMoreInteractions(mockHelper);

View File

@ -43,7 +43,7 @@ import com.google.common.annotations.VisibleForTesting;
import io.grpc.Attributes;
import io.grpc.ConnectivityStateInfo;
import io.grpc.EquivalentAddressGroup;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer;
import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.ResolvedServerInfoGroup;
@ -67,13 +67,13 @@ import java.util.logging.Logger;
import javax.annotation.Nullable;
/**
* A {@link LoadBalancer2} that uses the GRPCLB protocol.
* A {@link LoadBalancer} that uses the GRPCLB protocol.
*
* <p>Optionally, when requested by the naming system, will delegate the work to a local pick-first
* or round-robin balancer.
*/
class GrpclbLoadBalancer2 extends LoadBalancer2 implements WithLogId {
private static final Logger logger = Logger.getLogger(GrpclbLoadBalancer2.class.getName());
class GrpclbLoadBalancer extends LoadBalancer implements WithLogId {
private static final Logger logger = Logger.getLogger(GrpclbLoadBalancer.class.getName());
@VisibleForTesting
static final SubchannelPicker BUFFER_PICKER = new SubchannelPicker() {
@ -104,7 +104,7 @@ class GrpclbLoadBalancer2 extends LoadBalancer2 implements WithLogId {
// If not null, all work is delegated to it.
@Nullable
private LoadBalancer2 delegate;
private LoadBalancer delegate;
private LbPolicy lbPolicy;
///////////////////////////////////////////////////////////////////////////////
@ -128,7 +128,7 @@ class GrpclbLoadBalancer2 extends LoadBalancer2 implements WithLogId {
// A null element indicate a simulated error for throttling purpose
private List<EquivalentAddressGroup> roundRobinList = Collections.emptyList();
GrpclbLoadBalancer2(Helper helper, Factory pickFirstBalancerFactory,
GrpclbLoadBalancer(Helper helper, Factory pickFirstBalancerFactory,
Factory roundRobinBalancerFactory) {
this.helper = checkNotNull(helper, "helper");
this.serviceName = checkNotNull(helper.getAuthority(), "helper returns null authority");
@ -450,7 +450,7 @@ class GrpclbLoadBalancer2 extends LoadBalancer2 implements WithLogId {
}
@VisibleForTesting
LoadBalancer2 getDelegate() {
LoadBalancer getDelegate() {
return delegate;
}

View File

@ -32,36 +32,32 @@
package io.grpc.grpclb;
import io.grpc.ExperimentalApi;
import io.grpc.LoadBalancer2;
import io.grpc.PickFirstBalancerFactory2;
import io.grpc.util.RoundRobinLoadBalancerFactory2;
import io.grpc.LoadBalancer;
import io.grpc.PickFirstBalancerFactory;
import io.grpc.util.RoundRobinLoadBalancerFactory;
/**
* A factory for {@link LoadBalancer2}s that uses the GRPCLB protocol.
*
* <p><strong>TECHNICAL PREVIEW: </strong>The name of this class is temporary. It will be renamed to
* {@code GrpclbLoadBalancerFactory} during <a href="https://github.com/grpc/grpc-java/issues/2656">
* transition to LBv2</a>. You should use it only if you want to experiment the LBv2 code path.
* A factory for {@link LoadBalancer}s that uses the GRPCLB protocol.
*
* <p><b>Experimental:</b>This only works with the GRPCLB load-balancer service, which is not
* available yet. Right now it's only good for internal testing.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1782")
public class GrpclbLoadBalancerFactory2 extends LoadBalancer2.Factory {
public class GrpclbLoadBalancerFactory extends LoadBalancer.Factory {
private static final GrpclbLoadBalancerFactory2 instance = new GrpclbLoadBalancerFactory2();
private static final GrpclbLoadBalancerFactory instance = new GrpclbLoadBalancerFactory();
private GrpclbLoadBalancerFactory2() {
private GrpclbLoadBalancerFactory() {
}
public static GrpclbLoadBalancerFactory2 getInstance() {
public static GrpclbLoadBalancerFactory getInstance() {
return instance;
}
@Override
public LoadBalancer2 newLoadBalancer(LoadBalancer2.Helper helper) {
return new GrpclbLoadBalancer2(
helper, PickFirstBalancerFactory2.getInstance(),
RoundRobinLoadBalancerFactory2.getInstance());
public LoadBalancer newLoadBalancer(LoadBalancer.Helper helper) {
return new GrpclbLoadBalancer(
helper, PickFirstBalancerFactory.getInstance(),
RoundRobinLoadBalancerFactory.getInstance());
}
}

View File

@ -62,11 +62,11 @@ import io.grpc.Attributes;
import io.grpc.CallOptions;
import io.grpc.ConnectivityStateInfo;
import io.grpc.EquivalentAddressGroup;
import io.grpc.LoadBalancer2;
import io.grpc.LoadBalancer2.Helper;
import io.grpc.LoadBalancer2.PickResult;
import io.grpc.LoadBalancer2.Subchannel;
import io.grpc.LoadBalancer2.SubchannelPicker;
import io.grpc.LoadBalancer;
import io.grpc.LoadBalancer.Helper;
import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.Subchannel;
import io.grpc.LoadBalancer.SubchannelPicker;
import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
@ -76,8 +76,8 @@ import io.grpc.ResolvedServerInfoGroup;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.grpclb.GrpclbConstants.LbPolicy;
import io.grpc.grpclb.GrpclbLoadBalancer2.ErrorPicker;
import io.grpc.grpclb.GrpclbLoadBalancer2.RoundRobinPicker;
import io.grpc.grpclb.GrpclbLoadBalancer.ErrorPicker;
import io.grpc.grpclb.GrpclbLoadBalancer.RoundRobinPicker;
import io.grpc.inprocess.InProcessChannelBuilder;
import io.grpc.inprocess.InProcessServerBuilder;
import io.grpc.internal.SerializingExecutor;
@ -105,9 +105,9 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/** Unit tests for {@link GrpclbLoadBalancer2}. */
/** Unit tests for {@link GrpclbLoadBalancer}. */
@RunWith(JUnit4.class)
public class GrpclbLoadBalancer2Test {
public class GrpclbLoadBalancerTest {
private static final Attributes.Key<String> RESOLUTION_ATTR =
Attributes.Key.of("resolution-attr");
private static final String SERVICE_AUTHORITY = "api.google.com";
@ -159,14 +159,14 @@ public class GrpclbLoadBalancer2Test {
new SerializingExecutor(MoreExecutors.directExecutor());
private final Metadata headers = new Metadata();
@Mock
private LoadBalancer2.Factory pickFirstBalancerFactory;
private LoadBalancer.Factory pickFirstBalancerFactory;
@Mock
private LoadBalancer2 pickFirstBalancer;
private LoadBalancer pickFirstBalancer;
@Mock
private LoadBalancer2.Factory roundRobinBalancerFactory;
private LoadBalancer.Factory roundRobinBalancerFactory;
@Mock
private LoadBalancer2 roundRobinBalancer;
private GrpclbLoadBalancer2 balancer;
private LoadBalancer roundRobinBalancer;
private GrpclbLoadBalancer balancer;
@SuppressWarnings("unchecked")
@Before
@ -240,7 +240,7 @@ public class GrpclbLoadBalancer2Test {
}
}).when(helper).runSerialized(any(Runnable.class));
when(helper.getAuthority()).thenReturn(SERVICE_AUTHORITY);
balancer = new GrpclbLoadBalancer2(helper, pickFirstBalancerFactory, roundRobinBalancerFactory);
balancer = new GrpclbLoadBalancer(helper, pickFirstBalancerFactory, roundRobinBalancerFactory);
}
@After
@ -290,7 +290,7 @@ public class GrpclbLoadBalancer2Test {
@Test
public void bufferPicker() {
assertEquals(PickResult.withNoResult(),
GrpclbLoadBalancer2.BUFFER_PICKER.pickSubchannel(Attributes.EMPTY, headers));
GrpclbLoadBalancer.BUFFER_PICKER.pickSubchannel(Attributes.EMPTY, headers));
}
@Test
@ -553,11 +553,11 @@ public class GrpclbLoadBalancer2Test {
assertEquals(new EquivalentAddressGroup(backends1.get(1)), subchannel2.getAddresses());
// Before any subchannel is READY, a buffer picker will be provided
inOrder.verify(helper).updatePicker(same(GrpclbLoadBalancer2.BUFFER_PICKER));
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(GrpclbLoadBalancer2.BUFFER_PICKER));
inOrder.verify(helper, times(2)).updatePicker(same(GrpclbLoadBalancer.BUFFER_PICKER));
// Let subchannels be connected
deliverSubchannelState(subchannel2, ConnectivityStateInfo.forNonError(READY));
@ -724,7 +724,7 @@ public class GrpclbLoadBalancer2Test {
eq(new EquivalentAddressGroup(backends.get(0))), any(Attributes.class));
inOrder.verify(helper).createSubchannel(
eq(new EquivalentAddressGroup(backends.get(1))), any(Attributes.class));
inOrder.verify(helper).updatePicker(same(GrpclbLoadBalancer2.BUFFER_PICKER));
inOrder.verify(helper).updatePicker(same(GrpclbLoadBalancer.BUFFER_PICKER));
inOrder.verifyNoMoreInteractions();
}
@ -806,7 +806,7 @@ public class GrpclbLoadBalancer2Test {
Subchannel subchannel = subchannels[i];
if (subchannel == null) {
assertSame("list[" + i + "] should be drop",
GrpclbLoadBalancer2.THROTTLED_RESULT, picker.list.get(i));
GrpclbLoadBalancer.THROTTLED_RESULT, picker.list.get(i));
} else {
assertEquals("list[" + i + "] should be Subchannel",
subchannel, picker.list.get(i).getSubchannel());