gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

pickfirst.go (5095B)


      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 	"google.golang.org/grpc/balancer"
     26 	"google.golang.org/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 func (*pickfirstBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
     39 	return &pickfirstBalancer{cc: cc}
     40 }
     41 
     42 func (*pickfirstBuilder) Name() string {
     43 	return PickFirstBalancerName
     44 }
     45 
     46 type pickfirstBalancer struct {
     47 	state   connectivity.State
     48 	cc      balancer.ClientConn
     49 	subConn balancer.SubConn
     50 }
     51 
     52 func (b *pickfirstBalancer) ResolverError(err error) {
     53 	if logger.V(2) {
     54 		logger.Infof("pickfirstBalancer: ResolverError called with error: %v", err)
     55 	}
     56 	if b.subConn == nil {
     57 		b.state = connectivity.TransientFailure
     58 	}
     59 
     60 	if b.state != connectivity.TransientFailure {
     61 		// The picker will not change since the balancer does not currently
     62 		// report an error.
     63 		return
     64 	}
     65 	b.cc.UpdateState(balancer.State{
     66 		ConnectivityState: connectivity.TransientFailure,
     67 		Picker:            &picker{err: fmt.Errorf("name resolver error: %v", err)},
     68 	})
     69 }
     70 
     71 func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState) error {
     72 	if len(state.ResolverState.Addresses) == 0 {
     73 		// The resolver reported an empty address list. Treat it like an error by
     74 		// calling b.ResolverError.
     75 		if b.subConn != nil {
     76 			// Remove the old subConn. All addresses were removed, so it is no longer
     77 			// valid.
     78 			b.cc.RemoveSubConn(b.subConn)
     79 			b.subConn = nil
     80 		}
     81 		b.ResolverError(errors.New("produced zero addresses"))
     82 		return balancer.ErrBadResolverState
     83 	}
     84 
     85 	if b.subConn != nil {
     86 		b.cc.UpdateAddresses(b.subConn, state.ResolverState.Addresses)
     87 		return nil
     88 	}
     89 
     90 	subConn, err := b.cc.NewSubConn(state.ResolverState.Addresses, balancer.NewSubConnOptions{})
     91 	if err != nil {
     92 		if logger.V(2) {
     93 			logger.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err)
     94 		}
     95 		b.state = connectivity.TransientFailure
     96 		b.cc.UpdateState(balancer.State{
     97 			ConnectivityState: connectivity.TransientFailure,
     98 			Picker:            &picker{err: fmt.Errorf("error creating connection: %v", err)},
     99 		})
    100 		return balancer.ErrBadResolverState
    101 	}
    102 	b.subConn = subConn
    103 	b.state = connectivity.Idle
    104 	b.cc.UpdateState(balancer.State{
    105 		ConnectivityState: connectivity.Connecting,
    106 		Picker:            &picker{err: balancer.ErrNoSubConnAvailable},
    107 	})
    108 	b.subConn.Connect()
    109 	return nil
    110 }
    111 
    112 func (b *pickfirstBalancer) UpdateSubConnState(subConn balancer.SubConn, state balancer.SubConnState) {
    113 	if logger.V(2) {
    114 		logger.Infof("pickfirstBalancer: UpdateSubConnState: %p, %v", subConn, state)
    115 	}
    116 	if b.subConn != subConn {
    117 		if logger.V(2) {
    118 			logger.Infof("pickfirstBalancer: ignored state change because subConn is not recognized")
    119 		}
    120 		return
    121 	}
    122 	b.state = state.ConnectivityState
    123 	if state.ConnectivityState == connectivity.Shutdown {
    124 		b.subConn = nil
    125 		return
    126 	}
    127 
    128 	switch state.ConnectivityState {
    129 	case connectivity.Ready:
    130 		b.cc.UpdateState(balancer.State{
    131 			ConnectivityState: state.ConnectivityState,
    132 			Picker:            &picker{result: balancer.PickResult{SubConn: subConn}},
    133 		})
    134 	case connectivity.Connecting:
    135 		b.cc.UpdateState(balancer.State{
    136 			ConnectivityState: state.ConnectivityState,
    137 			Picker:            &picker{err: balancer.ErrNoSubConnAvailable},
    138 		})
    139 	case connectivity.Idle:
    140 		b.cc.UpdateState(balancer.State{
    141 			ConnectivityState: state.ConnectivityState,
    142 			Picker:            &idlePicker{subConn: subConn},
    143 		})
    144 	case connectivity.TransientFailure:
    145 		b.cc.UpdateState(balancer.State{
    146 			ConnectivityState: state.ConnectivityState,
    147 			Picker:            &picker{err: state.ConnectionError},
    148 		})
    149 	}
    150 }
    151 
    152 func (b *pickfirstBalancer) Close() {
    153 }
    154 
    155 func (b *pickfirstBalancer) ExitIdle() {
    156 	if b.subConn != nil && b.state == connectivity.Idle {
    157 		b.subConn.Connect()
    158 	}
    159 }
    160 
    161 type picker struct {
    162 	result balancer.PickResult
    163 	err    error
    164 }
    165 
    166 func (p *picker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
    167 	return p.result, p.err
    168 }
    169 
    170 // idlePicker is used when the SubConn is IDLE and kicks the SubConn into
    171 // CONNECTING when Pick is called.
    172 type idlePicker struct {
    173 	subConn balancer.SubConn
    174 }
    175 
    176 func (i *idlePicker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
    177 	i.subConn.Connect()
    178 	return balancer.PickResult{}, balancer.ErrNoSubConnAvailable
    179 }
    180 
    181 func init() {
    182 	balancer.Register(newPickfirstBuilder())
    183 }