* * 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 grpc

import (
	
	

	
	
	
	
	
	
)
scStateUpdate contains the subConn and the new state it changed to.
ccBalancerWrapper is a wrapper on top of cc for balancers. It implements balancer.ClientConn interface.
watcher balancer functions sequentially, so the balancer can be implemented lock-free.
func ( *ccBalancerWrapper) () {
	for {
		select {
		case  := <-.scBuffer.Get():
			.scBuffer.Load()
			if .done.HasFired() {
				break
			}
			.balancerMu.Lock()
			 := .(*scStateUpdate)
			.balancer.UpdateSubConnState(.sc, balancer.SubConnState{ConnectivityState: .state, ConnectionError: .err})
			.balancerMu.Unlock()
		case <-.done.Done():
		}

		if .done.HasFired() {
			.balancer.Close()
			.mu.Lock()
			 := .subConns
			.subConns = nil
			.mu.Unlock()
			for  := range  {
				.cc.removeAddrConn(.getAddrConn(), errConnDrain)
			}
			.UpdateState(balancer.State{ConnectivityState: connectivity.Connecting, Picker: nil})
			return
		}
	}
}

func ( *ccBalancerWrapper) () {
	.done.Fire()
}

When updating addresses for a SubConn, if the address in use is not in the new addresses, the old ac will be tearDown() and a new ac will be created. tearDown() generates a state change with Shutdown state, we don't want the balancer to receive this state change. So before tearDown() on the old ac, ac.acbw (acWrapper) will be set to nil, and this function will be called with (nil, Shutdown). We don't need to call balancer method in this case.
	if  == nil {
		return
	}
	.scBuffer.Put(&scStateUpdate{
		sc:    ,
		state: ,
		err:   ,
	})
}

func ( *ccBalancerWrapper) ( *balancer.ClientConnState) error {
	.balancerMu.Lock()
	defer .balancerMu.Unlock()
	return .balancer.UpdateClientConnState(*)
}

func ( *ccBalancerWrapper) ( error) {
	.balancerMu.Lock()
	.balancer.ResolverError()
	.balancerMu.Unlock()
}

func ( *ccBalancerWrapper) ( []resolver.Address,  balancer.NewSubConnOptions) (balancer.SubConn, error) {
	if len() <= 0 {
		return nil, fmt.Errorf("grpc: cannot create SubConn with empty address list")
	}
	.mu.Lock()
	defer .mu.Unlock()
	if .subConns == nil {
		return nil, fmt.Errorf("grpc: ClientConn balancer wrapper was closed")
	}
	,  := .cc.newAddrConn(, )
	if  != nil {
		return nil, 
	}
	 := &acBalancerWrapper{ac: }
	.ac.mu.Lock()
	.acbw = 
	.ac.mu.Unlock()
	.subConns[] = struct{}{}
	return , nil
}

func ( *ccBalancerWrapper) ( balancer.SubConn) {
	,  := .(*acBalancerWrapper)
	if ! {
		return
	}
	.mu.Lock()
	defer .mu.Unlock()
	if .subConns == nil {
		return
	}
	delete(.subConns, )
	.cc.removeAddrConn(.getAddrConn(), errConnDrain)
}

func ( *ccBalancerWrapper) ( balancer.State) {
	.mu.Lock()
	defer .mu.Unlock()
	if .subConns == nil {
		return
Update picker before updating state. Even though the ordering here does not matter, it can lead to multiple calls of Pick in the common start-up case where we wait for ready and then perform an RPC. If the picker is updated later, we could call the "connecting" picker when the state is updated, and then call the "ready" picker after the picker gets updated.
acBalancerWrapper is a wrapper on top of ac for balancers. It implements balancer.SubConn interface.
type acBalancerWrapper struct {
	mu sync.Mutex
	ac *addrConn
}

func ( *acBalancerWrapper) ( []resolver.Address) {
	.mu.Lock()
	defer .mu.Unlock()
	if len() <= 0 {
		.ac.tearDown(errConnDrain)
		return
	}
	if !.ac.tryUpdateAddrs() {
		 := .ac.cc
		 := .ac.scopts
Set old ac.acbw to nil so the Shutdown state update will be ignored by balancer. TODO(bar) the state transition could be wrong when tearDown() old ac and creating new ac, fix the transition.
		.ac.acbw = nil
		.ac.mu.Unlock()
		 := .ac.getState()
		.ac.tearDown(errConnDrain)

		if  == connectivity.Shutdown {
			return
		}

		,  := .newAddrConn(, )
		if  != nil {
			channelz.Warningf(logger, .ac.channelzID, "acBalancerWrapper: UpdateAddresses: failed to newAddrConn: %v", )
			return
		}
		.ac = 
		.mu.Lock()
		.acbw = 
		.mu.Unlock()
		if  != connectivity.Idle {
			.connect()
		}
	}
}

func ( *acBalancerWrapper) () {
	.mu.Lock()
	defer .mu.Unlock()
	.ac.connect()
}

func ( *acBalancerWrapper) () *addrConn {
	.mu.Lock()
	defer .mu.Unlock()
	return .ac