github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/internal/rate/rate.go (about)

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