1
0
Fork 0
telegraf/plugins/common/ratelimiter/limiters.go

67 lines
1.4 KiB
Go
Raw Permalink Normal View History

package ratelimiter
import (
"errors"
"math"
"time"
)
var (
ErrLimitExceeded = errors.New("not enough tokens")
)
type RateLimiter struct {
limit int64
period time.Duration
periodStart time.Time
remaining int64
}
func (r *RateLimiter) Remaining(t time.Time) int64 {
if r.limit == 0 {
return math.MaxInt64
}
// Check for corner case
if !r.periodStart.Before(t) {
return 0
}
// We are in a new period, so the complete size is available
deltat := t.Sub(r.periodStart)
if deltat >= r.period {
return r.limit
}
return r.remaining
}
func (r *RateLimiter) Accept(t time.Time, used int64) {
if r.limit == 0 || r.periodStart.After(t) {
return
}
// Remember the first query and reset if we are in a new period
if r.periodStart.IsZero() {
r.periodStart = t
r.remaining = r.limit
} else if deltat := t.Sub(r.periodStart); deltat >= r.period {
r.periodStart = r.periodStart.Add(deltat.Truncate(r.period))
r.remaining = r.limit
}
// Update the state
r.remaining = max(r.remaining-used, 0)
}
func (r *RateLimiter) Undo(t time.Time, used int64) {
// Do nothing if we are not in the current period or unlimited because we
// already reset the limit on a new window.
if r.limit == 0 || r.periodStart.IsZero() || r.periodStart.After(t) || t.Sub(r.periodStart) >= r.period {
return
}
// Undo the state update
r.remaining = min(r.remaining+used, r.limit)
}