func (gb *gcpBalancer) unbindSubConn(boundKey string) {
	gb.mu.Lock()
	defer gb.mu.Unlock()
	boundSC, ok := gb.affinityMap[boundKey]
	if ok {
		gb.scRefs[boundSC].affinityDecr()
		if gb.scRefs[boundSC].getAffinityCnt() <= 0 {
			delete(gb.affinityMap, boundKey)
		}
	}
}
unbindSubConn removes the existing binding associated with the key.
package balancer
import (
	"sync"
	"sync/atomic"
	"google.golang.org/grpc/balancer"
	"google.golang.org/grpc/connectivity"
	"google.golang.org/grpc/grpclog"
	"google.golang.org/grpc/resolver"
)
const (
	Name = "grpc_gcp"
	healthCheckEnabled = true
)
var (
	DefaultMinConnections = 5
	MinConnections = DefaultMinConnections
)
func init() {
	balancer.Register(newBuilder())
}
type gcpBalancerBuilder struct {
	name string
}
func (bb *gcpBalancerBuilder) Build(
	cc balancer.ClientConn,
	opt balancer.BuildOptions,
) balancer.Balancer {
	return &gcpBalancer{
		cc:          cc,
		affinityMap: make(map[string]balancer.SubConn),
		scRefs:      make(map[balancer.SubConn]*subConnRef),
		scStates:    make(map[balancer.SubConn]connectivity.State),
		csEvltr:     &connectivityStateEvaluator{},
		picker: newErrPicker(balancer.ErrNoSubConnAvailable),
	}
}
func (*gcpBalancerBuilder) Name() string {
	return Name
}
func newBuilder() balancer.Builder {
	return &gcpBalancerBuilder{
		name: Name,
	}
}
type connectivityStateEvaluator struct {
	numReady            uint64  
	numConnecting       uint64  
	numTransientFailure uint64  
}
func (cse *connectivityStateEvaluator) recordTransition(
	oldState,
	newState connectivity.State,
) connectivity.State {
	for idx, state := range []connectivity.State{oldState, newState} {
		updateVal := 2*uint64(idx) - 1  
		switch state {
		case connectivity.Ready:
			cse.numReady += updateVal
		case connectivity.Connecting:
			cse.numConnecting += updateVal
		case connectivity.TransientFailure:
			cse.numTransientFailure += updateVal
		}
	}
	if cse.numReady > 0 {
		return connectivity.Ready
	}
	if cse.numConnecting > 0 {
		return connectivity.Connecting
	}
	return connectivity.TransientFailure
}
type subConnRef struct {
	subConn     balancer.SubConn
	affinityCnt int32  
	streamsCnt  int32  
}
func (ref *subConnRef) getAffinityCnt() int32 {
	return atomic.LoadInt32(&ref.affinityCnt)
}
func (ref *subConnRef) getStreamsCnt() int32 {
	return atomic.LoadInt32(&ref.streamsCnt)
}
func (ref *subConnRef) affinityIncr() {
	atomic.AddInt32(&ref.affinityCnt, 1)
}
func (ref *subConnRef) affinityDecr() {
	atomic.AddInt32(&ref.affinityCnt, -1)
}
func (ref *subConnRef) streamsIncr() {
	atomic.AddInt32(&ref.streamsCnt, 1)
}
func (ref *subConnRef) streamsDecr() {
	atomic.AddInt32(&ref.streamsCnt, -1)
}
type gcpBalancer struct {
	balancer.Balancer  
	addrs             []resolver.Address
	cc                balancer.ClientConn
	csEvltr           *connectivityStateEvaluator
	state             connectivity.State
	mu          sync.RWMutex
	affinityMap map[string]balancer.SubConn
	scStates    map[balancer.SubConn]connectivity.State
	scRefs      map[balancer.SubConn]*subConnRef
	picker balancer.Picker
}
func (gb *gcpBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error {
	addrs := ccs.ResolverState.Addresses
	gb.addrs = addrs
	createdSubCons := false
	for len(gb.scRefs) < MinConnections {
		gb.newSubConn()
		createdSubCons = true
	}
	if createdSubCons {
		return nil
	}
	for _, scRef := range gb.scRefs {
		scRef.subConn.UpdateAddresses(addrs)
		scRef.subConn.Connect()
	}
	return nil
}
func (gb *gcpBalancer) ResolverError(err error) {
	grpclog.Warningf(
		"grpcgcp.gcpBalancer: ResolverError: %v",
		err,
	)
}
func (gb *gcpBalancer) getConnectionPoolSize() int {
	gb.mu.Lock()
	defer gb.mu.Unlock()
	return len(gb.scRefs)
}
func (gb *gcpBalancer) newSubConn() {
	gb.mu.Lock()
	defer gb.mu.Unlock()
	for _, scState := range gb.scStates {
		if scState == connectivity.Connecting {
			return
		}
	}
	sc, err := gb.cc.NewSubConn(
		gb.addrs,
		balancer.NewSubConnOptions{HealthCheckEnabled: healthCheckEnabled},
	)
	if err != nil {
		grpclog.Errorf("grpcgcp.gcpBalancer: failed to NewSubConn: %v", err)
		return
	}
	gb.scRefs[sc] = &subConnRef{
		subConn: sc,
	}
	gb.scStates[sc] = connectivity.Idle
	sc.Connect()
}
func (gb *gcpBalancer) getReadySubConnRef(boundKey string) (*subConnRef, bool) {
	gb.mu.RLock()
	defer gb.mu.RUnlock()
	if sc, ok := gb.affinityMap[boundKey]; ok {
		if gb.scStates[sc] != connectivity.Ready {
			return nil, true
		}
		return gb.scRefs[sc], true
	}
	return nil, false
}
func (gb *gcpBalancer) bindSubConn(bindKey string, sc balancer.SubConn) {
	gb.mu.Lock()
	defer gb.mu.Unlock()
	_, ok := gb.affinityMap[bindKey]
	if !ok {
		gb.affinityMap[bindKey] = sc
	}
	gb.scRefs[sc].affinityIncr()
}