in grpcgcp/gcp_balancer.go [457:549]
func (gb *gcpBalancer) UpdateSubConnState(sc balancer.SubConn, scs balancer.SubConnState) {
gb.mu.Lock()
defer gb.mu.Unlock()
s := scs.ConnectivityState
if scRef, found := gb.refreshingScRefs[sc]; found {
if gb.log.V(FINE) {
gb.log.Infof("handle replacement SubConn state change: %p, %v", sc, s)
}
if s != connectivity.Ready {
// Ignore the replacement sc until it's ready.
return
}
// Replace SubConn of the scRef with the fresh SubConn (sc) concluding
// the refresh process initiated by refresh(*subConnRef).
oldSc := scRef.subConn
gb.scStates[sc] = gb.scStates[oldSc]
delete(gb.refreshingScRefs, sc)
delete(gb.scRefs, oldSc)
delete(gb.scStates, oldSc)
gb.scRefs[sc] = scRef
scRef.subConn = sc
scRef.deCalls = 0
scRef.lastResp = time.Now()
scRef.refreshing = false
scRef.refreshCnt++
gb.cc.RemoveSubConn(oldSc)
}
if gb.log.V(FINE) {
gb.log.Infof("handle SubConn state change: %p, %v", sc, s)
}
oldS, ok := gb.scStates[sc]
if !ok {
if gb.log.V(FINE) {
gb.log.Infof(
"got state changes for an unknown/replaced SubConn: %p, %v",
sc,
s,
)
}
return
}
gb.scStates[sc] = s
switch s {
case connectivity.Idle:
sc.Connect()
case connectivity.Shutdown:
delete(gb.scRefs, sc)
delete(gb.scStates, sc)
}
if oldS == connectivity.Ready && s != oldS {
// Subconn is broken. Remove fallback mapping to this subconn.
for k, v := range gb.fallbackMap {
if v == sc {
delete(gb.fallbackMap, k)
}
}
}
if oldS != connectivity.Ready && s == connectivity.Ready {
// Remove fallback mapping for the keys of recovered subconn.
for k := range gb.fallbackMap {
if gb.affinityMap[k] == sc {
delete(gb.fallbackMap, k)
}
}
}
oldAggrState := gb.state
gb.state = gb.csEvltr.recordTransition(oldS, s)
// Regenerate picker when one of the following happens:
// - this sc became ready from not-ready
// - this sc became not-ready from ready
// - the aggregated state of balancer became TransientFailure from non-TransientFailure
// - the aggregated state of balancer became non-TransientFailure from TransientFailure
if (s == connectivity.Ready) != (oldS == connectivity.Ready) ||
(gb.state == connectivity.TransientFailure) != (oldAggrState == connectivity.TransientFailure) {
gb.regeneratePicker()
gb.cc.UpdateState(balancer.State{
ConnectivityState: gb.state,
Picker: gb.picker,
})
}
if scRef := gb.scRefs[sc]; scRef != nil {
// Inform of the state change.
close(scRef.stateSignal)
scRef.stateSignal = make(chan struct{})
}
}