github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/internal/rate/rate.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package rate provides a rate limiter.
     6  package rate // import "github.com/petermattis/pebble/internal/rate"
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  	"math"
    12  	"sync"
    13  	"time"
    14  )
    15  
    16  // Limit defines the maximum frequency of some events.
    17  // Limit is represented as number of events per second.
    18  // A zero Limit allows no events.
    19  type Limit float64
    20  
    21  // Inf is the infinite rate limit; it allows all events (even if burst is zero).
    22  const Inf = Limit(math.MaxFloat64)
    23  
    24  // Every converts a minimum time interval between events to a Limit.
    25  func Every(interval time.Duration) Limit {
    26  	if interval <= 0 {
    27  		return Inf
    28  	}
    29  	return 1 / Limit(interval.Seconds())
    30  }
    31  
    32  // A Limiter controls how frequently events are allowed to happen.
    33  // It implements a "token bucket" of size b, initially full and refilled
    34  // at rate r tokens per second.
    35  // Informally, in any large enough time interval, the Limiter limits the
    36  // rate to r tokens per second, with a maximum burst size of b events.
    37  // As a special case, if r == Inf (the infinite rate), b is ignored.
    38  // See https://en.wikipedia.org/wiki/Token_bucket for more about token buckets.
    39  //
    40  // The zero value is a valid Limiter, but it will reject all events.
    41  // Use NewLimiter to create non-zero Limiters.
    42  //
    43  // Limiter has three main methods, Allow, Reserve, and Wait.
    44  // Most callers should use Wait.
    45  //
    46  // Each of the three methods consumes a single token.
    47  // They differ in their behavior when no token is available.
    48  // If no token is available, Allow returns false.
    49  // If no token is available, Reserve returns a reservation for a future token
    50  // and the amount of time the caller must wait before using it.
    51  // If no token is available, Wait blocks until one can be obtained
    52  // or its associated context.Context is canceled.
    53  //
    54  // The methods AllowN, ReserveN, and WaitN consume n tokens.
    55  type Limiter struct {
    56  	limit Limit
    57  	burst int
    58  
    59  	mu     sync.Mutex
    60  	tokens float64
    61  	// last is the last time the limiter's tokens field was updated
    62  	last time.Time
    63  	// lastEvent is the latest time of a rate-limited event (past or future)
    64  	lastEvent time.Time
    65  }
    66  
    67  // Limit returns the maximum overall event rate.
    68  func (lim *Limiter) Limit() Limit {
    69  	lim.mu.Lock()
    70  	defer lim.mu.Unlock()
    71  	return lim.limit
    72  }
    73  
    74  // Burst returns the maximum burst size. Burst is the maximum number of tokens
    75  // that can be consumed in a single call to Allow, Reserve, or Wait, so higher
    76  // Burst values allow more events to happen at once.
    77  // A zero Burst allows no events, unless limit == Inf.
    78  func (lim *Limiter) Burst() int {
    79  	return lim.burst
    80  }
    81  
    82  // NewLimiter returns a new Limiter that allows events up to rate r and permits
    83  // bursts of at most b tokens.
    84  func NewLimiter(r Limit, b int) *Limiter {
    85  	return &Limiter{
    86  		limit: r,
    87  		burst: b,
    88  	}
    89  }
    90  
    91  // Allow is shorthand for AllowN(time.Now(), 1).
    92  func (lim *Limiter) Allow() bool {
    93  	return lim.AllowN(time.Now(), 1)
    94  }
    95  
    96  // AllowN reports whether n events may happen at time now.
    97  // Use this method if you intend to drop / skip events that exceed the rate limit.
    98  // Otherwise use Reserve or Wait.
    99  func (lim *Limiter) AllowN(now time.Time, n int) bool {
   100  	return lim.reserveN(now, n, 0).ok
   101  }
   102  
   103  // A Reservation holds information about events that are permitted by a Limiter to happen after a delay.
   104  // A Reservation may be canceled, which may enable the Limiter to permit additional events.
   105  type Reservation struct {
   106  	ok        bool
   107  	lim       *Limiter
   108  	tokens    int
   109  	timeToAct time.Time
   110  	// This is the Limit at reservation time, it can change later.
   111  	limit Limit
   112  }
   113  
   114  // OK returns whether the limiter can provide the requested number of tokens
   115  // within the maximum wait time.  If OK is false, Delay returns InfDuration, and
   116  // Cancel does nothing.
   117  func (r *Reservation) OK() bool {
   118  	return r.ok
   119  }
   120  
   121  // Delay is shorthand for DelayFrom(time.Now()).
   122  func (r *Reservation) Delay() time.Duration {
   123  	return r.DelayFrom(time.Now())
   124  }
   125  
   126  // InfDuration is the duration returned by Delay when a Reservation is not OK.
   127  const InfDuration = time.Duration(1<<63 - 1)
   128  
   129  // DelayFrom returns the duration for which the reservation holder must wait
   130  // before taking the reserved action.  Zero duration means act immediately.
   131  // InfDuration means the limiter cannot grant the tokens requested in this
   132  // Reservation within the maximum wait time.
   133  func (r *Reservation) DelayFrom(now time.Time) time.Duration {
   134  	if !r.ok {
   135  		return InfDuration
   136  	}
   137  	delay := r.timeToAct.Sub(now)
   138  	if delay < 0 {
   139  		return 0
   140  	}
   141  	return delay
   142  }
   143  
   144  // Cancel is shorthand for CancelAt(time.Now()).
   145  func (r *Reservation) Cancel() {
   146  	r.CancelAt(time.Now())
   147  }
   148  
   149  // CancelAt indicates that the reservation holder will not perform the reserved action
   150  // and reverses the effects of this Reservation on the rate limit as much as possible,
   151  // considering that other reservations may have already been made.
   152  func (r *Reservation) CancelAt(now time.Time) {
   153  	if !r.ok {
   154  		return
   155  	}
   156  
   157  	r.lim.mu.Lock()
   158  	defer r.lim.mu.Unlock()
   159  
   160  	if r.lim.limit == Inf || r.tokens == 0 || r.timeToAct.Before(now) {
   161  		return
   162  	}
   163  
   164  	// calculate tokens to restore
   165  	// The duration between lim.lastEvent and r.timeToAct tells us how many tokens were reserved
   166  	// after r was obtained. These tokens should not be restored.
   167  	restoreTokens := float64(r.tokens) - r.limit.tokensFromDuration(r.lim.lastEvent.Sub(r.timeToAct))
   168  	if restoreTokens <= 0 {
   169  		return
   170  	}
   171  	// advance time to now
   172  	now, _, tokens := r.lim.advance(now)
   173  	// calculate new number of tokens
   174  	tokens += restoreTokens
   175  	if burst := float64(r.lim.burst); tokens > burst {
   176  		tokens = burst
   177  	}
   178  	// update state
   179  	r.lim.last = now
   180  	r.lim.tokens = tokens
   181  	if r.timeToAct == r.lim.lastEvent {
   182  		prevEvent := r.timeToAct.Add(r.limit.durationFromTokens(float64(-r.tokens)))
   183  		if !prevEvent.Before(now) {
   184  			r.lim.lastEvent = prevEvent
   185  		}
   186  	}
   187  }
   188  
   189  // Reserve is shorthand for ReserveN(time.Now(), 1).
   190  func (lim *Limiter) Reserve() *Reservation {
   191  	return lim.ReserveN(time.Now(), 1)
   192  }
   193  
   194  // ReserveN returns a Reservation that indicates how long the caller must wait before n events happen.
   195  // The Limiter takes this Reservation into account when allowing future events.
   196  // ReserveN returns false if n exceeds the Limiter's burst size.
   197  // Usage example:
   198  //   r := lim.ReserveN(time.Now(), 1)
   199  //   if !r.OK() {
   200  //     // Not allowed to act! Did you remember to set lim.burst to be > 0 ?
   201  //     return
   202  //   }
   203  //   time.Sleep(r.Delay())
   204  //   Act()
   205  // Use this method if you wish to wait and slow down in accordance with the rate limit without dropping events.
   206  // If you need to respect a deadline or cancel the delay, use Wait instead.
   207  // To drop or skip events exceeding rate limit, use Allow instead.
   208  func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation {
   209  	r := lim.reserveN(now, n, InfDuration)
   210  	return &r
   211  }
   212  
   213  // Wait is shorthand for WaitN(ctx, 1).
   214  func (lim *Limiter) Wait(ctx context.Context) (err error) {
   215  	return lim.WaitN(ctx, 1)
   216  }
   217  
   218  // WaitN blocks until lim permits n events to happen.
   219  // It returns an error if n exceeds the Limiter's burst size, the Context is
   220  // canceled, or the expected wait time exceeds the Context's Deadline.
   221  func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {
   222  	if n > lim.burst && lim.limit != Inf {
   223  		return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, lim.burst)
   224  	}
   225  	// Check if ctx is already cancelled
   226  	select {
   227  	case <-ctx.Done():
   228  		return ctx.Err()
   229  	default:
   230  	}
   231  	// Determine wait limit
   232  	now := time.Now()
   233  	waitLimit := InfDuration
   234  	if deadline, ok := ctx.Deadline(); ok {
   235  		waitLimit = deadline.Sub(now)
   236  	}
   237  	// Reserve
   238  	r := lim.reserveN(now, n, waitLimit)
   239  	if !r.ok {
   240  		return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", n)
   241  	}
   242  	// Wait
   243  	d := r.DelayFrom(now)
   244  	if d <= 0 {
   245  		return nil
   246  	}
   247  	t := time.NewTimer(d)
   248  	defer t.Stop()
   249  	select {
   250  	case <-t.C:
   251  		// We can proceed.
   252  		return nil
   253  	case <-ctx.Done():
   254  		// Context was canceled before we could proceed.  Cancel the
   255  		// reservation, which may permit other events to proceed sooner.
   256  		r.Cancel()
   257  		return ctx.Err()
   258  	}
   259  }
   260  
   261  // SetLimit is shorthand for SetLimitAt(time.Now(), newLimit).
   262  func (lim *Limiter) SetLimit(newLimit Limit) {
   263  	lim.SetLimitAt(time.Now(), newLimit)
   264  }
   265  
   266  // SetLimitAt sets a new Limit for the limiter. The new Limit, and Burst, may be violated
   267  // or underutilized by those which reserved (using Reserve or Wait) but did not yet act
   268  // before SetLimitAt was called.
   269  func (lim *Limiter) SetLimitAt(now time.Time, newLimit Limit) {
   270  	lim.mu.Lock()
   271  	defer lim.mu.Unlock()
   272  
   273  	now, _, tokens := lim.advance(now)
   274  
   275  	lim.last = now
   276  	lim.tokens = tokens
   277  	lim.limit = newLimit
   278  }
   279  
   280  // reserveN is a helper method for AllowN, ReserveN, and WaitN.
   281  // maxFutureReserve specifies the maximum reservation wait duration allowed.
   282  // reserveN returns Reservation, not *Reservation, to avoid allocation in AllowN and WaitN.
   283  func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duration) Reservation {
   284  	lim.mu.Lock()
   285  
   286  	if lim.limit == Inf {
   287  		lim.mu.Unlock()
   288  		return Reservation{
   289  			ok:        true,
   290  			lim:       lim,
   291  			tokens:    n,
   292  			timeToAct: now,
   293  		}
   294  	}
   295  
   296  	now, last, tokens := lim.advance(now)
   297  
   298  	// Calculate the remaining number of tokens resulting from the request.
   299  	tokens -= float64(n)
   300  
   301  	// Calculate the wait duration
   302  	var waitDuration time.Duration
   303  	if tokens < 0 {
   304  		waitDuration = lim.limit.durationFromTokens(-tokens)
   305  	}
   306  
   307  	// Decide result
   308  	ok := n <= lim.burst && waitDuration <= maxFutureReserve
   309  
   310  	// Prepare reservation
   311  	r := Reservation{
   312  		ok:    ok,
   313  		lim:   lim,
   314  		limit: lim.limit,
   315  	}
   316  	if ok {
   317  		r.tokens = n
   318  		r.timeToAct = now.Add(waitDuration)
   319  	}
   320  
   321  	// Update state
   322  	if ok {
   323  		lim.last = now
   324  		lim.tokens = tokens
   325  		lim.lastEvent = r.timeToAct
   326  	} else {
   327  		lim.last = last
   328  	}
   329  
   330  	lim.mu.Unlock()
   331  	return r
   332  }
   333  
   334  // advance calculates and returns an updated state for lim resulting from the passage of time.
   335  // lim is not changed.
   336  func (lim *Limiter) advance(now time.Time) (newNow time.Time, newLast time.Time, newTokens float64) {
   337  	last := lim.last
   338  	if now.Before(last) {
   339  		last = now
   340  	}
   341  
   342  	// Avoid making delta overflow below when last is very old.
   343  	maxElapsed := lim.limit.durationFromTokens(float64(lim.burst) - lim.tokens)
   344  	elapsed := now.Sub(last)
   345  	if elapsed > maxElapsed {
   346  		elapsed = maxElapsed
   347  	}
   348  
   349  	// Calculate the new number of tokens, due to time that passed.
   350  	delta := lim.limit.tokensFromDuration(elapsed)
   351  	tokens := lim.tokens + delta
   352  	if burst := float64(lim.burst); tokens > burst {
   353  		tokens = burst
   354  	}
   355  
   356  	return now, last, tokens
   357  }
   358  
   359  // durationFromTokens is a unit conversion function from the number of tokens to the duration
   360  // of time it takes to accumulate them at a rate of limit tokens per second.
   361  func (limit Limit) durationFromTokens(tokens float64) time.Duration {
   362  	seconds := tokens / float64(limit)
   363  	return time.Nanosecond * time.Duration(1e9*seconds)
   364  }
   365  
   366  // tokensFromDuration is a unit conversion function from a time duration to the number of tokens
   367  // which could be accumulated during that duration at a rate of limit tokens per second.
   368  func (limit Limit) tokensFromDuration(d time.Duration) float64 {
   369  	return d.Seconds() * float64(limit)
   370  }