Add kafka and postgres clients to vendor directory

This commit is contained in:
Mark Haines 2017-02-02 18:26:18 +00:00
parent 2f965c6b33
commit a78e0cba8e
876 changed files with 73718 additions and 0 deletions

View file

@ -0,0 +1,34 @@
circuit-breaker
===============
[![Build Status](https://travis-ci.org/eapache/go-resiliency.svg?branch=master)](https://travis-ci.org/eapache/go-resiliency)
[![GoDoc](https://godoc.org/github.com/eapache/go-resiliency/breaker?status.svg)](https://godoc.org/github.com/eapache/go-resiliency/breaker)
[![Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-active-blue.svg)](https://eapache.github.io/conduct.html)
The circuit-breaker resiliency pattern for golang.
Creating a breaker takes three parameters:
- error threshold (for opening the breaker)
- success threshold (for closing the breaker)
- timeout (how long to keep the breaker open)
```go
b := breaker.New(3, 1, 5*time.Second)
for {
result := b.Run(func() error {
// communicate with some external service and
// return an error if the communication failed
return nil
})
switch result {
case nil:
// success!
case breaker.ErrBreakerOpen:
// our function wasn't run because the breaker was open
default:
// some other error
}
}
```

View file

@ -0,0 +1,161 @@
// Package breaker implements the circuit-breaker resiliency pattern for Go.
package breaker
import (
"errors"
"sync"
"sync/atomic"
"time"
)
// ErrBreakerOpen is the error returned from Run() when the function is not executed
// because the breaker is currently open.
var ErrBreakerOpen = errors.New("circuit breaker is open")
const (
closed uint32 = iota
open
halfOpen
)
// Breaker implements the circuit-breaker resiliency pattern
type Breaker struct {
errorThreshold, successThreshold int
timeout time.Duration
lock sync.Mutex
state uint32
errors, successes int
lastError time.Time
}
// New constructs a new circuit-breaker that starts closed.
// From closed, the breaker opens if "errorThreshold" errors are seen
// without an error-free period of at least "timeout". From open, the
// breaker half-closes after "timeout". From half-open, the breaker closes
// after "successThreshold" consecutive successes, or opens on a single error.
func New(errorThreshold, successThreshold int, timeout time.Duration) *Breaker {
return &Breaker{
errorThreshold: errorThreshold,
successThreshold: successThreshold,
timeout: timeout,
}
}
// Run will either return ErrBreakerOpen immediately if the circuit-breaker is
// already open, or it will run the given function and pass along its return
// value. It is safe to call Run concurrently on the same Breaker.
func (b *Breaker) Run(work func() error) error {
state := atomic.LoadUint32(&b.state)
if state == open {
return ErrBreakerOpen
}
return b.doWork(state, work)
}
// Go will either return ErrBreakerOpen immediately if the circuit-breaker is
// already open, or it will run the given function in a separate goroutine.
// If the function is run, Go will return nil immediately, and will *not* return
// the return value of the function. It is safe to call Go concurrently on the
// same Breaker.
func (b *Breaker) Go(work func() error) error {
state := atomic.LoadUint32(&b.state)
if state == open {
return ErrBreakerOpen
}
// errcheck complains about ignoring the error return value, but
// that's on purpose; if you want an error from a goroutine you have to
// get it over a channel or something
go b.doWork(state, work)
return nil
}
func (b *Breaker) doWork(state uint32, work func() error) error {
var panicValue interface{}
result := func() error {
defer func() {
panicValue = recover()
}()
return work()
}()
if result == nil && panicValue == nil && state == closed {
// short-circuit the normal, success path without contending
// on the lock
return nil
}
// oh well, I guess we have to contend on the lock
b.processResult(result, panicValue)
if panicValue != nil {
// as close as Go lets us come to a "rethrow" although unfortunately
// we lose the original panicing location
panic(panicValue)
}
return result
}
func (b *Breaker) processResult(result error, panicValue interface{}) {
b.lock.Lock()
defer b.lock.Unlock()
if result == nil && panicValue == nil {
if b.state == halfOpen {
b.successes++
if b.successes == b.successThreshold {
b.closeBreaker()
}
}
} else {
if b.errors > 0 {
expiry := b.lastError.Add(b.timeout)
if time.Now().After(expiry) {
b.errors = 0
}
}
switch b.state {
case closed:
b.errors++
if b.errors == b.errorThreshold {
b.openBreaker()
} else {
b.lastError = time.Now()
}
case halfOpen:
b.openBreaker()
}
}
}
func (b *Breaker) openBreaker() {
b.changeState(open)
go b.timer()
}
func (b *Breaker) closeBreaker() {
b.changeState(closed)
}
func (b *Breaker) timer() {
time.Sleep(b.timeout)
b.lock.Lock()
defer b.lock.Unlock()
b.changeState(halfOpen)
}
func (b *Breaker) changeState(newState uint32) {
b.errors = 0
b.successes = 0
atomic.StoreUint32(&b.state, newState)
}

View file

@ -0,0 +1,196 @@
package breaker
import (
"errors"
"testing"
"time"
)
var errSomeError = errors.New("errSomeError")
func alwaysPanics() error {
panic("foo")
}
func returnsError() error {
return errSomeError
}
func returnsSuccess() error {
return nil
}
func TestBreakerErrorExpiry(t *testing.T) {
breaker := New(2, 1, 1*time.Second)
for i := 0; i < 3; i++ {
if err := breaker.Run(returnsError); err != errSomeError {
t.Error(err)
}
time.Sleep(1 * time.Second)
}
for i := 0; i < 3; i++ {
if err := breaker.Go(returnsError); err != nil {
t.Error(err)
}
time.Sleep(1 * time.Second)
}
}
func TestBreakerPanicsCountAsErrors(t *testing.T) {
breaker := New(3, 2, 1*time.Second)
// three errors opens the breaker
for i := 0; i < 3; i++ {
func() {
defer func() {
val := recover()
if val.(string) != "foo" {
t.Error("incorrect panic")
}
}()
if err := breaker.Run(alwaysPanics); err != nil {
t.Error(err)
}
t.Error("shouldn't get here")
}()
}
// breaker is open
for i := 0; i < 5; i++ {
if err := breaker.Run(returnsError); err != ErrBreakerOpen {
t.Error(err)
}
}
}
func TestBreakerStateTransitions(t *testing.T) {
breaker := New(3, 2, 1*time.Second)
// three errors opens the breaker
for i := 0; i < 3; i++ {
if err := breaker.Run(returnsError); err != errSomeError {
t.Error(err)
}
}
// breaker is open
for i := 0; i < 5; i++ {
if err := breaker.Run(returnsError); err != ErrBreakerOpen {
t.Error(err)
}
}
// wait for it to half-close
time.Sleep(2 * time.Second)
// one success works, but is not enough to fully close
if err := breaker.Run(returnsSuccess); err != nil {
t.Error(err)
}
// error works, but re-opens immediately
if err := breaker.Run(returnsError); err != errSomeError {
t.Error(err)
}
// breaker is open
if err := breaker.Run(returnsError); err != ErrBreakerOpen {
t.Error(err)
}
// wait for it to half-close
time.Sleep(2 * time.Second)
// two successes is enough to close it for good
for i := 0; i < 2; i++ {
if err := breaker.Run(returnsSuccess); err != nil {
t.Error(err)
}
}
// error works
if err := breaker.Run(returnsError); err != errSomeError {
t.Error(err)
}
// breaker is still closed
if err := breaker.Run(returnsSuccess); err != nil {
t.Error(err)
}
}
func TestBreakerAsyncStateTransitions(t *testing.T) {
breaker := New(3, 2, 1*time.Second)
// three errors opens the breaker
for i := 0; i < 3; i++ {
if err := breaker.Go(returnsError); err != nil {
t.Error(err)
}
}
// just enough to yield the scheduler and let the goroutines work off
time.Sleep(1 * time.Millisecond)
// breaker is open
for i := 0; i < 5; i++ {
if err := breaker.Go(returnsError); err != ErrBreakerOpen {
t.Error(err)
}
}
// wait for it to half-close
time.Sleep(2 * time.Second)
// one success works, but is not enough to fully close
if err := breaker.Go(returnsSuccess); err != nil {
t.Error(err)
}
// error works, but re-opens immediately
if err := breaker.Go(returnsError); err != nil {
t.Error(err)
}
// just enough to yield the scheduler and let the goroutines work off
time.Sleep(1 * time.Millisecond)
// breaker is open
if err := breaker.Go(returnsError); err != ErrBreakerOpen {
t.Error(err)
}
// wait for it to half-close
time.Sleep(2 * time.Second)
// two successes is enough to close it for good
for i := 0; i < 2; i++ {
if err := breaker.Go(returnsSuccess); err != nil {
t.Error(err)
}
}
// just enough to yield the scheduler and let the goroutines work off
time.Sleep(1 * time.Millisecond)
// error works
if err := breaker.Go(returnsError); err != nil {
t.Error(err)
}
// just enough to yield the scheduler and let the goroutines work off
time.Sleep(1 * time.Millisecond)
// breaker is still closed
if err := breaker.Go(returnsSuccess); err != nil {
t.Error(err)
}
}
func ExampleBreaker() {
breaker := New(3, 1, 5*time.Second)
for {
result := breaker.Run(func() error {
// communicate with some external service and
// return an error if the communication failed
return nil
})
switch result {
case nil:
// success!
case ErrBreakerOpen:
// our function wasn't run because the breaker was open
default:
// some other error
}
}
}

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Evan Huus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,13 @@
# go-xerial-snappy
[![Build Status](https://travis-ci.org/eapache/go-xerial-snappy.svg?branch=master)](https://travis-ci.org/eapache/go-xerial-snappy)
Xerial-compatible Snappy framing support for golang.
Packages using Xerial for snappy encoding use a framing format incompatible with
basically everything else in existence. This package wraps Go's built-in snappy
package to support it.
Apps that use this format include Apache Kafka (see
https://github.com/dpkp/kafka-python/issues/126#issuecomment-35478921 for
details).

View file

@ -0,0 +1,43 @@
package snappy
import (
"bytes"
"encoding/binary"
master "github.com/golang/snappy"
)
var xerialHeader = []byte{130, 83, 78, 65, 80, 80, 89, 0}
// Encode encodes data as snappy with no framing header.
func Encode(src []byte) []byte {
return master.Encode(nil, src)
}
// Decode decodes snappy data whether it is traditional unframed
// or includes the xerial framing format.
func Decode(src []byte) ([]byte, error) {
if !bytes.Equal(src[:8], xerialHeader) {
return master.Decode(nil, src)
}
var (
pos = uint32(16)
max = uint32(len(src))
dst = make([]byte, 0, len(src))
chunk []byte
err error
)
for pos < max {
size := binary.BigEndian.Uint32(src[pos : pos+4])
pos += 4
chunk, err = master.Decode(chunk, src[pos:pos+size])
if err != nil {
return nil, err
}
pos += size
dst = append(dst, chunk...)
}
return dst, nil
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Evan Huus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,16 @@
Queue
=====
[![Build Status](https://travis-ci.org/eapache/queue.svg)](https://travis-ci.org/eapache/queue)
[![GoDoc](https://godoc.org/github.com/eapache/queue?status.png)](https://godoc.org/github.com/eapache/queue)
[![Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-active-blue.svg)](https://eapache.github.io/conduct.html)
A fast Golang queue using a ring-buffer, based on the version suggested by Dariusz Górecki.
Using this instead of other, simpler, queue implementations (slice+append or linked list) provides
substantial memory and time benefits, and fewer GC pauses.
The queue implemented here is as fast as it is in part because it is *not* thread-safe.
Follows semantic versioning using https://gopkg.in/ - import from
[`gopkg.in/eapache/queue.v1`](https://gopkg.in/eapache/queue.v1)
for guaranteed API stability.

View file

@ -0,0 +1,102 @@
/*
Package queue provides a fast, ring-buffer queue based on the version suggested by Dariusz Górecki.
Using this instead of other, simpler, queue implementations (slice+append or linked list) provides
substantial memory and time benefits, and fewer GC pauses.
The queue implemented here is as fast as it is for an additional reason: it is *not* thread-safe.
*/
package queue
// minQueueLen is smallest capacity that queue may have.
// Must be power of 2 for bitwise modulus: x % n == x & (n - 1).
const minQueueLen = 16
// Queue represents a single instance of the queue data structure.
type Queue struct {
buf []interface{}
head, tail, count int
}
// New constructs and returns a new Queue.
func New() *Queue {
return &Queue{
buf: make([]interface{}, minQueueLen),
}
}
// Length returns the number of elements currently stored in the queue.
func (q *Queue) Length() int {
return q.count
}
// resizes the queue to fit exactly twice its current contents
// this can result in shrinking if the queue is less than half-full
func (q *Queue) resize() {
newBuf := make([]interface{}, q.count<<1)
if q.tail > q.head {
copy(newBuf, q.buf[q.head:q.tail])
} else {
n := copy(newBuf, q.buf[q.head:])
copy(newBuf[n:], q.buf[:q.tail])
}
q.head = 0
q.tail = q.count
q.buf = newBuf
}
// Add puts an element on the end of the queue.
func (q *Queue) Add(elem interface{}) {
if q.count == len(q.buf) {
q.resize()
}
q.buf[q.tail] = elem
// bitwise modulus
q.tail = (q.tail + 1) & (len(q.buf) - 1)
q.count++
}
// Peek returns the element at the head of the queue. This call panics
// if the queue is empty.
func (q *Queue) Peek() interface{} {
if q.count <= 0 {
panic("queue: Peek() called on empty queue")
}
return q.buf[q.head]
}
// Get returns the element at index i in the queue. If the index is
// invalid, the call will panic. This method accepts both positive and
// negative index values. Index 0 refers to the first element, and
// index -1 refers to the last.
func (q *Queue) Get(i int) interface{} {
// If indexing backwards, convert to positive index.
if i < 0 {
i += q.count
}
if i < 0 || i >= q.count {
panic("queue: Get() called with index out of range")
}
// bitwise modulus
return q.buf[(q.head+i)&(len(q.buf)-1)]
}
// Remove removes and returns the element from the front of the queue. If the
// queue is empty, the call will panic.
func (q *Queue) Remove() interface{} {
if q.count <= 0 {
panic("queue: Remove() called on empty queue")
}
ret := q.buf[q.head]
q.buf[q.head] = nil
// bitwise modulus
q.head = (q.head + 1) & (len(q.buf) - 1)
q.count--
// Resize down if buffer 1/4 full.
if len(q.buf) > minQueueLen && (q.count<<2) == len(q.buf) {
q.resize()
}
return ret
}

View file

@ -0,0 +1,178 @@
package queue
import "testing"
func TestQueueSimple(t *testing.T) {
q := New()
for i := 0; i < minQueueLen; i++ {
q.Add(i)
}
for i := 0; i < minQueueLen; i++ {
if q.Peek().(int) != i {
t.Error("peek", i, "had value", q.Peek())
}
x := q.Remove()
if x != i {
t.Error("remove", i, "had value", x)
}
}
}
func TestQueueWrapping(t *testing.T) {
q := New()
for i := 0; i < minQueueLen; i++ {
q.Add(i)
}
for i := 0; i < 3; i++ {
q.Remove()
q.Add(minQueueLen + i)
}
for i := 0; i < minQueueLen; i++ {
if q.Peek().(int) != i+3 {
t.Error("peek", i, "had value", q.Peek())
}
q.Remove()
}
}
func TestQueueLength(t *testing.T) {
q := New()
if q.Length() != 0 {
t.Error("empty queue length not 0")
}
for i := 0; i < 1000; i++ {
q.Add(i)
if q.Length() != i+1 {
t.Error("adding: queue with", i, "elements has length", q.Length())
}
}
for i := 0; i < 1000; i++ {
q.Remove()
if q.Length() != 1000-i-1 {
t.Error("removing: queue with", 1000-i-i, "elements has length", q.Length())
}
}
}
func TestQueueGet(t *testing.T) {
q := New()
for i := 0; i < 1000; i++ {
q.Add(i)
for j := 0; j < q.Length(); j++ {
if q.Get(j).(int) != j {
t.Errorf("index %d doesn't contain %d", j, j)
}
}
}
}
func TestQueueGetNegative(t *testing.T) {
q := New()
for i := 0; i < 1000; i++ {
q.Add(i)
for j := 1; j <= q.Length(); j++ {
if q.Get(-j).(int) != q.Length()-j {
t.Errorf("index %d doesn't contain %d", -j, q.Length()-j)
}
}
}
}
func TestQueueGetOutOfRangePanics(t *testing.T) {
q := New()
q.Add(1)
q.Add(2)
q.Add(3)
assertPanics(t, "should panic when negative index", func() {
q.Get(-4)
})
assertPanics(t, "should panic when index greater than length", func() {
q.Get(4)
})
}
func TestQueuePeekOutOfRangePanics(t *testing.T) {
q := New()
assertPanics(t, "should panic when peeking empty queue", func() {
q.Peek()
})
q.Add(1)
q.Remove()
assertPanics(t, "should panic when peeking emptied queue", func() {
q.Peek()
})
}
func TestQueueRemoveOutOfRangePanics(t *testing.T) {
q := New()
assertPanics(t, "should panic when removing empty queue", func() {
q.Remove()
})
q.Add(1)
q.Remove()
assertPanics(t, "should panic when removing emptied queue", func() {
q.Remove()
})
}
func assertPanics(t *testing.T, name string, f func()) {
defer func() {
if r := recover(); r == nil {
t.Errorf("%s: didn't panic as expected", name)
}
}()
f()
}
// General warning: Go's benchmark utility (go test -bench .) increases the number of
// iterations until the benchmarks take a reasonable amount of time to run; memory usage
// is *NOT* considered. On my machine, these benchmarks hit around ~1GB before they've had
// enough, but if you have less than that available and start swapping, then all bets are off.
func BenchmarkQueueSerial(b *testing.B) {
q := New()
for i := 0; i < b.N; i++ {
q.Add(nil)
}
for i := 0; i < b.N; i++ {
q.Peek()
q.Remove()
}
}
func BenchmarkQueueGet(b *testing.B) {
q := New()
for i := 0; i < b.N; i++ {
q.Add(i)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
q.Get(i)
}
}
func BenchmarkQueueTickTock(b *testing.B) {
q := New()
for i := 0; i < b.N; i++ {
q.Add(nil)
q.Peek()
q.Remove()
}
}