mirror of
https://github.com/ipfs/kubo.git
synced 2025-07-01 02:30:39 +08:00
Move backoff to gx from Godeps
License: MIT Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
This commit is contained in:
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -26,10 +26,6 @@
|
||||
"ImportPath": "github.com/camlistore/lock",
|
||||
"Rev": "ae27720f340952636b826119b58130b9c1a847a0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cenkalti/backoff",
|
||||
"Rev": "9831e1e25c874e0a0601b6dc43641071414eec7a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cheggaaa/pb",
|
||||
"Rev": "d7729fd7ec1372c15b83db39834bf842bf2d69fb"
|
||||
|
22
Godeps/_workspace/src/github.com/cenkalti/backoff/.gitignore
generated
vendored
22
Godeps/_workspace/src/github.com/cenkalti/backoff/.gitignore
generated
vendored
@ -1,22 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
2
Godeps/_workspace/src/github.com/cenkalti/backoff/.travis.yml
generated
vendored
2
Godeps/_workspace/src/github.com/cenkalti/backoff/.travis.yml
generated
vendored
@ -1,2 +0,0 @@
|
||||
language: go
|
||||
go: 1.3.3
|
20
Godeps/_workspace/src/github.com/cenkalti/backoff/LICENSE
generated
vendored
20
Godeps/_workspace/src/github.com/cenkalti/backoff/LICENSE
generated
vendored
@ -1,20 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Cenk Altı
|
||||
|
||||
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.
|
69
Godeps/_workspace/src/github.com/cenkalti/backoff/README.md
generated
vendored
69
Godeps/_workspace/src/github.com/cenkalti/backoff/README.md
generated
vendored
@ -1,69 +0,0 @@
|
||||
# backoff
|
||||
|
||||
[](https://godoc.org/github.com/cenkalti/backoff)
|
||||
[](https://travis-ci.org/cenkalti/backoff)
|
||||
|
||||
This is a Go port of the exponential backoff algorithm from
|
||||
[google-http-java-client](https://code.google.com/p/google-http-java-client/wiki/ExponentialBackoff).
|
||||
|
||||
[Exponential backoff](http://en.wikipedia.org/wiki/Exponential_backoff)
|
||||
is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
|
||||
in order to gradually find an acceptable rate.
|
||||
The retries exponentially increase and stop increasing when a certain threshold is met.
|
||||
|
||||
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/cenkalti/backoff
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
Simple retry helper that uses exponential back-off algorithm:
|
||||
|
||||
```go
|
||||
operation := func() error {
|
||||
// An operation that might fail
|
||||
}
|
||||
|
||||
err := backoff.Retry(operation, backoff.NewExponentialBackOff())
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
|
||||
// operation is successfull
|
||||
```
|
||||
|
||||
Ticker example:
|
||||
|
||||
```go
|
||||
operation := func() error {
|
||||
// An operation that may fail
|
||||
}
|
||||
|
||||
b := backoff.NewExponentialBackOff()
|
||||
ticker := backoff.NewTicker(b)
|
||||
|
||||
var err error
|
||||
|
||||
// Ticks will continue to arrive when the previous operation is still running,
|
||||
// so operations that take a while to fail could run in quick succession.
|
||||
for t = range ticker.C {
|
||||
if err = operation(); err != nil {
|
||||
log.Println(err, "will retry...")
|
||||
continue
|
||||
}
|
||||
|
||||
ticker.Stop()
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// Operation has failed.
|
||||
}
|
||||
|
||||
// Operation is successfull.
|
||||
```
|
56
Godeps/_workspace/src/github.com/cenkalti/backoff/backoff.go
generated
vendored
56
Godeps/_workspace/src/github.com/cenkalti/backoff/backoff.go
generated
vendored
@ -1,56 +0,0 @@
|
||||
// Package backoff implements backoff algorithms for retrying operations.
|
||||
//
|
||||
// Also has a Retry() helper for retrying operations that may fail.
|
||||
package backoff
|
||||
|
||||
import "time"
|
||||
|
||||
// Back-off policy when retrying an operation.
|
||||
type BackOff interface {
|
||||
// Gets the duration to wait before retrying the operation or
|
||||
// backoff.Stop to indicate that no retries should be made.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// duration := backoff.NextBackOff();
|
||||
// if (duration == backoff.Stop) {
|
||||
// // do not retry operation
|
||||
// } else {
|
||||
// // sleep for duration and retry operation
|
||||
// }
|
||||
//
|
||||
NextBackOff() time.Duration
|
||||
|
||||
// Reset to initial state.
|
||||
Reset()
|
||||
}
|
||||
|
||||
// Indicates that no more retries should be made for use in NextBackOff().
|
||||
const Stop time.Duration = -1
|
||||
|
||||
// ZeroBackOff is a fixed back-off policy whose back-off time is always zero,
|
||||
// meaning that the operation is retried immediately without waiting.
|
||||
type ZeroBackOff struct{}
|
||||
|
||||
func (b *ZeroBackOff) Reset() {}
|
||||
|
||||
func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }
|
||||
|
||||
// StopBackOff is a fixed back-off policy that always returns backoff.Stop for
|
||||
// NextBackOff(), meaning that the operation should not be retried.
|
||||
type StopBackOff struct{}
|
||||
|
||||
func (b *StopBackOff) Reset() {}
|
||||
|
||||
func (b *StopBackOff) NextBackOff() time.Duration { return Stop }
|
||||
|
||||
type ConstantBackOff struct {
|
||||
Interval time.Duration
|
||||
}
|
||||
|
||||
func (b *ConstantBackOff) Reset() {}
|
||||
func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval }
|
||||
|
||||
func NewConstantBackOff(d time.Duration) *ConstantBackOff {
|
||||
return &ConstantBackOff{Interval: d}
|
||||
}
|
28
Godeps/_workspace/src/github.com/cenkalti/backoff/backoff_test.go
generated
vendored
28
Godeps/_workspace/src/github.com/cenkalti/backoff/backoff_test.go
generated
vendored
@ -1,28 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNextBackOffMillis(t *testing.T) {
|
||||
subtestNextBackOff(t, 0, new(ZeroBackOff))
|
||||
subtestNextBackOff(t, Stop, new(StopBackOff))
|
||||
}
|
||||
|
||||
func subtestNextBackOff(t *testing.T, expectedValue time.Duration, backOffPolicy BackOff) {
|
||||
for i := 0; i < 10; i++ {
|
||||
next := backOffPolicy.NextBackOff()
|
||||
if next != expectedValue {
|
||||
t.Errorf("got: %d expected: %d", next, expectedValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstantBackOff(t *testing.T) {
|
||||
backoff := NewConstantBackOff(time.Second)
|
||||
if backoff.NextBackOff() != time.Second {
|
||||
t.Error("invalid interval")
|
||||
}
|
||||
}
|
141
Godeps/_workspace/src/github.com/cenkalti/backoff/exponential.go
generated
vendored
141
Godeps/_workspace/src/github.com/cenkalti/backoff/exponential.go
generated
vendored
@ -1,141 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
ExponentialBackOff is an implementation of BackOff that increases the back off
|
||||
period for each retry attempt using a randomization function that grows exponentially.
|
||||
|
||||
NextBackOff() is calculated using the following formula:
|
||||
|
||||
randomized_interval =
|
||||
retry_interval * (random value in range [1 - randomization_factor, 1 + randomization_factor])
|
||||
|
||||
In other words NextBackOff() will range between the randomization factor
|
||||
percentage below and above the retry interval. For example, using 2 seconds as the base retry
|
||||
interval and 0.5 as the randomization factor, the actual back off period used in the next retry
|
||||
attempt will be between 1 and 3 seconds.
|
||||
|
||||
NOTE: max_interval caps the retry_interval and not the randomized_interval.
|
||||
|
||||
If the time elapsed since an ExponentialBackOff instance is created goes past the
|
||||
max_elapsed_time then the method NextBackOff() starts returning backoff.Stop.
|
||||
The elapsed time can be reset by calling Reset().
|
||||
|
||||
EXAMPLE: The default retry_interval is .5 seconds, default randomization_factor is 0.5, default
|
||||
multiplier is 1.5 and the default max_interval is 1 minute. For 10 tries the sequence will be
|
||||
(values in seconds) and assuming we go over the max_elapsed_time on the 10th try:
|
||||
|
||||
request# retry_interval randomized_interval
|
||||
|
||||
1 0.5 [0.25, 0.75]
|
||||
2 0.75 [0.375, 1.125]
|
||||
3 1.125 [0.562, 1.687]
|
||||
4 1.687 [0.8435, 2.53]
|
||||
5 2.53 [1.265, 3.795]
|
||||
6 3.795 [1.897, 5.692]
|
||||
7 5.692 [2.846, 8.538]
|
||||
8 8.538 [4.269, 12.807]
|
||||
9 12.807 [6.403, 19.210]
|
||||
10 19.210 backoff.Stop
|
||||
|
||||
Implementation is not thread-safe.
|
||||
*/
|
||||
type ExponentialBackOff struct {
|
||||
InitialInterval time.Duration
|
||||
RandomizationFactor float64
|
||||
Multiplier float64
|
||||
MaxInterval time.Duration
|
||||
// After MaxElapsedTime the ExponentialBackOff stops.
|
||||
// It never stops if MaxElapsedTime == 0.
|
||||
MaxElapsedTime time.Duration
|
||||
Clock Clock
|
||||
|
||||
currentInterval time.Duration
|
||||
startTime time.Time
|
||||
}
|
||||
|
||||
// Clock is an interface that returns current time for BackOff.
|
||||
type Clock interface {
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
// Default values for ExponentialBackOff.
|
||||
const (
|
||||
DefaultInitialInterval = 500 * time.Millisecond
|
||||
DefaultRandomizationFactor = 0.5
|
||||
DefaultMultiplier = 1.5
|
||||
DefaultMaxInterval = 60 * time.Second
|
||||
DefaultMaxElapsedTime = 15 * time.Minute
|
||||
)
|
||||
|
||||
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
||||
func NewExponentialBackOff() *ExponentialBackOff {
|
||||
return &ExponentialBackOff{
|
||||
InitialInterval: DefaultInitialInterval,
|
||||
RandomizationFactor: DefaultRandomizationFactor,
|
||||
Multiplier: DefaultMultiplier,
|
||||
MaxInterval: DefaultMaxInterval,
|
||||
MaxElapsedTime: DefaultMaxElapsedTime,
|
||||
Clock: SystemClock,
|
||||
}
|
||||
}
|
||||
|
||||
type systemClock struct{}
|
||||
|
||||
func (t systemClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// SystemClock implements Clock interface that uses time.Now().
|
||||
var SystemClock = systemClock{}
|
||||
|
||||
// Reset the interval back to the initial retry interval and restarts the timer.
|
||||
func (b *ExponentialBackOff) Reset() {
|
||||
b.currentInterval = b.InitialInterval
|
||||
b.startTime = b.Clock.Now()
|
||||
}
|
||||
|
||||
// NextBackOff calculates the next back off interval using the formula:
|
||||
// randomized_interval = retry_interval +/- (randomization_factor * retry_interval)
|
||||
func (b *ExponentialBackOff) NextBackOff() time.Duration {
|
||||
// Make sure we have not gone over the maximum elapsed time.
|
||||
if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime {
|
||||
return Stop
|
||||
}
|
||||
defer b.incrementCurrentInterval()
|
||||
return getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
|
||||
}
|
||||
|
||||
// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
|
||||
// is created and is reset when Reset() is called.
|
||||
//
|
||||
// The elapsed time is computed using time.Now().UnixNano().
|
||||
func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
|
||||
return b.Clock.Now().Sub(b.startTime)
|
||||
}
|
||||
|
||||
// Increments the current interval by multiplying it with the multiplier.
|
||||
func (b *ExponentialBackOff) incrementCurrentInterval() {
|
||||
// Check for overflow, if overflow is detected set the current interval to the max interval.
|
||||
if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
|
||||
b.currentInterval = b.MaxInterval
|
||||
} else {
|
||||
b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a random value from the interval:
|
||||
// [randomizationFactor * currentInterval, randomizationFactor * currentInterval].
|
||||
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
|
||||
var delta = randomizationFactor * float64(currentInterval)
|
||||
var minInterval = float64(currentInterval) - delta
|
||||
var maxInterval = float64(currentInterval) + delta
|
||||
// Get a random value from the range [minInterval, maxInterval].
|
||||
// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
|
||||
// we want a 33% chance for selecting either 1, 2 or 3.
|
||||
return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
|
||||
}
|
111
Godeps/_workspace/src/github.com/cenkalti/backoff/exponential_test.go
generated
vendored
111
Godeps/_workspace/src/github.com/cenkalti/backoff/exponential_test.go
generated
vendored
@ -1,111 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBackOff(t *testing.T) {
|
||||
var (
|
||||
testInitialInterval = 500 * time.Millisecond
|
||||
testRandomizationFactor = 0.1
|
||||
testMultiplier = 2.0
|
||||
testMaxInterval = 5 * time.Second
|
||||
testMaxElapsedTime = 15 * time.Minute
|
||||
)
|
||||
|
||||
exp := NewExponentialBackOff()
|
||||
exp.InitialInterval = testInitialInterval
|
||||
exp.RandomizationFactor = testRandomizationFactor
|
||||
exp.Multiplier = testMultiplier
|
||||
exp.MaxInterval = testMaxInterval
|
||||
exp.MaxElapsedTime = testMaxElapsedTime
|
||||
exp.Reset()
|
||||
|
||||
var expectedResults = []time.Duration{500, 1000, 2000, 4000, 5000, 5000, 5000, 5000, 5000, 5000}
|
||||
for i, d := range expectedResults {
|
||||
expectedResults[i] = d * time.Millisecond
|
||||
}
|
||||
|
||||
for _, expected := range expectedResults {
|
||||
assertEquals(t, expected, exp.currentInterval)
|
||||
// Assert that the next back off falls in the expected range.
|
||||
var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected))
|
||||
var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected))
|
||||
var actualInterval = exp.NextBackOff()
|
||||
if !(minInterval <= actualInterval && actualInterval <= maxInterval) {
|
||||
t.Error("error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRandomizedInterval(t *testing.T) {
|
||||
// 33% chance of being 1.
|
||||
assertEquals(t, 1, getRandomValueFromInterval(0.5, 0, 2))
|
||||
assertEquals(t, 1, getRandomValueFromInterval(0.5, 0.33, 2))
|
||||
// 33% chance of being 2.
|
||||
assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.34, 2))
|
||||
assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.66, 2))
|
||||
// 33% chance of being 3.
|
||||
assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.67, 2))
|
||||
assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.99, 2))
|
||||
}
|
||||
|
||||
type TestClock struct {
|
||||
i time.Duration
|
||||
start time.Time
|
||||
}
|
||||
|
||||
func (c *TestClock) Now() time.Time {
|
||||
t := c.start.Add(c.i)
|
||||
c.i += time.Second
|
||||
return t
|
||||
}
|
||||
|
||||
func TestGetElapsedTime(t *testing.T) {
|
||||
var exp = NewExponentialBackOff()
|
||||
exp.Clock = &TestClock{}
|
||||
exp.Reset()
|
||||
|
||||
var elapsedTime = exp.GetElapsedTime()
|
||||
if elapsedTime != time.Second {
|
||||
t.Errorf("elapsedTime=%d", elapsedTime)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxElapsedTime(t *testing.T) {
|
||||
var exp = NewExponentialBackOff()
|
||||
exp.Clock = &TestClock{start: time.Time{}.Add(10000 * time.Second)}
|
||||
if exp.NextBackOff() != Stop {
|
||||
t.Error("error2")
|
||||
}
|
||||
// Change the currentElapsedTime to be 0 ensuring that the elapsed time will be greater
|
||||
// than the max elapsed time.
|
||||
exp.startTime = time.Time{}
|
||||
assertEquals(t, Stop, exp.NextBackOff())
|
||||
}
|
||||
|
||||
func TestBackOffOverflow(t *testing.T) {
|
||||
var (
|
||||
testInitialInterval time.Duration = math.MaxInt64 / 2
|
||||
testMaxInterval time.Duration = math.MaxInt64
|
||||
testMultiplier float64 = 2.1
|
||||
)
|
||||
|
||||
exp := NewExponentialBackOff()
|
||||
exp.InitialInterval = testInitialInterval
|
||||
exp.Multiplier = testMultiplier
|
||||
exp.MaxInterval = testMaxInterval
|
||||
exp.Reset()
|
||||
|
||||
exp.NextBackOff()
|
||||
// Assert that when an overflow is possible the current varerval time.Duration is set to the max varerval time.Duration .
|
||||
assertEquals(t, testMaxInterval, exp.currentInterval)
|
||||
}
|
||||
|
||||
func assertEquals(t *testing.T, expected, value time.Duration) {
|
||||
if expected != value {
|
||||
t.Errorf("got: %d, expected: %d", value, expected)
|
||||
}
|
||||
}
|
47
Godeps/_workspace/src/github.com/cenkalti/backoff/retry.go
generated
vendored
47
Godeps/_workspace/src/github.com/cenkalti/backoff/retry.go
generated
vendored
@ -1,47 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import "time"
|
||||
|
||||
// Retry the function f until it does not return error or BackOff stops.
|
||||
// f is guaranteed to be run at least once.
|
||||
// It is the caller's responsibility to reset b after Retry returns.
|
||||
//
|
||||
// Retry sleeps the goroutine for the duration returned by BackOff after a
|
||||
// failed operation returns.
|
||||
//
|
||||
// Usage:
|
||||
// operation := func() error {
|
||||
// // An operation that may fail
|
||||
// }
|
||||
//
|
||||
// err := backoff.Retry(operation, backoff.NewExponentialBackOff())
|
||||
// if err != nil {
|
||||
// // Operation has failed.
|
||||
// }
|
||||
//
|
||||
// // Operation is successfull.
|
||||
//
|
||||
func Retry(f func() error, b BackOff) error { return RetryNotify(f, b, nil) }
|
||||
|
||||
// RetryNotify calls notify function with the error and wait duration for each failed attempt before sleep.
|
||||
func RetryNotify(f func() error, b BackOff, notify func(err error, wait time.Duration)) error {
|
||||
var err error
|
||||
var next time.Duration
|
||||
|
||||
b.Reset()
|
||||
for {
|
||||
if err = f(); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if next = b.NextBackOff(); next == Stop {
|
||||
return err
|
||||
}
|
||||
|
||||
if notify != nil {
|
||||
notify(err, next)
|
||||
}
|
||||
|
||||
time.Sleep(next)
|
||||
}
|
||||
}
|
34
Godeps/_workspace/src/github.com/cenkalti/backoff/retry_test.go
generated
vendored
34
Godeps/_workspace/src/github.com/cenkalti/backoff/retry_test.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRetry(t *testing.T) {
|
||||
const successOn = 3
|
||||
var i = 0
|
||||
|
||||
// This function is successfull on "successOn" calls.
|
||||
f := func() error {
|
||||
i++
|
||||
log.Printf("function is called %d. time\n", i)
|
||||
|
||||
if i == successOn {
|
||||
log.Println("OK")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Println("error")
|
||||
return errors.New("error")
|
||||
}
|
||||
|
||||
err := Retry(f, NewExponentialBackOff())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %s", err.Error())
|
||||
}
|
||||
if i != successOn {
|
||||
t.Errorf("invalid number of retries: %d", i)
|
||||
}
|
||||
}
|
105
Godeps/_workspace/src/github.com/cenkalti/backoff/ticker.go
generated
vendored
105
Godeps/_workspace/src/github.com/cenkalti/backoff/ticker.go
generated
vendored
@ -1,105 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff.
|
||||
//
|
||||
// Ticks will continue to arrive when the previous operation is still running,
|
||||
// so operations that take a while to fail could run in quick succession.
|
||||
//
|
||||
// Usage:
|
||||
// operation := func() error {
|
||||
// // An operation that may fail
|
||||
// }
|
||||
//
|
||||
// b := backoff.NewExponentialBackOff()
|
||||
// ticker := backoff.NewTicker(b)
|
||||
//
|
||||
// var err error
|
||||
// for _ = range ticker.C {
|
||||
// if err = operation(); err != nil {
|
||||
// log.Println(err, "will retry...")
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// ticker.Stop()
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// // Operation has failed.
|
||||
// }
|
||||
//
|
||||
// // Operation is successfull.
|
||||
//
|
||||
type Ticker struct {
|
||||
C <-chan time.Time
|
||||
c chan time.Time
|
||||
b BackOff
|
||||
stop chan struct{}
|
||||
stopOnce sync.Once
|
||||
}
|
||||
|
||||
// NewTicker returns a new Ticker containing a channel that will send the time at times
|
||||
// specified by the BackOff argument. Ticker is guaranteed to tick at least once.
|
||||
// The channel is closed when Stop method is called or BackOff stops.
|
||||
func NewTicker(b BackOff) *Ticker {
|
||||
c := make(chan time.Time)
|
||||
t := &Ticker{
|
||||
C: c,
|
||||
c: c,
|
||||
b: b,
|
||||
stop: make(chan struct{}),
|
||||
}
|
||||
go t.run()
|
||||
runtime.SetFinalizer(t, (*Ticker).Stop)
|
||||
return t
|
||||
}
|
||||
|
||||
// Stop turns off a ticker. After Stop, no more ticks will be sent.
|
||||
func (t *Ticker) Stop() {
|
||||
t.stopOnce.Do(func() { close(t.stop) })
|
||||
}
|
||||
|
||||
func (t *Ticker) run() {
|
||||
c := t.c
|
||||
defer close(c)
|
||||
t.b.Reset()
|
||||
|
||||
// Ticker is guaranteed to tick at least once.
|
||||
afterC := t.send(time.Now())
|
||||
|
||||
for {
|
||||
if afterC == nil {
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case tick := <-afterC:
|
||||
afterC = t.send(tick)
|
||||
case <-t.stop:
|
||||
t.c = nil // Prevent future ticks from being sent to the channel.
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Ticker) send(tick time.Time) <-chan time.Time {
|
||||
select {
|
||||
case t.c <- tick:
|
||||
case <-t.stop:
|
||||
return nil
|
||||
}
|
||||
|
||||
next := t.b.NextBackOff()
|
||||
if next == Stop {
|
||||
t.Stop()
|
||||
return nil
|
||||
}
|
||||
|
||||
return time.After(next)
|
||||
}
|
45
Godeps/_workspace/src/github.com/cenkalti/backoff/ticker_test.go
generated
vendored
45
Godeps/_workspace/src/github.com/cenkalti/backoff/ticker_test.go
generated
vendored
@ -1,45 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTicker(t *testing.T) {
|
||||
const successOn = 3
|
||||
var i = 0
|
||||
|
||||
// This function is successfull on "successOn" calls.
|
||||
f := func() error {
|
||||
i++
|
||||
log.Printf("function is called %d. time\n", i)
|
||||
|
||||
if i == successOn {
|
||||
log.Println("OK")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Println("error")
|
||||
return errors.New("error")
|
||||
}
|
||||
|
||||
b := NewExponentialBackOff()
|
||||
ticker := NewTicker(b)
|
||||
|
||||
var err error
|
||||
for _ = range ticker.C {
|
||||
if err = f(); err != nil {
|
||||
t.Log(err)
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %s", err.Error())
|
||||
}
|
||||
if i != successOn {
|
||||
t.Errorf("invalid number of retries: %d", i)
|
||||
}
|
||||
}
|
@ -4,9 +4,9 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
backoff "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cenkalti/backoff"
|
||||
blocks "github.com/ipfs/go-ipfs/blocks/blockstore"
|
||||
routing "github.com/ipfs/go-ipfs/routing"
|
||||
backoff "gx/ipfs/QmPJUtEJsm5YLUWhF6imvyCH8KZXRJa9Wup7FDMwTy5Ufz/backoff"
|
||||
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
|
||||
logging "gx/ipfs/QmaDNZ4QMdBdku1YZWBysufYyoQt1negQGNav6PLYarbY8/go-log"
|
||||
)
|
||||
|
@ -81,6 +81,12 @@
|
||||
"hash": "QmeWQMDa5dSdP4n8WDeoY5z8L2EKVqF4ZvK4VEHsLqXsGu",
|
||||
"name": "hamming",
|
||||
"version": "0.0.10"
|
||||
},
|
||||
{
|
||||
"author": "cenk",
|
||||
"hash": "QmPJUtEJsm5YLUWhF6imvyCH8KZXRJa9Wup7FDMwTy5Ufz",
|
||||
"name": "backoff",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"gxVersion": "0.4.0",
|
||||
|
Reference in New Issue
Block a user