BDE 4.14.0 Production release
Loading...
Searching...
No Matches
ball_fixedsizerecordbuffer.h
Go to the documentation of this file.
1/// @file ball_fixedsizerecordbuffer.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// ball_fixedsizerecordbuffer.h -*-C++-*-
8#ifndef INCLUDED_BALL_FIXEDSIZERECORDBUFFER
9#define INCLUDED_BALL_FIXEDSIZERECORDBUFFER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup ball_fixedsizerecordbuffer ball_fixedsizerecordbuffer
15/// @brief Provide a thread-safe fixed-size buffer of record handles.
16/// @addtogroup bal
17/// @{
18/// @addtogroup ball
19/// @{
20/// @addtogroup ball_fixedsizerecordbuffer
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#ball_fixedsizerecordbuffer-purpose"> Purpose</a>
25/// * <a href="#ball_fixedsizerecordbuffer-classes"> Classes </a>
26/// * <a href="#ball_fixedsizerecordbuffer-description"> Description </a>
27/// * <a href="#ball_fixedsizerecordbuffer-usage"> Usage </a>
28/// * <a href="#ball_fixedsizerecordbuffer-example-1-basic-usage"> Example 1: Basic Usage </a>
29///
30/// # Purpose {#ball_fixedsizerecordbuffer-purpose}
31/// Provide a thread-safe fixed-size buffer of record handles.
32///
33/// # Classes {#ball_fixedsizerecordbuffer-classes}
34///
35/// - ball::FixedSizeRecordBuffer: thread-safe fixed-size buffer of records
36///
37/// @see ball_recordbuffer
38///
39/// # Description {#ball_fixedsizerecordbuffer-description}
40/// This component provides a concrete thread-safe implementation
41/// of the `ball::RecordBuffer` protocol, `ball::FixedSizeRecordBuffer`:
42/// @code
43/// ( ball::FixedSizeRecordBuffer )
44/// | ctor
45/// V
46/// ( ball::RecordBuffer )
47/// dtor
48/// beginSequence
49/// endSequence
50/// popBack
51/// popFront
52/// pushBack
53/// pushFront
54/// removeAll
55/// length
56/// back
57/// front
58/// @endcode
59/// The thread-safe class `ball::FixedSizeRecordBuffer` manages record handles
60/// (specifically, the instances of `bsl::shared_ptr<ball::Record>`) in a
61/// double-ended buffer. At any time, the sum of sizes of all records contained
62/// in a `ball::FixedSizeRecordBuffer` object *plus* the amount of memory
63/// allocated by the `ball::FixedSizeRecordBuffer` object itself is guaranteed
64/// to be less than or equal to an upper bound specified at creation. In order
65/// to accommodate a record, existing records may be removed from the buffer
66/// (see below). The `ball::FixedSizeRecordBuffer` class provides methods to
67/// push a record handle into either end (back or front) of the buffer
68/// (`pushBack` and `pushFront`), to obtain read-only access to the log record
69/// positioned at either end (`back` and `front`) and to remove the record
70/// positioned at either end (`popBack` and `popFront`). In order to
71/// accommodate a `pushBack` request, the records from the front end of the
72/// buffer may be removed. Similarly, in order to accommodate a `pushFront`
73/// request, the records from the back end of the buffer may be removed. If a
74/// record can not be accommodated in the buffer, it is silently (but otherwise
75/// safely) discarded.
76///
77/// ## Usage {#ball_fixedsizerecordbuffer-usage}
78///
79///
80/// This section illustrates intended use of this component.
81///
82/// ### Example 1: Basic Usage {#ball_fixedsizerecordbuffer-example-1-basic-usage}
83///
84///
85/// In the following example we demonstrate creation of a limited record buffer
86/// followed by concurrent access to it by multiple threads.
87/// @code
88/// enum {
89/// KILO_BYTE = 1024, // one kilo is (2^10) bytes
90/// MAX_TOTAL_SIZE = 32 * K, // 'maxTotalSize' parameter
91/// NUM_ITERATIONS = 1000, // number of iterations
92/// NUM_THREADS = 4 // number of threads
93/// };
94/// bslma::Allocator *basicAllocator = bslma::Default::defaultAllocator();
95/// @endcode
96/// First we create a record buffer.
97/// @code
98/// bdlma::DefaultDeleter<ball::Record> recordDeleter(basicAllocator);
99/// ball::FixedSizeRecordBuffer recordBuffer(MAX_TOTAL_SIZE, basicAllocator);
100/// @endcode
101/// Note that since the record buffer will contain shared pointers to the
102/// records, `recordDeleter` must be created before `recordBuffer` to ensure
103/// that the former has the longer lifetime.
104///
105/// Now we create several threads each of which repeatedly performs the
106/// following operations in a tight loop;
107/// (1) create a record;
108/// (2) build a message and store it into the record;
109/// (3) create a record handle;
110/// (4) push this record handle at the back end of the record buffer
111///
112/// @code
113/// void *workerThread(void *arg)
114/// {
115/// int id = (int)arg; // thread id
116/// for (int i = 0; i < NUM_ITERATIONS; ++i) {
117/// ball::Record *record =
118/// new (*basicAllocator) ball::Record(basicAllocator);
119///
120/// // build a message
121/// enum { MAX_SIZE = 100 };
122/// char msg[MAX_SIZE];
123/// sprintf(msg, "message no. %d from thread no. %d", i, id);
124///
125/// record->getFixedFields().setMessage(msg);
126///
127/// bsl::shared_ptr<ball::Record>
128/// handle(record, &recordDeleter, basicAllocator);
129///
130/// recordBuffer.pushBack(handle);
131/// }
132/// @endcode
133/// After completing the loop each thread iterates, in LIFO order, over all of
134/// the records contained in record buffer.
135/// @code
136/// // print messages in LIFO order
137/// recordBuffer.beginSequence();
138/// while (recordBuffer.length()) {
139/// const ball::Record &rec = recordBuffer.back();
140/// bsl::cout << rec.getFixedFields().message() << bsl::endl;
141/// recordBuffer.popBack();
142/// }
143/// recordBuffer.endSequence();
144///
145/// return NULL;
146/// }
147/// @endcode
148/// @}
149/** @} */
150/** @} */
151
152/** @addtogroup bal
153 * @{
154 */
155/** @addtogroup ball
156 * @{
157 */
158/** @addtogroup ball_fixedsizerecordbuffer
159 * @{
160 */
161
162#include <balscm_version.h>
163
165#include <ball_record.h>
166#include <ball_recordbuffer.h>
167
168#include <bslmt_lockguard.h>
169#include <bslmt_recursivemutex.h>
170
171#include <bslma_allocator.h>
173
175
176#include <bsls_keyword.h>
177
178#include <bsl_deque.h>
179#include <bsl_memory.h>
180
181
182namespace ball {
183
184 // ===========================
185 // class FixedSizeRecordBuffer
186 // ===========================
187
188/// This class provides a concrete, thread-safe implementation of the
189/// `RecordBuffer` protocol. This class is a mechanism. At any time, the
190/// sum of sizes of all records contained in a `FixedSizeRecordBuffer`
191/// object *plus* the amount of memory allocated by the
192/// `FixedSizeRecordBuffer` object itself is guaranteed to be less than or
193/// equal to an upper bound specified at creation. The class is
194/// thread-safe, except that the methods `front` and `back` must be called
195/// after locking the buffer by invoking `beginSequence`. In order to
196/// accommodate a `pushBack` request, the records from the front end of the
197/// buffer may be removed. Similarly, in order to accommodate a `pushFront`
198/// request, the records from the back end of the buffer may be removed. If
199/// a record can not accommodate in the buffer, it is silently (but
200/// otherwise safely) discarded.
201///
202/// See @ref ball_fixedsizerecordbuffer
204
205 // DATA
206 mutable bslmt::RecursiveMutex d_mutex; // synchronizes access to the
207 // buffer
208
209 int d_maxTotalSize;
210 // maximum possible sum of
211 // sizes of contained records
212
213 int d_currentTotalSize;
214 // current sum of sizes of
215 // contained records
216
217 // Implementation note: The order of the following data members is
218 // required to ensure proper initialization order.
219
220 CountingAllocator d_allocator; // allocator for `d_deque`
221
223 d_deque; // deque of record handles
224
225 // NOT IMPLEMENTED
228
229 public:
230 // TRAITS
233
234 // CREATORS
235
236 /// Create a limited record buffer such that at any time the sum of
237 /// sizes of all records contained *plus* the amount of memory allocated
238 /// by this object is guaranteed to be less than or equal to the
239 /// specified `maxTotalSize`. Optionally specify a `basicAllocator`
240 /// used to supply memory. If `basicAllocator` is 0, the currently
241 /// installed default allocator is used. The behavior is undefined
242 /// unless `maxTotalSize > 0`.
243 FixedSizeRecordBuffer(int maxTotalSize,
244 bslma::Allocator *basicAllocator = 0);
245
246 /// Remove all record handles from this record buffer and destroy this
247 /// record buffer.
249
250 // MANIPULATORS
251
252 /// *Lock* this record buffer so that a sequence of method invocations
253 /// on this record buffer can occur uninterrupted by other threads. The
254 /// buffer will remain *locked* until `endSequence` is called. It is
255 /// valid to invoke other methods on this record buffer between the
256 /// calls to `beginSequence` and `endSequence` (the implementation
257 /// guarantees this by employing a recursive mutex).
259
260 /// *Unlock* this record buffer, thus allowing other threads to access
261 /// it. The behavior is undefined unless the buffer is already *locked*
262 /// by `beginSequence`.
264
265 /// Remove from this record buffer the record handle positioned at the
266 /// back end of the buffer. The behavior is undefined unless
267 /// `0 < length()`.
269
270 /// Remove from this record buffer the record handle positioned at the
271 /// front end of the buffer. The behavior is undefined unless
272 /// `0 < length()`.
274
275 /// Push the specified `handle` at the back end of this record buffer.
276 /// Return 0 on success, and a non-zero value otherwise. In order to
277 /// accommodate a record, the records from the front end of the buffer
278 /// may be removed. If a record can not be accommodated in the buffer,
279 /// it is silently discarded.
280 int pushBack(const bsl::shared_ptr<Record>& handle) BSLS_KEYWORD_OVERRIDE;
281
282 /// Push the specified `handle` at the front end of this record buffer.
283 /// Return 0 on success, and a non-zero value otherwise. In order to
284 /// accommodate a record, the records from the end end of the buffer may
285 /// be removed. If a record can not be accommodated in the buffer, it
286 /// is silently discarded.
287 int pushFront(const bsl::shared_ptr<Record>& handle) BSLS_KEYWORD_OVERRIDE;
288
289 /// Remove all record handles stored in this record buffer. Note that
290 /// `length()` is now 0.
292
293 // ACCESSORS
294
295 /// Return a reference of the shared pointer referring to the record
296 /// positioned at the back end of this record buffer. The behavior is
297 /// undefined unless this record buffer has been locked by the
298 /// `beginSequence` method and unless `0 < length()`.
299 const bsl::shared_ptr<Record>& back() const BSLS_KEYWORD_OVERRIDE;
300
301 /// Return a reference of the shared pointer referring to the record
302 /// positioned at the front end of this record buffer. The behavior is
303 /// undefined unless this record buffer has been locked by the
304 /// `beginSequence` method and unless `0 < length()`.
305 const bsl::shared_ptr<Record>& front() const BSLS_KEYWORD_OVERRIDE;
306
307 /// Return the number of record handles in this record buffer.
308 int length() const BSLS_KEYWORD_OVERRIDE;
309};
310
311// ============================================================================
312// INLINE DEFINITIONS
313// ============================================================================
314
315 // ---------------------------
316 // class FixedSizeRecordBuffer
317 // ---------------------------
318
319// CREATORS
320inline
322 bslma::Allocator *basicAllocator)
323: d_maxTotalSize(maxTotalSize)
324, d_currentTotalSize(0)
325, d_allocator(basicAllocator)
326, d_deque(&d_allocator)
327{
328}
329
330// MANIPULATORS
331inline
333{
334 d_mutex.lock();
335}
336
337inline
339{
340 d_mutex.unlock();
341}
342
343inline
345{
347 d_deque.clear();
348 d_currentTotalSize = 0;
349}
350
351// ACCESSORS
352inline
354{
356 return d_deque.back();
357}
358
359inline
361{
363 return d_deque.front();
364}
365
366inline
368{
370 return static_cast<int>(d_deque.size());
371}
372
373} // close package namespace
374
375
376#endif
377
378// ----------------------------------------------------------------------------
379// Copyright 2015 Bloomberg Finance L.P.
380//
381// Licensed under the Apache License, Version 2.0 (the "License");
382// you may not use this file except in compliance with the License.
383// You may obtain a copy of the License at
384//
385// http://www.apache.org/licenses/LICENSE-2.0
386//
387// Unless required by applicable law or agreed to in writing, software
388// distributed under the License is distributed on an "AS IS" BASIS,
389// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
390// See the License for the specific language governing permissions and
391// limitations under the License.
392// ----------------------------- END-OF-FILE ----------------------------------
393
394/** @} */
395/** @} */
396/** @} */
Definition ball_countingallocator.h:138
Definition ball_fixedsizerecordbuffer.h:203
void removeAll() BSLS_KEYWORD_OVERRIDE
Definition ball_fixedsizerecordbuffer.h:344
int pushFront(const bsl::shared_ptr< Record > &handle) BSLS_KEYWORD_OVERRIDE
void endSequence() BSLS_KEYWORD_OVERRIDE
Definition ball_fixedsizerecordbuffer.h:338
void beginSequence() BSLS_KEYWORD_OVERRIDE
Definition ball_fixedsizerecordbuffer.h:332
~FixedSizeRecordBuffer() BSLS_KEYWORD_OVERRIDE
BSLMF_NESTED_TRAIT_DECLARATION(FixedSizeRecordBuffer, bslma::UsesBslmaAllocator)
void popFront() BSLS_KEYWORD_OVERRIDE
int length() const BSLS_KEYWORD_OVERRIDE
Return the number of record handles in this record buffer.
Definition ball_fixedsizerecordbuffer.h:367
const bsl::shared_ptr< Record > & front() const BSLS_KEYWORD_OVERRIDE
Definition ball_fixedsizerecordbuffer.h:360
int pushBack(const bsl::shared_ptr< Record > &handle) BSLS_KEYWORD_OVERRIDE
void popBack() BSLS_KEYWORD_OVERRIDE
const bsl::shared_ptr< Record > & back() const BSLS_KEYWORD_OVERRIDE
Definition ball_fixedsizerecordbuffer.h:353
Definition ball_recordbuffer.h:288
Definition ball_record.h:178
reference back()
Definition bslstl_deque.h:1997
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements contained by this deque.
Definition bslstl_deque.h:2074
reference front()
Definition bslstl_deque.h:1987
Definition bslstl_deque.h:772
void swap(deque< VALUE_TYPE, ALLOCATOR > &other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(AllocatorTraits void clear() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_deque.h:1454
Definition bslstl_sharedptr.h:1830
Definition bslma_allocator.h:457
Definition bslmt_lockguard.h:234
Definition bslmt_recursivemutex.h:130
void unlock()
Definition bslmt_recursivemutex.h:206
void lock()
Definition bslmt_recursivemutex.h:194
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition ball_administration.h:214
Definition bdlb_printmethods.h:283
Definition balxml_encoderoptions.h:68
Definition bslma_usesbslmaallocator.h:343