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 }