rate: the state of the limiter should not be changed when the requests failed In the following cases, the reserveN is a no-op, and the state of the limiter should not be changed: 1. n exceeds the Limiter's burst size 2. maxFutureReserve is less than the waitDuration Fixes golang/go#52584 Change-Id: I5f38afa5da696bc10178a4bd0640d92062a8b009 GitHub-Last-Rev: e408718f070679209aca64bfbc18e4297777c311 GitHub-Pull-Request: golang/time#22 Reviewed-on: https://go-review.googlesource.com/c/time/+/406154 Reviewed-by: Russ Cox <rsc@golang.org> Auto-Submit: Sameer Ajmani <sameer@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Sameer Ajmani <sameer@golang.org> Auto-Submit: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org>
diff --git a/rate/rate.go b/rate/rate.go index 8f7c29f..f0e0cf3 100644 --- a/rate/rate.go +++ b/rate/rate.go
@@ -83,7 +83,7 @@ // TokensAt returns the number of tokens available at time t. func (lim *Limiter) TokensAt(t time.Time) float64 { lim.mu.Lock() - _, _, tokens := lim.advance(t) // does not mutute lim + _, tokens := lim.advance(t) // does not mutate lim lim.mu.Unlock() return tokens } @@ -183,7 +183,7 @@ return } // advance time to now - t, _, tokens := r.lim.advance(t) + t, tokens := r.lim.advance(t) // calculate new number of tokens tokens += restoreTokens if burst := float64(r.lim.burst); tokens > burst { @@ -304,7 +304,7 @@ lim.mu.Lock() defer lim.mu.Unlock() - t, _, tokens := lim.advance(t) + t, tokens := lim.advance(t) lim.last = t lim.tokens = tokens @@ -321,7 +321,7 @@ lim.mu.Lock() defer lim.mu.Unlock() - t, _, tokens := lim.advance(t) + t, tokens := lim.advance(t) lim.last = t lim.tokens = tokens @@ -356,7 +356,7 @@ } } - t, last, tokens := lim.advance(t) + t, tokens := lim.advance(t) // Calculate the remaining number of tokens resulting from the request. tokens -= float64(n) @@ -379,15 +379,11 @@ if ok { r.tokens = n r.timeToAct = t.Add(waitDuration) - } - // Update state - if ok { + // Update state lim.last = t lim.tokens = tokens lim.lastEvent = r.timeToAct - } else { - lim.last = last } return r @@ -396,7 +392,7 @@ // advance calculates and returns an updated state for lim resulting from the passage of time. // lim is not changed. // advance requires that lim.mu is held. -func (lim *Limiter) advance(t time.Time) (newT time.Time, newLast time.Time, newTokens float64) { +func (lim *Limiter) advance(t time.Time) (newT time.Time, newTokens float64) { last := lim.last if t.Before(last) { last = t @@ -409,7 +405,7 @@ if burst := float64(lim.burst); tokens > burst { tokens = burst } - return t, last, tokens + return t, tokens } // durationFromTokens is a unit conversion function from the number of tokens to the duration
diff --git a/rate/rate_test.go b/rate/rate_test.go index d0d9149..a063e35 100644 --- a/rate/rate_test.go +++ b/rate/rate_test.go
@@ -427,6 +427,12 @@ runReserve(t, lim, request{t1, 2, t1, true}) // start at t1 runReserve(t, lim, request{t0, 1, t1, true}) // should violate Limit,Burst runReserve(t, lim, request{t2, 2, t3, true}) + // burst size is 2, so n=3 always fails, and the state of lim should not be changed + runReserve(t, lim, request{t0, 3, time.Time{}, false}) + runReserve(t, lim, request{t2, 1, t4, true}) + // the maxReserve is not enough so it fails, and the state of lim should not be changed + runReserveMax(t, lim, request{t0, 2, time.Time{}, false}, d) + runReserve(t, lim, request{t2, 1, t5, true}) } func TestReserveJumpBackCancel(t *testing.T) {