BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balb_ratelimiter.h
Go to the documentation of this file.
1/// @file balb_ratelimiter.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balb_ratelimiter.h -*-C++-*-
8#ifndef INCLUDED_BALB_RATELIMITER
9#define INCLUDED_BALB_RATELIMITER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balb_ratelimiter balb_ratelimiter
15/// @brief Provide a mechanism to limit peak and sustained consumption rates.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balb
19/// @{
20/// @addtogroup balb_ratelimiter
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balb_ratelimiter-purpose"> Purpose</a>
25/// * <a href="#balb_ratelimiter-classes"> Classes </a>
26/// * <a href="#balb_ratelimiter-description"> Description </a>
27/// * <a href="#balb_ratelimiter-internal-model"> Internal Model </a>
28/// * <a href="#balb_ratelimiter-monitoring-resource-usage"> Monitoring Resource Usage </a>
29/// * <a href="#balb_ratelimiter-time-synchronization"> Time Synchronization </a>
30/// * <a href="#balb_ratelimiter-usage"> Usage </a>
31/// * <a href="#balb_ratelimiter-example-1-controlling-network-traffic-generation"> Example 1: Controlling Network Traffic Generation </a>
32///
33/// # Purpose {#balb_ratelimiter-purpose}
34/// Provide a mechanism to limit peak and sustained consumption rates.
35///
36/// # Classes {#balb_ratelimiter-classes}
37///
38/// - balb::RateLimiter: mechanism to monitor resource consumption rates
39///
40/// @see balb_leakybucket
41///
42/// # Description {#balb_ratelimiter-description}
43/// This component provides a mechanism, `balb::RateLimiter`, that
44/// enables clients to monitor and control the use of a resource such that the
45/// peak consumption rate and the sustained consumption rate do not exceed their
46/// respective configured limits.
47///
48/// The limits on resource consumption rates of a `balb::RateLimiter` object are
49/// configured using a specified peak rate (measured in `units/s`) along with
50/// its time-window, and a specified sustained rate (measured in `units/s`)
51/// along with its time-window. The peak-rate time-window indicates a sliding
52/// time period over which the average consumption rate shall not exceed the
53/// peak-rate; similarly, the sustained-rate time-window indicates a sliding
54/// time period over which the average consumption rate shall not exceed the
55/// sustained rate. `unit` is a generic unit of measurement (e.g., bytes,
56/// megabytes, number of messages, packets, liters, clock cycles, etc.).
57///
58/// ## Internal Model {#balb_ratelimiter-internal-model}
59///
60///
61/// Internally, a rate limiter (currently) models resource usage using two
62/// corresponding `balb::LeakyBucket` objects, one for limiting peak resource
63/// usage and one for limiting sustained resource usage. Each leaky bucket
64/// provides an approximation for a moving total, where the configured time
65/// window corresponds to the period of the moving total, and that time window
66/// multiplied by the corresponding rate indicates the sum that the moving total
67/// may not exceed (i.e., the capacity of the leaky bucket). As the units are
68/// submitted to a rate limiter, they are added to both the peak and sustained
69/// rate moving-totals, and then removed over time at the corresponding
70/// configured rate.
71///
72/// Figure 1 illustrates the behavior of a rate limiter during a typical usage
73/// scenario using moving-totals:
74/// @code
75/// Fig. 1:
76///
77/// Rp (peak rate) = 2 units/s
78/// Wp (peak-rate time-window) = 2 s
79/// Rs (sustained rate) = 1 units/s
80/// Ws (sustained-rate time-window) = 7 s
81///
82/// Submit 5 Submit 7
83///
84/// | | | | | | | | | | 7|~~~|
85/// 12| | 6| | 12| | 6| | 12| | 6|~~~|
86/// 11| | 5|~~~| 11| | 5| | 11| | 5|~~~|
87/// 10| | Lp-4|~~~| 10| | Lp-4|---| 10| | Lp-4|~~~|
88/// 9| | 3|~~~| 9| | 3| | 9|~~~| 3|~~~|
89/// 8| | 2|~~~| 8| | 2| | 8|~~~| 2|~~~|
90/// Ls-7|---| 1|~~~| Ls-7|---| 1|~~~| Ls-7|~~~| 1|~~~|
91/// 6| | +- -+ 6| | +- -+ 6|~~~| +- -+
92/// 5|~~~| 5| | 5|~~~|
93/// 4|~~~| 4| | 4|~~~|
94/// 3|~~~| 3|~~~| 3|~~~|
95/// 2|~~~| 2|~~~| 2|~~~|
96/// 1|~~~| 1|~~~| 1|~~~|
97/// +- -+ +- -+ +- -+
98///
99/// Time: t0 t0 + 2s t0 + 2s
100///
101///
102/// Submit 2
103///
104/// | | 7| | | | 7| | | | 7| |
105/// 12| | 6| | 12| | 6| | 12| | 6| |
106/// 11| | 5| | 11| | 5| | 11| | 5| |
107/// 10| | Lp-4|---| 10| | Lp-4|---| 10| | Lp-4|---|
108/// 9| | 3|~~~| 9| | 3| | 9| | 3|~~~|
109/// 8| | 2|~~~| 8| | 2| | 8| | 2|~~~|
110/// Ls-7|~~~| 1|~~~| Ls-7|---| 1|~~~| Ls-7|~~~| 1|~~~|
111/// 6|~~~| +- -+ 6|---| +- -+ 6|~~~| +- -+
112/// 5|~~~| 5|~~~| 5|~~~|
113/// 4|~~~| 4|~~~| 4|~~~|
114/// 3|~~~| 3|~~~| 3|~~~|
115/// 2|~~~| 2|~~~| 2|~~~|
116/// 1|~~~| 1|~~~| 1|~~~|
117/// +- -+ +- -+ +- -+
118///
119/// Time: t0 + 4s t0 + 6s t0 + 6s
120/// @endcode
121/// Suppose we have a rate limiter with a peak rate of `Rp = 2 units/s`, a
122/// peak-rate time-window of `Wp = 2 s`, a sustained rate of `Rs = 1 units/s`,
123/// and a sustained-rate time-window of `Ws = 7 s`.
124///
125/// This rate limiter maintains a moving-total having a capacity
126/// `Lp = Rp * Wp = 4 units` that controls the peak rate and another
127/// moving-total having a capacity `Ls = Rs * Ws = 7 units` that controls the
128/// sustained rate.
129///
130/// Figure 1 shows the following sequence of events:
131/// * At time `t0s`, we submit 5 units. The submitted units are added to the
132/// both moving-totals, and as a result the `Lp` is exceeded, which means
133/// that the average consumption rate over the peak-rate time-window has
134/// exceeded the peak rate. Note that we can not submit any more units at
135/// this time even though `Ls` is not exceeded (the average consumption rate
136/// over the sustained-rate time-windows has not exceeded the sustained
137/// rate).
138/// * At time `t0 + 2s` the number of units contained moving-totals are
139/// recalculated. As a result, 4 units (`Rp * 2 s`) are subtracted from the
140/// peak rate moving-total, and 2 units (`Rs * 2 s`) are subtracted from the
141/// sustained rate moving-total. Now, capacities of both moving-totals are
142/// no longer exceeded, so we are free to submit more units. We submit 7
143/// units, causing both `Lp` and `Ls` to be exceeded.
144/// * At time `t0 + 4s`, the moving-totals are again updated. The `Lp` limit
145/// is no longer exceeded. The number of units held by the moving-total
146/// tracking sustained rate matches the moving-total's capacity, and this
147/// boundary condition imply and no units can be submitted, because
148/// submitting any amount of units would cause `Ls` to be exceeded.
149/// * At time `t0 + 6s`, the moving-totals are again updated. Both `Lp` and
150/// `Ls` are no longer exceeded. We submit 2 units. The `Lp` limit is not
151/// exceeded, but `Ls` limit is exceeded.
152///
153/// ## Monitoring Resource Usage {#balb_ratelimiter-monitoring-resource-usage}
154///
155///
156/// A `balb::LeakyBucket` provides methods to both submit units and reserve
157/// units for future submission. Submitting a unit indicates that it has been
158/// consumed by the entity being modeled, and it is added to the moving-totals
159/// tracking both peak and sustained resource usage.
160///
161/// Reserving a unit guarantees that available capacity will be reserved so that
162/// unit can be submitted in the future without exceeding the configured limits.
163/// Reserved units may be later submitted using the `submitReserved` method or
164/// canceled using the `cancelReserved` method. Reserved units permanently
165/// reside in the two moving-totals of consumed units, resulting in the
166/// reduction in the effective capacities of the moving-totals, until the
167/// reserved units are canceled or submitted. Reserving units effectively
168/// shortens the time-window during which the average sustained and peak rate
169/// are enforced. Therefore, the time interval between reserving units and
170/// submitting or canceling them should be kept as short as possible. For a
171/// practical example of using reserved units, please see
172/// @ref balb_reservationguard .
173///
174/// The recommended usage of a rate limiter is to first check whether 1 unit can
175/// be added without exceeding the rate limiter's configured limits, and if so,
176/// consume the desired amount of the resource. Afterwards, submit the amount
177/// of consumed resource to the rate limiter.
178///
179/// Whether submitting more units would exceed the configured limits can be
180/// determined using the `wouldExceedBandwidth` method. The estimated amount of
181/// time to wait before 1 more unit will be allowed to be submitted can be
182/// determined using the `calculateTimeToSubmit` method.
183///
184/// ## Time Synchronization {#balb_ratelimiter-time-synchronization}
185///
186///
187/// rate limiter does not utilize an internal timer, so timing must be handled
188/// manually. Clients can specify an initial time interval for a rate limiter
189/// object at construction or using the `reset` method. Whenever the state of a
190/// rate limiter object needs to be updated, clients must invoke the
191/// `updateState` method specifying the current time interval. Since rate
192/// limiter cares only about the elapsed time (not absolute time), the specified
193/// time intervals may be relative to any arbitrary time origin, though all of
194/// them must refer to the same origin. For the sake of consistency, clients
195/// are encouraged to use the unix epoch time (such as the values returned by
196/// `bdlt::CurrentTime::now`).
197///
198/// ## Usage {#balb_ratelimiter-usage}
199///
200///
201/// This section illustrates the intended use of this component.
202///
203/// ## Example 1: Controlling Network Traffic Generation {#balb_ratelimiter-example-1-controlling-network-traffic-generation}
204///
205///
206/// Suppose that we want to send data over a network interface with the load
207/// spike limitations explained below:
208///
209/// * The long term average rate of resource usage (i.e., the sustained rate)
210/// should not exceed 1024 bytes/s (`Rs`).
211/// * The period over which to monitor the long term average rate (i.e., the
212/// sustained-rate time-window) should be 0.5s (`Wp`).
213/// * The peak resource usage (i.e., the peak rate) should not exceed 2048
214/// bytes/s (`Rp`).
215/// * The period over which to monitor the peak resource usage should be
216/// 0.0625s (Wp).
217///
218/// This is shown in Figure 2 below.
219/// @code
220/// Fig. 2:
221///
222/// ^ Rate (Units per second)
223/// | _____ .
224/// | / B \ .
225/// 2048|---------------------------/-------\--------Rp (Maximum peak rate)
226/// | __ / \ .
227/// | / \ / A2 \ .
228/// | / A1 \ / \ .
229/// 1024|--------/------\ ------/---------------\----Rs (Maximum sustained rate)
230/// | __ / \ / \__.
231/// |__/ \/ \___/ .
232/// | .
233/// --------------------------------------------->
234/// T (seconds)
235/// @endcode
236/// Notice that we can understand the limitations imposed by the rate-limiter
237/// graphically as the maximum area above the respective lines, `Rp` and `Rs`,
238/// that the usage curve to allowed to achieve. In the example above:
239///
240/// o The area above the sustained rate `Rs` (e.g., `A1` or `A2+B`) should
241/// contain no more than 512 bytes (Rs * Ws).
242///
243/// o The area above the peak rate `Rp` should contain no more than 128 bytes
244/// (Rp * Wp).
245///
246/// Further suppose that we have a function, `sendData`, that transmits a
247/// specified amount of data over that network:
248/// @code
249/// bool sendData(bsl::size_t dataSize);
250/// // Send a specified 'dataSize' amount of data over the network.
251/// // Return 'true' if data was sent successfully and 'false' otherwise.
252/// @endcode
253/// First, we create a `balb::RateLimiter` object having a sustained rate of
254/// 1024 bytes/s, a sustained-rate time-window of 0.5s
255/// (512 bytes / 1024 bytes/s), a peak-rate of 2048 bytes/s, and a peak-rate
256/// time-window of 0.0625s (128 bytes / 2048 bytes/s):
257/// @code
258/// bsls::Types::Uint64 sustainedRateLimit = 1024;
259/// bsls::TimeInterval sustainedRateWindow(0.5);
260/// bsls::Types::Uint64 peakRateLimit = 2048;
261/// bsls::TimeInterval peakRateWindow(0.0625);
262/// bsls::TimeInterval now = bdlt::CurrentTime::now();
263///
264/// balb::RateLimiter rateLimiter(sustainedRateLimit,
265/// sustainedRateWindow,
266/// peakRateLimit,
267/// peakRateWindow,
268/// now);
269/// @endcode
270/// Note that the rate limiter does not prevent the rate at any instant from
271/// exceeding either the peak-rate or the sustained rate; instead, it prevents
272/// the average rate over the peak-rate time-window from exceeding maximum
273/// peak-rate and the average rate over the sustained-rate time-window from
274/// exceeding the maximum sustained-rate.
275///
276/// Then, we define the size of data to be send, the size of each data chunk,
277/// and a counter of data actually sent:
278/// @code
279/// bsl::size_t sizeOfData = 10 * 1024; // in bytes
280/// bsl::size_t chunkSize = 64; // in bytes
281/// bsl::size_t bytesSent = 0;
282/// @endcode
283/// Now, we send the chunks of data using a loop. For each iteration, we check
284/// whether submitting another byte would exceed the rate limiter's bandwidth
285/// limits. If not, we send an additional chunk of data and submit the number
286/// of bytes sent to the leaky bucket. Note that `submit` is invoked only after
287/// the data has been sent.
288/// @code
289/// while (bytesSent < sizeOfData) {
290/// now = bdlt::CurrentTime::now();
291/// if (!rateLimiter.wouldExceedBandwidth(now)) {
292/// if (true == sendData(chunkSize)) {
293/// rateLimiter.submit(chunkSize);
294/// bytesSent += chunkSize;
295/// }
296/// }
297/// @endcode
298/// Finally, if submitting another byte will cause the rate limiter to exceed
299/// its bandwidth limits, then we wait until the submission will be allowed by
300/// waiting for an amount time returned by the `calculateTimeToSubmit` method:
301/// @code
302/// else {
303/// bsls::TimeInterval timeToSubmit =
304/// rateLimiter.calculateTimeToSubmit(now);
305/// bsls::Types::Uint64 uS = timeToSubmit.totalMicroseconds() +
306/// (timeToSubmit.nanoseconds() % 1000 ? 1 : 0);
307/// bslmt::ThreadUtil::microSleep(static_cast<int>(uS));
308/// }
309/// }
310/// @endcode
311/// Notice that we wait by putting the thread into a sleep state instead of
312/// using busy-waiting to better optimize for multi-threaded applications.
313/// @}
314/** @} */
315/** @} */
316
317/** @addtogroup bal
318 * @{
319 */
320/** @addtogroup balb
321 * @{
322 */
323/** @addtogroup balb_ratelimiter
324 * @{
325 */
326
327#include <balscm_version.h>
328
329#include <balb_leakybucket.h>
330
331#include <bsls_assert.h>
332#include <bsls_timeinterval.h>
333#include <bsls_types.h>
334
335#include <bsl_algorithm.h>
336#include <bsl_climits.h>
337
338#include <bsl_c_limits.h>
339
340
341namespace balb {
342
343 //==================
344 // class RateLimiter
345 //==================
346
347/// This mechanism implements a rate limiter that allows clients to monitor
348/// and control the usage of a resource such that the rate of consumption
349/// stays within configured limits. The behavior of a rate limiter is
350/// determined by four properties: the sustained rate (in units/s), the
351/// sustained-rate time-window (in seconds), the peak rate (in units/s), and
352/// the peak-rate time-window (in seconds). All of these properties can be
353/// specified at construction or using the `setRateLimits` method.
354///
355/// Units can be indicated to a rate limiter as consumed by either
356/// submitting them using the `submit` method. Units can be marked as
357/// reserved, which effectively shorten the sustained-rate time-window and
358/// the peak-rate time-window, by using the `reserve` method.
359///
360/// Whether submitting 1 more unit would exceed the configured limits can be
361/// determined using the `wouldExceedBandwidth` method. The estimated
362/// amount of time to wait before 1 more unit will be allowed to be
363/// submitted can be determined using the `calculateTimeToSubmit` method.
364///
365/// The state of a rate limiter must be updated manually using the
366/// `updateState` method supplying the current time interval. The time
367/// intervals supplied should all refer to the same time origin.
368///
369/// A rate limiter keeps some statistics, including the number of submitted
370/// units, that can be accessed using the `getStatistics` and reset using
371/// the `resetStatistics` method.
372///
373/// This class:
374/// * is *exception* *neutral* (agnostic)
375/// * is *const* *thread-safe*
376/// For terminology see @ref bsldoc_glossary .
377///
378/// See @ref balb_ratelimiter
380
381 // DATA
382 LeakyBucket d_peakRateBucket; // 'balb::LeakyBucket' object for
383 // handling peak load
384
385 LeakyBucket d_sustainedRateBucket; // 'balb::LeakyBucket' object for
386 // handling sustained load
387
388 private:
389 // NOT IMPLEMENTED
390 RateLimiter& operator=(const RateLimiter&);
391 RateLimiter(const RateLimiter&);
392
393 public:
394 // CREATORS
395
396 /// Create a RateLimiter object, having the specified
397 /// `sustainedRateLimit`, the specified `sustainedRateWindow`, the
398 /// specified `peakRateLimit`, the specified `peakRateWindow`, and using
399 /// the specified `currentTime` as the initial `lastUpdateTime`. The
400 /// behavior is undefined unless `0 < sustainedRateLimit`,
401 /// `0 < sustainedRateWindow`, `0 < peakRateLimit`,
402 /// `0 < peakRateWindow`, the product of `sustainedRateLimit` and
403 /// `sustainedRateWindow` can be represented by 64-bit unsigned integral
404 /// type, and the product of `peakRateLimit` and `peakRateWindow` can be
405 /// represented by 64-bit unsigned integral type.
410 const bsls::TimeInterval& currentTime);
411
412 /// Destroy this object.
414
415 // CLASS METHODS
416
417 /// Returns `true` if, supposing the specified `sustainedRateLimit`,
418 /// `sustainedRateWindow`, `peakRateLimit`, and `peakRateWindow` are
419 /// used to initialize a `RateLimiter` object, the corresponding query
420 /// methods return the same values. The implementation of `RateLimiter`
421 /// uses `balb::LeakyBucket` objects, and for some combinations of
422 /// values the capacity of the `balb::LeakyBucket` is rounded such that
423 /// the rederived values differ. Note that this method is most likely
424 /// to return `true` when the product of each corresponding pair of
425 /// limit and window (as a fraction of a second) is integral.
426 static bool
431
432 // MANIPULATORS
433
434 /// Update the state of this rate limiter to the specified
435 /// `currentTime`. Return the estimated time interval that should pass
436 /// from `currentTime` until 1 more unit can be submitted to this rate
437 /// limiter without exceeding its configured limits. The number of
438 /// nanoseconds in the returned time interval is rounded up. Note that
439 /// a time interval of 0 is returned if 1 or more units can be submitted
440 /// at `currentTime`. Also note that after waiting for the returned
441 /// time interval, clients should typically check again using this
442 /// method, because additional units may have been submitted in the
443 /// interim.
445 const bsls::TimeInterval& currentTime);
446
447 /// Cancel the specified `numUnits` that were previously reserved. The
448 /// behavior is undefined unless `numUnits <= unitsReserved()`.
449 void cancelReserved(bsls::Types::Uint64 numUnits);
450
451 /// Reserve the specified `numUnits` for future use by this rate
452 /// limiter. The behavior is undefined unless the sum of `numUnits`,
453 /// unused units previously submitted to this rate limiter, and
454 /// `unitsReserved` can be represented by a 64-bit unsigned integral
455 /// type.
456 void reserve(bsls::Types::Uint64 numUnits);
457
458 /// Reset the statistics counter for this rate limiter to 0, and set the
459 /// `lastUpdateTime` of this rate limiter to the specified
460 /// `currentTime`.
461 void reset(const bsls::TimeInterval& currentTime);
462
463 /// Reset the statics collected for this rate limiter by setting the
464 /// number of units used and the number of units submitted to 0, and set
465 /// the `statisticsCollectionStartTime` to the `lastUpdateTime` of this
466 /// leaky bucket.
467 void resetStatistics();
468
469 /// Set the sustained rate of this rate limiter to the specified
470 /// `sustainedRateLimit`, the sustained-rate time-window to the
471 /// specified `sustainedRateWindow`, the peak rate to the specified
472 /// `peakRateLimit` and the peak-rate time-window to the specified
473 /// `peakRateWindow`. The behavior is undefined unless
474 /// `0 < sustainedRateLimit`, `0 < sustainedRateWindow`,
475 /// `0 < peakRateLimit`, `0 < peakRateWindow`, the product of
476 /// `sustainedRateLimit` and `sustainedRateWindow` can be represented by
477 /// 64-bit unsigned integral type, and the product of `peakRateLimit`
478 /// and `peakRateWindow` can be represented by 64-bit unsigned integral
479 /// type.
484
485 /// Submit the specified `numUnits` to this rate limiter. The behavior
486 /// is undefined unless the sum of `numUnits`, unused units previously
487 /// submitted to this rate limiter, and `unitsReserved` can be
488 /// represented by a 64-bit unsigned integral type.
489 void submit(bsls::Types::Uint64 numUnits);
490
491 /// Submit the specified `numUnits` that were previously reserved. The
492 /// behavior is undefined unless `numUnits <= unitsReserved()`.
493 void submitReserved(bsls::Types::Uint64 numUnits);
494
495 /// Set the `lastUpdateTime` of this rate limiter to the specified
496 /// `currentTime`. If the `currentTime` is after `lastUpdateTime`, then
497 /// recalculate number of units available for consumption based on the
498 /// `peakRate`, `sustainedRate` and the time interval between
499 /// `lastUpdateTime` and `currentTime`. If `currentTime` is before
500 /// `statisticsCollectionStartTime`, set it' to `currentTime`.
501 void updateState(const bsls::TimeInterval& currentTime);
502
503 /// Update the state of this rate limiter to the specified
504 /// `currentTime`. Return `true` if submitting 1 unit at the
505 /// `currentTime` would exceed the configured limits, and false
506 /// otherwise.
507 bool wouldExceedBandwidth(const bsls::TimeInterval& currentTime);
508
509 // ACCESSORS
510
511 /// Load, into the specified `submittedUnits` and the specified
512 /// `unusedUnits` respectively, the numbers of submitted units and the
513 /// number of unused units for this rate limiter from the
514 /// `statisticsCollectionStartTime` to the 'lastUpdateTime. The number
515 /// of unused units is the difference between the number of units that
516 /// could have been consumed at the sustained rate and the number of
517 /// units actually submitted for the time period.
518 void getStatistics(bsls::Types::Uint64* submittedUnits,
519 bsls::Types::Uint64* unusedUnits) const;
520
521 /// Return the time when this rate limiter was last updated.
523
524 /// Return the peak rate of this rate limiter.
526
527 /// Return the peak-rate time-period of this rate limiter. Note that
528 /// this period is generally significantly shorter than
529 /// `sustainedRateWindow`.
531
532 /// Return the time interval when the collection of the statistics (as
533 /// returned by `getStatistics`) started.
535
536 /// Return the sustained rate of this rate limiter.
538
539 /// Return the sustained-rate time-period of this rate limiter. Note
540 /// that this period is generally significantly longer than the
541 /// `peakRateWindow`.
543
544 /// Return the number of reserved units for this rate limiter.
546};
547
548// ============================================================================
549// INLINE FUNCTION DEFINITIONS
550// ============================================================================
551
552 //------------------
553 // class RateLimiter
554 //------------------
555
556// MANIPULATORS
557inline
559{
560 BSLS_ASSERT(numUnits <= unitsReserved());
561
562 d_peakRateBucket.cancelReserved(numUnits);
563 d_sustainedRateBucket.cancelReserved(numUnits);
564}
565
566inline
568{
569 BSLS_ASSERT_SAFE(numUnits <= ULLONG_MAX - unitsReserved());
570
571 BSLS_ASSERT_SAFE(d_sustainedRateBucket.unitsInBucket() <=
572 ULLONG_MAX - unitsReserved()- numUnits);
573
574 BSLS_ASSERT_SAFE(d_peakRateBucket.unitsInBucket() <=
575 ULLONG_MAX - unitsReserved()- numUnits);
576
577 d_peakRateBucket.reserve(numUnits);
578 d_sustainedRateBucket.reserve(numUnits);
579}
580
581inline
583{
584 d_peakRateBucket.reset(currentTime);
585 d_sustainedRateBucket.reset(currentTime);
586}
587
588inline
590{
591 d_sustainedRateBucket.resetStatistics();
592}
593
594inline
596{
597 BSLS_ASSERT_SAFE(numUnits <=
598 ULLONG_MAX - d_sustainedRateBucket.unitsInBucket());
599
601 ULLONG_MAX - d_sustainedRateBucket.unitsInBucket()- numUnits);
602
603 BSLS_ASSERT_SAFE(numUnits <=
604 ULLONG_MAX - d_peakRateBucket.unitsInBucket());
605
607 ULLONG_MAX - d_peakRateBucket.unitsInBucket()- numUnits);
608
609 d_peakRateBucket.submit(numUnits);
610 d_sustainedRateBucket.submit(numUnits);
611}
612
613inline
615{
616 BSLS_ASSERT(numUnits <= unitsReserved());
617
618 // There is no need to check whether 'numUnits' causes overflow because the
619 // reserved units was already checked by the 'reserve' method.
620
621 d_peakRateBucket.submitReserved(numUnits);
622 d_sustainedRateBucket.submitReserved(numUnits);
623}
624
625inline
627{
628 d_peakRateBucket.updateState(currentTime);
629 d_sustainedRateBucket.updateState(currentTime);
630}
631
632inline
634{
635 return (d_peakRateBucket.wouldOverflow(currentTime) ||
636 d_sustainedRateBucket.wouldOverflow(currentTime));
637}
638
639// ACCESSORS
640inline
642 bsls::Types::Uint64* unusedUnits) const
643{
644 BSLS_ASSERT_SAFE(0 != submittedUnits);
645 BSLS_ASSERT_SAFE(0 != unusedUnits);
646
647 // The statistics is collected from the sustained rate leaky bucket.
648
649 d_sustainedRateBucket.getStatistics(submittedUnits, unusedUnits);
650}
651
652inline
654{
655 return bsl::max(d_sustainedRateBucket.lastUpdateTime(),
656 d_peakRateBucket.lastUpdateTime());
657}
658
659inline
661{
662 return d_peakRateBucket.drainRate();
663}
664
665inline
667{
668 return LeakyBucket::calculateTimeWindow(d_peakRateBucket.drainRate(),
669 d_peakRateBucket.capacity());
670}
671
672inline
677
678inline
680{
681 return d_sustainedRateBucket.drainRate();
682}
683
684inline
686{
687 return LeakyBucket::calculateTimeWindow(d_sustainedRateBucket.drainRate(),
688 d_sustainedRateBucket.capacity());
689}
690
691inline
693{
694 BSLS_ASSERT_SAFE(d_sustainedRateBucket.unitsReserved() ==
695 d_peakRateBucket.unitsReserved());
696
697 return d_sustainedRateBucket.unitsReserved();
698}
699
700} // close package namespace
701
702
703#endif
704
705// ----------------------------------------------------------------------------
706// Copyright 2021 Bloomberg Finance L.P.
707//
708// Licensed under the Apache License, Version 2.0 (the "License");
709// you may not use this file except in compliance with the License.
710// You may obtain a copy of the License at
711//
712// http://www.apache.org/licenses/LICENSE-2.0
713//
714// Unless required by applicable law or agreed to in writing, software
715// distributed under the License is distributed on an "AS IS" BASIS,
716// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
717// See the License for the specific language governing permissions and
718// limitations under the License.
719// ----------------------------- END-OF-FILE ----------------------------------
720
721/** @} */
722/** @} */
723/** @} */
Definition balb_leakybucket.h:421
void submitReserved(bsls::Types::Uint64 numUnits)
Definition balb_leakybucket.h:714
bsls::Types::Uint64 unitsInBucket() const
Return the number of submitted units in this leaky bucket.
Definition balb_leakybucket.h:749
void submit(bsls::Types::Uint64 numUnits)
Definition balb_leakybucket.h:699
void reserve(bsls::Types::Uint64 numUnits)
Definition balb_leakybucket.h:666
bsls::TimeInterval lastUpdateTime() const
Return the time interval when this leaky bucket was last updated.
Definition balb_leakybucket.h:737
void reset(const bsls::TimeInterval &currentTime)
Definition balb_leakybucket.h:680
void getStatistics(bsls::Types::Uint64 *submittedUnits, bsls::Types::Uint64 *unusedUnits) const
bool wouldOverflow(const bsls::TimeInterval &currentTime)
bsls::TimeInterval statisticsCollectionStartTime() const
Definition balb_leakybucket.h:743
void updateState(const bsls::TimeInterval &currentTime)
static bsls::TimeInterval calculateTimeWindow(bsls::Types::Uint64 drainRate, bsls::Types::Uint64 capacity)
bsls::Types::Uint64 unitsReserved() const
Return the number of reserved units in this leaky bucket.
Definition balb_leakybucket.h:755
bsls::Types::Uint64 drainRate() const
Return the drain rate of this leaky bucket.
Definition balb_leakybucket.h:731
bsls::Types::Uint64 capacity() const
Return the capacity of this leaky bucket.
Definition balb_leakybucket.h:725
void cancelReserved(bsls::Types::Uint64 numUnits)
Definition balb_leakybucket.h:653
void resetStatistics()
Definition balb_leakybucket.h:691
Definition balb_ratelimiter.h:379
void setRateLimits(bsls::Types::Uint64 sustainedRateLimit, const bsls::TimeInterval &sustainedRateWindow, bsls::Types::Uint64 peakRateLimit, const bsls::TimeInterval &peakRateWindow)
void reset(const bsls::TimeInterval &currentTime)
Definition balb_ratelimiter.h:582
static bool supportsRateLimitsExactly(bsls::Types::Uint64 sustainedRateLimit, const bsls::TimeInterval &sustainedRateWindow, bsls::Types::Uint64 peakRateLimit, const bsls::TimeInterval &peakRateWindow)
bsls::Types::Uint64 unitsReserved() const
Return the number of reserved units for this rate limiter.
Definition balb_ratelimiter.h:692
void getStatistics(bsls::Types::Uint64 *submittedUnits, bsls::Types::Uint64 *unusedUnits) const
Definition balb_ratelimiter.h:641
bsls::TimeInterval sustainedRateWindow() const
Definition balb_ratelimiter.h:685
~RateLimiter()
Destroy this object.
bsls::TimeInterval statisticsCollectionStartTime() const
Definition balb_ratelimiter.h:673
bsls::TimeInterval lastUpdateTime() const
Return the time when this rate limiter was last updated.
Definition balb_ratelimiter.h:653
bsls::TimeInterval peakRateWindow() const
Definition balb_ratelimiter.h:666
bsls::TimeInterval calculateTimeToSubmit(const bsls::TimeInterval &currentTime)
bool wouldExceedBandwidth(const bsls::TimeInterval &currentTime)
Definition balb_ratelimiter.h:633
void updateState(const bsls::TimeInterval &currentTime)
Definition balb_ratelimiter.h:626
void resetStatistics()
Definition balb_ratelimiter.h:589
void cancelReserved(bsls::Types::Uint64 numUnits)
Definition balb_ratelimiter.h:558
void submitReserved(bsls::Types::Uint64 numUnits)
Definition balb_ratelimiter.h:614
bsls::Types::Uint64 sustainedRateLimit() const
Return the sustained rate of this rate limiter.
Definition balb_ratelimiter.h:679
void submit(bsls::Types::Uint64 numUnits)
Definition balb_ratelimiter.h:595
RateLimiter(bsls::Types::Uint64 sustainedRateLimit, const bsls::TimeInterval &sustainedRateWindow, bsls::Types::Uint64 peakRateLimit, const bsls::TimeInterval &peakRateWindow, const bsls::TimeInterval &currentTime)
void reserve(bsls::Types::Uint64 numUnits)
Definition balb_ratelimiter.h:567
bsls::Types::Uint64 peakRateLimit() const
Return the peak rate of this rate limiter.
Definition balb_ratelimiter.h:660
Definition bsls_timeinterval.h:301
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition balb_controlmanager.h:133
unsigned long long Uint64
Definition bsls_types.h:137