package base
import (
)
var logger = grpclog.Component("balancer")
type baseBuilder struct {
name string
pickerBuilder PickerBuilder
config Config
}
func ( *baseBuilder) ( balancer.ClientConn, balancer.BuildOptions) balancer.Balancer {
:= &baseBalancer{
cc: ,
pickerBuilder: .pickerBuilder,
subConns: resolver.NewAddressMap(),
scStates: make(map[balancer.SubConn]connectivity.State),
csEvltr: &balancer.ConnectivityStateEvaluator{},
config: .config,
state: connectivity.Connecting,
}
.picker = NewErrPicker(balancer.ErrNoSubConnAvailable)
return
}
func ( *baseBuilder) () string {
return .name
}
type baseBalancer struct {
cc balancer.ClientConn
pickerBuilder PickerBuilder
csEvltr *balancer.ConnectivityStateEvaluator
state connectivity.State
subConns *resolver.AddressMap
scStates map[balancer.SubConn]connectivity.State
picker balancer.Picker
config Config
resolverErr error
connErr error
}
func ( *baseBalancer) ( error) {
.resolverErr =
if .subConns.Len() == 0 {
.state = connectivity.TransientFailure
}
if .state != connectivity.TransientFailure {
return
}
.regeneratePicker()
.cc.UpdateState(balancer.State{
ConnectivityState: .state,
Picker: .picker,
})
}
func ( *baseBalancer) ( balancer.ClientConnState) error {
if logger.V(2) {
logger.Info("base.baseBalancer: got new ClientConn state: ", )
}
.resolverErr = nil
:= resolver.NewAddressMap()
for , := range .ResolverState.Addresses {
.Set(, nil)
if , := .subConns.Get(); ! {
, := .cc.NewSubConn([]resolver.Address{}, balancer.NewSubConnOptions{HealthCheckEnabled: .config.HealthCheck})
if != nil {
logger.Warningf("base.baseBalancer: failed to create new SubConn: %v", )
continue
}
.subConns.Set(, )
.scStates[] = connectivity.Idle
.csEvltr.RecordTransition(connectivity.Shutdown, connectivity.Idle)
.Connect()
}
}
for , := range .subConns.Keys() {
, := .subConns.Get()
:= .(balancer.SubConn)
if , := .Get(); ! {
.cc.RemoveSubConn()
.subConns.Delete()
}
}
if len(.ResolverState.Addresses) == 0 {
.ResolverError(errors.New("produced zero addresses"))
return balancer.ErrBadResolverState
}
.regeneratePicker()
.cc.UpdateState(balancer.State{ConnectivityState: .state, Picker: .picker})
return nil
}
func ( *baseBalancer) () error {
if .connErr == nil {
return fmt.Errorf("last resolver error: %v", .resolverErr)
}
if .resolverErr == nil {
return fmt.Errorf("last connection error: %v", .connErr)
}
return fmt.Errorf("last connection error: %v; last resolver error: %v", .connErr, .resolverErr)
}
func ( *baseBalancer) () {
if .state == connectivity.TransientFailure {
.picker = NewErrPicker(.mergeErrors())
return
}
:= make(map[balancer.SubConn]SubConnInfo)
for , := range .subConns.Keys() {
, := .subConns.Get()
:= .(balancer.SubConn)
if , := .scStates[]; && == connectivity.Ready {
[] = SubConnInfo{Address: }
}
}
.picker = .pickerBuilder.Build(PickerBuildInfo{ReadySCs: })
}
func ( *baseBalancer) ( balancer.SubConn, balancer.SubConnState) {
:= .ConnectivityState
if logger.V(2) {
logger.Infof("base.baseBalancer: handle SubConn state change: %p, %v", , )
}
, := .scStates[]
if ! {
if logger.V(2) {
logger.Infof("base.baseBalancer: got state changes for an unknown SubConn: %p, %v", , )
}
return
}
if == connectivity.TransientFailure &&
( == connectivity.Connecting || == connectivity.Idle) {
if == connectivity.Idle {
.Connect()
}
return
}
.scStates[] =
switch {
case connectivity.Idle:
.Connect()
case connectivity.Shutdown:
delete(.scStates, )
case connectivity.TransientFailure:
.connErr = .ConnectionError
}
.state = .csEvltr.RecordTransition(, )
if ( == connectivity.Ready) != ( == connectivity.Ready) ||
.state == connectivity.TransientFailure {
.regeneratePicker()
}
.cc.UpdateState(balancer.State{ConnectivityState: .state, Picker: .picker})
}
func ( *baseBalancer) () {
}
func ( *baseBalancer) () {
}
func ( error) balancer.Picker {
return &errPicker{err: }
}
var NewErrPickerV2 = NewErrPicker
type errPicker struct {
err error
}
func ( *errPicker) ( balancer.PickInfo) (balancer.PickResult, error) {
return balancer.PickResult{}, .err
}