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 }