google.golang.org/grpc@v1.62.1/balancer_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 "context" 23 "fmt" 24 "strings" 25 "sync" 26 27 "google.golang.org/grpc/balancer" 28 "google.golang.org/grpc/connectivity" 29 "google.golang.org/grpc/internal/balancer/gracefulswitch" 30 "google.golang.org/grpc/internal/channelz" 31 "google.golang.org/grpc/internal/grpcsync" 32 "google.golang.org/grpc/resolver" 33 ) 34 35 // ccBalancerWrapper sits between the ClientConn and the Balancer. 36 // 37 // ccBalancerWrapper implements methods corresponding to the ones on the 38 // balancer.Balancer interface. The ClientConn is free to call these methods 39 // concurrently and the ccBalancerWrapper ensures that calls from the ClientConn 40 // to the Balancer happen in order by performing them in the serializer, without 41 // any mutexes held. 42 // 43 // ccBalancerWrapper also implements the balancer.ClientConn interface and is 44 // passed to the Balancer implementations. It invokes unexported methods on the 45 // ClientConn to handle these calls from the Balancer. 46 // 47 // It uses the gracefulswitch.Balancer internally to ensure that balancer 48 // switches happen in a graceful manner. 49 type ccBalancerWrapper struct { 50 // The following fields are initialized when the wrapper is created and are 51 // read-only afterwards, and therefore can be accessed without a mutex. 52 cc *ClientConn 53 opts balancer.BuildOptions 54 serializer *grpcsync.CallbackSerializer 55 serializerCancel context.CancelFunc 56 57 // The following fields are only accessed within the serializer or during 58 // initialization. 59 curBalancerName string 60 balancer *gracefulswitch.Balancer 61 62 // The following field is protected by mu. Caller must take cc.mu before 63 // taking mu. 64 mu sync.Mutex 65 closed bool 66 } 67 68 // newCCBalancerWrapper creates a new balancer wrapper in idle state. The 69 // underlying balancer is not created until the switchTo() method is invoked. 70 func newCCBalancerWrapper(cc *ClientConn) *ccBalancerWrapper { 71 ctx, cancel := context.WithCancel(cc.ctx) 72 ccb := &ccBalancerWrapper{ 73 cc: cc, 74 opts: balancer.BuildOptions{ 75 DialCreds: cc.dopts.copts.TransportCredentials, 76 CredsBundle: cc.dopts.copts.CredsBundle, 77 Dialer: cc.dopts.copts.Dialer, 78 Authority: cc.authority, 79 CustomUserAgent: cc.dopts.copts.UserAgent, 80 ChannelzParentID: cc.channelzID, 81 Target: cc.parsedTarget, 82 }, 83 serializer: grpcsync.NewCallbackSerializer(ctx), 84 serializerCancel: cancel, 85 } 86 ccb.balancer = gracefulswitch.NewBalancer(ccb, ccb.opts) 87 return ccb 88 } 89 90 // updateClientConnState is invoked by grpc to push a ClientConnState update to 91 // the underlying balancer. This is always executed from the serializer, so 92 // it is safe to call into the balancer here. 93 func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnState) error { 94 errCh := make(chan error) 95 ok := ccb.serializer.Schedule(func(ctx context.Context) { 96 defer close(errCh) 97 if ctx.Err() != nil || ccb.balancer == nil { 98 return 99 } 100 err := ccb.balancer.UpdateClientConnState(*ccs) 101 if logger.V(2) && err != nil { 102 logger.Infof("error from balancer.UpdateClientConnState: %v", err) 103 } 104 errCh <- err 105 }) 106 if !ok { 107 return nil 108 } 109 return <-errCh 110 } 111 112 // resolverError is invoked by grpc to push a resolver error to the underlying 113 // balancer. The call to the balancer is executed from the serializer. 114 func (ccb *ccBalancerWrapper) resolverError(err error) { 115 ccb.serializer.Schedule(func(ctx context.Context) { 116 if ctx.Err() != nil || ccb.balancer == nil { 117 return 118 } 119 ccb.balancer.ResolverError(err) 120 }) 121 } 122 123 // switchTo is invoked by grpc to instruct the balancer wrapper to switch to the 124 // LB policy identified by name. 125 // 126 // ClientConn calls newCCBalancerWrapper() at creation time. Upon receipt of the 127 // first good update from the name resolver, it determines the LB policy to use 128 // and invokes the switchTo() method. Upon receipt of every subsequent update 129 // from the name resolver, it invokes this method. 130 // 131 // the ccBalancerWrapper keeps track of the current LB policy name, and skips 132 // the graceful balancer switching process if the name does not change. 133 func (ccb *ccBalancerWrapper) switchTo(name string) { 134 ccb.serializer.Schedule(func(ctx context.Context) { 135 if ctx.Err() != nil || ccb.balancer == nil { 136 return 137 } 138 // TODO: Other languages use case-sensitive balancer registries. We should 139 // switch as well. See: https://github.com/grpc/grpc-go/issues/5288. 140 if strings.EqualFold(ccb.curBalancerName, name) { 141 return 142 } 143 ccb.buildLoadBalancingPolicy(name) 144 }) 145 } 146 147 // buildLoadBalancingPolicy performs the following: 148 // - retrieve a balancer builder for the given name. Use the default LB 149 // policy, pick_first, if no LB policy with name is found in the registry. 150 // - instruct the gracefulswitch balancer to switch to the above builder. This 151 // will actually build the new balancer. 152 // - update the `curBalancerName` field 153 // 154 // Must be called from a serializer callback. 155 func (ccb *ccBalancerWrapper) buildLoadBalancingPolicy(name string) { 156 builder := balancer.Get(name) 157 if builder == nil { 158 channelz.Warningf(logger, ccb.cc.channelzID, "Channel switches to new LB policy %q, since the specified LB policy %q was not registered", PickFirstBalancerName, name) 159 builder = newPickfirstBuilder() 160 } else { 161 channelz.Infof(logger, ccb.cc.channelzID, "Channel switches to new LB policy %q", name) 162 } 163 164 if err := ccb.balancer.SwitchTo(builder); err != nil { 165 channelz.Errorf(logger, ccb.cc.channelzID, "Channel failed to build new LB policy %q: %v", name, err) 166 return 167 } 168 ccb.curBalancerName = builder.Name() 169 } 170 171 // close initiates async shutdown of the wrapper. cc.mu must be held when 172 // calling this function. To determine the wrapper has finished shutting down, 173 // the channel should block on ccb.serializer.Done() without cc.mu held. 174 func (ccb *ccBalancerWrapper) close() { 175 ccb.mu.Lock() 176 ccb.closed = true 177 ccb.mu.Unlock() 178 channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: closing") 179 ccb.serializer.Schedule(func(context.Context) { 180 if ccb.balancer == nil { 181 return 182 } 183 ccb.balancer.Close() 184 ccb.balancer = nil 185 }) 186 ccb.serializerCancel() 187 } 188 189 // exitIdle invokes the balancer's exitIdle method in the serializer. 190 func (ccb *ccBalancerWrapper) exitIdle() { 191 ccb.serializer.Schedule(func(ctx context.Context) { 192 if ctx.Err() != nil || ccb.balancer == nil { 193 return 194 } 195 ccb.balancer.ExitIdle() 196 }) 197 } 198 199 func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) { 200 ccb.cc.mu.Lock() 201 defer ccb.cc.mu.Unlock() 202 203 ccb.mu.Lock() 204 if ccb.closed { 205 ccb.mu.Unlock() 206 return nil, fmt.Errorf("balancer is being closed; no new SubConns allowed") 207 } 208 ccb.mu.Unlock() 209 210 if len(addrs) == 0 { 211 return nil, fmt.Errorf("grpc: cannot create SubConn with empty address list") 212 } 213 ac, err := ccb.cc.newAddrConnLocked(addrs, opts) 214 if err != nil { 215 channelz.Warningf(logger, ccb.cc.channelzID, "acBalancerWrapper: NewSubConn: failed to newAddrConn: %v", err) 216 return nil, err 217 } 218 acbw := &acBalancerWrapper{ 219 ccb: ccb, 220 ac: ac, 221 producers: make(map[balancer.ProducerBuilder]*refCountedProducer), 222 stateListener: opts.StateListener, 223 } 224 ac.acbw = acbw 225 return acbw, nil 226 } 227 228 func (ccb *ccBalancerWrapper) RemoveSubConn(sc balancer.SubConn) { 229 // The graceful switch balancer will never call this. 230 logger.Errorf("ccb RemoveSubConn(%v) called unexpectedly, sc") 231 } 232 233 func (ccb *ccBalancerWrapper) UpdateAddresses(sc balancer.SubConn, addrs []resolver.Address) { 234 acbw, ok := sc.(*acBalancerWrapper) 235 if !ok { 236 return 237 } 238 acbw.UpdateAddresses(addrs) 239 } 240 241 func (ccb *ccBalancerWrapper) UpdateState(s balancer.State) { 242 ccb.cc.mu.Lock() 243 defer ccb.cc.mu.Unlock() 244 245 ccb.mu.Lock() 246 if ccb.closed { 247 ccb.mu.Unlock() 248 return 249 } 250 ccb.mu.Unlock() 251 // Update picker before updating state. Even though the ordering here does 252 // not matter, it can lead to multiple calls of Pick in the common start-up 253 // case where we wait for ready and then perform an RPC. If the picker is 254 // updated later, we could call the "connecting" picker when the state is 255 // updated, and then call the "ready" picker after the picker gets updated. 256 257 // Note that there is no need to check if the balancer wrapper was closed, 258 // as we know the graceful switch LB policy will not call cc if it has been 259 // closed. 260 ccb.cc.pickerWrapper.updatePicker(s.Picker) 261 ccb.cc.csMgr.updateState(s.ConnectivityState) 262 } 263 264 func (ccb *ccBalancerWrapper) ResolveNow(o resolver.ResolveNowOptions) { 265 ccb.cc.mu.RLock() 266 defer ccb.cc.mu.RUnlock() 267 268 ccb.mu.Lock() 269 if ccb.closed { 270 ccb.mu.Unlock() 271 return 272 } 273 ccb.mu.Unlock() 274 ccb.cc.resolveNowLocked(o) 275 } 276 277 func (ccb *ccBalancerWrapper) Target() string { 278 return ccb.cc.target 279 } 280 281 // acBalancerWrapper is a wrapper on top of ac for balancers. 282 // It implements balancer.SubConn interface. 283 type acBalancerWrapper struct { 284 ac *addrConn // read-only 285 ccb *ccBalancerWrapper // read-only 286 stateListener func(balancer.SubConnState) 287 288 mu sync.Mutex 289 producers map[balancer.ProducerBuilder]*refCountedProducer 290 } 291 292 // updateState is invoked by grpc to push a subConn state update to the 293 // underlying balancer. 294 func (acbw *acBalancerWrapper) updateState(s connectivity.State, err error) { 295 acbw.ccb.serializer.Schedule(func(ctx context.Context) { 296 if ctx.Err() != nil || acbw.ccb.balancer == nil { 297 return 298 } 299 // Even though it is optional for balancers, gracefulswitch ensures 300 // opts.StateListener is set, so this cannot ever be nil. 301 // TODO: delete this comment when UpdateSubConnState is removed. 302 acbw.stateListener(balancer.SubConnState{ConnectivityState: s, ConnectionError: err}) 303 }) 304 } 305 306 func (acbw *acBalancerWrapper) String() string { 307 return fmt.Sprintf("SubConn(id:%d)", acbw.ac.channelzID.Int()) 308 } 309 310 func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) { 311 acbw.ac.updateAddrs(addrs) 312 } 313 314 func (acbw *acBalancerWrapper) Connect() { 315 go acbw.ac.connect() 316 } 317 318 func (acbw *acBalancerWrapper) Shutdown() { 319 acbw.ccb.cc.removeAddrConn(acbw.ac, errConnDrain) 320 } 321 322 // NewStream begins a streaming RPC on the addrConn. If the addrConn is not 323 // ready, blocks until it is or ctx expires. Returns an error when the context 324 // expires or the addrConn is shut down. 325 func (acbw *acBalancerWrapper) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) { 326 transport, err := acbw.ac.getTransport(ctx) 327 if err != nil { 328 return nil, err 329 } 330 return newNonRetryClientStream(ctx, desc, method, transport, acbw.ac, opts...) 331 } 332 333 // Invoke performs a unary RPC. If the addrConn is not ready, returns 334 // errSubConnNotReady. 335 func (acbw *acBalancerWrapper) Invoke(ctx context.Context, method string, args any, reply any, opts ...CallOption) error { 336 cs, err := acbw.NewStream(ctx, unaryStreamDesc, method, opts...) 337 if err != nil { 338 return err 339 } 340 if err := cs.SendMsg(args); err != nil { 341 return err 342 } 343 return cs.RecvMsg(reply) 344 } 345 346 type refCountedProducer struct { 347 producer balancer.Producer 348 refs int // number of current refs to the producer 349 close func() // underlying producer's close function 350 } 351 352 func (acbw *acBalancerWrapper) GetOrBuildProducer(pb balancer.ProducerBuilder) (balancer.Producer, func()) { 353 acbw.mu.Lock() 354 defer acbw.mu.Unlock() 355 356 // Look up existing producer from this builder. 357 pData := acbw.producers[pb] 358 if pData == nil { 359 // Not found; create a new one and add it to the producers map. 360 p, close := pb.Build(acbw) 361 pData = &refCountedProducer{producer: p, close: close} 362 acbw.producers[pb] = pData 363 } 364 // Account for this new reference. 365 pData.refs++ 366 367 // Return a cleanup function wrapped in a OnceFunc to remove this reference 368 // and delete the refCountedProducer from the map if the total reference 369 // count goes to zero. 370 unref := func() { 371 acbw.mu.Lock() 372 pData.refs-- 373 if pData.refs == 0 { 374 defer pData.close() // Run outside the acbw mutex 375 delete(acbw.producers, pb) 376 } 377 acbw.mu.Unlock() 378 } 379 return pData.producer, grpcsync.OnceFunc(unref) 380 }