BDE 4.39.x 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 all actions.
364 ///
365 /// \pre The behavior is undefined unless
366 /// `0 <= nanosecondsPerAction`, `0 <= maxSimultaneousActions`,
367 /// `0 < nanosecondsPerAction || 0 < maxSimultaneousActions`, and
368 /// `maxSimultaneousActions * nanosecondsPerActionLeak <= LLONG_MAX`.
369 ///
370 /// \note Note that the behavior for other methods is undefined unless this `Throttle`
371 /// is initialized (either using one of the overloads of this function, or
372 /// a `BDLMT_THROTTLE_INIT` macro) prior to being called.
377
378#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
379 /// Initialize this `Throttle` to limit the average period of actions
380 /// permitted to the specified `nanosecondsPerAction`, and the maximum
381 /// number of simultaneous actions allowed to the specified
382 /// `maxSimultaneousActions`. Use the realtime system clock to measure
383 /// time (see @ref bdlmt_throttle-supported-clock-types ).
384 /// The configured throttle will over time limit the average number of
385 /// actions permitted to a rate of `1 / nanosecondsPerAction`. If
386 /// `maxSimultaneousActions` is 0, the throttle will be configured to
387 /// permit no actions, otherwise if `nanosecondsPerAction` is 0, the
388 /// throttle will be configured to permit all actions.
389 ///
390 /// \pre The behavior is undefined unless `0 <= nanosecondsPerAction`,
391 /// `0 <= maxSimultaneousActions`,
392 /// `0 < nanosecondsPerAction || 0 < maxSimultaneousActions`, and
393 /// `maxSimultaneousActions * nanosecondsPerActionLeak <= LLONG_MAX`.
394 ///
395 /// \note Note that the behavior for other methods is undefined unless this
396 /// `Throttle` is initialized (either using one of the overloads of this
397 /// function, or a `BDLMT_THROTTLE_INIT` macro) prior to being called.
400 const bsl::chrono::system_clock&);
401
402 /// Initialize this `Throttle` to limit the average period of actions
403 /// permitted to the specified `nanosecondsPerAction`, and the maximum
404 /// number of simultaneous actions allowed to the specified
405 /// `maxSimultaneousActions`. Use the monotonic system clock to measure
406 /// time (see @ref bdlmt_throttle-supported-clock-types ).
407 /// The configured throttle will over time limit the average number of
408 /// actions permitted to a rate of `1 / nanosecondsPerAction`. If
409 /// `maxSimultaneousActions` is 0, the throttle will be configured to
410 /// permit no actions, otherwise if `nanosecondsPerAction` is 0, the
411 /// throttle will be configured to permit all actions.
412 ///
413 /// \pre The behavior is undefined unless `0 <= nanosecondsPerAction`,
414 /// `0 <= maxSimultaneousActions`,
415 /// `0 < nanosecondsPerAction || 0 < maxSimultaneousActions`, and
416 /// `maxSimultaneousActions * nanosecondsPerActionLeak <= LLONG_MAX`.
417 ///
418 /// \note Note that the behavior for other methods is undefined unless this
419 /// `Throttle` is initialized (either using one of the overloads of this
420 /// function, or a `BDLMT_THROTTLE_INIT` macro) prior to being called.
423 const bsl::chrono::steady_clock&);
424#endif
425
426 /// Return `true` if the time debt incurred by taking the indicated
427 /// action(s) would *not* exceed the maximum allowed time debt
428 /// configured for this `Throttle` object
429 /// (`nanosecondsPerAction * maxSimultaneousActions`), and `false`
430 /// otherwise. Optionally specify `now` indicating the current time of
431 /// the system clock for which this object is configured (`now` is a
432 /// offset from that clocks epoch). If `now` is not supplied, the
433 /// current time is obtained from the configured system clock.
434 /// Optionally specify `numActions` indicating the number of actions
435 /// requested. If `numActions` is not supplied, one action is
436 /// requested. If this function returns `true` then
437 /// `numActions * nanosecondsPerAction` is added to the time debt accumulated by this component.
438 ///
439 /// \pre The behavior is undefined unless
440 /// this throttle has been initialized (either by calling an overload of
441 /// `initialize` or using one of the `BDLMT_THROTTLE_INIT*` macros),
442 /// `0 < numActions`, (`numActions <= maxSimultaneousActions` or
443 /// `0 == maxSimultaneousActions`), and the value of `now`, if
444 /// specified, can be expressed in nanoseconds as a 64-bit signed integer.
445 ///
446 /// \note Note that `requestPermissionIfValid`, unlike these
447 /// methods, does not have any preconditions on the value of
448 /// `numActions`.
449 bool requestPermission();
451 bool requestPermission(int numActions);
452 bool requestPermission(int numActions,
453 const bsls::TimeInterval& now);
454
455 /// Set the specified `*result` to `true` if the time debt incurred by
456 /// taking the specified `numActions` would *not* exceed the maximum
457 /// allowed time debt configured for this `Throttle` object
458 /// (`nanosecondsPerAction * maxSimultaneousActions`), and set `*result`
459 /// to `false` otherwise. Optionally specify `now` indicating the
460 /// current time of the system clock for which this object is configured
461 /// (`now` is a offset from that clocks epoch). If `now` is not
462 /// supplied, the current time is obtained from the configured system
463 /// clock. If `*result` is set to `true` then
464 /// `numActions * nanosecondsPerAction` is added to the time debt
465 /// accumulated by this component. Return 0 if `0 <= numActions`,
466 /// (`numActions <= maxSimultaneousActions` or
467 /// `0 == maxSimultaneousActions`), and the value of `now`, if
468 /// specified, can be expressed in nanoseconds as a 64-bit signed
469 /// integer, and a non-zero value otherwise.
470 ///
471 /// \pre The behavior is undefined unless this throttle has been initialized (either by calling an
472 /// overload of `initialize` or using one of the `BDLMT_THROTTLE_INIT*` macros).
473 ///
474 /// \note Note that unless 0 is returned, `*result` is unaffected.
475 int requestPermissionIfValid(bool *result,
476 int numActions);
477 int requestPermissionIfValid(bool *result,
478 int numActions,
479 const bsls::TimeInterval& now);
480
481 // ACCESSOR
482
483 /// Return the system clock type with which this `Throttle` is configured
484 /// to observe the passage of time.
486
487 /// Return the maximum number of simultaneous actions for which this
488 /// `Throttle` is configured to permit.
489 int maxSimultaneousActions() const;
490
491 /// Return the time debt, in nanoseconds, that this `Throttle` is
492 /// configured to incur for each action permitted.
493 Int64 nanosecondsPerAction() const;
494
495 /// Load into the specified `result` the earliest *absolute* *time*
496 /// (according to system clock configured at initialization) when the
497 /// specified `numActions` will next be permitted. Return 0 on success,
498 /// and a non-zero value (with no effect on `result`) if this throttle
499 /// is configured such that `numActions` will never be permitted (i.e.,
500 /// return an error if `numActions > maxSimultaneousActions`) or if
501 /// `numActions <= 0`. The returned `result` is an offset from the
502 /// epoch of the system clock for which this throttle is configured.
503 ///
504 /// \pre The behavior is undefined unless this throttle has been initialized
505 /// (either by calling `initialize` or using a `BDLMT_THROTTLE_INIT*` macro).
506 ///
507 /// \note Note that `result` may be in the past, and this function
508 /// does *not* obtain the current time from the system clock.
509 int nextPermit(bsls::TimeInterval *result, int numActions) const;
510};
511
512 // =========================
513 // class Throttle_InitHelper
514 // =========================
515
516/// [**PRIVATE**] This component private meta-function is used to implement
517/// the initialization macros. This type provides the following:
518/// * Ensures arguments are evaluated at compile time (which won't be the case
519/// for floating point arguments)
520/// * Enables compile time checks with BSLMF_ASSERT
521/// * Handles special cases if 0 is passed for `t_MAX_SIMULTANEOUS_ACTIONS` or
522/// `t_NANOSECONDS_PER_ACTION`
523///
524/// See @ref bdlmt_throttle
525template <int t_MAX_SIMULTANEOUS_ACTIONS,
526 bsls::Types::Int64 t_NANOSECONDS_PER_ACTION>
528
529 BSLMF_ASSERT(0 <= t_MAX_SIMULTANEOUS_ACTIONS);
530 BSLMF_ASSERT(0 <= t_NANOSECONDS_PER_ACTION);
531 BSLMF_ASSERT(t_MAX_SIMULTANEOUS_ACTIONS || t_NANOSECONDS_PER_ACTION);
532 BSLMF_ASSERT(LLONG_MAX / (t_MAX_SIMULTANEOUS_ACTIONS
533 ? t_MAX_SIMULTANEOUS_ACTIONS
534 : 1) >=
535 t_NANOSECONDS_PER_ACTION);
536
537 public:
538 // PUBLIC CONSTANTS
540 0 == t_MAX_SIMULTANEOUS_ACTIONS ? Throttle::k_ALLOW_NONE
541 : t_NANOSECONDS_PER_ACTION ? t_NANOSECONDS_PER_ACTION
542 : Throttle::k_ALLOW_ALL;
543
544 static const int k_msaValue = 0 == t_NANOSECONDS_PER_ACTION
545 ? INT_MAX
546 : t_MAX_SIMULTANEOUS_ACTIONS;
547};
548
549//=============================================================================
550// INLINE DEFINITIONS
551//=============================================================================
552
553 // --------------
554 // class Throttle
555 // --------------
556
557// MANIPULATORS
558#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
559inline
561 int maxSimultaneousActions,
562 Int64 nanosecondsPerAction,
563 const bsl::chrono::system_clock&)
564{
568}
569
570inline
572 int maxSimultaneousActions,
573 Int64 nanosecondsPerAction,
574 const bsl::chrono::steady_clock&)
575{
579}
580#endif
581
582inline
587
588inline
589bool Throttle::requestPermission(int numActions)
590{
591 return this->requestPermission(numActions,
593}
594
595inline
597 int numActions)
598{
599 if (numActions <= 0 || (d_maxSimultaneousActions < numActions &&
601 return -1; // RETURN
602 }
603
604 *result = this->requestPermission(numActions,
606 return 0;
607}
608
609// ACCESSORS
610inline
615
616inline
621
622inline
627
628 // ---------------------------
629 // BDLMT_THROTTLE_INIT* macros
630 // ---------------------------
631
632#define BDLMT_THROTTLE_INIT(maxSimultaneousActions, \
633 nanosecondsPerAction) { \
634 { -BloombergLP::bdlmt::Throttle::k_TEN_YEARS_NANOSECONDS }, \
635 BloombergLP::bdlmt::Throttle_InitHelper< \
636 (maxSimultaneousActions), \
637 (nanosecondsPerAction)>::k_npaValue, \
638 bsl::integral_constant<BloombergLP::bsls::Types::Int64, \
639 1LL * (maxSimultaneousActions) * (nanosecondsPerAction)>::value, \
640 BloombergLP::bdlmt::Throttle_InitHelper< \
641 (maxSimultaneousActions), \
642 (nanosecondsPerAction)>::k_msaValue, \
643 BloombergLP::bsls::SystemClockType::e_MONOTONIC \
644 }
645
646#define BDLMT_THROTTLE_INIT_REALTIME(maxSimultaneousActions, \
647 nanosecondsPerAction) { \
648 { -BloombergLP::bdlmt::Throttle::k_TEN_YEARS_NANOSECONDS }, \
649 BloombergLP::bdlmt::Throttle_InitHelper< \
650 (maxSimultaneousActions), \
651 (nanosecondsPerAction)>::k_npaValue, \
652 bsl::integral_constant<BloombergLP::bsls::Types::Int64, \
653 1LL * (maxSimultaneousActions) * (nanosecondsPerAction)>::value, \
654 BloombergLP::bdlmt::Throttle_InitHelper< \
655 (maxSimultaneousActions), \
656 (nanosecondsPerAction)>::k_msaValue, \
657 BloombergLP::bsls::SystemClockType::e_REALTIME \
658 }
659
660#define BDLMT_THROTTLE_INIT_ALLOW_ALL BDLMT_THROTTLE_INIT(1, 0)
661#define BDLMT_THROTTLE_INIT_ALLOW_NONE BDLMT_THROTTLE_INIT(0, 1)
662
663 // ---------------------------
664 // 'BDLMT_THROTTLE_IF*' macros
665 // ---------------------------
666
667#define BDLMT_THROTTLE_IF(maxSimultaneousActions, \
668 nanosecondsPerAction) \
669 if (bool bdlmt_throttle_iFsToP = false) {} \
670 else \
671 for (static BloombergLP::bdlmt::Throttle bdlmt_throttle_iFtHrOtTlE = \
672 BDLMT_THROTTLE_INIT((maxSimultaneousActions), \
673 (nanosecondsPerAction)); \
674 !bdlmt_throttle_iFsToP; \
675 bdlmt_throttle_iFsToP = true) \
676 if (bdlmt_throttle_iFtHrOtTlE.requestPermission())
677
678#define BDLMT_THROTTLE_IF_REALTIME(maxSimultaneousActions, \
679 nanosecondsPerAction) \
680 if (bool bdlmt_throttle_iFsToP = false) {} \
681 else \
682 for (static BloombergLP::bdlmt::Throttle bdlmt_throttle_iFtHrOtTlE = \
683 BDLMT_THROTTLE_INIT_REALTIME((maxSimultaneousActions), \
684 (nanosecondsPerAction)); \
685 !bdlmt_throttle_iFsToP; \
686 bdlmt_throttle_iFsToP = true) \
687 if (bdlmt_throttle_iFtHrOtTlE.requestPermission())
688
689#define BDLMT_THROTTLE_IF_ALLOW_ALL BDLMT_THROTTLE_IF(1, 0)
690#define BDLMT_THROTTLE_IF_ALLOW_NONE BDLMT_THROTTLE_IF(0, 1)
691
692} // close package namespace
693
694
695#endif
696
697// ----------------------------------------------------------------------------
698// Copyright 2017 Bloomberg Finance L.P.
699//
700// Licensed under the Apache License, Version 2.0 (the "License");
701// you may not use this file except in compliance with the License.
702// You may obtain a copy of the License at
703//
704// http://www.apache.org/licenses/LICENSE-2.0
705//
706// Unless required by applicable law or agreed to in writing, software
707// distributed under the License is distributed on an "AS IS" BASIS,
708// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
709// See the License for the specific language governing permissions and
710// limitations under the License.
711// ----------------------------- END-OF-FILE ----------------------------------
712
713
714/** @} */
715/** @} */
716/** @} */
Definition bdlmt_throttle.h:527
static const bsls::Types::Int64 k_npaValue
Definition bdlmt_throttle.h:539
static const int k_msaValue
Definition bdlmt_throttle.h:544
Definition bdlmt_throttle.h:306
bsls::SystemClockType::Enum d_clockType
Definition bdlmt_throttle.h:340
int maxSimultaneousActions() const
Definition bdlmt_throttle.h:617
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:583
Int64 nanosecondsPerAction() const
Definition bdlmt_throttle.h:623
bsls::SystemClockType::Enum clockType() const
Definition bdlmt_throttle.h:611
int requestPermissionIfValid(bool *result, int numActions)
Definition bdlmt_throttle.h:596
static const Int64 k_TEN_YEARS_NANOSECONDS
Definition bdlmt_throttle.h:323
bool requestPermission(const bsls::TimeInterval &now)
Definition bsls_timeinterval.h:307
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlmt_eventscheduler.h:550
static const bsls::Types::Int64 k_NANOSECONDS_PER_DAY
Definition bdlt_timeunitratio.h:228
Definition bsls_atomicoperations.h:836
Definition bsls_atomicoperations_default.h:333
Enum
Definition bsls_systemclocktype.h:119
@ e_MONOTONIC
Definition bsls_systemclocktype.h:128
@ e_REALTIME
Definition bsls_systemclocktype.h:122
static TimeInterval now(SystemClockType::Enum clockType)
Definition bsls_systemtime.h:177
long long Int64
Definition bsls_types.h:134