Moved to google.golang.org/genproto/googleapis/api/annotations
Fixes #52
This commit is contained in:
		
							
								
								
									
										2
									
								
								vendor/github.com/go-kit/kit/util/conn/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/go-kit/kit/util/conn/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
// Package conn provides utilities related to connections.
 | 
			
		||||
package conn
 | 
			
		||||
							
								
								
									
										145
									
								
								vendor/github.com/go-kit/kit/util/conn/manager.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								vendor/github.com/go-kit/kit/util/conn/manager.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
package conn
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-kit/kit/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Dialer imitates net.Dial. Dialer is assumed to yield connections that are
 | 
			
		||||
// safe for use by multiple concurrent goroutines.
 | 
			
		||||
type Dialer func(network, address string) (net.Conn, error)
 | 
			
		||||
 | 
			
		||||
// AfterFunc imitates time.After.
 | 
			
		||||
type AfterFunc func(time.Duration) <-chan time.Time
 | 
			
		||||
 | 
			
		||||
// Manager manages a net.Conn.
 | 
			
		||||
//
 | 
			
		||||
// Clients provide a way to create the connection with a Dialer, network, and
 | 
			
		||||
// address. Clients should Take the connection when they want to use it, and Put
 | 
			
		||||
// back whatever error they receive from its use. When a non-nil error is Put,
 | 
			
		||||
// the connection is invalidated, and a new connection is established.
 | 
			
		||||
// Connection failures are retried after an exponential backoff.
 | 
			
		||||
