Skip to content

Commit 772484e

Browse files
leesiogopherbot
authored andcommitted
x/time/rate: correctly handle 0 limits
Decrementing the burst in the reserveN method will frequently lead to us setting the burst to 0 which makes the limiter mostly unusable. This code was originally added in https://go.dev/cl/323429 to fix #39984 but the implementation introduced a different bug. To avoid regressing to the behaviour described in #39984, pre-fill the limiter to the burst value in the constructor. Fixes #68541 Change-Id: Iab3b85d548a44fcb2d058336e5bbf11b19ea67b1 Reviewed-on: https://go-review.googlesource.com/c/time/+/600876 Reviewed-by: Sameer Ajmani <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Auto-Submit: Sameer Ajmani <[email protected]>
1 parent 5d9ef58 commit 772484e

File tree

2 files changed

+23
-14
lines changed

2 files changed

+23
-14
lines changed

rate/rate.go

+3-14
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ func (lim *Limiter) Tokens() float64 {
9999
// bursts of at most b tokens.
100100
func NewLimiter(r Limit, b int) *Limiter {
101101
return &Limiter{
102-
limit: r,
103-
burst: b,
102+
limit: r,
103+
burst: b,
104+
tokens: float64(b),
104105
}
105106
}
106107

@@ -344,18 +345,6 @@ func (lim *Limiter) reserveN(t time.Time, n int, maxFutureReserve time.Duration)
344345
tokens: n,
345346
timeToAct: t,
346347
}
347-
} else if lim.limit == 0 {
348-
var ok bool
349-
if lim.burst >= n {
350-
ok = true
351-
lim.burst -= n
352-
}
353-
return Reservation{
354-
ok: ok,
355-
lim: lim,
356-
tokens: lim.burst,
357-
timeToAct: t,
358-
}
359348
}
360349

361350
t, tokens := lim.advance(t)

rate/rate_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -618,3 +618,23 @@ func TestZeroLimit(t *testing.T) {
618618
t.Errorf("Limit(0, 1) want false when already used")
619619
}
620620
}
621+
622+
func TestSetAfterZeroLimit(t *testing.T) {
623+
lim := NewLimiter(0, 1)
624+
// The limiter should start off full, so even though our rate limit is 0, our first request
625+
// should be allowed…
626+
if !lim.Allow() {
627+
t.Errorf("Limit(0, 1) want true when first used")
628+
}
629+
// …the token bucket is not being replenished though, so the second request should not succeed
630+
if lim.Allow() {
631+
t.Errorf("Limit(0, 1) want false when already used")
632+
}
633+
634+
lim.SetLimit(10)
635+
636+
tt := makeTestTime(t)
637+
638+
// We set the limit to 10/s so expect to get another token in 100ms
639+
runWait(t, tt, lim, wait{"wait-after-set-nonzero-after-zero", context.Background(), 1, 1, true})
640+
}

0 commit comments

Comments
 (0)