2015-02-06 04:14:05 +03:00
/ *
*
2017-06-08 15:42:19 +03:00
* Copyright 2014 gRPC authors .
2015-02-06 04:14:05 +03:00
*
2017-06-08 15:42:19 +03:00
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
2015-02-06 04:14:05 +03:00
*
2017-06-08 15:42:19 +03:00
* http : //www.apache.org/licenses/LICENSE-2.0
2015-02-06 04:14:05 +03:00
*
2017-06-08 15:42:19 +03:00
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
2015-02-06 04:14:05 +03:00
*
* /
2015-02-09 03:35:38 +03:00
package grpc
2015-02-06 04:14:05 +03:00
import (
2015-02-19 14:57:41 +03:00
"errors"
2017-10-02 19:22:57 +03:00
"fmt"
2017-08-14 22:24:23 +03:00
"math"
2015-04-17 23:50:18 +03:00
"net"
2017-08-31 20:59:09 +03:00
"reflect"
2017-04-04 02:03:05 +03:00
"strings"
2015-02-06 04:14:05 +03:00
"sync"
"time"
2015-02-19 09:15:13 +03:00
"golang.org/x/net/context"
2015-09-23 22:18:41 +03:00
"golang.org/x/net/trace"
2017-08-31 20:59:09 +03:00
"google.golang.org/grpc/balancer"
2017-10-19 21:32:06 +03:00
_ "google.golang.org/grpc/balancer/roundrobin" // To register roundrobin.
streams: Stop cleaning up after orphaned streams (#1854)
This change introduces some behavior changes that should not impact users that
are following the proper stream protocol. Specifically, one of the following
conditions must be satisfied:
1. The user calls Close on the ClientConn.
2. The user cancels the context provided to NewClientStream, or its deadline
expires. (Note that it if the context is no longer needed before the deadline
expires, it is still recommended to call cancel to prevent bloat.) It is always
recommended to cancel contexts when they are no longer needed, and to
never use the background context directly, so all users should always be
doing this.
3. The user calls RecvMsg (or Recv in generated code) until a non-nil error is
returned.
4. The user receives any error from Header or SendMsg (or Send in generated
code) besides io.EOF. If none of the above happen, this will leak a goroutine
and a context, and grpc will not call the optionally-configured stats handler
with a stats.End message.
Before this change, if a user created a stream and the server ended the stream,
the stats handler would be invoked with a stats.End containing the final status
of the stream. Subsequent calls to RecvMsg would then trigger the stats handler
with InPayloads, which may be unexpected by stats handlers.
2018-02-08 21:51:16 +03:00
"google.golang.org/grpc/codes"
2017-08-09 20:31:12 +03:00
"google.golang.org/grpc/connectivity"
2015-02-09 03:39:06 +03:00
"google.golang.org/grpc/credentials"
2015-05-09 12:43:59 +03:00
"google.golang.org/grpc/grpclog"
2017-02-28 22:49:51 +03:00
"google.golang.org/grpc/keepalive"
2017-08-31 20:59:09 +03:00
"google.golang.org/grpc/resolver"
2017-10-20 22:03:44 +03:00
_ "google.golang.org/grpc/resolver/dns" // To register dns resolver.
_ "google.golang.org/grpc/resolver/passthrough" // To register passthrough resolver.
2017-01-10 04:11:32 +03:00
"google.golang.org/grpc/stats"
streams: Stop cleaning up after orphaned streams (#1854)
This change introduces some behavior changes that should not impact users that
are following the proper stream protocol. Specifically, one of the following
conditions must be satisfied:
1. The user calls Close on the ClientConn.
2. The user cancels the context provided to NewClientStream, or its deadline
expires. (Note that it if the context is no longer needed before the deadline
expires, it is still recommended to call cancel to prevent bloat.) It is always
recommended to cancel contexts when they are no longer needed, and to
never use the background context directly, so all users should always be
doing this.
3. The user calls RecvMsg (or Recv in generated code) until a non-nil error is
returned.
4. The user receives any error from Header or SendMsg (or Send in generated
code) besides io.EOF. If none of the above happen, this will leak a goroutine
and a context, and grpc will not call the optionally-configured stats handler
with a stats.End message.
Before this change, if a user created a stream and the server ended the stream,
the stats handler would be invoked with a stats.End containing the final status
of the stream. Subsequent calls to RecvMsg would then trigger the stats handler
with InPayloads, which may be unexpected by stats handlers.
2018-02-08 21:51:16 +03:00
"google.golang.org/grpc/status"
2015-02-09 03:39:06 +03:00
"google.golang.org/grpc/transport"
2015-02-06 04:14:05 +03:00
)
2015-02-19 14:57:41 +03:00
var (
2016-05-25 21:28:45 +03:00
// ErrClientConnClosing indicates that the operation is illegal because
// the ClientConn is closing.
streams: Stop cleaning up after orphaned streams (#1854)
This change introduces some behavior changes that should not impact users that
are following the proper stream protocol. Specifically, one of the following
conditions must be satisfied:
1. The user calls Close on the ClientConn.
2. The user cancels the context provided to NewClientStream, or its deadline
expires. (Note that it if the context is no longer needed before the deadline
expires, it is still recommended to call cancel to prevent bloat.) It is always
recommended to cancel contexts when they are no longer needed, and to
never use the background context directly, so all users should always be
doing this.
3. The user calls RecvMsg (or Recv in generated code) until a non-nil error is
returned.
4. The user receives any error from Header or SendMsg (or Send in generated
code) besides io.EOF. If none of the above happen, this will leak a goroutine
and a context, and grpc will not call the optionally-configured stats handler
with a stats.End message.
Before this change, if a user created a stream and the server ended the stream,
the stats handler would be invoked with a stats.End containing the final status
of the stream. Subsequent calls to RecvMsg would then trigger the stats handler
with InPayloads, which may be unexpected by stats handlers.
2018-02-08 21:51:16 +03:00
//
// Deprecated: this error should not be relied upon by users; use the status
// code of Canceled instead.
ErrClientConnClosing = status . Error ( codes . Canceled , "grpc: the client connection is closing" )
2017-11-07 00:45:11 +03:00
// errConnDrain indicates that the connection starts to be drained and does not accept any new RPCs.
errConnDrain = errors . New ( "grpc: the connection is drained" )
// errConnClosing indicates that the connection is closing.
errConnClosing = errors . New ( "grpc: the connection is closing" )
// errConnUnavailable indicates that the connection is unavailable.
errConnUnavailable = errors . New ( "grpc: the connection is unavailable" )
// errBalancerClosed indicates that the balancer is closed.
errBalancerClosed = errors . New ( "grpc: balancer is closed" )
// minimum time to give a connection to complete
minConnectTimeout = 20 * time . Second
)
2016-05-25 21:28:45 +03:00
2017-11-07 00:45:11 +03:00
// The following errors are returned from Dial and DialContext
var (
2016-05-25 21:28:45 +03:00
// errNoTransportSecurity indicates that there is no transport security
2016-03-17 02:40:16 +03:00
// being set for ClientConn. Users should either set one or explicitly
2015-08-28 03:21:52 +03:00
// call WithInsecure DialOption to disable security.
2016-05-25 21:28:45 +03:00
errNoTransportSecurity = errors . New ( "grpc: no transport security set (use grpc.WithInsecure() explicitly or set credentials)" )
2016-06-08 23:44:43 +03:00
// errTransportCredentialsMissing indicates that users want to transmit security
// information (e.g., oauth2 token) which requires secure connection on an insecure
2015-08-28 23:19:36 +03:00
// connection.
2016-06-08 23:44:43 +03:00
errTransportCredentialsMissing = errors . New ( "grpc: the credentials require transport level security (use grpc.WithTransportCredentials() to set)" )
// errCredentialsConflict indicates that grpc.WithTransportCredentials()
// and grpc.WithInsecure() are both called for a connection.
errCredentialsConflict = errors . New ( "grpc: transport credentials are set for an insecure connection (grpc.WithTransportCredentials() and grpc.WithInsecure() are both called)" )
2016-07-28 21:07:42 +03:00
// errNetworkIO indicates that the connection is down due to some network I/O error.
2016-05-25 21:28:45 +03:00
errNetworkIO = errors . New ( "grpc: failed with network I/O error" )
2015-02-19 14:57:41 +03:00
)
2015-04-02 00:02:26 +03:00
// dialOptions configure a Dial call. dialOptions are set by the DialOption
// values passed to Dial.
type dialOptions struct {
2017-04-27 01:50:58 +03:00
unaryInt UnaryClientInterceptor
streamInt StreamClientInterceptor
cp Compressor
dc Decompressor
bs backoffStrategy
block bool
insecure bool
timeout time . Duration
scChan <- chan ServiceConfig
copts transport . ConnectOptions
callOptions [ ] CallOption
2017-12-19 02:35:42 +03:00
// This is used by v1 balancer dial option WithBalancer to support v1
// balancer, and also by WithBalancerName dial option.
2017-08-31 20:59:09 +03:00
balancerBuilder balancer . Builder
2017-11-27 22:16:26 +03:00
// This is to support grpclb.
2018-02-05 23:52:35 +03:00
resolverBuilder resolver . Builder
waitForHandshake bool
2015-04-02 00:02:26 +03:00
}
2017-04-07 00:08:04 +03:00
const (
defaultClientMaxReceiveMessageSize = 1024 * 1024 * 4
2017-08-14 22:24:23 +03:00
defaultClientMaxSendMessageSize = math . MaxInt32
2017-04-07 00:08:04 +03:00
)
2017-03-10 03:58:23 +03:00
2015-03-04 04:08:39 +03:00
// DialOption configures how we set up the connection.
2015-04-02 00:02:26 +03:00
type DialOption func ( * dialOptions )
2017-12-01 20:55:42 +03:00
// WithWaitForHandshake blocks until the initial settings frame is received from the
// server before assigning RPCs to the connection.
// Experimental API.
func WithWaitForHandshake ( ) DialOption {
return func ( o * dialOptions ) {
o . waitForHandshake = true
}
}
2017-09-29 00:11:14 +03:00
// WithWriteBufferSize lets you set the size of write buffer, this determines how much data can be batched
// before doing a write on the wire.
func WithWriteBufferSize ( s int ) DialOption {
return func ( o * dialOptions ) {
o . copts . WriteBufferSize = s
}
}
// WithReadBufferSize lets you set the size of read buffer, this determines how much data can be read at most
// for each read syscall.
func WithReadBufferSize ( s int ) DialOption {
return func ( o * dialOptions ) {
o . copts . ReadBufferSize = s
}
}
2017-05-05 23:26:56 +03:00
// WithInitialWindowSize returns a DialOption which sets the value for initial window size on a stream.
// The lower bound for window size is 64K and any value smaller than that will be ignored.
func WithInitialWindowSize ( s int32 ) DialOption {
return func ( o * dialOptions ) {
o . copts . InitialWindowSize = s
}
}
// WithInitialConnWindowSize returns a DialOption which sets the value for initial window size on a connection.
// The lower bound for window size is 64K and any value smaller than that will be ignored.
func WithInitialConnWindowSize ( s int32 ) DialOption {
return func ( o * dialOptions ) {
o . copts . InitialConnWindowSize = s
}
}
2017-05-19 21:08:40 +03:00
// WithMaxMsgSize returns a DialOption which sets the maximum message size the client can receive. Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead.
2017-03-10 03:58:23 +03:00
func WithMaxMsgSize ( s int ) DialOption {
2017-05-19 21:08:40 +03:00
return WithDefaultCallOptions ( MaxCallRecvMsgSize ( s ) )
2017-04-04 01:03:24 +03:00
}
2017-04-27 01:50:58 +03:00
// WithDefaultCallOptions returns a DialOption which sets the default CallOptions for calls over the connection.
func WithDefaultCallOptions ( cos ... CallOption ) DialOption {
2017-03-10 03:58:23 +03:00
return func ( o * dialOptions ) {
2017-04-27 01:50:58 +03:00
o . callOptions = append ( o . callOptions , cos ... )
2017-03-10 03:58:23 +03:00
}
}
2015-04-02 00:02:26 +03:00
// WithCodec returns a DialOption which sets a codec for message marshaling and unmarshaling.
2018-01-23 22:39:40 +03:00
//
// Deprecated: use WithDefaultCallOptions(CallCustomCodec(c)) instead.
2015-04-02 00:22:53 +03:00
func WithCodec ( c Codec ) DialOption {
2018-01-23 22:39:40 +03:00
return WithDefaultCallOptions ( CallCustomCodec ( c ) )
2015-04-02 00:02:26 +03:00
}
2015-02-06 04:14:05 +03:00
2017-11-17 20:24:54 +03:00
// WithCompressor returns a DialOption which sets a Compressor to use for
// message compression. It has lower priority than the compressor set by
// the UseCompressor CallOption.
//
// Deprecated: use UseCompressor instead.
2016-01-30 01:38:20 +03:00
func WithCompressor ( cp Compressor ) DialOption {
2016-01-23 05:21:41 +03:00
return func ( o * dialOptions ) {
2016-01-30 01:38:20 +03:00
o . cp = cp
2016-01-23 05:21:41 +03:00
}
}
2017-11-17 20:24:54 +03:00
// WithDecompressor returns a DialOption which sets a Decompressor to use for
// incoming message decompression. If incoming response messages are encoded
// using the decompressor's Type(), it will be used. Otherwise, the message
// encoding will be used to look up the compressor registered via
// encoding.RegisterCompressor, which will then be used to decompress the
// message. If no compressor is registered for the encoding, an Unimplemented
// status error will be returned.
//
// Deprecated: use encoding.RegisterCompressor instead.
2016-01-30 01:38:20 +03:00
func WithDecompressor ( dc Decompressor ) DialOption {
2016-01-23 05:21:41 +03:00
return func ( o * dialOptions ) {
2016-01-30 01:38:20 +03:00
o . dc = dc
2016-01-23 05:21:41 +03:00
}
}
2017-08-31 20:59:09 +03:00
// WithBalancer returns a DialOption which sets a load balancer with the v1 API.
// Name resolver will be ignored if this DialOption is specified.
2017-12-19 02:35:42 +03:00
//
// Deprecated: use the new balancer APIs in balancer package and WithBalancerName.
2016-05-13 05:19:14 +03:00
func WithBalancer ( b Balancer ) DialOption {
return func ( o * dialOptions ) {
2017-08-31 20:59:09 +03:00
o . balancerBuilder = & balancerWrapperBuilder {
b : b ,
}
2016-05-13 05:19:14 +03:00
}
}
2017-12-19 02:35:42 +03:00
// WithBalancerName sets the balancer that the ClientConn will be initialized
// with. Balancer registered with balancerName will be used. This function
// panics if no balancer was registered by balancerName.
//
// The balancer cannot be overridden by balancer option specified by service
// config.
//
// This is an EXPERIMENTAL API.
func WithBalancerName ( balancerName string ) DialOption {
builder := balancer . Get ( balancerName )
if builder == nil {
panic ( fmt . Sprintf ( "grpc.WithBalancerName: no balancer is registered for name %v" , balancerName ) )
}
2017-10-02 19:22:57 +03:00
return func ( o * dialOptions ) {
2017-12-19 02:35:42 +03:00
o . balancerBuilder = builder
2017-10-02 19:22:57 +03:00
}
}
2017-11-27 22:16:26 +03:00
// withResolverBuilder is only for grpclb.
func withResolverBuilder ( b resolver . Builder ) DialOption {
return func ( o * dialOptions ) {
o . resolverBuilder = b
}
}
2016-12-20 03:31:00 +03:00
// WithServiceConfig returns a DialOption which has a channel to read the service configuration.
2017-10-19 22:09:19 +03:00
// DEPRECATED: service config should be received through name resolver, as specified here.
// https://github.com/grpc/grpc/blob/master/doc/service_config.md
2016-12-20 03:31:00 +03:00
func WithServiceConfig ( c <- chan ServiceConfig ) DialOption {
return func ( o * dialOptions ) {
o . scChan = c
}
}
2016-04-15 04:40:32 +03:00
// WithBackoffMaxDelay configures the dialer to use the provided maximum delay
// when backing off after failed connection attempts.
func WithBackoffMaxDelay ( md time . Duration ) DialOption {
2016-04-18 21:33:39 +03:00
return WithBackoffConfig ( BackoffConfig { MaxDelay : md } )
2016-04-15 04:40:32 +03:00
}
2016-03-23 21:49:05 +03:00
// WithBackoffConfig configures the dialer to use the provided backoff
// parameters after connection failures.
2016-04-15 04:40:32 +03:00
//
// Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up
// for use.
2016-04-18 21:33:39 +03:00
func WithBackoffConfig ( b BackoffConfig ) DialOption {
2016-04-15 04:40:32 +03:00
// Set defaults to ensure that provided BackoffConfig is valid and
// unexported fields get default values.
2016-04-18 23:15:27 +03:00
setDefaults ( & b )
2016-03-23 21:49:05 +03:00
return withBackoff ( b )
}
2017-12-01 20:55:42 +03:00
// withBackoff sets the backoff strategy used for connectRetryNum after a
2016-03-23 21:49:05 +03:00
// failed connection attempt.
//
2016-06-03 04:00:07 +03:00
// This can be exported if arbitrary backoff strategies are allowed by gRPC.
2016-03-23 21:49:05 +03:00
func withBackoff ( bs backoffStrategy ) DialOption {
return func ( o * dialOptions ) {
o . bs = bs
}
}
2015-06-05 01:45:06 +03:00
// WithBlock returns a DialOption which makes caller of Dial blocks until the underlying
2015-06-05 01:47:02 +03:00
// connection is up. Without this, Dial returns immediately and connecting the server
// happens in background.
2015-06-05 01:45:06 +03:00
func WithBlock ( ) DialOption {
return func ( o * dialOptions ) {
o . block = true
}
}
2016-01-08 01:18:20 +03:00
// WithInsecure returns a DialOption which disables transport security for this ClientConn.
// Note that transport security is required unless WithInsecure is set.
2015-08-28 03:21:52 +03:00
func WithInsecure ( ) DialOption {
return func ( o * dialOptions ) {
o . insecure = true
}
}
2015-02-26 09:57:07 +03:00
// WithTransportCredentials returns a DialOption which configures a
// connection level security credentials (e.g., TLS/SSL).
2016-06-08 21:10:23 +03:00
func WithTransportCredentials ( creds credentials . TransportCredentials ) DialOption {
2015-04-02 00:02:26 +03:00
return func ( o * dialOptions ) {
2016-06-08 21:10:23 +03:00
o . copts . TransportCredentials = creds
2015-02-06 04:14:05 +03:00
}
}
2015-02-18 23:02:43 +03:00
// WithPerRPCCredentials returns a DialOption which sets
2017-05-04 20:16:29 +03:00
// credentials and places auth state on each outbound RPC.
2016-06-07 03:28:10 +03:00
func WithPerRPCCredentials ( creds credentials . PerRPCCredentials ) DialOption {
2015-04-02 00:02:26 +03:00
return func ( o * dialOptions ) {
2016-06-07 03:28:10 +03:00
o . copts . PerRPCCredentials = append ( o . copts . PerRPCCredentials , creds )
2015-03-04 04:08:39 +03:00
}
}
2016-06-06 22:13:00 +03:00
// WithTimeout returns a DialOption that configures a timeout for dialing a ClientConn
// initially. This is valid if and only if WithBlock() is present.
2017-06-27 01:18:57 +03:00
// Deprecated: use DialContext and context.WithTimeout instead.
2015-03-04 04:08:39 +03:00
func WithTimeout ( d time . Duration ) DialOption {
2015-04-02 00:02:26 +03:00
return func ( o * dialOptions ) {
2016-06-06 22:08:11 +03:00
o . timeout = d
2015-02-06 04:14:05 +03:00
}
}
2017-11-27 22:16:26 +03:00
func withContextDialer ( f func ( context . Context , string ) ( net . Conn , error ) ) DialOption {
return func ( o * dialOptions ) {
o . copts . Dialer = f
}
}
2015-04-22 02:48:41 +03:00
// WithDialer returns a DialOption that specifies a function to use for dialing network addresses.
2016-11-12 01:16:58 +03:00
// If FailOnNonTempDialError() is set to true, and an error is returned by f, gRPC checks the error's
// Temporary() method to decide if it should try to reconnect to the network address.
2016-07-29 00:00:23 +03:00
func WithDialer ( f func ( string , time . Duration ) ( net . Conn , error ) ) DialOption {
2017-11-27 22:16:26 +03:00
return withContextDialer (
func ( ctx context . Context , addr string ) ( net . Conn , error ) {
2016-07-29 20:16:56 +03:00
if deadline , ok := ctx . Deadline ( ) ; ok {
return f ( addr , deadline . Sub ( time . Now ( ) ) )
}
return f ( addr , 0 )
2017-11-27 22:16:26 +03:00
} )
2015-04-17 23:50:18 +03:00
}
2017-01-10 04:11:32 +03:00
// WithStatsHandler returns a DialOption that specifies the stats handler
// for all the RPCs and underlying network connections in this ClientConn.
func WithStatsHandler ( h stats . Handler ) DialOption {
return func ( o * dialOptions ) {
o . copts . StatsHandler = h
}
}
2017-05-04 20:16:29 +03:00
// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on non-temporary dial errors.
2016-11-12 01:16:58 +03:00
// If f is true, and dialer returns a non-temporary error, gRPC will fail the connection to the network
// address and won't try to reconnect.
// The default value of FailOnNonTempDialError is false.
// This is an EXPERIMENTAL API.
func FailOnNonTempDialError ( f bool ) DialOption {
return func ( o * dialOptions ) {
o . copts . FailOnNonTempDialError = f
}
}
2015-07-24 21:19:08 +03:00
// WithUserAgent returns a DialOption that specifies a user agent string for all the RPCs.
func WithUserAgent ( s string ) DialOption {
return func ( o * dialOptions ) {
o . copts . UserAgent = s
}
}
2017-09-21 00:55:57 +03:00
// WithKeepaliveParams returns a DialOption that specifies keepalive parameters for the client transport.
2017-02-28 22:49:51 +03:00
func WithKeepaliveParams ( kp keepalive . ClientParameters ) DialOption {
2016-11-18 04:50:52 +03:00
return func ( o * dialOptions ) {
2017-02-01 03:09:40 +03:00
o . copts . KeepaliveParams = kp
2016-11-18 04:50:52 +03:00
}
}
2016-08-26 23:50:38 +03:00
// WithUnaryInterceptor returns a DialOption that specifies the interceptor for unary RPCs.
func WithUnaryInterceptor ( f UnaryClientInterceptor ) DialOption {
return func ( o * dialOptions ) {
o . unaryInt = f
}
}
// WithStreamInterceptor returns a DialOption that specifies the interceptor for streaming RPCs.
func WithStreamInterceptor ( f StreamClientInterceptor ) DialOption {
return func ( o * dialOptions ) {
o . streamInt = f
}
}
2017-02-04 04:01:38 +03:00
// WithAuthority returns a DialOption that specifies the value to be used as
2017-02-09 21:44:13 +03:00
// the :authority pseudo-header. This value only works with WithInsecure and
// has no effect if TransportCredentials are present.
2017-02-04 04:01:38 +03:00
func WithAuthority ( a string ) DialOption {
return func ( o * dialOptions ) {
o . copts . Authority = a
}
}
2016-08-15 20:17:09 +03:00
// Dial creates a client connection to the given target.
2015-02-06 04:14:05 +03:00
func Dial ( target string , opts ... DialOption ) ( * ClientConn , error ) {
2016-08-15 20:17:09 +03:00
return DialContext ( context . Background ( ) , target , opts ... )
}
2016-08-24 04:18:18 +03:00
// DialContext creates a client connection to the given target. ctx can be used to
2017-05-04 20:16:29 +03:00
// cancel or expire the pending connection. Once this function returns, the
2016-08-24 05:23:04 +03:00
// cancellation and expiration of ctx will be noop. Users should call ClientConn.Close
// to terminate all the pending operations after this function returns.
2018-01-19 00:10:52 +03:00
//
// The target name syntax is defined in
// https://github.com/grpc/grpc/blob/master/doc/naming.md.
// e.g. to use dns resolver, a "dns:///" prefix should be applied to the target.
2016-08-24 22:56:16 +03:00
func DialContext ( ctx context . Context , target string , opts ... DialOption ) ( conn * ClientConn , err error ) {
2015-09-29 20:24:03 +03:00
cc := & ClientConn {
target : target ,
2017-07-25 01:00:53 +03:00
csMgr : & connectivityStateManager { } ,
2017-08-31 20:59:09 +03:00
conns : make ( map [ * addrConn ] struct { } ) ,
2017-10-02 19:22:57 +03:00
blockingpicker : newPickerWrapper ( ) ,
2015-09-29 20:24:03 +03:00
}
2016-08-24 04:18:18 +03:00
cc . ctx , cc . cancel = context . WithCancel ( context . Background ( ) )
2017-04-04 01:03:24 +03:00
2016-12-20 03:31:00 +03:00
for _ , opt := range opts {
opt ( & cc . dopts )
}
2017-10-02 19:22:57 +03:00
if ! cc . dopts . insecure {
if cc . dopts . copts . TransportCredentials == nil {
return nil , errNoTransportSecurity
}
} else {
if cc . dopts . copts . TransportCredentials != nil {
return nil , errCredentialsConflict
}
for _ , cd := range cc . dopts . copts . PerRPCCredentials {
if cd . RequireTransportSecurity ( ) {
return nil , errTransportCredentialsMissing
}
}
}
2017-04-11 00:33:51 +03:00
cc . mkp = cc . dopts . copts . KeepaliveParams
2017-03-24 21:29:02 +03:00
2017-04-18 02:08:50 +03:00
if cc . dopts . copts . Dialer == nil {
cc . dopts . copts . Dialer = newProxyDialer (
func ( ctx context . Context , addr string ) ( net . Conn , error ) {
2017-10-20 22:05:20 +03:00
return dialContext ( ctx , "tcp" , addr )
2017-04-18 02:08:50 +03:00
} ,
)
}
2017-03-24 21:29:02 +03:00
if cc . dopts . copts . UserAgent != "" {
cc . dopts . copts . UserAgent += " " + grpcUA
} else {
cc . dopts . copts . UserAgent = grpcUA
}
2016-12-20 03:31:00 +03:00
if cc . dopts . timeout > 0 {
var cancel context . CancelFunc
ctx , cancel = context . WithTimeout ( ctx , cc . dopts . timeout )
defer cancel ( )
}
2016-08-24 22:56:16 +03:00
defer func ( ) {
2016-08-24 04:18:18 +03:00
select {
case <- ctx . Done ( ) :
2016-08-25 22:18:19 +03:00
conn , err = nil , ctx . Err ( )
2016-08-24 22:56:16 +03:00
default :
2016-08-24 04:18:18 +03:00
}
2016-08-25 22:18:19 +03:00
if err != nil {
cc . Close ( )
}
2016-08-24 04:18:18 +03:00
} ( )
2017-05-15 23:51:11 +03:00
scSet := false
2016-12-20 03:31:00 +03:00
if cc . dopts . scChan != nil {
2017-04-05 21:08:50 +03:00
// Try to get an initial service config.
2016-12-20 03:31:00 +03:00
select {
case sc , ok := <- cc . dopts . scChan :
if ok {
cc . sc = sc
2017-05-15 23:51:11 +03:00
scSet = true
2016-12-20 03:31:00 +03:00
}
2017-04-05 21:08:50 +03:00
default :
2016-12-20 03:31:00 +03:00
}
2015-02-06 04:14:05 +03:00
}
2016-03-23 21:49:05 +03:00
if cc . dopts . bs == nil {
cc . dopts . bs = DefaultBackoffConfig
}
2017-10-23 21:40:43 +03:00
cc . parsedTarget = parseTarget ( cc . target )
2016-09-20 01:11:57 +03:00
creds := cc . dopts . copts . TransportCredentials
if creds != nil && creds . Info ( ) . ServerName != "" {
cc . authority = creds . Info ( ) . ServerName
2017-02-09 21:44:13 +03:00
} else if cc . dopts . insecure && cc . dopts . copts . Authority != "" {
cc . authority = cc . dopts . copts . Authority
2016-09-20 01:11:57 +03:00
} else {
2017-10-23 21:40:43 +03:00
// Use endpoint from "scheme://authority/endpoint" as the default
// authority for ClientConn.
cc . authority = cc . parsedTarget . Endpoint
2016-09-20 01:11:57 +03:00
}
2017-08-31 20:59:09 +03:00
2017-05-15 23:51:11 +03:00
if cc . dopts . scChan != nil && ! scSet {
2017-05-16 00:36:20 +03:00
// Blocking wait for the initial service config.
2017-05-15 23:51:11 +03:00
select {
case sc , ok := <- cc . dopts . scChan :
if ok {
cc . sc = sc
}
case <- ctx . Done ( ) :
return nil , ctx . Err ( )
}
}
2016-12-20 03:31:00 +03:00
if cc . dopts . scChan != nil {
go cc . scWatcher ( )
}
2017-03-21 21:35:53 +03:00
2017-10-19 21:32:06 +03:00
var credsClone credentials . TransportCredentials
if creds := cc . dopts . copts . TransportCredentials ; creds != nil {
credsClone = creds . Clone ( )
}
cc . balancerBuildOpts = balancer . BuildOptions {
DialCreds : credsClone ,
Dialer : cc . dopts . copts . Dialer ,
}
2017-10-02 19:22:57 +03:00
// Build the resolver.
cc . resolverWrapper , err = newCCResolverWrapper ( cc )
if err != nil {
return nil , fmt . Errorf ( "failed to build resolver: %v" , err )
}
2017-11-29 00:16:53 +03:00
// Start the resolver wrapper goroutine after resolverWrapper is created.
//
// If the goroutine is started before resolverWrapper is ready, the
// following may happen: The goroutine sends updates to cc. cc forwards
// those to balancer. Balancer creates new addrConn. addrConn fails to
// connect, and calls resolveNow(). resolveNow() tries to use the non-ready
// resolverWrapper.
cc . resolverWrapper . start ( )
2017-10-02 19:22:57 +03:00
2017-08-31 20:59:09 +03:00
// A blocking dial blocks until the clientConn is ready.
if cc . dopts . block {
for {
s := cc . GetState ( )
if s == connectivity . Ready {
break
}
if ! cc . WaitForStateChange ( ctx , s ) {
// ctx got timeout or canceled.
return nil , ctx . Err ( )
}
}
}
2015-09-29 20:24:03 +03:00
return cc , nil
2015-09-23 22:18:41 +03:00
}
2017-08-09 20:31:12 +03:00
// connectivityStateManager keeps the connectivity.State of ClientConn.
2017-07-25 01:00:53 +03:00
// This struct will eventually be exported so the balancers can access it.
type connectivityStateManager struct {
mu sync . Mutex
2017-08-09 20:31:12 +03:00
state connectivity . State
2017-07-25 01:00:53 +03:00
notifyChan chan struct { }
}
2017-08-09 20:31:12 +03:00
// updateState updates the connectivity.State of ClientConn.
2017-07-25 01:00:53 +03:00
// If there's a change it notifies goroutines waiting on state change to
// happen.
2017-08-09 20:31:12 +03:00
func ( csm * connectivityStateManager ) updateState ( state connectivity . State ) {
2017-07-25 01:00:53 +03:00
csm . mu . Lock ( )
defer csm . mu . Unlock ( )
2017-08-09 20:31:12 +03:00
if csm . state == connectivity . Shutdown {
2017-07-25 01:00:53 +03:00
return
}
if csm . state == state {
return
}
csm . state = state
if csm . notifyChan != nil {
// There are other goroutines waiting on this channel.
close ( csm . notifyChan )
csm . notifyChan = nil
}
}
2017-08-09 20:31:12 +03:00
func ( csm * connectivityStateManager ) getState ( ) connectivity . State {
2017-07-25 01:00:53 +03:00
csm . mu . Lock ( )
defer csm . mu . Unlock ( )
return csm . state
}
func ( csm * connectivityStateManager ) getNotifyChan ( ) <- chan struct { } {
csm . mu . Lock ( )
defer csm . mu . Unlock ( )
if csm . notifyChan == nil {
csm . notifyChan = make ( chan struct { } )
}
return csm . notifyChan
}
2016-05-18 21:18:10 +03:00
// ClientConn represents a client connection to an RPC server.
2015-02-06 04:14:05 +03:00
type ClientConn struct {
2016-07-29 20:16:56 +03:00
ctx context . Context
cancel context . CancelFunc
2017-10-23 21:40:43 +03:00
target string
parsedTarget resolver . Target
authority string
dopts dialOptions
csMgr * connectivityStateManager
2015-09-24 05:09:37 +03:00
2017-10-19 21:32:06 +03:00
balancerBuildOpts balancer . BuildOptions
resolverWrapper * ccResolverWrapper
blockingpicker * pickerWrapper
2017-08-31 20:59:09 +03:00
2016-05-07 01:47:09 +03:00
mu sync . RWMutex
2016-12-20 03:31:00 +03:00
sc ServiceConfig
2017-10-19 22:09:19 +03:00
scRaw string
2017-08-31 20:59:09 +03:00
conns map [ * addrConn ] struct { }
2017-06-16 19:59:37 +03:00
// Keepalive parameter can be updated if a GoAway is received.
2017-10-19 21:32:06 +03:00
mkp keepalive . ClientParameters
curBalancerName string
2017-12-12 23:45:05 +03:00
preBalancerName string // previous balancer name.
2017-10-19 21:32:06 +03:00
curAddresses [ ] resolver . Address
balancerWrapper * ccBalancerWrapper
2015-09-24 05:09:37 +03:00
}
2017-08-09 20:31:12 +03:00
// WaitForStateChange waits until the connectivity.State of ClientConn changes from sourceState or
2017-07-25 01:00:53 +03:00
// ctx expires. A true value is returned in former case and false in latter.
2017-08-09 20:31:12 +03:00
// This is an EXPERIMENTAL API.
func ( cc * ClientConn ) WaitForStateChange ( ctx context . Context , sourceState connectivity . State ) bool {
2017-07-25 01:00:53 +03:00
ch := cc . csMgr . getNotifyChan ( )
if cc . csMgr . getState ( ) != sourceState {
return true
}
select {
case <- ctx . Done ( ) :
return false
case <- ch :
return true
}
}
2017-08-09 20:31:12 +03:00
// GetState returns the connectivity.State of ClientConn.
// This is an EXPERIMENTAL API.
func ( cc * ClientConn ) GetState ( ) connectivity . State {
2017-07-25 01:00:53 +03:00
return cc . csMgr . getState ( )
}
2016-12-20 03:31:00 +03:00
func ( cc * ClientConn ) scWatcher ( ) {
for {
select {
case sc , ok := <- cc . dopts . scChan :
if ! ok {
return
}
cc . mu . Lock ( )
// TODO: load balance policy runtime change is ignored.
// We may revist this decision in the future.
cc . sc = sc
2017-10-19 22:09:19 +03:00
cc . scRaw = ""
2016-12-20 03:31:00 +03:00
cc . mu . Unlock ( )
case <- cc . ctx . Done ( ) :
return
}
}
}
2017-10-19 21:32:06 +03:00
func ( cc * ClientConn ) handleResolvedAddrs ( addrs [ ] resolver . Address , err error ) {
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
if cc . conns == nil {
2017-11-29 00:16:53 +03:00
// cc was closed.
return
}
if reflect . DeepEqual ( cc . curAddresses , addrs ) {
2017-10-19 21:32:06 +03:00
return
}
2017-12-12 23:45:05 +03:00
cc . curAddresses = addrs
2017-12-19 02:35:42 +03:00
if cc . dopts . balancerBuilder == nil {
// Only look at balancer types and switch balancer if balancer dial
// option is not set.
2017-12-12 23:45:05 +03:00
var isGRPCLB bool
for _ , a := range addrs {
if a . Type == resolver . GRPCLB {
isGRPCLB = true
break
}
2017-11-29 00:16:53 +03:00
}
2017-12-12 23:45:05 +03:00
var newBalancerName string
if isGRPCLB {
newBalancerName = grpclbName
} else {
// Address list doesn't contain grpclb address. Try to pick a
// non-grpclb balancer.
newBalancerName = cc . curBalancerName
// If current balancer is grpclb, switch to the previous one.
if newBalancerName == grpclbName {
newBalancerName = cc . preBalancerName
}
// The following could be true in two cases:
// - the first time handling resolved addresses
// (curBalancerName="")
// - the first time handling non-grpclb addresses
// (curBalancerName="grpclb", preBalancerName="")
if newBalancerName == "" {
2017-12-19 02:35:42 +03:00
newBalancerName = PickFirstBalancerName
2017-12-12 23:45:05 +03:00
}
}
cc . switchBalancer ( newBalancerName )
2017-12-19 02:35:42 +03:00
} else if cc . balancerWrapper == nil {
// Balancer dial option was set, and this is the first time handling
// resolved addresses. Build a balancer with dopts.balancerBuilder.
cc . balancerWrapper = newCCBalancerWrapper ( cc , cc . dopts . balancerBuilder , cc . balancerBuildOpts )
2017-10-19 21:32:06 +03:00
}
2017-12-19 02:35:42 +03:00
2017-10-19 21:32:06 +03:00
cc . balancerWrapper . handleResolvedAddrs ( addrs , nil )
}
2017-12-12 23:45:05 +03:00
// switchBalancer starts the switching from current balancer to the balancer
// with the given name.
//
// It will NOT send the current address list to the new balancer. If needed,
// caller of this function should send address list to the new balancer after
// this function returns.
2017-11-23 00:59:20 +03:00
//
// Caller must hold cc.mu.
2017-10-19 21:32:06 +03:00
func ( cc * ClientConn ) switchBalancer ( name string ) {
if cc . conns == nil {
return
}
2017-12-12 23:45:05 +03:00
if strings . ToLower ( cc . curBalancerName ) == strings . ToLower ( name ) {
2017-10-19 21:32:06 +03:00
return
}
2017-12-12 23:45:05 +03:00
grpclog . Infof ( "ClientConn switching balancer to %q" , name )
if cc . dopts . balancerBuilder != nil {
2017-12-19 02:35:42 +03:00
grpclog . Infoln ( "ignoring balancer switching: Balancer DialOption used instead" )
2017-10-19 21:32:06 +03:00
return
}
// TODO(bar switching) change this to two steps: drain and close.
// Keep track of sc in wrapper.
2017-11-23 00:59:20 +03:00
if cc . balancerWrapper != nil {
cc . balancerWrapper . close ( )
}
2017-10-19 21:32:06 +03:00
builder := balancer . Get ( name )
if builder == nil {
2017-12-12 23:45:05 +03:00
grpclog . Infof ( "failed to get balancer builder for: %v, using pick_first instead" , name )
2017-10-19 21:32:06 +03:00
builder = newPickfirstBuilder ( )
}
2017-12-12 23:45:05 +03:00
cc . preBalancerName = cc . curBalancerName
2017-10-19 21:32:06 +03:00
cc . curBalancerName = builder . Name ( )
cc . balancerWrapper = newCCBalancerWrapper ( cc , builder , cc . balancerBuildOpts )
}
func ( cc * ClientConn ) handleSubConnStateChange ( sc balancer . SubConn , s connectivity . State ) {
cc . mu . Lock ( )
if cc . conns == nil {
cc . mu . Unlock ( )
return
}
// TODO(bar switching) send updates to all balancer wrappers when balancer
// gracefully switching is supported.
cc . balancerWrapper . handleSubConnStateChange ( sc , s )
cc . mu . Unlock ( )
}
2017-08-31 20:59:09 +03:00
// newAddrConn creates an addrConn for addrs and adds it to cc.conns.
2017-11-23 00:59:20 +03:00
//
// Caller needs to make sure len(addrs) > 0.
2017-08-31 20:59:09 +03:00
func ( cc * ClientConn ) newAddrConn ( addrs [ ] resolver . Address ) ( * addrConn , error ) {
ac := & addrConn {
cc : cc ,
addrs : addrs ,
dopts : cc . dopts ,
2017-08-21 22:27:04 +03:00
}
2017-08-31 20:59:09 +03:00
ac . ctx , ac . cancel = context . WithCancel ( cc . ctx )
// Track ac in cc. This needs to be done before any getTransport(...) is called.
cc . mu . Lock ( )
if cc . conns == nil {
cc . mu . Unlock ( )
return nil , ErrClientConnClosing
2017-08-21 22:27:04 +03:00
}
2017-08-31 20:59:09 +03:00
cc . conns [ ac ] = struct { } { }
cc . mu . Unlock ( )
return ac , nil
2017-08-21 22:27:04 +03:00
}
2017-08-31 20:59:09 +03:00
// removeAddrConn removes the addrConn in the subConn from clientConn.
// It also tears down the ac with the given error.
func ( cc * ClientConn ) removeAddrConn ( ac * addrConn , err error ) {
cc . mu . Lock ( )
if cc . conns == nil {
cc . mu . Unlock ( )
2017-08-21 22:27:04 +03:00
return
}
2017-08-31 20:59:09 +03:00
delete ( cc . conns , ac )
cc . mu . Unlock ( )
ac . tearDown ( err )
2017-08-21 22:27:04 +03:00
}
2017-08-31 20:59:09 +03:00
// connect starts to creating transport and also starts the transport monitor
// goroutine for this ac.
2017-10-02 19:22:57 +03:00
// It does nothing if the ac is not IDLE.
2017-08-31 20:59:09 +03:00
// TODO(bar) Move this to the addrConn section.
// This was part of resetAddrConn, keep it here to make the diff look clean.
2017-10-24 00:06:33 +03:00
func ( ac * addrConn ) connect ( ) error {
2017-08-31 20:59:09 +03:00
ac . mu . Lock ( )
if ac . state == connectivity . Shutdown {
ac . mu . Unlock ( )
return errConnClosing
2017-08-21 22:27:04 +03:00
}
2017-10-02 19:22:57 +03:00
if ac . state != connectivity . Idle {
ac . mu . Unlock ( )
return nil
2015-09-24 05:09:37 +03:00
}
2017-10-02 19:22:57 +03:00
ac . state = connectivity . Connecting
2017-10-19 21:32:06 +03:00
ac . cc . handleSubConnStateChange ( ac . acbw , ac . state )
2017-10-02 19:22:57 +03:00
ac . mu . Unlock ( )
2017-08-31 20:59:09 +03:00
2017-10-24 00:06:33 +03:00
// Start a goroutine connecting to the server asynchronously.
go func ( ) {
2017-10-02 21:56:31 +03:00
if err := ac . resetTransport ( ) ; err != nil {
2017-10-24 00:06:33 +03:00
grpclog . Warningf ( "Failed to dial %s: %v; please retry." , ac . addrs [ 0 ] . Addr , err )
2016-07-16 02:20:34 +03:00
if err != errConnClosing {
2017-10-24 00:06:33 +03:00
// Keep this ac in cc.conns, to get the reason it's torn down.
2016-07-16 02:20:34 +03:00
ac . tearDown ( err )
}
2017-10-24 00:06:33 +03:00
return
2015-09-24 05:09:37 +03:00
}
2017-10-24 00:06:33 +03:00
ac . transportMonitor ( )
} ( )
2016-05-17 01:31:00 +03:00
return nil
2015-09-24 05:09:37 +03:00
}
2017-08-31 20:59:09 +03:00
// tryUpdateAddrs tries to update ac.addrs with the new addresses list.
//
// It checks whether current connected address of ac is in the new addrs list.
// - If true, it updates ac.addrs and returns true. The ac will keep using
// the existing connection.
// - If false, it does nothing and returns false.
func ( ac * addrConn ) tryUpdateAddrs ( addrs [ ] resolver . Address ) bool {
ac . mu . Lock ( )
defer ac . mu . Unlock ( )
grpclog . Infof ( "addrConn: tryUpdateAddrs curAddr: %v, addrs: %v" , ac . curAddr , addrs )
if ac . state == connectivity . Shutdown {
ac . addrs = addrs
return true
}
var curAddrFound bool
for _ , a := range addrs {
if reflect . DeepEqual ( ac . curAddr , a ) {
curAddrFound = true
break
}
}
grpclog . Infof ( "addrConn: tryUpdateAddrs curAddrFound: %v" , curAddrFound )
if curAddrFound {
ac . addrs = addrs
2017-12-01 20:55:42 +03:00
ac . reconnectIdx = 0 // Start reconnecting from beginning in the new list.
2017-08-31 20:59:09 +03:00
}
return curAddrFound
}
2017-05-20 02:02:02 +03:00
// GetMethodConfig gets the method config of the input method.
// If there's an exact match for input method (i.e. /service/method), we return
// the corresponding MethodConfig.
// If there isn't an exact match for the input method, we look for the default config
// under the service (i.e /service/). If there is a default MethodConfig for
2018-02-21 21:14:52 +03:00
// the service, we return it.
2017-05-20 02:02:02 +03:00
// Otherwise, we return an empty MethodConfig.
2017-05-15 23:51:11 +03:00
func ( cc * ClientConn ) GetMethodConfig ( method string ) MethodConfig {
2017-05-20 02:02:02 +03:00
// TODO: Avoid the locking here.
2016-12-20 03:31:00 +03:00
cc . mu . RLock ( )
defer cc . mu . RUnlock ( )
2017-05-15 23:51:11 +03:00
m , ok := cc . sc . Methods [ method ]
2017-04-04 01:03:24 +03:00
if ! ok {
i := strings . LastIndex ( method , "/" )
2017-05-19 21:52:09 +03:00
m , _ = cc . sc . Methods [ method [ : i + 1 ] ]
2017-04-04 01:03:24 +03:00
}
2017-05-15 23:51:11 +03:00
return m
2016-12-20 03:31:00 +03:00
}
2017-10-02 19:22:57 +03:00
func ( cc * ClientConn ) getTransport ( ctx context . Context , failfast bool ) ( transport . ClientTransport , func ( balancer . DoneInfo ) , error ) {
t , done , err := cc . blockingpicker . pick ( ctx , failfast , balancer . PickOptions { } )
2016-05-07 01:47:09 +03:00
if err != nil {
2017-10-02 19:22:57 +03:00
return nil , nil , toRPCErr ( err )
2015-09-24 05:09:37 +03:00
}
2017-10-02 19:22:57 +03:00
return t , done , nil
2015-09-24 05:09:37 +03:00
}
2017-10-19 22:09:19 +03:00
// handleServiceConfig parses the service config string in JSON format to Go native
// struct ServiceConfig, and store both the struct and the JSON string in ClientConn.
func ( cc * ClientConn ) handleServiceConfig ( js string ) error {
sc , err := parseServiceConfig ( js )
if err != nil {
return err
}
cc . mu . Lock ( )
cc . scRaw = js
cc . sc = sc
2017-12-12 23:45:05 +03:00
if sc . LB != nil && * sc . LB != grpclbName { // "grpclb" is not a valid balancer option in service config.
if cc . curBalancerName == grpclbName {
// If current balancer is grpclb, there's at least one grpclb
// balancer address in the resolved list. Don't switch the balancer,
// but change the previous balancer name, so if a new resolved
// address list doesn't contain grpclb address, balancer will be
// switched to *sc.LB.
cc . preBalancerName = * sc . LB
} else {
cc . switchBalancer ( * sc . LB )
cc . balancerWrapper . handleResolvedAddrs ( cc . curAddresses , nil )
}
2017-11-17 22:11:05 +03:00
}
2017-10-19 22:09:19 +03:00
cc . mu . Unlock ( )
return nil
}
2017-11-29 00:16:53 +03:00
func ( cc * ClientConn ) resolveNow ( o resolver . ResolveNowOption ) {
cc . mu . Lock ( )
r := cc . resolverWrapper
cc . mu . Unlock ( )
if r == nil {
return
}
go r . resolveNow ( o )
}
2016-05-18 03:18:54 +03:00
// Close tears down the ClientConn and all underlying connections.
2016-05-07 01:47:09 +03:00
func ( cc * ClientConn ) Close ( ) error {
2016-07-29 20:16:56 +03:00
cc . cancel ( )
2015-08-01 00:16:02 +03:00
cc . mu . Lock ( )
2016-05-11 05:29:44 +03:00
if cc . conns == nil {
2016-05-07 01:47:09 +03:00
cc . mu . Unlock ( )
return ErrClientConnClosing
}
2016-05-11 05:29:44 +03:00
conns := cc . conns
cc . conns = nil
2017-08-09 20:31:12 +03:00
cc . csMgr . updateState ( connectivity . Shutdown )
2017-10-19 21:32:06 +03:00
rWrapper := cc . resolverWrapper
cc . resolverWrapper = nil
bWrapper := cc . balancerWrapper
cc . balancerWrapper = nil
2016-05-07 01:47:09 +03:00
cc . mu . Unlock ( )
2017-10-02 19:22:57 +03:00
cc . blockingpicker . close ( )
2017-10-19 21:32:06 +03:00
if rWrapper != nil {
rWrapper . close ( )
2017-10-02 19:22:57 +03:00
}
2017-10-19 21:32:06 +03:00
if bWrapper != nil {
bWrapper . close ( )
2016-07-19 01:58:41 +03:00
}
2017-08-31 20:59:09 +03:00
for ac := range conns {
2016-05-11 05:29:44 +03:00
ac . tearDown ( ErrClientConnClosing )
2016-05-07 01:47:09 +03:00
}
return nil
}
// addrConn is a network connection to a given address.
type addrConn struct {
2016-07-29 20:16:56 +03:00
ctx context . Context
cancel context . CancelFunc
2017-12-01 20:55:42 +03:00
cc * ClientConn
addrs [ ] resolver . Address
dopts dialOptions
events trace . EventLog
acbw balancer . SubConn
2016-05-07 01:47:09 +03:00
2017-12-01 20:55:42 +03:00
mu sync . Mutex
curAddr resolver . Address
reconnectIdx int // The index in addrs list to start reconnecting from.
state connectivity . State
2016-05-07 01:47:09 +03:00
// ready is closed and becomes nil when a new transport is up or failed
// due to timeout.
ready chan struct { }
transport transport . ClientTransport
2016-07-16 02:20:34 +03:00
// The reason this addrConn is torn down.
tearDownErr error
2017-12-01 20:55:42 +03:00
connectRetryNum int
// backoffDeadline is the time until which resetTransport needs to
// wait before increasing connectRetryNum count.
backoffDeadline time . Time
// connectDeadline is the time by which all connection
// negotiations must complete.
connectDeadline time . Time
2016-05-07 01:47:09 +03:00
}
2017-04-11 00:33:51 +03:00
// adjustParams updates parameters used to create transports upon
// receiving a GoAway.
func ( ac * addrConn ) adjustParams ( r transport . GoAwayReason ) {
switch r {
2017-11-07 00:45:11 +03:00
case transport . GoAwayTooManyPings :
2017-04-11 00:33:51 +03:00
v := 2 * ac . dopts . copts . KeepaliveParams . Time
ac . cc . mu . Lock ( )
if v > ac . cc . mkp . Time {
ac . cc . mkp . Time = v
}
ac . cc . mu . Unlock ( )
}
}
2016-05-07 01:47:09 +03:00
// printf records an event in ac's event log, unless ac has been closed.
// REQUIRES ac.mu is held.
func ( ac * addrConn ) printf ( format string , a ... interface { } ) {
if ac . events != nil {
ac . events . Printf ( format , a ... )
}
}
// errorf records an error in ac's event log, unless ac has been closed.
// REQUIRES ac.mu is held.
func ( ac * addrConn ) errorf ( format string , a ... interface { } ) {
if ac . events != nil {
ac . events . Errorf ( format , a ... )
}
}
2017-10-02 21:56:31 +03:00
// resetTransport recreates a transport to the address for ac. The old
// transport will close itself on error or when the clientconn is closed.
2017-12-01 20:55:42 +03:00
// The created transport must receive initial settings frame from the server.
// In case that doesnt happen, transportMonitor will kill the newly created
// transport after connectDeadline has expired.
// In case there was an error on the transport before the settings frame was
// received, resetTransport resumes connecting to backends after the one that
// was previously connected to. In case end of the list is reached, resetTransport
// backs off until the original deadline.
// If the DialOption WithWaitForHandshake was set, resetTrasport returns
// successfully only after server settings are received.
2017-10-24 00:06:33 +03:00
//
2017-08-31 20:59:09 +03:00
// TODO(bar) make sure all state transitions are valid.
2017-10-02 21:56:31 +03:00
func ( ac * addrConn ) resetTransport ( ) error {
2017-07-20 23:22:59 +03:00
ac . mu . Lock ( )
2017-08-09 20:31:12 +03:00
if ac . state == connectivity . Shutdown {
2017-07-20 23:22:59 +03:00
ac . mu . Unlock ( )
return errConnClosing
}
2017-08-31 20:59:09 +03:00
if ac . ready != nil {
close ( ac . ready )
ac . ready = nil
}
2017-07-20 23:22:59 +03:00
ac . transport = nil
2017-12-01 20:55:42 +03:00
ridx := ac . reconnectIdx
2017-07-20 23:22:59 +03:00
ac . mu . Unlock ( )
ac . cc . mu . RLock ( )
ac . dopts . copts . KeepaliveParams = ac . cc . mkp
ac . cc . mu . RUnlock ( )
2017-12-01 20:55:42 +03:00
var backoffDeadline , connectDeadline time . Time
for connectRetryNum := 0 ; ; connectRetryNum ++ {
2017-08-31 20:59:09 +03:00
ac . mu . Lock ( )
2017-12-01 20:55:42 +03:00
if ac . backoffDeadline . IsZero ( ) {
// This means either a successful HTTP2 connection was established
// or this is the first time this addrConn is trying to establish a
// connection.
backoffFor := ac . dopts . bs . backoff ( connectRetryNum ) // time.Duration.
// This will be the duration that dial gets to finish.
dialDuration := minConnectTimeout
if backoffFor > dialDuration {
// Give dial more time as we keep failing to connect.
dialDuration = backoffFor
}
start := time . Now ( )
backoffDeadline = start . Add ( backoffFor )
connectDeadline = start . Add ( dialDuration )
ridx = 0 // Start connecting from the beginning.
} else {
// Continue trying to conect with the same deadlines.
connectRetryNum = ac . connectRetryNum
backoffDeadline = ac . backoffDeadline
connectDeadline = ac . connectDeadline
ac . backoffDeadline = time . Time { }
ac . connectDeadline = time . Time { }
ac . connectRetryNum = 0
2015-07-28 21:12:07 +03:00
}
2017-08-31 20:59:09 +03:00
if ac . state == connectivity . Shutdown {
ac . mu . Unlock ( )
return errConnClosing
}
ac . printf ( "connecting" )
2017-10-24 00:06:33 +03:00
if ac . state != connectivity . Connecting {
ac . state = connectivity . Connecting
ac . cc . handleSubConnStateChange ( ac . acbw , ac . state )
}
2017-08-21 22:27:04 +03:00
// copy ac.addrs in case of race
2017-08-31 20:59:09 +03:00
addrsIter := make ( [ ] resolver . Address , len ( ac . addrs ) )
2017-08-21 22:27:04 +03:00
copy ( addrsIter , ac . addrs )
2017-10-02 19:22:57 +03:00
copts := ac . dopts . copts
2017-08-21 22:27:04 +03:00
ac . mu . Unlock ( )
2017-12-01 20:55:42 +03:00
connected , err := ac . createTransport ( connectRetryNum , ridx , backoffDeadline , connectDeadline , addrsIter , copts )
if err != nil {
return err
}
if connected {
return nil
}
}
}
// createTransport creates a connection to one of the backends in addrs.
// It returns true if a connection was established.
func ( ac * addrConn ) createTransport ( connectRetryNum , ridx int , backoffDeadline , connectDeadline time . Time , addrs [ ] resolver . Address , copts transport . ConnectOptions ) ( bool , error ) {
for i := ridx ; i < len ( addrs ) ; i ++ {
addr := addrs [ i ]
target := transport . TargetInfo {
Addr : addr . Addr ,
Metadata : addr . Metadata ,
Authority : ac . cc . authority ,
}
done := make ( chan struct { } )
onPrefaceReceipt := func ( ) {
2017-08-21 22:27:04 +03:00
ac . mu . Lock ( )
2018-01-04 22:16:47 +03:00
close ( done )
2017-12-01 20:55:42 +03:00
if ! ac . backoffDeadline . IsZero ( ) {
// If we haven't already started reconnecting to
// other backends.
// Note, this can happen when writer notices an error
// and triggers resetTransport while at the same time
// reader receives the preface and invokes this closure.
ac . backoffDeadline = time . Time { }
ac . connectDeadline = time . Time { }
ac . connectRetryNum = 0
2017-08-21 22:27:04 +03:00
}
ac . mu . Unlock ( )
2017-12-01 20:55:42 +03:00
}
// Do not cancel in the success path because of
// this issue in Go1.6: https://github.com/golang/go/issues/15078.
connectCtx , cancel := context . WithDeadline ( ac . ctx , connectDeadline )
newTr , err := transport . NewClientTransport ( connectCtx , ac . cc . ctx , target , copts , onPrefaceReceipt )
if err != nil {
cancel ( )
2018-02-15 01:13:10 +03:00
ac . cc . blockingpicker . updateConnectionError ( err )
2016-05-07 01:47:09 +03:00
ac . mu . Lock ( )
2017-08-09 20:31:12 +03:00
if ac . state == connectivity . Shutdown {
2016-05-07 01:47:09 +03:00
// ac.tearDown(...) has been invoked.
ac . mu . Unlock ( )
2017-12-01 20:55:42 +03:00
return false , errConnClosing
2015-09-25 23:21:25 +03:00
}
2016-05-07 01:47:09 +03:00
ac . mu . Unlock ( )
2017-12-01 20:55:42 +03:00
grpclog . Warningf ( "grpc: addrConn.createTransport failed to connect to %v. Err :%v. Reconnecting..." , addr , err )
continue
}
if ac . dopts . waitForHandshake {
select {
case <- done :
case <- connectCtx . Done ( ) :
// Didn't receive server preface, must kill this new transport now.
grpclog . Warningf ( "grpc: addrConn.createTransport failed to receive server preface before deadline." )
newTr . Close ( )
break
case <- ac . ctx . Done ( ) :
}
2015-03-05 20:45:50 +03:00
}
2017-08-31 20:59:09 +03:00
ac . mu . Lock ( )
2017-12-01 20:55:42 +03:00
if ac . state == connectivity . Shutdown {
ac . mu . Unlock ( )
// ac.tearDonn(...) has been invoked.
newTr . Close ( )
return false , errConnClosing
}
ac . printf ( "ready" )
ac . state = connectivity . Ready
2017-10-19 21:32:06 +03:00
ac . cc . handleSubConnStateChange ( ac . acbw , ac . state )
2017-12-01 20:55:42 +03:00
ac . transport = newTr
ac . curAddr = addr
2017-08-31 20:59:09 +03:00
if ac . ready != nil {
close ( ac . ready )
ac . ready = nil
}
2018-01-04 22:16:47 +03:00
select {
case <- done :
// If the server has responded back with preface already,
// don't set the reconnect parameters.
default :
ac . connectRetryNum = connectRetryNum
ac . backoffDeadline = backoffDeadline
ac . connectDeadline = connectDeadline
ac . reconnectIdx = i + 1 // Start reconnecting from the next backend in the list.
}
2017-08-31 20:59:09 +03:00
ac . mu . Unlock ( )
2017-12-01 20:55:42 +03:00
return true , nil
}
ac . mu . Lock ( )
ac . state = connectivity . TransientFailure
ac . cc . handleSubConnStateChange ( ac . acbw , ac . state )
ac . cc . resolveNow ( resolver . ResolveNowOption { } )
if ac . ready != nil {
close ( ac . ready )
ac . ready = nil
}
ac . mu . Unlock ( )
timer := time . NewTimer ( backoffDeadline . Sub ( time . Now ( ) ) )
select {
case <- timer . C :
case <- ac . ctx . Done ( ) :
2017-08-21 22:27:04 +03:00
timer . Stop ( )
2017-12-01 20:55:42 +03:00
return false , ac . ctx . Err ( )
2015-02-06 04:14:05 +03:00
}
2017-12-01 20:55:42 +03:00
return false , nil
2015-02-06 04:14:05 +03:00
}
// Run in a goroutine to track the error in transport and create the
// new transport if an error happens. It returns when the channel is closing.
2016-05-07 01:47:09 +03:00
func ( ac * addrConn ) transportMonitor ( ) {
2015-02-06 04:14:05 +03:00
for {
2017-12-01 20:55:42 +03:00
var timer * time . Timer
var cdeadline <- chan time . Time
2016-05-07 01:47:09 +03:00
ac . mu . Lock ( )
t := ac . transport
2017-12-01 20:55:42 +03:00
if ! ac . connectDeadline . IsZero ( ) {
timer = time . NewTimer ( ac . connectDeadline . Sub ( time . Now ( ) ) )
cdeadline = timer . C
}
2016-05-07 01:47:09 +03:00
ac . mu . Unlock ( )
2017-10-02 21:56:31 +03:00
// Block until we receive a goaway or an error occurs.
2015-02-06 04:14:05 +03:00
select {
2016-07-22 02:19:34 +03:00
case <- t . GoAway ( ) :
case <- t . Error ( ) :
2017-12-01 20:55:42 +03:00
case <- cdeadline :
ac . mu . Lock ( )
// This implies that client received server preface.
if ac . backoffDeadline . IsZero ( ) {
ac . mu . Unlock ( )
continue
}
ac . mu . Unlock ( )
timer = nil
// No server preface received until deadline.
// Kill the connection.
grpclog . Warningf ( "grpc: addrConn.transportMonitor didn't get server preface after waiting. Closing the new transport now." )
t . Close ( )
}
if timer != nil {
timer . Stop ( )
2017-10-02 21:56:31 +03:00
}
// If a GoAway happened, regardless of error, adjust our keepalive
// parameters as appropriate.
select {
case <- t . GoAway ( ) :
ac . adjustParams ( t . GetGoAwayReason ( ) )
default :
}
2017-10-24 00:06:33 +03:00
ac . mu . Lock ( )
2017-11-02 19:56:04 +03:00
if ac . state == connectivity . Shutdown {
ac . mu . Unlock ( )
return
}
2017-10-24 00:06:33 +03:00
// Set connectivity state to TransientFailure before calling
// resetTransport. Transition READY->CONNECTING is not valid.
ac . state = connectivity . TransientFailure
ac . cc . handleSubConnStateChange ( ac . acbw , ac . state )
2017-11-29 00:16:53 +03:00
ac . cc . resolveNow ( resolver . ResolveNowOption { } )
2017-10-24 00:06:33 +03:00
ac . curAddr = resolver . Address { }
ac . mu . Unlock ( )
2017-10-02 21:56:31 +03:00
if err := ac . resetTransport ( ) ; err != nil {
ac . mu . Lock ( )
ac . printf ( "transport exiting: %v" , err )
ac . mu . Unlock ( )
grpclog . Warningf ( "grpc: addrConn.transportMonitor exits due to: %v" , err )
if err != errConnClosing {
// Keep this ac in cc.conns, to get the reason it's torn down.
ac . tearDown ( err )
2015-02-06 04:14:05 +03:00
}
2017-10-02 21:56:31 +03:00
return
2015-02-06 04:14:05 +03:00
}
}
}
2016-06-28 00:36:59 +03:00
// wait blocks until i) the new transport is up or ii) ctx is done or iii) ac is closed or
2017-08-09 20:31:12 +03:00
// iv) transport is in connectivity.TransientFailure and there is a balancer/failfast is true.
2016-08-17 00:16:42 +03:00
func ( ac * addrConn ) wait ( ctx context . Context , hasBalancer , failfast bool ) ( transport . ClientTransport , error ) {
2015-02-06 04:14:05 +03:00
for {
2016-05-07 01:47:09 +03:00
ac . mu . Lock ( )
2015-02-06 04:14:05 +03:00
switch {
2017-08-09 20:31:12 +03:00
case ac . state == connectivity . Shutdown :
2016-08-17 00:16:42 +03:00
if failfast || ! hasBalancer {
// RPC is failfast or balancer is nil. This RPC should fail with ac.tearDownErr.
err := ac . tearDownErr
ac . mu . Unlock ( )
return nil , err
}
2016-05-07 01:47:09 +03:00
ac . mu . Unlock ( )
2016-08-17 00:16:42 +03:00
return nil , errConnClosing
2017-08-09 20:31:12 +03:00
case ac . state == connectivity . Ready :
2016-05-07 01:47:09 +03:00
ct := ac . transport
ac . mu . Unlock ( )
2016-02-23 03:26:15 +03:00
return ct , nil
2017-08-09 20:31:12 +03:00
case ac . state == connectivity . TransientFailure :
2016-08-17 00:16:42 +03:00
if failfast || hasBalancer {
ac . mu . Unlock ( )
return nil , errConnUnavailable
2015-02-06 04:14:05 +03:00
}
}
2016-08-17 00:16:42 +03:00
ready := ac . ready
if ready == nil {
ready = make ( chan struct { } )
ac . ready = ready
}
ac . mu . Unlock ( )
select {
case <- ctx . Done ( ) :
return nil , toRPCErr ( ctx . Err ( ) )
// Wait until the new transport is ready or failed.
case <- ready :
}
2015-02-06 04:14:05 +03:00
}
}
2017-10-02 19:22:57 +03:00
// getReadyTransport returns the transport if ac's state is READY.
// Otherwise it returns nil, false.
// If ac's state is IDLE, it will trigger ac to connect.
func ( ac * addrConn ) getReadyTransport ( ) ( transport . ClientTransport , bool ) {
ac . mu . Lock ( )
if ac . state == connectivity . Ready {
t := ac . transport
ac . mu . Unlock ( )
return t , true
}
var idle bool
if ac . state == connectivity . Idle {
idle = true
}
ac . mu . Unlock ( )
// Trigger idle ac to connect.
if idle {
2017-10-24 00:06:33 +03:00
ac . connect ( )
2017-10-02 19:22:57 +03:00
}
return nil , false
}
2016-05-17 01:31:00 +03:00
// tearDown starts to tear down the addrConn.
2015-02-06 04:14:05 +03:00
// TODO(zhaoq): Make this synchronous to avoid unbounded memory consumption in
2016-05-07 01:47:09 +03:00
// some edge cases (e.g., the caller opens and closes many addrConn's in a
2015-02-06 04:14:05 +03:00
// tight loop.
2016-07-29 22:57:38 +03:00
// tearDown doesn't remove ac from ac.cc.conns.
2016-05-07 01:47:09 +03:00
func ( ac * addrConn ) tearDown ( err error ) {
2016-07-29 20:16:56 +03:00
ac . cancel ( )
2016-05-07 01:47:09 +03:00
ac . mu . Lock ( )
2016-07-29 22:57:38 +03:00
defer ac . mu . Unlock ( )
2017-12-15 23:03:41 +03:00
if ac . state == connectivity . Shutdown {
return
}
2017-10-20 01:16:16 +03:00
ac . curAddr = resolver . Address { }
2016-07-26 02:35:32 +03:00
if err == errConnDrain && ac . transport != nil {
// GracefulClose(...) may be executed multiple times when
// i) receiving multiple GoAway frames from the server; or
// ii) there are concurrent name resolver/Balancer triggered
// address removal and GoAway.
ac . transport . GracefulClose ( )
}
2017-08-09 20:31:12 +03:00
ac . state = connectivity . Shutdown
2016-07-16 02:20:34 +03:00
ac . tearDownErr = err
2017-10-19 21:32:06 +03:00
ac . cc . handleSubConnStateChange ( ac . acbw , ac . state )
2016-05-07 01:47:09 +03:00
if ac . events != nil {
ac . events . Finish ( )
ac . events = nil
2015-03-05 00:00:47 +03:00
}
2016-05-07 01:47:09 +03:00
if ac . ready != nil {
close ( ac . ready )
ac . ready = nil
2015-03-04 06:04:29 +03:00
}
2016-05-07 01:47:09 +03:00
return
2015-02-06 04:14:05 +03:00
}
2017-08-31 20:59:09 +03:00
func ( ac * addrConn ) getState ( ) connectivity . State {
ac . mu . Lock ( )
defer ac . mu . Unlock ( )
return ac . state
}
streams: Stop cleaning up after orphaned streams (#1854)
This change introduces some behavior changes that should not impact users that
are following the proper stream protocol. Specifically, one of the following
conditions must be satisfied:
1. The user calls Close on the ClientConn.
2. The user cancels the context provided to NewClientStream, or its deadline
expires. (Note that it if the context is no longer needed before the deadline
expires, it is still recommended to call cancel to prevent bloat.) It is always
recommended to cancel contexts when they are no longer needed, and to
never use the background context directly, so all users should always be
doing this.
3. The user calls RecvMsg (or Recv in generated code) until a non-nil error is
returned.
4. The user receives any error from Header or SendMsg (or Send in generated
code) besides io.EOF. If none of the above happen, this will leak a goroutine
and a context, and grpc will not call the optionally-configured stats handler
with a stats.End message.
Before this change, if a user created a stream and the server ended the stream,
the stats handler would be invoked with a stats.End containing the final status
of the stream. Subsequent calls to RecvMsg would then trigger the stats handler
with InPayloads, which may be unexpected by stats handlers.
2018-02-08 21:51:16 +03:00
// ErrClientConnTimeout indicates that the ClientConn cannot establish the
// underlying connections within the specified timeout.
//
// Deprecated: This error is never returned by grpc and should not be
// referenced by users.
var ErrClientConnTimeout = errors . New ( "grpc: timed out when dialing" )