BDE 4.39.x 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 private:
226 // NOT IMPLEMENTED
229
230 public:
231 // TRAITS
234
235 // CREATORS
236
237 /// Create a limited record buffer such that at any time the sum of
238 /// sizes of all records contained *plus* the amount of memory allocated
239 /// by this object is guaranteed to be less than or equal to the
240 /// specified `maxTotalSize`. Optionally specify a `basicAllocator`
241 /// used to supply memory. If `basicAllocator` is 0, the currently
242 /// installed default allocator is used.
243 ///
244 /// \pre The behavior is undefined unless `maxTotalSize > 0`.
245 FixedSizeRecordBuffer(int maxTotalSize,
246 bslma::Allocator *basicAllocator = 0);
247
248 /// Remove all record handles from this record buffer and destroy this
249 /// record buffer.
251
252 // MANIPULATORS
253
254 /// *Lock* this record buffer so that a sequence of method invocations
255 /// on this record buffer can occur uninterrupted by other threads. The
256 /// buffer will remain *locked* until `endSequence` is called. It is
257 /// valid to invoke other methods on this record buffer between the
258 /// calls to `beginSequence` and `endSequence` (the implementation
259 /// guarantees this by employing a recursive mutex).
261
262 /// *Unlock* this record buffer, thus allowing other threads to access it.
263 ///
264 /// \pre The behavior is undefined unless the buffer is already *locked*
265 /// by `beginSequence`.
267
268 /// Remove from this record buffer the record handle positioned at the back end of the buffer.
269 ///
270 /// \pre The behavior is undefined unless
271 /// `0 < length()`.
273
274 /// Remove from this record buffer the record handle positioned at the front end of the buffer.
275 ///
276 /// \pre The behavior is undefined unless
277 /// `0 < length()`.
279
280 /// Push the specified `handle` at the back end of this record buffer.
281 /// Return 0 on success, and a non-zero value otherwise. In order to
282 /// accommodate a record, the records from the front end of the buffer
283 /// may be removed. If a record can not be accommodated in the buffer,
284 /// it is silently discarded.
285 int pushBack(const bsl::shared_ptr<Record>& handle) BSLS_KEYWORD_OVERRIDE;
286
287 /// Push the specified `handle` at the front end of this record buffer.
288 /// Return 0 on success, and a non-zero value otherwise. In order to
289 /// accommodate a record, the records from the end end of the buffer may
290 /// be removed. If a record can not be accommodated in the buffer, it
291 /// is silently discarded.
292 int pushFront(const bsl::shared_ptr<Record>& handle) BSLS_KEYWORD_OVERRIDE;
293
294 /// Remove all record handles stored in this record buffer.
295 ///
296 /// \note Note that `length()` is now 0.
298
299 // ACCESSORS
300
301 /// Return a reference of the shared pointer referring to the record
302 /// positioned at the back end of this record buffer.
303 ///
304 /// \pre The behavior is undefined unless this record buffer has been locked by the
305 /// `beginSequence` method and unless `0 < length()`.
306 const bsl::shared_ptr<Record>& back() const BSLS_KEYWORD_OVERRIDE;
307
308 /// Return a reference of the shared pointer referring to the record
309 /// positioned at the front end of this record buffer.
310 ///
311 /// \pre The behavior is undefined unless this record buffer has been locked by the
312 /// `beginSequence` method and unless `0 < length()`.
313 const bsl::shared_ptr<Record>& front() const BSLS_KEYWORD_OVERRIDE;
314
315 /// Return the number of record handles in this record buffer.
316 int length() const BSLS_KEYWORD_OVERRIDE;
317};
318
319// ============================================================================
320// INLINE DEFINITIONS
321// ============================================================================
322
323 // ---------------------------
324 // class FixedSizeRecordBuffer
325 // ---------------------------
326
327// CREATORS
328inline
330 bslma::Allocator *basicAllocator)
331: d_maxTotalSize(maxTotalSize)
332, d_currentTotalSize(0)
333, d_allocator(basicAllocator)
334, d_deque(&d_allocator)
335{
336}
337
338// MANIPULATORS
339inline
341{
342 d_mutex.lock();
343}
344
345inline
347{
348 d_mutex.unlock();
349}
350
351inline
353{
355 d_deque.clear();
356 d_currentTotalSize = 0;
357}
358
359// ACCESSORS
360inline
362{
364 return d_deque.back();
365}
366
367inline
369{
371 return d_deque.front();
372}
373
374inline
376{
378 return static_cast<int>(d_deque.size());
379}
380
381} // close package namespace
382
383
384#endif
385
386// ----------------------------------------------------------------------------
387// Copyright 2015 Bloomberg Finance L.P.
388//
389// Licensed under the Apache License, Version 2.0 (the "License");
390// you may not use this file except in compliance with the License.
391// You may obtain a copy of the License at
392//
393// http://www.apache.org/licenses/LICENSE-2.0
394//
395// Unless required by applicable law or agreed to in writing, software
396// distributed under the License is distributed on an "AS IS" BASIS,
397// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
398// See the License for the specific language governing permissions and
399// limitations under the License.
400// ----------------------------- END-OF-FILE ----------------------------------
401
402/** @} */
403/** @} */
404/** @} */
Definition ball_countingallocator.h:138
Definition ball_fixedsizerecordbuffer.h:203
void removeAll() BSLS_KEYWORD_OVERRIDE
Definition ball_fixedsizerecordbuffer.h:352
int pushFront(const bsl::shared_ptr< Record > &handle) BSLS_KEYWORD_OVERRIDE
void endSequence() BSLS_KEYWORD_OVERRIDE
Definition ball_fixedsizerecordbuffer.h:346
void beginSequence() BSLS_KEYWORD_OVERRIDE
Definition ball_fixedsizerecordbuffer.h:340
~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:375
const bsl::shared_ptr< Record > & front() const BSLS_KEYWORD_OVERRIDE
Definition ball_fixedsizerecordbuffer.h:368
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:361
Definition ball_recordbuffer.h:288
Definition ball_record.h:176
reference back()
Definition bslstl_deque.h:2164
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements contained by this deque.
Definition bslstl_deque.h:2241
reference front()
Definition bslstl_deque.h:2154
Definition bslstl_deque.h:814
void swap(deque< VALUE_TYPE, ALLOCATOR > &other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(AllocatorTraits void clear() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_deque.h:1604
Definition bslstl_sharedptr.h:1838
Definition bslma_allocator.h:545
Definition bslmt_lockguard.h:234
Definition bslmt_recursivemutex.h:131
void unlock()
Definition bslmt_recursivemutex.h:209
void lock()
Definition bslmt_recursivemutex.h:197
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:695
Definition ball_administration.h:214
Definition bdlat_valuetypefunctions.h:939
Definition baljsn_encoder_testtypes.h:76
Definition bslma_usesbslmaallocator.h:344