type Manager struct {
 | 
			
		||||
	dialer  Dialer
 | 
			
		||||
	network string
 | 
			
		||||
	address string
 | 
			
		||||
	after   AfterFunc
 | 
			
		||||
	logger  log.Logger
 | 
			
		||||
 | 
			
		||||
	takec chan net.Conn
 | 
			
		||||
	putc  chan error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewManager returns a connection manager using the passed Dialer, network, and
 | 
			
		||||
// address. The AfterFunc is used to control exponential backoff and retries.
 | 
			
		||||
// The logger is used to log errors; pass a log.NopLogger if you don't care to
 | 
			
		||||
// receive them. For normal use, prefer NewDefaultManager.
 | 
			
		||||
func NewManager(d Dialer, network, address string, after AfterFunc, logger log.Logger) *Manager {
 | 
			
		||||
	m := &Manager{
 | 
			
		||||
		dialer:  d,
 | 
			
		||||
		network: network,
 | 
			
		||||
		address: address,
 | 
			
		||||
		after:   after,
 | 
			
		||||
		logger:  logger,
 | 
			
		||||
 | 
			
		||||
		takec: make(chan net.Conn),
 | 
			
		||||
		putc:  make(chan error),
 | 
			
		||||
	}
 | 
			
		||||
	go m.loop()
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewDefaultManager is a helper constructor, suitable for most normal use in
 | 
			
		||||
// real (non-test) code. It uses the real net.Dial and time.After functions.
 | 
			
		||||
func NewDefaultManager(network, address string, logger log.Logger) *Manager {
 | 
			
		||||
	return NewManager(net.Dial, network, address, time.After, logger)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Take yields the current connection. It may be nil.
 | 
			
		||||
func (m *Manager) Take() net.Conn {
 | 
			
		||||
	return <-m.takec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Put accepts an error that came from a previously yielded connection. If the
 | 
			
		||||
// error is non-nil, the manager will invalidate the current connection and try
 | 
			
		||||
// to reconnect, with exponential backoff. Putting a nil error is a no-op.
 | 
			
		||||
func (m *Manager) Put(err error) {
 | 
			
		||||
	m.putc <- err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write writes the passed data to the connection in a single Take/Put cycle.
 | 
			
		||||
func (m *Manager) Write(b []byte) (int, error) {
 | 
			
		||||
	conn := m.Take()
 | 
			
		||||
	if conn == nil {
 | 
			
		||||
		return 0, ErrConnectionUnavailable
 | 
			
		||||
	}
 | 
			
		||||
	n, err := conn.Write(b)
 | 
			
		||||
	defer m.Put(err)
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Manager) loop() {
 | 
			
		||||
	var (
 | 
			
		||||
		conn       = dial(m.dialer, m.network, m.address, m.logger) // may block slightly
 | 
			
		||||
		connc      = make(chan net.Conn, 1)
 | 
			
		||||
		reconnectc <-chan time.Time // initially nil
 | 
			
		||||
		backoff    = time.Second
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// If the initial dial fails, we need to trigger a reconnect via the loop
 | 
			
		||||
	// body, below. If we did this in a goroutine, we would race on the conn
 | 
			
		||||
	// variable. So we use a buffered chan instead.
 | 
			
		||||
	connc <- conn
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-reconnectc:
 | 
			
		||||
			reconnectc = nil // one-shot
 | 
			
		||||
			go func() { connc <- dial(m.dialer, m.network, m.address, m.logger) }()
 | 
			
		||||
 | 
			
		||||
		case conn = <-connc:
 | 
			
		||||
			if conn == nil {
 | 
			
		||||
				// didn't work
 | 
			
		||||
				backoff = exponential(backoff) // wait longer
 | 
			
		||||
				reconnectc = m.after(backoff)  // try again
 | 
			
		||||
			} else {
 | 
			
		||||
				// worked!
 | 
			
		||||
				backoff = time.Second // reset wait time
 | 
			
		||||
				reconnectc = nil      // no retry necessary
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case m.takec <- conn:
 | 
			
		||||
 | 
			
		||||
		case err := <-m.putc:
 | 
			
		||||
			if err != nil && conn != nil {
 | 
			
		||||
				m.logger.Log("err", err)
 | 
			
		||||
				conn = nil                            // connection is bad
 | 
			
		||||
				reconnectc = m.after(time.Nanosecond) // trigger immediately
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dial(d Dialer, network, address string, logger log.Logger) net.Conn {
 | 
			
		||||
	conn, err := d(network, address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Log("err", err)
 | 
			
		||||
		conn = nil // just to be sure
 | 
			
		||||
	}
 | 
			
		||||
	return conn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func exponential(d time.Duration) time.Duration {
 | 
			
		||||
	d *= 2
 | 
			
		||||
	if d > time.Minute {
 | 
			
		||||
		d = time.Minute
 | 
			
		||||
	}
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrConnectionUnavailable is returned by the Manager's Write method when the
 | 
			
		||||
// manager cannot yield a good connection.
 | 
			
		||||
var ErrConnectionUnavailable = errors.New("connection unavailable")
 | 
			
		||||
							
								
								
									
										159
									
								
								vendor/github.com/go-kit/kit/util/conn/manager_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								vendor/github.com/go-kit/kit/util/conn/manager_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
package conn
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-kit/kit/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestManager(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		tickc    = make(chan time.Time)
 | 
			
		||||
		after    = func(time.Duration) <-chan time.Time { return tickc }
 | 
			
		||||
		dialconn = &mockConn{}
 | 
			
		||||
		dialerr  = error(nil)
 | 
			
		||||
		dialer   = func(string, string) (net.Conn, error) { return dialconn, dialerr }
 | 
			
		||||
		mgr      = NewManager(dialer, "netw", "addr", after, log.NewNopLogger())
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// First conn should be fine.
 | 
			
		||||
	conn := mgr.Take()
 | 
			
		||||
	if conn == nil {
 | 
			
		||||
		t.Fatal("nil conn")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Write and check it went through.
 | 
			
		||||
	if _, err := conn.Write([]byte{1, 2, 3}); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if want, have := uint64(3), atomic.LoadUint64(&dialconn.wr); want != have {
 | 
			
		||||
		t.Errorf("want %d, have %d", want, have)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Put an error to kill the conn.
 | 
			
		||||
	mgr.Put(errors.New("should kill the connection"))
 | 
			
		||||
 | 
			
		||||
	// First takes should fail.
 | 
			
		||||
	for i := 0; i < 10; i++ {
 | 
			
		||||
		if conn = mgr.Take(); conn != nil {
 | 
			
		||||
			t.Fatalf("want nil conn, got real conn")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Trigger the reconnect.
 | 
			
		||||
	tickc <- time.Now()
 | 
			
		||||
 | 
			
		||||
	// The dial should eventually succeed and yield a good conn.
 | 
			
		||||
	if !within(100*time.Millisecond, func() bool {
 | 
			
		||||
		conn = mgr.Take()
 | 
			
		||||
		return conn != nil
 | 
			
		||||
	}) {
 | 
			
		||||
		t.Fatal("conn remained nil")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Write and check it went through.
 | 
			
		||||
	if _, err := conn.Write([]byte{4, 5}); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if want, have := uint64(5), atomic.LoadUint64(&dialconn.wr); want != have {
 | 
			
		||||
		t.Errorf("want %d, have %d", want, have)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Dial starts failing.
 | 
			
		||||
	dialconn, dialerr = nil, errors.New("oh noes")
 | 
			
		||||
	mgr.Put(errors.New("trigger that reconnect y'all"))
 | 
			
		||||
	if conn = mgr.Take(); conn != nil {
 | 
			
		||||
		t.Fatalf("want nil conn, got real conn")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// As many reconnects as they want.
 | 
			
		||||
	go func() {
 | 
			
		||||
		done := time.After(100 * time.Millisecond)
 | 
			
		||||
		for {
 | 
			
		||||
			select {
 | 
			
		||||
			case tickc <- time.Now():
 | 
			
		||||
			case <-done:
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// The dial should never succeed.
 | 
			
		||||
	if within(100*time.Millisecond, func() bool {
 | 
			
		||||
		conn = mgr.Take()
 | 
			
		||||
		return conn != nil
 | 
			
		||||
	}) {
 | 
			
		||||
		t.Fatal("eventually got a good conn, despite failing dialer")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIssue292(t *testing.T) {
 | 
			
		||||
	// The util/conn.Manager won't attempt to reconnect to the provided endpoint
 | 
			
		||||
	// if the endpoint is initially unavailable (e.g. dial tcp :8080:
 | 
			
		||||
	// getsockopt: connection refused). If the endpoint is up when
 | 
			
		||||
	// conn.NewManager is called and then goes down/up, it reconnects just fine.
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		tickc    = make(chan time.Time)
 | 
			
		||||
		after    = func(time.Duration) <-chan time.Time { return tickc }
 | 
			
		||||
		dialconn = net.Conn(nil)
 | 
			
		||||
		dialerr  = errors.New("fail")
 | 
			
		||||
		dialer   = func(string, string) (net.Conn, error) { return dialconn, dialerr }
 | 
			
		||||
		mgr      = NewManager(dialer, "netw", "addr", after, log.NewNopLogger())
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if conn := mgr.Take(); conn != nil {
 | 
			
		||||
		t.Fatal("first Take should have yielded nil conn, but didn't")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dialconn, dialerr = &mockConn{}, nil
 | 
			
		||||
	select {
 | 
			
		||||
	case tickc <- time.Now():
 | 
			
		||||
	case <-time.After(time.Second):
 | 
			
		||||
		t.Fatal("manager isn't listening for a tick, despite a failed dial")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !within(time.Second, func() bool {
 | 
			
		||||
		return mgr.Take() != nil
 | 
			
		||||
	}) {
 | 
			
		||||
		t.Fatal("second Take should have yielded good conn, but didn't")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type mockConn struct {
 | 
			
		||||
	rd, wr uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *mockConn) Read(b []byte) (n int, err error) {
 | 
			
		||||
	atomic.AddUint64(&c.rd, uint64(len(b)))
 | 
			
		||||
	return len(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *mockConn) Write(b []byte) (n int, err error) {
 | 
			
		||||
	atomic.AddUint64(&c.wr, uint64(len(b)))
 | 
			
		||||
	return len(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *mockConn) Close() error                       { return nil }
 | 
			
		||||
func (c *mockConn) LocalAddr() net.Addr                { return nil }
 | 
			
		||||
func (c *mockConn) RemoteAddr() net.Addr               { return nil }
 | 
			
		||||
func (c *mockConn) SetDeadline(t time.Time) error      { return nil }
 | 
			
		||||
func (c *mockConn) SetReadDeadline(t time.Time) error  { return nil }
 | 
			
		||||
func (c *mockConn) SetWriteDeadline(t time.Time) error { return nil }
 | 
			
		||||
 | 
			
		||||
func within(d time.Duration, f func() bool) bool {
 | 
			
		||||
	deadline := time.Now().Add(d)
 | 
			
		||||
	for {
 | 
			
		||||
		if time.Now().After(deadline) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		if f() {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		time.Sleep(d / 10)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user