Merge pull request #31396 from foxish/integer-overflow

Automatic merge from submit-queue

Fixed integer overflow bug in rate limiter.

```release-note
Fix overflow issue in controller-manager rate limiter
```

This PR fixes a bug in the delayed work-queue used by some controllers.
The integer overflow bug would previously cause hotlooping behavior after a few failures 
as `time.Duration(..)` on values larger than MaxInt64 behaves unpredictably, and 
after a certain value returns 0 always.

cc @bprashanth @pwittrock
This commit is contained in:
Kubernetes Submit Queue 2016-08-25 11:17:38 -07:00 committed by GitHub
commit c63cd8fc20
2 changed files with 41 additions and 1 deletions

View File

@ -90,9 +90,16 @@ func (r *ItemExponentialFailureRateLimiter) When(item interface{}) time.Duration
r.failuresLock.Lock()
defer r.failuresLock.Unlock()
exp := r.failures[item]
r.failures[item] = r.failures[item] + 1
calculated := r.baseDelay * time.Duration(math.Pow10(r.failures[item]-1))
// The backoff is capped such that 'calculated' value never overflows.
backoff := float64(r.baseDelay.Nanoseconds()) * math.Pow10(exp)
if backoff > math.MaxInt64 {
return r.maxDelay
}
calculated := time.Duration(backoff)
if calculated > r.maxDelay {
return r.maxDelay
}

View File

@ -63,6 +63,39 @@ func TestItemExponentialFailureRateLimiter(t *testing.T) {
}
func TestItemExponentialFailureRateLimiterOverFlow(t *testing.T) {
limiter := NewItemExponentialFailureRateLimiter(1*time.Millisecond, 1000*time.Second)
for i := 0; i < 5; i++ {
limiter.When("one")
}
if e, a := 100000*time.Millisecond, limiter.When("one"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
for i := 0; i < 1000; i++ {
limiter.When("overflow1")
}
if e, a := 1000*time.Second, limiter.When("overflow1"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
limiter = NewItemExponentialFailureRateLimiter(1*time.Minute, 1000*time.Hour)
for i := 0; i < 2; i++ {
limiter.When("two")
}
if e, a := 100*time.Minute, limiter.When("two"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
for i := 0; i < 1000; i++ {
limiter.When("overflow2")
}
if e, a := 1000*time.Hour, limiter.When("overflow2"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestItemFastSlowRateLimiter(t *testing.T) {
limiter := NewItemFastSlowRateLimiter(5*time.Millisecond, 10*time.Second, 3)