gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/grpc/pickfirst.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  
    25  	"gitee.com/zhaochuninhefei/gmgo/grpc/balancer"
    26  	"gitee.com/zhaochuninhefei/gmgo/grpc/connectivity"
    27  )
    28  
    29  // PickFirstBalancerName is the name of the pick_first balancer.
    30  const PickFirstBalancerName = "pick_first"
    31  
    32  func newPickfirstBuilder() balancer.Builder {
    33  	return &pickfirstBuilder{}
    34  }
    35  
    36  type pickfirstBuilder struct{}
    37  
    38  //goland:noinspection GoUnusedParameter
    39  func (*pickfirstBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
    40  	return &pickfirstBalancer{cc: cc}
    41  }
    42  
    43  func (*pickfirstBuilder) Name() string {
    44  	return PickFirstBalancerName
    45  }
    46  
    47  type pickfirstBalancer struct {
    48  	state connectivity.State
    49  	cc    balancer.ClientConn
    50  	sc    balancer.SubConn
    51  }
    52  
    53  func (b *pickfirstBalancer) ResolverError(err error) {
    54  	switch b.state {
    55  	case connectivity.TransientFailure, connectivity.Idle, connectivity.Connecting:
    56  		// Set a failing picker if we don't have a good picker.
    57  		b.cc.UpdateState(balancer.State{ConnectivityState: connectivity.TransientFailure,
    58  			Picker: &picker{err: fmt.Errorf("name resolver error: %v", err)},
    59  		})
    60  	default:
    61  		panic("unhandled default case")
    62  	}
    63  	if logger.V(2) {
    64  		logger.Infof("pickfirstBalancer: ResolverError called with error %v", err)
    65  	}
    66  }
    67  
    68  func (b *pickfirstBalancer) UpdateClientConnState(cs balancer.ClientConnState) error {
    69  	if len(cs.ResolverState.Addresses) == 0 {
    70  		b.ResolverError(errors.New("produced zero addresses"))
    71  		return balancer.ErrBadResolverState
    72  	}
    73  	if b.sc == nil {
    74  		var err error
    75  		b.sc, err = b.cc.NewSubConn(cs.ResolverState.Addresses, balancer.NewSubConnOptions{})
    76  		if err != nil {
    77  			if logger.V(2) {
    78  				logger.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err)
    79  			}
    80  			b.state = connectivity.TransientFailure
    81  			b.cc.UpdateState(balancer.State{ConnectivityState: connectivity.TransientFailure,
    82  				Picker: &picker{err: fmt.Errorf("error creating connection: %v", err)},
    83  			})
    84  			return balancer.ErrBadResolverState
    85  		}
    86  		b.state = connectivity.Idle
    87  		b.cc.UpdateState(balancer.State{ConnectivityState: connectivity.Idle, Picker: &picker{result: balancer.PickResult{SubConn: b.sc}}})
    88  		b.sc.Connect()
    89  	} else {
    90  		b.cc.UpdateAddresses(b.sc, cs.ResolverState.Addresses)
    91  		b.sc.Connect()
    92  	}
    93  	return nil
    94  }
    95  
    96  func (b *pickfirstBalancer) UpdateSubConnState(sc balancer.SubConn, s balancer.SubConnState) {
    97  	if logger.V(2) {
    98  		logger.Infof("pickfirstBalancer: UpdateSubConnState: %p, %v", sc, s)
    99  	}
   100  	if b.sc != sc {
   101  		if logger.V(2) {
   102  			logger.Infof("pickfirstBalancer: ignored state change because sc is not recognized")
   103  		}
   104  		return
   105  	}
   106  	b.state = s.ConnectivityState
   107  	if s.ConnectivityState == connectivity.Shutdown {
   108  		b.sc = nil
   109  		return
   110  	}
   111  
   112  	switch s.ConnectivityState {
   113  	case connectivity.Ready:
   114  		b.cc.UpdateState(balancer.State{ConnectivityState: s.ConnectivityState, Picker: &picker{result: balancer.PickResult{SubConn: sc}}})
   115  	case connectivity.Connecting:
   116  		b.cc.UpdateState(balancer.State{ConnectivityState: s.ConnectivityState, Picker: &picker{err: balancer.ErrNoSubConnAvailable}})
   117  	case connectivity.Idle:
   118  		b.cc.UpdateState(balancer.State{ConnectivityState: s.ConnectivityState, Picker: &idlePicker{sc: sc}})
   119  	case connectivity.TransientFailure:
   120  		b.cc.UpdateState(balancer.State{
   121  			ConnectivityState: s.ConnectivityState,
   122  			Picker:            &picker{err: s.ConnectionError},
   123  		})
   124  	default:
   125  		panic("unhandled default case")
   126  	}
   127  }
   128  
   129  func (b *pickfirstBalancer) Close() {
   130  }
   131  
   132  func (b *pickfirstBalancer) ExitIdle() {
   133  	if b.sc != nil && b.state == connectivity.Idle {
   134  		b.sc.Connect()
   135  	}
   136  }
   137  
   138  type picker struct {
   139  	result balancer.PickResult
   140  	err    error
   141  }
   142  
   143  //goland:noinspection GoUnusedParameter
   144  func (p *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
   145  	return p.result, p.err
   146  }
   147  
   148  // idlePicker is used when the SubConn is IDLE and kicks the SubConn into
   149  // CONNECTING when Pick is called.
   150  type idlePicker struct {
   151  	sc balancer.SubConn
   152  }
   153  
   154  //goland:noinspection GoUnusedParameter
   155  func (i *idlePicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
   156  	i.sc.Connect()
   157  	return balancer.PickResult{}, balancer.ErrNoSubConnAvailable
   158  }
   159  
   160  func init() {
   161  	balancer.Register(newPickfirstBuilder())
   162  }