Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component ball_fixedsizerecordbuffer
[Package ball]

Provide a thread-safe fixed-size buffer of record handles. More...

Namespaces

namespace  ball

Detailed Description

Outline
Purpose:
Provide a thread-safe fixed-size buffer of record handles.
Classes:
ball::FixedSizeRecordBuffer thread-safe fixed-size buffer of records
See also:
Component ball_recordbuffer
Description:
This component provides a concrete thread-safe implementation of the ball::RecordBuffer protocol, ball::FixedSizeRecordBuffer:
              ( ball::FixedSizeRecordBuffer )
                            |              ctor
                            V
                  ( ball::RecordBuffer )
                                           dtor
                                           beginSequence
                                           endSequence
                                           popBack
                                           popFront
                                           pushBack
                                           pushFront
                                           removeAll
                                           length
                                           back
                                           front
The thread-safe class ball::FixedSizeRecordBuffer manages record handles (specifically, the instances of bsl::shared_ptr<ball::Record>) in a double-ended buffer. At any time, the sum of sizes of all records contained in a ball::FixedSizeRecordBuffer object plus the amount of memory allocated by the ball::FixedSizeRecordBuffer object itself is guaranteed to be less than or equal to an upper bound specified at creation. In order to accommodate a record, existing records may be removed from the buffer (see below). The ball::FixedSizeRecordBuffer class provides methods to push a record handle into either end (back or front) of the buffer (pushBack and pushFront), to obtain read-only access to the log record positioned at either end (back and front) and to remove the record positioned at either end (popBack and popFront). In order to accommodate a pushBack request, the records from the front end of the buffer may be removed. Similarly, in order to accommodate a pushFront request, the records from the back end of the buffer may be removed. If a record can not be accommodated in the buffer, it is silently (but otherwise safely) discarded.
Usage:
In the following example we demonstrate creation of a limited record buffer followed by concurrent access to it by multiple threads.
  enum {
      KILO_BYTE      = 1024,   // one kilo is (2^10) bytes
      MAX_TOTAL_SIZE = 32 * K, // 'maxTotalSize' parameter
      NUM_ITERATIONS = 1000,   // number of iterations
      NUM_THREADS    = 4       // number of threads
  };
  bslma::Allocator *basicAllocator = bslma::Default::defaultAllocator();
First we create a record buffer.
  bdlma::DefaultDeleter<ball::Record> recordDeleter(basicAllocator);
  ball::FixedSizeRecordBuffer recordBuffer(MAX_TOTAL_SIZE, basicAllocator);
Note that since the record buffer will contain shared pointers to the records, recordDeleter must be created before recordBuffer to ensure that the former has the longer lifetime.
Now we create several threads each of which repeatedly performs the following operations in a tight loop; (1) create a record; (2) build a message and store it into the record; (3) create a record handle; (4) push this record handle at the back end of the record buffer
  void *workerThread(void *arg)
  {
      int id = (int)arg; // thread id
      for (int i = 0; i < NUM_ITERATIONS; ++i) {
          ball::Record *record =
                        new (*basicAllocator) ball::Record(basicAllocator);

          // build a message
          enum { MAX_SIZE = 100 };
          char msg[MAX_SIZE];
          sprintf(msg, "message no. %d from thread no. %d", i, id);

          record->getFixedFields().setMessage(msg);

          bsl::shared_ptr<ball::Record>
            handle(record, &recordDeleter, basicAllocator);

          recordBuffer.pushBack(handle);
      }
After completing the loop each thread iterates, in LIFO order, over all of the records contained in record buffer.
      // print messages in LIFO order
      recordBuffer.beginSequence();
      while (recordBuffer.length()) {
          const ball::Record &rec = recordBuffer.back();
          bsl::cout << rec.getFixedFields().message() << bsl::endl;
          recordBuffer.popBack();
      }
      recordBuffer.endSequence();

      return NULL;
  }