balancer.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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. package base
  19. import (
  20. "golang.org/x/net/context"
  21. "google.golang.org/grpc/balancer"
  22. "google.golang.org/grpc/connectivity"
  23. "google.golang.org/grpc/grpclog"
  24. "google.golang.org/grpc/resolver"
  25. )
  26. type baseBuilder struct {
  27. name string
  28. pickerBuilder PickerBuilder
  29. }
  30. func (bb *baseBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
  31. return &baseBalancer{
  32. cc: cc,
  33. pickerBuilder: bb.pickerBuilder,
  34. subConns: make(map[resolver.Address]balancer.SubConn),
  35. scStates: make(map[balancer.SubConn]connectivity.State),
  36. csEvltr: &connectivityStateEvaluator{},
  37. // Initialize picker to a picker that always return
  38. // ErrNoSubConnAvailable, because when state of a SubConn changes, we
  39. // may call UpdateBalancerState with this picker.
  40. picker: NewErrPicker(balancer.ErrNoSubConnAvailable),
  41. }
  42. }
  43. func (bb *baseBuilder) Name() string {
  44. return bb.name
  45. }
  46. type baseBalancer struct {
  47. cc balancer.ClientConn
  48. pickerBuilder PickerBuilder
  49. csEvltr *connectivityStateEvaluator
  50. state connectivity.State
  51. subConns map[resolver.Address]balancer.SubConn
  52. scStates map[balancer.SubConn]connectivity.State
  53. picker balancer.Picker
  54. }
  55. func (b *baseBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error) {
  56. if err != nil {
  57. grpclog.Infof("base.baseBalancer: HandleResolvedAddrs called with error %v", err)
  58. return
  59. }
  60. grpclog.Infoln("base.baseBalancer: got new resolved addresses: ", addrs)
  61. // addrsSet is the set converted from addrs, it's used for quick lookup of an address.
  62. addrsSet := make(map[resolver.Address]struct{})
  63. for _, a := range addrs {
  64. addrsSet[a] = struct{}{}
  65. if _, ok := b.subConns[a]; !ok {
  66. // a is a new address (not existing in b.subConns).
  67. sc, err := b.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{})
  68. if err != nil {
  69. grpclog.Warningf("base.baseBalancer: failed to create new SubConn: %v", err)
  70. continue
  71. }
  72. b.subConns[a] = sc
  73. b.scStates[sc] = connectivity.Idle
  74. sc.Connect()
  75. }
  76. }
  77. for a, sc := range b.subConns {
  78. // a was removed by resolver.
  79. if _, ok := addrsSet[a]; !ok {
  80. b.cc.RemoveSubConn(sc)
  81. delete(b.subConns, a)
  82. // Keep the state of this sc in b.scStates until sc's state becomes Shutdown.
  83. // The entry will be deleted in HandleSubConnStateChange.
  84. }
  85. }
  86. }
  87. // regeneratePicker takes a snapshot of the balancer, and generates a picker
  88. // from it. The picker is
  89. // - errPicker with ErrTransientFailure if the balancer is in TransientFailure,
  90. // - built by the pickerBuilder with all READY SubConns otherwise.
  91. func (b *baseBalancer) regeneratePicker() {
  92. if b.state == connectivity.TransientFailure {
  93. b.picker = NewErrPicker(balancer.ErrTransientFailure)
  94. return
  95. }
  96. readySCs := make(map[resolver.Address]balancer.SubConn)
  97. // Filter out all ready SCs from full subConn map.
  98. for addr, sc := range b.subConns {
  99. if st, ok := b.scStates[sc]; ok && st == connectivity.Ready {
  100. readySCs[addr] = sc
  101. }
  102. }
  103. b.picker = b.pickerBuilder.Build(readySCs)
  104. }
  105. func (b *baseBalancer) HandleSubConnStateChange(sc balancer.SubConn, s connectivity.State) {
  106. grpclog.Infof("base.baseBalancer: handle SubConn state change: %p, %v", sc, s)
  107. oldS, ok := b.scStates[sc]
  108. if !ok {
  109. grpclog.Infof("base.baseBalancer: got state changes for an unknown SubConn: %p, %v", sc, s)
  110. return
  111. }
  112. b.scStates[sc] = s
  113. switch s {
  114. case connectivity.Idle:
  115. sc.Connect()
  116. case connectivity.Shutdown:
  117. // When an address was removed by resolver, b called RemoveSubConn but
  118. // kept the sc's state in scStates. Remove state for this sc here.
  119. delete(b.scStates, sc)
  120. }
  121. oldAggrState := b.state
  122. b.state = b.csEvltr.recordTransition(oldS, s)
  123. // Regenerate picker when one of the following happens:
  124. // - this sc became ready from not-ready
  125. // - this sc became not-ready from ready
  126. // - the aggregated state of balancer became TransientFailure from non-TransientFailure
  127. // - the aggregated state of balancer became non-TransientFailure from TransientFailure
  128. if (s == connectivity.Ready) != (oldS == connectivity.Ready) ||
  129. (b.state == connectivity.TransientFailure) != (oldAggrState == connectivity.TransientFailure) {
  130. b.regeneratePicker()
  131. }
  132. b.cc.UpdateBalancerState(b.state, b.picker)
  133. }
  134. // Close is a nop because base balancer doesn't have internal state to clean up,
  135. // and it doesn't need to call RemoveSubConn for the SubConns.
  136. func (b *baseBalancer) Close() {
  137. }
  138. // NewErrPicker returns a picker that always returns err on Pick().
  139. func NewErrPicker(err error) balancer.Picker {
  140. return &errPicker{err: err}
  141. }
  142. type errPicker struct {
  143. err error // Pick() always returns this err.
  144. }
  145. func (p *errPicker) Pick(ctx context.Context, opts balancer.PickOptions) (balancer.SubConn, func(balancer.DoneInfo), error) {
  146. return nil, nil, p.err
  147. }
  148. // connectivityStateEvaluator gets updated by addrConns when their
  149. // states transition, based on which it evaluates the state of
  150. // ClientConn.
  151. type connectivityStateEvaluator struct {
  152. numReady uint64 // Number of addrConns in ready state.
  153. numConnecting uint64 // Number of addrConns in connecting state.
  154. numTransientFailure uint64 // Number of addrConns in transientFailure.
  155. }
  156. // recordTransition records state change happening in every subConn and based on
  157. // that it evaluates what aggregated state should be.
  158. // It can only transition between Ready, Connecting and TransientFailure. Other states,
  159. // Idle and Shutdown are transitioned into by ClientConn; in the beginning of the connection
  160. // before any subConn is created ClientConn is in idle state. In the end when ClientConn
  161. // closes it is in Shutdown state.
  162. //
  163. // recordTransition should only be called synchronously from the same goroutine.
  164. func (cse *connectivityStateEvaluator) recordTransition(oldState, newState connectivity.State) connectivity.State {
  165. // Update counters.
  166. for idx, state := range []connectivity.State{oldState, newState} {
  167. updateVal := 2*uint64(idx) - 1 // -1 for oldState and +1 for new.
  168. switch state {
  169. case connectivity.Ready:
  170. cse.numReady += updateVal
  171. case connectivity.Connecting:
  172. cse.numConnecting += updateVal
  173. case connectivity.TransientFailure:
  174. cse.numTransientFailure += updateVal
  175. }
  176. }
  177. // Evaluate.
  178. if cse.numReady > 0 {
  179. return connectivity.Ready
  180. }
  181. if cse.numConnecting > 0 {
  182. return connectivity.Connecting
  183. }
  184. return connectivity.TransientFailure
  185. }