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