Add kafka and postgres clients to vendor directory
This commit is contained in:
parent
2f965c6b33
commit
a78e0cba8e
876 changed files with 73718 additions and 0 deletions
34
vendor/src/github.com/eapache/go-resiliency/breaker/README.md
vendored
Normal file
34
vendor/src/github.com/eapache/go-resiliency/breaker/README.md
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
circuit-breaker
|
||||
===============
|
||||
|
||||
[](https://travis-ci.org/eapache/go-resiliency)
|
||||
[](https://godoc.org/github.com/eapache/go-resiliency/breaker)
|
||||
[](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
|
||||
}
|
||||
}
|
||||
```
|
||||
161
vendor/src/github.com/eapache/go-resiliency/breaker/breaker.go
vendored
Normal file
161
vendor/src/github.com/eapache/go-resiliency/breaker/breaker.go
vendored
Normal 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)
|
||||
}
|
||||
196
vendor/src/github.com/eapache/go-resiliency/breaker/breaker_test.go
vendored
Normal file
196
vendor/src/github.com/eapache/go-resiliency/breaker/breaker_test.go
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
21
vendor/src/github.com/eapache/go-xerial-snappy/LICENSE
vendored
Normal file
21
vendor/src/github.com/eapache/go-xerial-snappy/LICENSE
vendored
Normal 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.
|
||||
13
vendor/src/github.com/eapache/go-xerial-snappy/README.md
vendored
Normal file
13
vendor/src/github.com/eapache/go-xerial-snappy/README.md
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# go-xerial-snappy
|
||||
|
||||
[](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).
|
||||
43
vendor/src/github.com/eapache/go-xerial-snappy/snappy.go
vendored
Normal file
43
vendor/src/github.com/eapache/go-xerial-snappy/snappy.go
vendored
Normal 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
|
||||
}
|
||||
49
vendor/src/github.com/eapache/go-xerial-snappy/snappy_test.go
vendored
Normal file
49
vendor/src/github.com/eapache/go-xerial-snappy/snappy_test.go
vendored
Normal file
File diff suppressed because one or more lines are too long
21
vendor/src/github.com/eapache/queue/LICENSE
vendored
Normal file
21
vendor/src/github.com/eapache/queue/LICENSE
vendored
Normal 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.
|
||||
16
vendor/src/github.com/eapache/queue/README.md
vendored
Normal file
16
vendor/src/github.com/eapache/queue/README.md
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
Queue
|
||||
=====
|
||||
|
||||
[](https://travis-ci.org/eapache/queue)
|
||||
[](https://godoc.org/github.com/eapache/queue)
|
||||
[](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.
|
||||
102
vendor/src/github.com/eapache/queue/queue.go
vendored
Normal file
102
vendor/src/github.com/eapache/queue/queue.go
vendored
Normal 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
|
||||
}
|
||||
178
vendor/src/github.com/eapache/queue/queue_test.go
vendored
Normal file
178
vendor/src/github.com/eapache/queue/queue_test.go
vendored
Normal 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()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue