gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/grpc/resolver_conn_wrapper.go (about)

     1  /*
     2   *
     3   * Copyright 2017 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package grpc
    20  
    21  import (
    22  	"errors"
    23  	"fmt"
    24  	"strings"
    25  	"sync"
    26  
    27  	"gitee.com/zhaochuninhefei/gmgo/grpc/balancer"
    28  	"gitee.com/zhaochuninhefei/gmgo/grpc/credentials"
    29  	"gitee.com/zhaochuninhefei/gmgo/grpc/internal/channelz"
    30  	"gitee.com/zhaochuninhefei/gmgo/grpc/internal/grpcsync"
    31  	"gitee.com/zhaochuninhefei/gmgo/grpc/resolver"
    32  	"gitee.com/zhaochuninhefei/gmgo/grpc/serviceconfig"
    33  )
    34  
    35  // ccResolverWrapper is a wrapper on top of cc for resolvers.
    36  // It implements resolver.ClientConn interface.
    37  type ccResolverWrapper struct {
    38  	cc         *ClientConn
    39  	resolverMu sync.Mutex
    40  	resolver   resolver.Resolver
    41  	done       *grpcsync.Event
    42  	curState   resolver.State
    43  
    44  	incomingMu sync.Mutex // Synchronizes all the incoming calls.
    45  }
    46  
    47  // newCCResolverWrapper uses the resolver.Builder to build a Resolver and
    48  // returns a ccResolverWrapper object which wraps the newly built resolver.
    49  func newCCResolverWrapper(cc *ClientConn, rb resolver.Builder) (*ccResolverWrapper, error) {
    50  	ccr := &ccResolverWrapper{
    51  		cc:   cc,
    52  		done: grpcsync.NewEvent(),
    53  	}
    54  
    55  	var credsClone credentials.TransportCredentials
    56  	if creds := cc.dopts.copts.TransportCredentials; creds != nil {
    57  		credsClone = creds.Clone()
    58  	}
    59  	rbo := resolver.BuildOptions{
    60  		DisableServiceConfig: cc.dopts.disableServiceConfig,
    61  		DialCreds:            credsClone,
    62  		CredsBundle:          cc.dopts.copts.CredsBundle,
    63  		Dialer:               cc.dopts.copts.Dialer,
    64  	}
    65  
    66  	var err error
    67  	// We need to hold the lock here while we assign to the ccr.resolver field
    68  	// to guard against a data race caused by the following code path,
    69  	// rb.Build-->ccr.ReportError-->ccr.poll-->ccr.resolveNow, would end up
    70  	// accessing ccr.resolver which is being assigned here.
    71  	ccr.resolverMu.Lock()
    72  	defer ccr.resolverMu.Unlock()
    73  	ccr.resolver, err = rb.Build(cc.parsedTarget, ccr, rbo)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	return ccr, nil
    78  }
    79  
    80  func (ccr *ccResolverWrapper) resolveNow(o resolver.ResolveNowOptions) {
    81  	ccr.resolverMu.Lock()
    82  	if !ccr.done.HasFired() {
    83  		ccr.resolver.ResolveNow(o)
    84  	}
    85  	ccr.resolverMu.Unlock()
    86  }
    87  
    88  func (ccr *ccResolverWrapper) close() {
    89  	ccr.resolverMu.Lock()
    90  	ccr.resolver.Close()
    91  	ccr.done.Fire()
    92  	ccr.resolverMu.Unlock()
    93  }
    94  
    95  func (ccr *ccResolverWrapper) UpdateState(s resolver.State) error {
    96  	ccr.incomingMu.Lock()
    97  	defer ccr.incomingMu.Unlock()
    98  	if ccr.done.HasFired() {
    99  		return nil
   100  	}
   101  	channelz.Infof(logger, ccr.cc.channelzID, "ccResolverWrapper: sending update to cc: %v", s)
   102  	if channelz.IsOn() {
   103  		ccr.addChannelzTraceEvent(s)
   104  	}
   105  	ccr.curState = s
   106  	if err := ccr.cc.updateResolverState(ccr.curState, nil); errors.Is(err, balancer.ErrBadResolverState) {
   107  		return balancer.ErrBadResolverState
   108  	}
   109  	return nil
   110  }
   111  
   112  func (ccr *ccResolverWrapper) ReportError(err error) {
   113  	ccr.incomingMu.Lock()
   114  	defer ccr.incomingMu.Unlock()
   115  	if ccr.done.HasFired() {
   116  		return
   117  	}
   118  	channelz.Warningf(logger, ccr.cc.channelzID, "ccResolverWrapper: reporting error to cc: %v", err)
   119  	_ = ccr.cc.updateResolverState(resolver.State{}, err)
   120  }
   121  
   122  // NewAddress is called by the resolver implementation to send addresses to gRPC.
   123  func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) {
   124  	ccr.incomingMu.Lock()
   125  	defer ccr.incomingMu.Unlock()
   126  	if ccr.done.HasFired() {
   127  		return
   128  	}
   129  	channelz.Infof(logger, ccr.cc.channelzID, "ccResolverWrapper: sending new addresses to cc: %v", addrs)
   130  	if channelz.IsOn() {
   131  		ccr.addChannelzTraceEvent(resolver.State{Addresses: addrs, ServiceConfig: ccr.curState.ServiceConfig})
   132  	}
   133  	ccr.curState.Addresses = addrs
   134  	_ = ccr.cc.updateResolverState(ccr.curState, nil)
   135  }
   136  
   137  // NewServiceConfig is called by the resolver implementation to send service
   138  // configs to gRPC.
   139  func (ccr *ccResolverWrapper) NewServiceConfig(sc string) {
   140  	ccr.incomingMu.Lock()
   141  	defer ccr.incomingMu.Unlock()
   142  	if ccr.done.HasFired() {
   143  		return
   144  	}
   145  	channelz.Infof(logger, ccr.cc.channelzID, "ccResolverWrapper: got new service config: %v", sc)
   146  	if ccr.cc.dopts.disableServiceConfig {
   147  		channelz.Info(logger, ccr.cc.channelzID, "Service config lookups disabled; ignoring config")
   148  		return
   149  	}
   150  	scpr := parseServiceConfig(sc)
   151  	if scpr.Err != nil {
   152  		channelz.Warningf(logger, ccr.cc.channelzID, "ccResolverWrapper: error parsing service config: %v", scpr.Err)
   153  		return
   154  	}
   155  	if channelz.IsOn() {
   156  		ccr.addChannelzTraceEvent(resolver.State{Addresses: ccr.curState.Addresses, ServiceConfig: scpr})
   157  	}
   158  	ccr.curState.ServiceConfig = scpr
   159  	_ = ccr.cc.updateResolverState(ccr.curState, nil)
   160  }
   161  
   162  func (ccr *ccResolverWrapper) ParseServiceConfig(scJSON string) *serviceconfig.ParseResult {
   163  	return parseServiceConfig(scJSON)
   164  }
   165  
   166  func (ccr *ccResolverWrapper) addChannelzTraceEvent(s resolver.State) {
   167  	var updates []string
   168  	var oldSC, newSC *ServiceConfig
   169  	var oldOK, newOK bool
   170  	if ccr.curState.ServiceConfig != nil {
   171  		oldSC, oldOK = ccr.curState.ServiceConfig.Config.(*ServiceConfig)
   172  	}
   173  	if s.ServiceConfig != nil {
   174  		newSC, newOK = s.ServiceConfig.Config.(*ServiceConfig)
   175  	}
   176  	if oldOK != newOK || (oldOK && newOK && oldSC.rawJSONString != newSC.rawJSONString) {
   177  		updates = append(updates, "service config updated")
   178  	}
   179  	if len(ccr.curState.Addresses) > 0 && len(s.Addresses) == 0 {
   180  		updates = append(updates, "resolver returned an empty address list")
   181  	} else if len(ccr.curState.Addresses) == 0 && len(s.Addresses) > 0 {
   182  		updates = append(updates, "resolver returned new addresses")
   183  	}
   184  	channelz.AddTraceEvent(logger, ccr.cc.channelzID, 0, &channelz.TraceEventDesc{
   185  		Desc:     fmt.Sprintf("Resolver state updated: %+v (%v)", s, strings.Join(updates, "; ")),
   186  		Severity: channelz.CtInfo,
   187  	})
   188  }