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

	
	
	
	
	
	
)
ccResolverWrapper is a wrapper on top of cc for resolvers. It implements resolver.ClientConn interface.
newCCResolverWrapper uses the resolver.Builder to build a Resolver and returns a ccResolverWrapper object which wraps the newly built resolver.
We need to hold the lock here while we assign to the ccr.resolver field to guard against a data race caused by the following code path, rb.Build-->ccr.ReportError-->ccr.poll-->ccr.resolveNow, would end up accessing ccr.resolver which is being assigned here.
	.resolverMu.Lock()
	defer .resolverMu.Unlock()
	.resolver,  = .Build(.parsedTarget, , )
	if  != nil {
		return nil, 
	}
	return , nil
}

func ( *ccResolverWrapper) ( resolver.ResolveNowOptions) {
	.resolverMu.Lock()
	if !.done.HasFired() {
		.resolver.ResolveNow()
	}
	.resolverMu.Unlock()
}

func ( *ccResolverWrapper) () {
	.resolverMu.Lock()
	.resolver.Close()
	.done.Fire()
	.resolverMu.Unlock()
}
poll begins or ends asynchronous polling of the resolver based on whether err is ErrBadResolverState.
func ( *ccResolverWrapper) ( error) {
	.pollingMu.Lock()
	defer .pollingMu.Unlock()
stop polling
		if .polling != nil {
			close(.polling)
			.polling = nil
		}
		return
	}
already polling
		return
	}
	 := make(chan struct{})
	.polling = 
	go func() {
		for  := 0; ; ++ {
			.resolveNow(resolver.ResolveNowOptions{})
			 := time.NewTimer(.cc.dopts.resolveNowBackoff())
			select {
			case <-:
				.Stop()
				return
Resolver has been closed.
				.Stop()
				return
			case <-.C:
				select {
				case <-:
					return
				default:
Timer expired; re-resolve.
			}
		}
	}()
}

func ( *ccResolverWrapper) ( resolver.State) {
	if .done.HasFired() {
		return
	}
	channelz.Infof(logger, .cc.channelzID, "ccResolverWrapper: sending update to cc: %v", )
	if channelz.IsOn() {
		.addChannelzTraceEvent()
	}
	.curState = 
	.poll(.cc.updateResolverState(.curState, nil))
}

func ( *ccResolverWrapper) ( error) {
	if .done.HasFired() {
		return
	}
	channelz.Warningf(logger, .cc.channelzID, "ccResolverWrapper: reporting error to cc: %v", )
	.poll(.cc.updateResolverState(resolver.State{}, ))
}
NewAddress is called by the resolver implementation to send addresses to gRPC.
func ( *ccResolverWrapper) ( []resolver.Address) {
	if .done.HasFired() {
		return
	}
	channelz.Infof(logger, .cc.channelzID, "ccResolverWrapper: sending new addresses to cc: %v", )
	if channelz.IsOn() {
		.addChannelzTraceEvent(resolver.State{Addresses: , ServiceConfig: .curState.ServiceConfig})
	}
	.curState.Addresses = 
	.poll(.cc.updateResolverState(.curState, nil))
}
NewServiceConfig is called by the resolver implementation to send service configs to gRPC.
func ( *ccResolverWrapper) ( string) {
	if .done.HasFired() {
		return
	}
	channelz.Infof(logger, .cc.channelzID, "ccResolverWrapper: got new service config: %v", )
	if .cc.dopts.disableServiceConfig {
		channelz.Info(logger, .cc.channelzID, "Service config lookups disabled; ignoring config")
		return
	}
	 := parseServiceConfig()
	if .Err != nil {
		channelz.Warningf(logger, .cc.channelzID, "ccResolverWrapper: error parsing service config: %v", .Err)
		.poll(balancer.ErrBadResolverState)
		return
	}
	if channelz.IsOn() {
		.addChannelzTraceEvent(resolver.State{Addresses: .curState.Addresses, ServiceConfig: })
	}
	.curState.ServiceConfig = 
	.poll(.cc.updateResolverState(.curState, nil))
}

func ( *ccResolverWrapper) ( string) *serviceconfig.ParseResult {
	return parseServiceConfig()
}

func ( *ccResolverWrapper) ( resolver.State) {
	var  []string
	var ,  *ServiceConfig
	var ,  bool
	if .curState.ServiceConfig != nil {
		,  = .curState.ServiceConfig.Config.(*ServiceConfig)
	}
	if .ServiceConfig != nil {
		,  = .ServiceConfig.Config.(*ServiceConfig)
	}
	if  !=  || ( &&  && .rawJSONString != .rawJSONString) {
		 = append(, "service config updated")
	}
	if len(.curState.Addresses) > 0 && len(.Addresses) == 0 {
		 = append(, "resolver returned an empty address list")
	} else if len(.curState.Addresses) == 0 && len(.Addresses) > 0 {
		 = append(, "resolver returned new addresses")
	}
	channelz.AddTraceEvent(logger, .cc.channelzID, 0, &channelz.TraceEventDesc{
		Desc:     fmt.Sprintf("Resolver state updated: %+v (%v)", , strings.Join(, "; ")),
		Severity: channelz.CtINFO,
	})