BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlmt_throttle.h
Go to the documentation of this file.
1/// @file bdlmt_throttle.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlmt_throttle.h -*-C++-*-
8#ifndef INCLUDED_BDLMT_THROTTLE
9#define INCLUDED_BDLMT_THROTTLE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlmt_throttle bdlmt_throttle
15/// @brief Provide mechanism for limiting the rate at which actions may occur.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlmt
19/// @{
20/// @addtogroup bdlmt_throttle
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlmt_throttle-purpose"> Purpose</a>
25/// * <a href="#bdlmt_throttle-classes"> Classes </a>
26/// * <a href="#bdlmt_throttle-macros"> Macros </a>
27/// * <a href="#bdlmt_throttle-description"> Description </a>
28/// * <a href="#bdlmt_throttle-supported-clock-types"> Supported Clock-Types </a>
29/// * <a href="#bdlmt_throttle-thread-safety"> Thread Safety </a>
30/// * <a href="#bdlmt_throttle-static-throttle-objects"> Static Throttle Objects </a>
31/// * <a href="#bdlmt_throttle-macro-reference"> Macro Reference </a>
32/// * <a href="#bdlmt_throttle-bldmt_throttle_init-macros"> BLDMT_THROTTLE_INIT macros </a>
33/// * <a href="#bdlmt_throttle-bdlmt_throttle_if-macros"> BDLMT_THROTTLE_IF macros </a>
34/// * <a href="#bdlmt_throttle-lack-of-bsl-chrono-based-overloads-for-requestpermission"> Lack of bsl::chrono-Based Overloads for requestPermission </a>
35/// * <a href="#bdlmt_throttle-usage"> Usage </a>
36/// * <a href="#bdlmt_throttle-example-1-error-reporting"> Example 1: Error Reporting </a>
37///
38/// # Purpose {#bdlmt_throttle-purpose}
39/// Provide mechanism for limiting the rate at which actions may occur.
40///
41/// # Classes {#bdlmt_throttle-classes}
42///
43/// - bdlmt::Throttle: a mechanism for limiting the rate at which actions occur
44///
45/// # Macros {#bdlmt_throttle-macros}
46///
47/// - BDLMT_THROTTLE_INIT, BDLMT_THROTTLE_INIT_REALTIME,
48/// - BDLMT_THROTTLE_INIT_ALLOW_ALL, BDLMT_THROTTLE_INIT_ALLOW_NONE,
49/// - BDLMT_THROTTLE_IF, BDLMT_THROTTLE_IF_REALTIME,
50/// - BDLMT_THROTTLE_IF_ALLOW_ALL, BDLMT_THROTTLE_IF_ALLOW_NONE
51///
52/// @see bslmt_turnstile, btls_leakybucket
53///
54/// # Description {#bdlmt_throttle-description}
55/// This component provides a mechanism, `bdlmt::Throttle`, that
56/// can be used by clients to regulate the frequency at which actions can be
57/// taken. Clients initialize a `Throttle` with configuration values for
58/// `nanosecondsPerAction`, `maxSimultaneousActions`, and clock type. Then
59/// clients request permission from this component to execute actions. The
60/// component keeps track of the number of actions requested, and over time
61/// throttles the average number of actions permitted to a rate of
62/// `1 / nanosecondsPerAction` (actions-per-nanosecond). So, for example, to
63/// limit the average rate of actions permitted to 10 actions per second
64/// (10 actions / one billion nanoseconds), the value for `nanosecondsPerAction`
65/// would be 100000000 (which is one billion / 10).
66///
67/// As clients request permission to perform actions the component accumulates a
68/// time debt for those actions that dissipates over time. The maximum value
69/// for this time debt is given by
70/// `maxSimultaneousActions * nanosecondsPerAction`. The
71/// `maxSimultaneousActions` configuration parameter thereby limits the maximum
72/// number of actions that can be simultaneously permitted.
73///
74/// This behavior is known as a "leaky-bucket" algorithm: actions permitted
75/// place water in the bucket, the passage of time drains water from the bucket,
76/// and the bucket has a maximum capacity. Actions are permitted when there is
77/// enough empty room in the bucket that the water placed won't overflow it. A
78/// leaky bucket is an efficiently implementable approximation for allowing a
79/// certain number of actions over a window of time.
80///
81/// ## Supported Clock-Types {#bdlmt_throttle-supported-clock-types}
82///
83///
84/// The component `bsls::SystemClockType` supplies the enumeration indicating
85/// the system clock by which this component measures time. By default, this
86/// component uses `bsls::SystemClock::e_MONOTONIC`. If the clock type
87/// indicated at initialization is `bsls::SystemClockType::e_MONOTONIC`, the
88/// timeout should be expressed as an absolute offset since the epoch of this
89/// clock (which matches the epoch used in
90/// `bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC)`. If the clock
91/// type indicated at initialization is `bsls::SystemClockType::e_REALTIME`, the
92/// time should be expressed as an absolute offset since 00:00:00 UTC, January
93/// 1, 1970 (which matches the epoch used in
94/// `bsls::SystemTime::now(bsls::SystemClockType::e_REALTIME)`.
95///
96/// ## Thread Safety {#bdlmt_throttle-thread-safety}
97///
98///
99/// `bdlmt::Throttle` is fully *thread-safe*, meaning that all
100/// non-initialization operations on a given instance instance can be safely
101/// invoked simultaneously from multiple threads.
102///
103/// ## Static Throttle Objects {#bdlmt_throttle-static-throttle-objects}
104///
105///
106/// `Throttle` objects declared with static storage duration must be initialized
107/// using one of the `BDLMT_THROTTLE_INIT*` macros. In order to provide thread
108/// safety on C++03 compilers (which do not have `constexpr`), these macros
109/// perform aggregate initialization that can be evaluated at compile time.
110///
111/// ## Macro Reference {#bdlmt_throttle-macro-reference}
112///
113///
114///
115/// ### BLDMT_THROTTLE_INIT macros {#bdlmt_throttle-bldmt_throttle_init-macros}
116///
117///
118/// One of these macros must be used to aggregate initialize `bdlmt::Throttle`
119/// objects that have static storage duration -- the values are guaranteed to be
120/// evaluated at compile-time, avoiding race conditions.
121/// @code
122/// BDLMT_THROTTLE_INIT(maxSimultaneousActions,
123/// nanosecondsPerAction)
124/// BDLMT_THROTTLE_INIT_REALTIME(maxSimultaneousActions,
125/// nanosecondsPerAction)
126/// Initialize this 'Throttle' to limit the average period of actions
127/// permitted to the specified 'nanosecondsPerAction', and the maximum
128/// number of actions allowed at one time to the specified
129/// 'maxSimultaneousActions', where time is measured according to the
130/// monotonic system clock. These macros must be used for 'Throttle'
131/// objects having static storage duration. If 'maxSimultaneousActions'
132/// is 0, the throttle will be configured to permit no actions. If
133/// 'nanosecondsPerAction' is 0, the throttle will be configured to permit
134/// all actions. Use the '_REALTIME' variant of this macro to use the
135/// real-time system clock to measure time, otherwise (by default) the
136/// monotonic clock is used. The behavior is undefined unless
137/// '0 <= maxSimultaneousActions', '0 <= nanosecondsPerAction',
138/// '0 < maxSimultaneousActions || 0 < nanosecondsPerAction', and
139/// 'maxSimultaneousActions * nanosecondsPerAction <= LLONG_MAX'. Note
140/// that floating-point expressions are not allowed in any of the
141/// arguments, as they cannot be evaluated at compile-time on some
142/// platforms.
143///
144/// BDLMT_THROTTLE_INIT_ALLOW_ALL
145/// Initialize this 'Throttle' to allow all actions.
146///
147/// BDLMT_THROTTLE_INIT_ALLOW_NONE
148/// Initialize this 'Throttle' to allow no actions.
149/// @endcode
150/// ### BDLMT_THROTTLE_IF macros {#bdlmt_throttle-bdlmt_throttle_if-macros}
151///
152///
153/// @code
154/// BDLMT_THROTTLE_IF(maxSimultaneousActions,
155/// nanosecondsPerAction)
156/// BDLMT_THROTTLE_IF_REALTIME(maxSimultaneousActions,
157/// nanosecondsPerAction)
158/// This macro behaves like an 'if' clause, executing the subsequent
159/// statement or block if the time debt incurred by taking a single action
160/// would *not* exceed the maximum allowed time debt indicated by the
161/// specified 'nanosecondsPerAction' and 'maxSimultaneousActions'. If
162/// this 'if' clause is 'true' (and the subsequent statement or block is
163/// executed), then 'nanosecondsPerAction' is added to the time debt
164/// accumulated by this macro instantiation. 'nanosecondsPerAction' is
165/// the minimum average period between actions permitted by this macro
166/// instantiation, and 'nanosecondsPerAction' is the maximum number of
167/// simultaneous actions permitted by this macro instantiation. If
168/// 'maxSimultaneousActions' is 0, the 'if' clause will evaluate to
169/// 'false'. If 'nanosecondsPerAction' is 0, the 'if' clause will
170/// evaluate to 'true'. Use the '_REALTIME' variant of this macro to use
171/// the real-time system clock to measure time, otherwise (by default) the
172/// monotonic clock is used. The behavior is undefined unless
173/// '0 <= maxSimultaneousActions', '0 <= nanosecondsPerAction', and
174/// '0 < maxSimultaneousActions || 0 < nanosecondsPerAction'. Note that
175/// floating-point expressions are not allowed in any of the arguments, as
176/// they cannot be evaluated at compile-time on some platforms.
177///
178/// BDLMT_THROTTLE_IF_ALLOW_ALL
179/// Create an 'if' statement whose condition is always 'true', always
180/// allowing execution of the statement controlled by it and never
181/// allowing execution of any 'else' clause present.
182///
183/// BDLMT_THROTTLE_IF_ALLOW_NONE
184/// Create an 'if' statement whose condition is always 'false', never
185/// allowing execution of the statement controlled by it and always
186/// allowing execution of any 'else' clause present.
187/// @endcode
188/// ### Lack of bsl::chrono-Based Overloads for requestPermission {#bdlmt_throttle-lack-of-bsl-chrono-based-overloads-for-requestpermission}
189///
190///
191/// `bdlmt::Throttle` does not provide overloads for `requestPermission` and
192/// `requestPermissionIfValid` that take a `bsl::chrono::time_point` as a
193/// representation for `now`. There are three reasons for this. First,
194/// converting between different clocks is expensive, involving at least two
195/// calls to `now` (one for the clock defined in the time point, and one for the
196/// clock used by the throttle). This is supposed to be a performant component,
197/// allowing the caller to avoid the call to `bsls::SystemTime::now` by passing
198/// in their own value of `now`. Second, it is inherently imprecise;
199/// conversions with the same input can return slightly different results,
200/// depending on the scheduling of the calls to `now`. Third, we have no way to
201/// support clocks that run at different rates.
202///
203/// ## Usage {#bdlmt_throttle-usage}
204///
205///
206/// In this section we show intended usage of this component.
207///
208/// ### Example 1: Error Reporting {#bdlmt_throttle-example-1-error-reporting}
209///
210///
211/// Suppose we have an error reporting function `reportError`, that prints an
212/// error message to a log stream. There is a possibility that `reportError`
213/// will be called very frequently, and that reports of this error will
214/// overwhelm the other contents of the log, so we want to throttle the number
215/// of times this error will be reported. For our application we decide that we
216/// want to see at most 10 reports of the error at any given time, and that if
217/// the error is occurring continuously, that we want a maximum sustained rate
218/// of one error report every five seconds.
219///
220/// First, we declare the signature of our `reportError` function:
221/// @code
222/// /// Report an error to the specified `stream`.
223/// void reportError(bsl::ostream& stream)
224/// {
225/// @endcode
226/// Then, we define the maximum number of traces that can happen at a time to be
227/// 10:
228/// @code
229/// static const int maxSimultaneousTraces = 10;
230/// @endcode
231/// Next, we define the minimum interval between subsequent reported errors, if
232/// errors are being continuously reported to be one report every 5 seconds.
233/// Note that the units are nanoseconds, which must be represented using a 64
234/// bit integral value:
235/// @code
236/// static const bsls::Types::Int64 nanosecondsPerSustainedTrace =
237/// 5 * bdlt::TimeUnitRatio::k_NANOSECONDS_PER_SECOND;
238/// @endcode
239/// Then, we declare our `throttle` object and use the `BDLMT_THROTTLE_INIT`
240/// macro to initialize it, using the two above constants. Note that the two
241/// above constants *MUST* be calculated at compile-time, which means, among
242/// other things, that they can't contain any floating point sub-expressions:
243/// @code
244/// static bdlmt::Throttle throttle = BDLMT_THROTTLE_INIT(
245/// maxSimultaneousTraces, nanosecondsPerSustainedTrace);
246/// @endcode
247/// Now, we call `requestPermission` at run-time to determine whether to report
248/// the next error to the log:
249/// @code
250/// if (throttle.requestPermission()) {
251/// @endcode
252/// Finally, we write the message to the log:
253/// @code
254/// stream << "Help! I'm being held prisoner in a microprocessor!\n";
255/// }
256/// }
257/// @endcode
258/// @}
259/** @} */
260/** @} */
261
262/** @addtogroup bdl
263 * @{
264 */
265/** @addtogroup bdlmt
266 * @{
267 */
268/** @addtogroup bdlmt_throttle
269 * @{
270 */
271
272#include <bdlscm_version.h>
273
274#include <bdlt_timeunitratio.h>
275
276#include <bslmf_assert.h>
278
280#include <bsls_libraryfeatures.h>
281#include <bsls_systemclocktype.h>
282#include <bsls_systemtime.h>
283#include <bsls_timeinterval.h>
284#include <bsls_types.h>
285
286#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
287#include <bsl_chrono.h>
288#endif
289
290#include <bsl_climits.h>
291
292
293namespace bdlmt {
294
295 // ==============
296 // class Throttle
297 // ==============
298
299/// This `class` provides a mechanism that can be used by clients to
300/// regulate the frequency at which actions can be taken. The data members
301/// of `Throttle` are currently public to allow for compile-time (aggregate)
302/// initialization of `Throttle` objects having static storage duration (for
303/// C++03 compilers that do not provide `constexpr`).
304///
305/// See @ref bdlmt_throttle
306class Throttle {
307
308 // PRIVATE TYPES
309 typedef bsls::Types::Int64 Int64;
312
313 // PRIVATE CONSTANTS
314 enum { k_BILLION = 1000 * 1000 * 1000 };
315
316 static const Int64 k_ALLOW_ALL = LLONG_MIN;
317 static const Int64 k_ALLOW_NONE = LLONG_MAX;
318 static const Int64 k_MAX_SECONDS = LLONG_MAX / k_BILLION;
319 static const Int64 k_MIN_SECONDS = LLONG_MIN / k_BILLION;
320
321 public:
322 // PUBLIC CONSTANTS
323 static const Int64 k_TEN_YEARS_NANOSECONDS = 10 * 366 *
325
326 // PUBLIC DATA
327 AtomicTypes::Int64 d_prevLeakTime; // effective time of
328 // previous leak
329
330 Int64 d_nanosecondsPerAction; // nanoseconds per
331 // sustained action
332
333 Int64 d_nanosecondsPerTotalReset; // total bucket
334 // capacity in time
335
336 int d_maxSimultaneousActions; // total bucket
337 // capacity in actions
338
340 d_clockType; // clock type --
341 // monotonic or
342 // realtime
343
344 private:
345 // FRIENDS
346 template <int t_MAX_SIMULTANEOUS_ACTIONS,
347 bsls::Types::Int64 t_NANOSECONDS_PER_ACTION>
349
350 public:
351 // MANIPULATORS
352
353 /// Initialize this `Throttle` to limit the average period of actions
354 /// permitted to the specified `nanosecondsPerAction`, and the maximum
355 /// number of simultaneous actions allowed to the specified
356 /// `maxSimultaneousActions`. Optionally specify `clockType` to
357 /// indicate the system clock that will be used to measure time (see
358 /// @ref bdlmt_throttle-supported-clock-types . If `clockType` is not supplied the
359 /// monotonic system clock is used. The configured throttle will over time
360 /// limit the average number of actions permitted to a rate of `1 /
361 /// nanosecondsPerAction`. If `maxSimultaneousActions` is 0, the throttle
362 /// will be configured to permit no actions, otherwise if
363 /// `nanosecondsPerAction` is 0, the throttle will be configured to permit
364 /// all actions. The behavior is undefined unless
365 /// `0 <= nanosecondsPerAction`, `0 <= maxSimultaneousActions`,
366 /// `0 < nanosecondsPerAction || 0 < maxSimultaneousActions`, and
367 /// `maxSimultaneousActions * nanosecondsPerActionLeak <= LLONG_MAX`. Note
368 /// that the behavior for other methods is undefined unless this `Throttle`
369 /// is initialized (either using one of the overloads of this function, or
370 /// a `BDLMT_THROTTLE_INIT` macro) prior to being called.
375
376#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
377 /// Initialize this `Throttle` to limit the average period of actions
378 /// permitted to the specified `nanosecondsPerAction`, and the maximum
379 /// number of simultaneous actions allowed to the specified
380 /// `maxSimultaneousActions`. Use the realtime system clock to measure
381 /// time (see @ref bdlmt_throttle-supported-clock-types .
382 /// The configured throttle will over time limit the average number of
383 /// actions permitted to a rate of `1 / nanosecondsPerAction`. If
384 /// `maxSimultaneousActions` is 0, the throttle will be configured to
385 /// permit no actions, otherwise if `nanosecondsPerAction` is 0, the
386 /// throttle will be configured to permit all actions. The behavior is
387 /// undefined unless `0 <= nanosecondsPerAction`,
388 /// `0 <= maxSimultaneousActions`,
389 /// `0 < nanosecondsPerAction || 0 < maxSimultaneousActions`, and
390 /// `maxSimultaneousActions * nanosecondsPerActionLeak <= LLONG_MAX`.
391 /// Note that the behavior for other methods is undefined unless this
392 /// `Throttle` is initialized (either using one of the overloads of this
393 /// function, or a `BDLMT_THROTTLE_INIT` macro) prior to being called.
396 const bsl::chrono::system_clock&);
397
398 /// Initialize this `Throttle` to limit the average period of actions
399 /// permitted to the specified `nanosecondsPerAction`, and the maximum
400 /// number of simultaneous actions allowed to the specified
401 /// `maxSimultaneousActions`. Use the monotonic system clock to measure
402 /// time (see @ref bdlmt_throttle-supported-clock-types .
403 /// The configured throttle will over time limit the average number of
404 /// actions permitted to a rate of `1 / nanosecondsPerAction`. If
405 /// `maxSimultaneousActions` is 0, the throttle will be configured to
406 /// permit no actions, otherwise if `nanosecondsPerAction` is 0, the
407 /// throttle will be configured to permit all actions. The behavior is
408 /// undefined unless `0 <= nanosecondsPerAction`,
409 /// `0 <= maxSimultaneousActions`,
410 /// `0 < nanosecondsPerAction || 0 < maxSimultaneousActions`, and
411 /// `maxSimultaneousActions * nanosecondsPerActionLeak <= LLONG_MAX`.
412 /// Note that the behavior for other methods is undefined unless this
413 /// `Throttle` is initialized (either using one of the overloads of this
414 /// function, or a `BDLMT_THROTTLE_INIT` macro) prior to being called.
417 const bsl::chrono::steady_clock&);
418#endif
419
420 bool requestPermission();
422 bool requestPermission(int numActions);
423 /// Return `true` if the time debt incurred by taking the indicated
424 /// action(s) would *not* exceed the maximum allowed time debt
425 /// configured for this `Throttle` object
426 /// (`nanosecondsPerAction * maxSimultaneousActions`), and `false`
427 /// otherwise. Optionally specify `now` indicating the current time of
428 /// the system clock for which this object is configured (`now` is a
429 /// offset from that clocks epoch). If `now` is not supplied, the
430 /// current time is obtained from the configured system clock.
431 /// Optionally specify `numActions` indicating the number of actions
432 /// requested. If `numActions` is not supplied, one action is
433 /// requested. If this function returns `true` then
434 /// `numActions * nanosecondsPerAction` is added to the time debt
435 /// accumulated by this component. The behavior is undefined unless
436 /// this throttle has been initialized (either by calling an overload of
437 /// `initialize` or using one of the `BDLMT_THROTTLE_INIT*` macros),
438 /// `0 < numActions`, (`numActions <= maxSimultaneousActions` or
439 /// `0 == maxSimultaneousActions`), and the value of `now`, if
440 /// specified, can be expressed in nanoseconds as a 64-bit signed
441 /// integer. Note that `requestPermissionIfValid`, unlike these
442 /// methods, does not have any preconditions on the value of
443 /// `numActions`.
444 bool requestPermission(int numActions,
445 const bsls::TimeInterval& now);
446
447 int requestPermissionIfValid(bool *result,
448 int numActions);
449 /// Set the specified `*result` to `true` if the time debt incurred by
450 /// taking the specified `numActions` would *not* exceed the maximum
451 /// allowed time debt configured for this `Throttle` object
452 /// (`nanosecondsPerAction * maxSimultaneousActions`), and set `*result`
453 /// to `false` otherwise. Optionally specify `now` indicating the
454 /// current time of the system clock for which this object is configured
455 /// (`now` is a offset from that clocks epoch). If `now` is not
456 /// supplied, the current time is obtained from the configured system
457 /// clock. If `*result` is set to `true` then
458 /// `numActions * nanosecondsPerAction` is added to the time debt
459 /// accumulated by this component. Return 0 if `0 <= numActions`,
460 /// (`numActions <= maxSimultaneousActions` or
461 /// `0 == maxSimultaneousActions`), and the value of `now`, if
462 /// specified, can be expressed in nanoseconds as a 64-bit signed
463 /// integer, and a non-zero value otherwise. The behavior is undefined
464 /// unless this throttle has been initialized (either by calling an
465 /// overload of `initialize` or using one of the `BDLMT_THROTTLE_INIT*`
466 /// macros). Note that unless 0 is returned, `*result` is unaffected.
467 int requestPermissionIfValid(bool *result,
468 int numActions,
469 const bsls::TimeInterval& now);
470
471 // ACCESSOR
472
473 /// Return the system clock type with which this `Throttle` is configured
474 /// to observe the passage of time.
476
477 /// Return the maximum number of simultaneous actions for which this
478 /// `Throttle` is configured to permit.
479 int maxSimultaneousActions() const;
480
481 /// Return the time debt, in nanoseconds, that this `Throttle` is
482 /// configured to incur for each action permitted.
483 Int64 nanosecondsPerAction() const;
484
485 /// Load into the specified `result` the earliest *absolute* *time*
486 /// (according to system clock configured at initialization) when the
487 /// specified `numActions` will next be permitted. Return 0 on success,
488 /// and a non-zero value (with no effect on `result`) if this throttle
489 /// is configured such that `numActions` will never be permitted (i.e.,
490 /// return an error if `numActions > maxSimultaneousActions`) or if
491 /// `numActions <= 0`. The returned `result` is an offset from the
492 /// epoch of the system clock for which this throttle is configured.
493 /// The behavior is undefined unless this throttle has been initialized
494 /// (either by calling `initialize` or using a `BDLMT_THROTTLE_INIT*`
495 /// macro). Note that `result` may be in the past, and this function
496 /// does *not* obtain the current time from the system clock.
497 int nextPermit(bsls::TimeInterval *result, int numActions) const;
498};
499
500 // =========================
501 // class Throttle_InitHelper
502 // =========================
503
504/// [**PRIVATE**] This component private meta-function is used to implement
505/// the initialization macros. This type provides the following:
506/// * Ensures arguments are evaluated at compile time (which won't be the case
507/// for floating point arguments)
508/// * Enables compile time checks with BSLMF_ASSERT
509/// * Handles special cases if 0 is passed for `t_MAX_SIMULTANEOUS_ACTIONS` or
510/// `t_NANOSECONDS_PER_ACTION`
511///
512/// See @ref bdlmt_throttle
513template <int t_MAX_SIMULTANEOUS_ACTIONS,
514 bsls::Types::Int64 t_NANOSECONDS_PER_ACTION>
516
517 BSLMF_ASSERT(0 <= t_MAX_SIMULTANEOUS_ACTIONS);
518 BSLMF_ASSERT(0 <= t_NANOSECONDS_PER_ACTION);
519 BSLMF_ASSERT(t_MAX_SIMULTANEOUS_ACTIONS || t_NANOSECONDS_PER_ACTION);
520 BSLMF_ASSERT(LLONG_MAX / (t_MAX_SIMULTANEOUS_ACTIONS
521 ? t_MAX_SIMULTANEOUS_ACTIONS
522 : 1) >=
523 t_NANOSECONDS_PER_ACTION);
524
525 public:
526 // PUBLIC CONSTANTS
528 0 == t_MAX_SIMULTANEOUS_ACTIONS ? Throttle::k_ALLOW_NONE
529 : t_NANOSECONDS_PER_ACTION ? t_NANOSECONDS_PER_ACTION
530 : Throttle::k_ALLOW_ALL;
531
532 static const int k_msaValue = 0 == t_NANOSECONDS_PER_ACTION
533 ? INT_MAX
534 : t_MAX_SIMULTANEOUS_ACTIONS;
535};
536
537//=============================================================================
538// INLINE DEFINITIONS
539//=============================================================================
540
541 // --------------
542 // class Throttle
543 // --------------
544
545// MANIPULATORS
546#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
547inline
549 int maxSimultaneousActions,
550 Int64 nanosecondsPerAction,
551 const bsl::chrono::system_clock&)
552{
556}
557
558inline
560 int maxSimultaneousActions,
561 Int64 nanosecondsPerAction,
562 const bsl::chrono::steady_clock&)
563{
567}
568#endif
569
570inline
575
576inline
577bool Throttle::requestPermission(int numActions)
578{
579 return this->requestPermission(numActions,
581}
582
583inline
585 int numActions)
586{
587 if (numActions <= 0 || (d_maxSimultaneousActions < numActions &&
589 return -1; // RETURN
590 }
591
592 *result = this->requestPermission(numActions,
594 return 0;
595}
596
597// ACCESSORS
598inline
603
604inline
609
610inline
615
616 // ---------------------------
617 // BDLMT_THROTTLE_INIT* macros
618 // ---------------------------
619
620#define BDLMT_THROTTLE_INIT(maxSimultaneousActions, \
621 nanosecondsPerAction) { \
622 { -BloombergLP::bdlmt::Throttle::k_TEN_YEARS_NANOSECONDS }, \
623 BloombergLP::bdlmt::Throttle_InitHelper< \
624 (maxSimultaneousActions), \
625 (nanosecondsPerAction)>::k_npaValue, \
626 bsl::integral_constant<BloombergLP::bsls::Types::Int64, \
627 1LL * (maxSimultaneousActions) * (nanosecondsPerAction)>::value, \
628 BloombergLP::bdlmt::Throttle_InitHelper< \
629 (maxSimultaneousActions), \
630 (nanosecondsPerAction)>::k_msaValue, \
631 BloombergLP::bsls::SystemClockType::e_MONOTONIC \
632 }
633
634#define BDLMT_THROTTLE_INIT_REALTIME(maxSimultaneousActions, \
635 nanosecondsPerAction) { \
636 { -BloombergLP::bdlmt::Throttle::k_TEN_YEARS_NANOSECONDS }, \
637 BloombergLP::bdlmt::Throttle_InitHelper< \
638 (maxSimultaneousActions), \
639 (nanosecondsPerAction)>::k_npaValue, \
640 bsl::integral_constant<BloombergLP::bsls::Types::Int64, \
641 1LL * (maxSimultaneousActions) * (nanosecondsPerAction)>::value, \
642 BloombergLP::bdlmt::Throttle_InitHelper< \
643 (maxSimultaneousActions), \
644 (nanosecondsPerAction)>::k_msaValue, \
645 BloombergLP::bsls::SystemClockType::e_REALTIME \
646 }
647
648#define BDLMT_THROTTLE_INIT_ALLOW_ALL BDLMT_THROTTLE_INIT(1, 0)
649#define BDLMT_THROTTLE_INIT_ALLOW_NONE BDLMT_THROTTLE_INIT(0, 1)
650
651 // ---------------------------
652 // 'BDLMT_THROTTLE_IF*' macros
653 // ---------------------------
654
655#define BDLMT_THROTTLE_IF(maxSimultaneousActions, \
656 nanosecondsPerAction) \
657 if (bool bdlmt_throttle_iFsToP = false) {} \
658 else \
659 for (static BloombergLP::bdlmt::Throttle bdlmt_throttle_iFtHrOtTlE = \
660 BDLMT_THROTTLE_INIT((maxSimultaneousActions), \
661 (nanosecondsPerAction)); \
662 !bdlmt_throttle_iFsToP; \
663 bdlmt_throttle_iFsToP = true) \
664 if (bdlmt_throttle_iFtHrOtTlE.requestPermission())
665
666#define BDLMT_THROTTLE_IF_REALTIME(maxSimultaneousActions, \
667 nanosecondsPerAction) \
668 if (bool bdlmt_throttle_iFsToP = false) {} \
669 else \
670 for (static BloombergLP::bdlmt::Throttle bdlmt_throttle_iFtHrOtTlE = \
671 BDLMT_THROTTLE_INIT_REALTIME((maxSimultaneousActions), \
672 (nanosecondsPerAction)); \
673 !bdlmt_throttle_iFsToP; \
674 bdlmt_throttle_iFsToP = true) \
675 if (bdlmt_throttle_iFtHrOtTlE.requestPermission())
676
677#define BDLMT_THROTTLE_IF_ALLOW_ALL BDLMT_THROTTLE_IF(1, 0)
678#define BDLMT_THROTTLE_IF_ALLOW_NONE BDLMT_THROTTLE_IF(0, 1)
679
680} // close package namespace
681
682
683#endif
684
685// ----------------------------------------------------------------------------
686// Copyright 2017 Bloomberg Finance L.P.
687//
688// Licensed under the Apache License, Version 2.0 (the "License");
689// you may not use this file except in compliance with the License.
690// You may obtain a copy of the License at
691//
692// http://www.apache.org/licenses/LICENSE-2.0
693//
694// Unless required by applicable law or agreed to in writing, software
695// distributed under the License is distributed on an "AS IS" BASIS,
696// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
697// See the License for the specific language governing permissions and
698// limitations under the License.
699// ----------------------------- END-OF-FILE ----------------------------------
700
701
702/** @} */
703/** @} */
704/** @} */
Definition bdlmt_throttle.h:515
static const bsls::Types::Int64 k_npaValue
Definition bdlmt_throttle.h:527
static const int k_msaValue
Definition bdlmt_throttle.h:532
Definition bdlmt_throttle.h:306
bsls::SystemClockType::Enum d_clockType
Definition bdlmt_throttle.h:340
int maxSimultaneousActions() const
Definition bdlmt_throttle.h:605
void initialize(int maxSimultaneousActions, Int64 nanosecondsPerAction, bsls::SystemClockType::Enum clockType=bsls::SystemClockType::e_MONOTONIC)
bool requestPermission(int numActions, const bsls::TimeInterval &now)
AtomicTypes::Int64 d_prevLeakTime
Definition bdlmt_throttle.h:327
Int64 d_nanosecondsPerTotalReset
Definition bdlmt_throttle.h:333
int d_maxSimultaneousActions
Definition bdlmt_throttle.h:336
int nextPermit(bsls::TimeInterval *result, int numActions) const
int requestPermissionIfValid(bool *result, int numActions, const bsls::TimeInterval &now)
Int64 d_nanosecondsPerAction
Definition bdlmt_throttle.h:330
bool requestPermission()
Definition bdlmt_throttle.h:571
Int64 nanosecondsPerAction() const
Definition bdlmt_throttle.h:611
bsls::SystemClockType::Enum clockType() const
Definition bdlmt_throttle.h:599
int requestPermissionIfValid(bool *result, int numActions)
Definition bdlmt_throttle.h:584
static const Int64 k_TEN_YEARS_NANOSECONDS
Definition bdlmt_throttle.h:323
bool requestPermission(const bsls::TimeInterval &now)
Definition bsls_timeinterval.h:301
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlmt_eventscheduler.h:522
static const bsls::Types::Int64 k_NANOSECONDS_PER_DAY
Definition bdlt_timeunitratio.h:226
Definition bsls_atomicoperations.h:834
Definition bsls_atomicoperations_default.h:333
Enum
Definition bsls_systemclocktype.h:117
@ e_MONOTONIC
Definition bsls_systemclocktype.h:126
@ e_REALTIME
Definition bsls_systemclocktype.h:120
static TimeInterval now(SystemClockType::Enum clockType)
Definition bsls_systemtime.h:175
long long Int64
Definition bsls_types.h:132