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 }