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  }