|
@@ -29,11 +29,31 @@ import (
|
|
|
// This error is returned only when opts.BlockingWait is true.
|
|
// This error is returned only when opts.BlockingWait is true.
|
|
|
var ErrNoAddrAvilable = grpc.Errorf(codes.Unavailable, "there is no address available")
|
|
var ErrNoAddrAvilable = grpc.Errorf(codes.Unavailable, "there is no address available")
|
|
|
|
|
|
|
|
|
|
+type balancer interface {
|
|
|
|
|
+ grpc.Balancer
|
|
|
|
|
+ ConnectNotify() <-chan struct{}
|
|
|
|
|
+
|
|
|
|
|
+ endpoint(host string) string
|
|
|
|
|
+ endpoints() []string
|
|
|
|
|
+
|
|
|
|
|
+ // up is Up but includes whether the balancer will use the connection.
|
|
|
|
|
+ up(addr grpc.Address) (func(error), bool)
|
|
|
|
|
+
|
|
|
|
|
+ // updateAddrs changes the balancer's endpoints.
|
|
|
|
|
+ updateAddrs(endpoints ...string)
|
|
|
|
|
+ // ready returns a channel that closes when the balancer first connects.
|
|
|
|
|
+ ready() <-chan struct{}
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// simpleBalancer does the bare minimum to expose multiple eps
|
|
// simpleBalancer does the bare minimum to expose multiple eps
|
|
|
// to the grpc reconnection code path
|
|
// to the grpc reconnection code path
|
|
|
type simpleBalancer struct {
|
|
type simpleBalancer struct {
|
|
|
- // addrs are the client's endpoints for grpc
|
|
|
|
|
|
|
+ // addrs are the client's endpoint addresses for grpc
|
|
|
addrs []grpc.Address
|
|
addrs []grpc.Address
|
|
|
|
|
+
|
|
|
|
|
+ // eps holds the raw endpoints from the client
|
|
|
|
|
+ eps []string
|
|
|
|
|
+
|
|
|
// notifyCh notifies grpc of the set of addresses for connecting
|
|
// notifyCh notifies grpc of the set of addresses for connecting
|
|
|
notifyCh chan []grpc.Address
|
|
notifyCh chan []grpc.Address
|
|
|
|
|
|
|
@@ -73,12 +93,10 @@ type simpleBalancer struct {
|
|
|
|
|
|
|
|
func newSimpleBalancer(eps []string) *simpleBalancer {
|
|
func newSimpleBalancer(eps []string) *simpleBalancer {
|
|
|
notifyCh := make(chan []grpc.Address, 1)
|
|
notifyCh := make(chan []grpc.Address, 1)
|
|
|
- addrs := make([]grpc.Address, len(eps))
|
|
|
|
|
- for i := range eps {
|
|
|
|
|
- addrs[i].Addr = getHost(eps[i])
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ addrs := eps2addrs(eps)
|
|
|
sb := &simpleBalancer{
|
|
sb := &simpleBalancer{
|
|
|
addrs: addrs,
|
|
addrs: addrs,
|
|
|
|
|
+ eps: eps,
|
|
|
notifyCh: notifyCh,
|
|
notifyCh: notifyCh,
|
|
|
readyc: make(chan struct{}),
|
|
readyc: make(chan struct{}),
|
|
|
upc: make(chan struct{}),
|
|
upc: make(chan struct{}),
|
|
@@ -101,12 +119,20 @@ func (b *simpleBalancer) ConnectNotify() <-chan struct{} {
|
|
|
return b.upc
|
|
return b.upc
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (b *simpleBalancer) getEndpoint(host string) string {
|
|
|
|
|
|
|
+func (b *simpleBalancer) ready() <-chan struct{} { return b.readyc }
|
|
|
|
|
+
|
|
|
|
|
+func (b *simpleBalancer) endpoint(host string) string {
|
|
|
b.mu.Lock()
|
|
b.mu.Lock()
|
|
|
defer b.mu.Unlock()
|
|
defer b.mu.Unlock()
|
|
|
return b.host2ep[host]
|
|
return b.host2ep[host]
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func (b *simpleBalancer) endpoints() []string {
|
|
|
|
|
+ b.mu.RLock()
|
|
|
|
|
+ defer b.mu.RUnlock()
|
|
|
|
|
+ return b.eps
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func getHost2ep(eps []string) map[string]string {
|
|
func getHost2ep(eps []string) map[string]string {
|
|
|
hm := make(map[string]string, len(eps))
|
|
hm := make(map[string]string, len(eps))
|
|
|
for i := range eps {
|
|
for i := range eps {
|
|
@@ -116,7 +142,7 @@ func getHost2ep(eps []string) map[string]string {
|
|
|
return hm
|
|
return hm
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (b *simpleBalancer) updateAddrs(eps []string) {
|
|
|
|
|
|
|
+func (b *simpleBalancer) updateAddrs(eps ...string) {
|
|
|
np := getHost2ep(eps)
|
|
np := getHost2ep(eps)
|
|
|
|
|
|
|
|
b.mu.Lock()
|
|
b.mu.Lock()
|
|
@@ -135,17 +161,12 @@ func (b *simpleBalancer) updateAddrs(eps []string) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
b.host2ep = np
|
|
b.host2ep = np
|
|
|
-
|
|
|
|
|
- addrs := make([]grpc.Address, 0, len(eps))
|
|
|
|
|
- for i := range eps {
|
|
|
|
|
- addrs = append(addrs, grpc.Address{Addr: getHost(eps[i])})
|
|
|
|
|
- }
|
|
|
|
|
- b.addrs = addrs
|
|
|
|
|
|
|
+ b.addrs, b.eps = eps2addrs(eps), eps
|
|
|
|
|
|
|
|
// updating notifyCh can trigger new connections,
|
|
// updating notifyCh can trigger new connections,
|
|
|
// only update addrs if all connections are down
|
|
// only update addrs if all connections are down
|
|
|
// or addrs does not include pinAddr.
|
|
// or addrs does not include pinAddr.
|
|
|
- update := !hasAddr(addrs, b.pinAddr)
|
|
|
|
|
|
|
+ update := !hasAddr(b.addrs, b.pinAddr)
|
|
|
b.mu.Unlock()
|
|
b.mu.Unlock()
|
|
|
|
|
|
|
|
if update {
|
|
if update {
|
|
@@ -230,6 +251,11 @@ func (b *simpleBalancer) notifyAddrs() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (b *simpleBalancer) Up(addr grpc.Address) func(error) {
|
|
func (b *simpleBalancer) Up(addr grpc.Address) func(error) {
|
|
|
|
|
+ f, _ := b.up(addr)
|
|
|
|
|
+ return f
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (b *simpleBalancer) up(addr grpc.Address) (func(error), bool) {
|
|
|
b.mu.Lock()
|
|
b.mu.Lock()
|
|
|
defer b.mu.Unlock()
|
|
defer b.mu.Unlock()
|
|
|
|
|
|
|
@@ -237,15 +263,15 @@ func (b *simpleBalancer) Up(addr grpc.Address) func(error) {
|
|
|
// to "fix" it up at application layer. Otherwise, will panic
|
|
// to "fix" it up at application layer. Otherwise, will panic
|
|
|
// if b.upc is already closed.
|
|
// if b.upc is already closed.
|
|
|
if b.closed {
|
|
if b.closed {
|
|
|
- return func(err error) {}
|
|
|
|
|
|
|
+ return func(err error) {}, false
|
|
|
}
|
|
}
|
|
|
// gRPC might call Up on a stale address.
|
|
// gRPC might call Up on a stale address.
|
|
|
// Prevent updating pinAddr with a stale address.
|
|
// Prevent updating pinAddr with a stale address.
|
|
|
if !hasAddr(b.addrs, addr.Addr) {
|
|
if !hasAddr(b.addrs, addr.Addr) {
|
|
|
- return func(err error) {}
|
|
|
|
|
|
|
+ return func(err error) {}, false
|
|
|
}
|
|
}
|
|
|
if b.pinAddr != "" {
|
|
if b.pinAddr != "" {
|
|
|
- return func(err error) {}
|
|
|
|
|
|
|
+ return func(err error) {}, false
|
|
|
}
|
|
}
|
|
|
// notify waiting Get()s and pin first connected address
|
|
// notify waiting Get()s and pin first connected address
|
|
|
close(b.upc)
|
|
close(b.upc)
|
|
@@ -259,7 +285,7 @@ func (b *simpleBalancer) Up(addr grpc.Address) func(error) {
|
|
|
close(b.downc)
|
|
close(b.downc)
|
|
|
b.pinAddr = ""
|
|
b.pinAddr = ""
|
|
|
b.mu.Unlock()
|
|
b.mu.Unlock()
|
|
|
- }
|
|
|
|
|
|
|
+ }, true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (b *simpleBalancer) Get(ctx context.Context, opts grpc.BalancerGetOptions) (grpc.Address, func(), error) {
|
|
func (b *simpleBalancer) Get(ctx context.Context, opts grpc.BalancerGetOptions) (grpc.Address, func(), error) {
|
|
@@ -354,3 +380,11 @@ func getHost(ep string) string {
|
|
|
}
|
|
}
|
|
|
return url.Host
|
|
return url.Host
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+func eps2addrs(eps []string) []grpc.Address {
|
|
|
|
|
+ addrs := make([]grpc.Address, len(eps))
|
|
|
|
|
+ for i := range eps {
|
|
|
|
|
+ addrs[i].Addr = getHost(eps[i])
|
|
|
|
|
+ }
|
|
|
|
|
+ return addrs
|
|
|
|
|
+}
|