package grpc
import (
)
const PickFirstBalancerName = "pick_first"
func () balancer.Builder {
return &pickfirstBuilder{}
}
type pickfirstBuilder struct{}
func (*pickfirstBuilder) ( balancer.ClientConn, balancer.BuildOptions) balancer.Balancer {
return &pickfirstBalancer{cc: }
}
func (*pickfirstBuilder) () string {
return PickFirstBalancerName
}
type pickfirstBalancer struct {
state connectivity.State
cc balancer.ClientConn
subConn balancer.SubConn
}
func ( *pickfirstBalancer) ( error) {
if logger.V(2) {
logger.Infof("pickfirstBalancer: ResolverError called with error: %v", )
}
if .subConn == nil {
.state = connectivity.TransientFailure
}
if .state != connectivity.TransientFailure {
return
}
.cc.UpdateState(balancer.State{
ConnectivityState: connectivity.TransientFailure,
Picker: &picker{err: fmt.Errorf("name resolver error: %v", )},
})
}
func ( *pickfirstBalancer) ( balancer.ClientConnState) error {
if len(.ResolverState.Addresses) == 0 {
if .subConn != nil {
.cc.RemoveSubConn(.subConn)
.subConn = nil
}
.ResolverError(errors.New("produced zero addresses"))
return balancer.ErrBadResolverState
}
if .subConn != nil {
.cc.UpdateAddresses(.subConn, .ResolverState.Addresses)
return nil
}
, := .cc.NewSubConn(.ResolverState.Addresses, balancer.NewSubConnOptions{})
if != nil {
if logger.V(2) {
logger.Errorf("pickfirstBalancer: failed to NewSubConn: %v", )
}
.state = connectivity.TransientFailure
.cc.UpdateState(balancer.State{
ConnectivityState: connectivity.TransientFailure,
Picker: &picker{err: fmt.Errorf("error creating connection: %v", )},
})
return balancer.ErrBadResolverState
}
.subConn =
.state = connectivity.Idle
.cc.UpdateState(balancer.State{
ConnectivityState: connectivity.Connecting,
Picker: &picker{err: balancer.ErrNoSubConnAvailable},
})
.subConn.Connect()
return nil
}
func ( *pickfirstBalancer) ( balancer.SubConn, balancer.SubConnState) {
if logger.V(2) {
logger.Infof("pickfirstBalancer: UpdateSubConnState: %p, %v", , )
}
if .subConn != {
if logger.V(2) {
logger.Infof("pickfirstBalancer: ignored state change because subConn is not recognized")
}
return
}
.state = .ConnectivityState
if .ConnectivityState == connectivity.Shutdown {
.subConn = nil
return
}
switch .ConnectivityState {
case connectivity.Ready:
.cc.UpdateState(balancer.State{
ConnectivityState: .ConnectivityState,
Picker: &picker{result: balancer.PickResult{SubConn: }},
})
case connectivity.Connecting:
.cc.UpdateState(balancer.State{
ConnectivityState: .ConnectivityState,
Picker: &picker{err: balancer.ErrNoSubConnAvailable},
})
case connectivity.Idle:
.cc.UpdateState(balancer.State{
ConnectivityState: .ConnectivityState,
Picker: &idlePicker{subConn: },
})
case connectivity.TransientFailure:
.cc.UpdateState(balancer.State{
ConnectivityState: .ConnectivityState,
Picker: &picker{err: .ConnectionError},
})
}
}
func ( *pickfirstBalancer) () {
}
func ( *pickfirstBalancer) () {
if .subConn != nil && .state == connectivity.Idle {
.subConn.Connect()
}
}
type picker struct {
result balancer.PickResult
err error
}
func ( *picker) (balancer.PickInfo) (balancer.PickResult, error) {
return .result, .err
}
type idlePicker struct {
subConn balancer.SubConn
}
func ( *idlePicker) (balancer.PickInfo) (balancer.PickResult, error) {
.subConn.Connect()
return balancer.PickResult{}, balancer.ErrNoSubConnAvailable
}
func () {
balancer.Register(newPickfirstBuilder())
}