* * Copyright 2017 gRPC authors. * * 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 * * http:www.apache.org/licenses/LICENSE-2.0 * * 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. *

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: make(map[resolver.Address]balancer.SubConn),
		scStates: make(map[balancer.SubConn]connectivity.State),
		csEvltr:  &balancer.ConnectivityStateEvaluator{},
		config:   .config,
Initialize picker to a picker that always returns ErrNoSubConnAvailable, because when state of a SubConn changes, we may call UpdateState with this picker.
	.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 map[resolver.Address]balancer.SubConn
	scStates map[balancer.SubConn]connectivity.State
	picker   balancer.Picker
	config   Config

	resolverErr error // the last error reported by the resolver; cleared on successful resolution
	connErr     error // the last connection error; cleared upon leaving TransientFailure
}

func ( *baseBalancer) ( error) {
	.resolverErr = 
	if len(.subConns) == 0 {
		.state = connectivity.TransientFailure
	}

The picker will not change since the balancer does not currently report an error.
TODO: handle s.ResolverState.ServiceConfig?
	if logger.V(2) {
		logger.Info("base.baseBalancer: got new ClientConn state: ", )
Successful resolution; clear resolver error and ensure we return nil.
addrsSet is the set converted from addrs, it's used for quick lookup of an address.
	 := make(map[resolver.Address]struct{})
	for ,  := range .ResolverState.Addresses {
		[] = struct{}{}
a is a new address (not existing in b.subConns).
			,  := .cc.NewSubConn([]resolver.Address{}, balancer.NewSubConnOptions{HealthCheckEnabled: .config.HealthCheck})
			if  != nil {
				logger.Warningf("base.baseBalancer: failed to create new SubConn: %v", )
				continue
			}
			.subConns[] = 
			.scStates[] = connectivity.Idle
			.Connect()
		}
	}
a was removed by resolver.
		if ,  := []; ! {
			.cc.RemoveSubConn()
Keep the state of this sc in b.scStates until sc's state becomes Shutdown. The entry will be deleted in UpdateSubConnState.
		}
If resolver state contains no addresses, return an error so ClientConn will trigger re-resolve. Also records this as an resolver error, so when the overall state turns transient failure, the error message will have the zero address information.
	if len(.ResolverState.Addresses) == 0 {
		.ResolverError(errors.New("produced zero addresses"))
		return balancer.ErrBadResolverState
	}
	return nil
}
mergeErrors builds an error from the last connection error and the last resolver error. Must only be called if b.state is TransientFailure.
connErr must always be non-nil unless there are no SubConns, in which case resolverErr must be non-nil.
	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)
}
regeneratePicker takes a snapshot of the balancer, and generates a picker from it. The picker is - errPicker if the balancer is in TransientFailure, - built by the pickerBuilder with all READY SubConns otherwise.
Filter out all ready SCs from full subConn map.
	for ,  := range .subConns {
		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
	}
Once a subconn enters TRANSIENT_FAILURE, ignore subsequent CONNECTING transitions to prevent the aggregated state from being always CONNECTING when many backends exist but are all down.
		return
	}
	.scStates[] = 
	switch  {
	case connectivity.Idle:
		.Connect()
When an address was removed by resolver, b called RemoveSubConn but kept the sc's state in scStates. Remove state for this sc here.
		delete(.scStates, )
Save error to be reported via picker.
Regenerate picker when one of the following happens: - this sc entered or left ready - the aggregated state of balancer is TransientFailure (may need to update error message)
Close is a nop because base balancer doesn't have internal state to clean up, and it doesn't need to call RemoveSubConn for the SubConns.
func ( *baseBalancer) () {
}
NewErrPicker returns a Picker that always returns err on Pick().
func ( error) balancer.Picker {
	return &errPicker{err: }
}
NewErrPickerV2 is temporarily defined for backward compatibility reasons. Deprecated: use NewErrPicker instead.
var NewErrPickerV2 = NewErrPicker

type errPicker struct {
	err error // Pick() always returns this err.
}

func ( *errPicker) ( balancer.PickInfo) (balancer.PickResult, error) {
	return balancer.PickResult{}, .err