sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/internal/rate/rate.go (about)

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