BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balb_reservationguard.h
Go to the documentation of this file.
1/// @file balb_reservationguard.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balb_reservationguard.h -*-C++-*-
8#ifndef INCLUDED_BALB_RESERVATIONGUARD
9#define INCLUDED_BALB_RESERVATIONGUARD
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balb_reservationguard balb_reservationguard
15/// @brief Provide a generic proctor for rate controlling objects.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balb
19/// @{
20/// @addtogroup balb_reservationguard
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balb_reservationguard-purpose"> Purpose</a>
25/// * <a href="#balb_reservationguard-classes"> Classes </a>
26/// * <a href="#balb_reservationguard-description"> Description </a>
27/// * <a href="#balb_reservationguard-usage"> Usage </a>
28/// * <a href="#balb_reservationguard-example-1-guarding-units-reservation-in-operations-with-balb-leakybucket"> Example 1: Guarding units reservation in operations with balb::LeakyBucket </a>
29///
30/// # Purpose {#balb_reservationguard-purpose}
31/// Provide a generic proctor for rate controlling objects.
32///
33/// # Classes {#balb_reservationguard-classes}
34///
35/// - balb::ReservationGuard: a guard for reserving resources from rate limiters.
36///
37/// @see balb_leakybucket, balb_ratelimiter
38///
39/// # Description {#balb_reservationguard-description}
40/// This component provides generic proctor to automatically
41/// reserve and release units from a rate controlling object. The rate
42/// controlling object can be of any type (typically either a
43/// `balb::RateLimiter` or `balb::LeakyBucket`) that provides the following
44/// methods:
45/// @code
46/// void reserve(bsls::Types::Uint64 numOfUnits);
47/// void submitReserved(bsls::Types::Uint64 numOfUnits);
48/// void cancelReserved(bsls::Types::Uint64 numOfUnits);
49/// @endcode
50/// Use `balb::ReservationGuard` to ensure that reserved units will be correctly
51/// returned to a rate controlling object in a programming scope. Note that
52/// `balb::ReservationGuard` does not assume ownership of the rate controlling
53/// object.
54///
55/// ## Usage {#balb_reservationguard-usage}
56///
57///
58/// This section illustrates the intended use of this component.
59///
60/// ## Example 1: Guarding units reservation in operations with balb::LeakyBucket {#balb_reservationguard-example-1-guarding-units-reservation-in-operations-with-balb-leakybucket}
61///
62///
63/// Suppose that we are limiting the rate of network traffic generation using a
64/// `balb::LeakyBucket` object. We send data buffer over a network interface
65/// using the `mySendData` function:
66/// @code
67/// bsls::Types::Uint64 mySendData(size_t dataSize);
68/// // Send a specified 'dataSize' amount of data over the network. Return
69/// // the amount of data actually sent. Throw an exception if a network
70/// // failure is detected.
71/// @endcode
72/// Notice that the `mySendData` function may throw an exception; therefore, we
73/// should wait until `mySendData` returns before indicating the amount of data
74/// sent to the leaky bucket.
75///
76/// Further suppose that multiple threads are sending network data and sharing
77/// the same leaky bucket. If every thread simply checks for overflowing of the
78/// leaky bucket, send data, and then submit to the leaky bucket, then the rate
79/// of data usage may exceed the limits imposed by the leaky bucket due to race
80/// conditions. We can avoid the this issue by reserving the amount of data
81/// immediately after checking whether the leaky bucket has overflown and submit
82/// the reserved amount after the data has been sent. However, this process
83/// could lead to the loss of the reserved units (effectively decreasing the
84/// leaky bucket's capacity) if `mySendData` throws an exception.
85/// `balb::ReservationGuard` is designed to resolve this issue.
86///
87/// First, we define the size of each data chunk and the total size of the data
88/// to send:
89/// @code
90/// const bsls::Types::Uint64 CHUNK_SIZE = 256;
91/// bsls::Types::Uint64 bytesSent = 0;
92/// bsls::Types::Uint64 totalSize = 10 * 1024; // in bytes
93/// @endcode
94/// Then, we create a `balb::LeakyBucket` object to limit the rate of data
95/// transmission:
96/// @code
97/// bsls::Types::Uint64 rate = 512;
98/// bsls::Types::Uint64 capacity = 1536;
99/// bsls::TimeInterval now = bdlt::CurrentTime::now();
100/// balb::LeakyBucket bucket(rate, capacity, now);
101/// @endcode
102/// Next, we send the chunks of data using a loop. For each iteration, we check
103/// whether submitting another byte would cause the leaky bucket to overflow:
104/// @code
105/// while (bytesSent < totalSize) {
106///
107/// now = bdlt::CurrentTime::now();
108/// if (!bucket.wouldOverflow(now)) {
109/// @endcode
110/// Now, if the leaky bucket would not overflow, we create a
111/// `balb::ReservationGuard` object to reserve the amount of data to be sent:
112/// @code
113/// balb::ReservationGuard<balb::LeakyBucket> guard(&bucket,
114/// CHUNK_SIZE);
115/// @endcode
116/// Then, we use the `mySendData` function to send the data chunk over the
117/// network. After the data had been sent, we submit the amount of reserved
118/// data that was actually sent:
119/// @code
120/// bsls::Types::Uint64 result;
121/// result = mySendData(CHUNK_SIZE);
122/// bytesSent += result;
123/// guard.submitReserved(result);
124/// @endcode
125/// Note that we do not have manually cancel any remaining units reserved by the
126/// `balb::ReservationGuard` object either because `mySendData` threw an
127/// exception, or the data was only partially sent, because when the guard
128/// object goes out of scope, all remaining reserved units will be automatically
129/// cancelled.
130/// @code
131/// }
132/// @endcode
133/// Finally, if submitting another byte will cause the leaky bucket to overflow,
134/// then we wait until the submission will be allowed by waiting for an amount
135/// time returned by the `calculateTimeToSubmit` method:
136/// @code
137/// else {
138/// bsls::TimeInterval timeToSubmit = bucket.calculateTimeToSubmit(
139/// now);
140/// bsls::Types::Uint64 uS = timeToSubmit.totalMicroseconds() +
141/// (timeToSubmit.nanoseconds() % 1000) ? 1 : 0;
142/// bslmt::ThreadUtil::microSleep(static_cast<int>(uS));
143/// }
144/// }
145/// @endcode
146/// @}
147/** @} */
148/** @} */
149
150/** @addtogroup bal
151 * @{
152 */
153/** @addtogroup balb
154 * @{
155 */
156/** @addtogroup balb_reservationguard
157 * @{
158 */
159
160#include <balscm_version.h>
161
162#include <bsls_assert.h>
163#include <bsls_asserttest.h>
164#include <bsls_types.h>
165
166
167namespace balb {
168
169 //=======================
170 // class ReservationGuard
171 //=======================
172
173/// This class template implements a proctor for reserving and cancelling
174/// units in a rate controlling object.
175///
176/// This class:
177/// * is *exception* *neutral* (agnostic)
178/// * is *const* *thread-safe*
179/// For terminology see @ref bsldoc_glossary .
180///
181/// See @ref balb_reservationguard
182template<class TYPE>
184
185 // DATA
186 TYPE *d_rateController_p; // Pointer to the rate
187 // controlling object in which
188 // the units are reserved.
189
190 bsls::Types::Uint64 d_unitsReserved; // Number of units reserved by
191 // this object.
192
193 private:
194 // NOT IMPLEMENTED
196 ReservationGuard& operator =(const ReservationGuard<TYPE>&);
198
199 public:
200 // CREATORS
201
202 /// Create a `ReservationGuard` object guarding the specified
203 /// `rateController` and reserving the specified `numUnits`.
204 ReservationGuard(TYPE* rateController, bsls::Types::Uint64 numUnits);
205
206 /// Destroy this object. Invoke the `cancelReserved` method for the
207 /// remaining remaining units reserved by this proctor.
209
210 // MANIPULATORS
211
212 /// Cancel the specified `numUnits` from the reserve units guarded by
213 /// this object. Subtract the `numUnits` from `unitsReserved` and
214 /// invoke the `cancelReserved` method on the guarded object for
215 /// `numUnits`. After this operation, the number of reserved units
216 /// guarded by this object will be reduced by `numUnits`. The behavior
217 /// is undefined unless `numUnits <= unitsReserved()`.
218 void cancelReserved(bsls::Types::Uint64 numUnits);
219
220 /// Submit the specified `numUnits` from the reserve units guarded by
221 /// this object. After this operation, the number of reserved units
222 /// guarded by this object will be reduced by `numUnits`. The behavior
223 /// is undefined unless `numUnits <= unitsReserved()`.
224 void submitReserved(bsls::Types::Uint64 numUnits);
225
226 // ACCESSORS
227
228 /// Return a pointer to the rate controlling object used by this object.
229 TYPE *ptr() const;
230
231 /// Return the number of units reserved by this object.
233};
234
235// ============================================================================
236// INLINE FUNCTION DEFINITIONS
237// ============================================================================
238
239 //-----------------------
240 // class ReservationGuard
241 //-----------------------
242
243// CREATORS
244template <class TYPE>
245inline
247 bsls::Types::Uint64 numUnits)
248{
249 BSLS_ASSERT_SAFE(0 != rateController);
250
251 d_rateController_p = rateController;
252 d_unitsReserved = numUnits;
253
254 d_rateController_p->reserve(numUnits);
255}
256
257template <class TYPE>
258inline
260{
261 d_rateController_p->cancelReserved(d_unitsReserved);
262}
263
264// ACCESSORS
265template <class TYPE>
266inline
268{
269 return d_rateController_p;
270}
271
272template <class TYPE>
273inline
275{
276 return d_unitsReserved;
277}
278
279// MANIPULATORS
280template <class TYPE>
281inline
283{
284 BSLS_ASSERT_SAFE(numUnits <= d_unitsReserved);
285
286 d_rateController_p->cancelReserved(numUnits);
287 d_unitsReserved -= numUnits;
288}
289
290template <class TYPE>
291inline
293{
294 BSLS_ASSERT_SAFE(numUnits <= d_unitsReserved);
295
296 d_rateController_p->submitReserved(numUnits);
297 d_unitsReserved -= numUnits;
298}
299
300} // close package namespace
301
302
303#endif
304
305// ----------------------------------------------------------------------------
306// Copyright 2021 Bloomberg Finance L.P.
307//
308// Licensed under the Apache License, Version 2.0 (the "License");
309// you may not use this file except in compliance with the License.
310// You may obtain a copy of the License at
311//
312// http://www.apache.org/licenses/LICENSE-2.0
313//
314// Unless required by applicable law or agreed to in writing, software
315// distributed under the License is distributed on an "AS IS" BASIS,
316// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
317// See the License for the specific language governing permissions and
318// limitations under the License.
319// ----------------------------- END-OF-FILE ----------------------------------
320
321/** @} */
322/** @} */
323/** @} */
Definition balb_reservationguard.h:183
~ReservationGuard()
Definition balb_reservationguard.h:259
bsls::Types::Uint64 unitsReserved() const
Return the number of units reserved by this object.
Definition balb_reservationguard.h:274
TYPE * ptr() const
Return a pointer to the rate controlling object used by this object.
Definition balb_reservationguard.h:267
void submitReserved(bsls::Types::Uint64 numUnits)
Definition balb_reservationguard.h:292
void cancelReserved(bsls::Types::Uint64 numUnits)
Definition balb_reservationguard.h:282
#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