OpenSDN source code
trace.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #ifndef __TRACE_H__
6 #define __TRACE_H__
7 
8 #include <tbb/mutex.h>
9 #include <map>
10 #include <vector>
11 #include <stdexcept>
12 #include <boost/function.hpp>
13 #include <boost/ptr_container/ptr_circular_buffer.hpp>
14 #include <boost/weak_ptr.hpp>
15 #include <boost/shared_ptr.hpp>
16 #include "base/util.h"
17 
22 template<typename TraceEntryT>
23 class TraceBuffer {
24 public:
25 
27  typedef std::map<const std::string,
28  boost::weak_ptr<TraceBuffer<TraceEntryT> > > TraceBufMap;
29 
32  TraceBuffer(const std::string& buf_name, size_t size, bool trace_enable)
33  : trace_buf_name_(buf_name),
34  trace_buf_size_(size),
36  write_index_(0),
37  read_index_(0),
38  wrap_(false) {
39  seqno_ = 0;
40  trace_enable_ = trace_enable;
41  }
42 
45  read_context_map_.clear();
46  trace_buf_.clear();
47  }
48 
50  std::string Name() {
51  return trace_buf_name_;
52  }
53 
55  void TraceOn() {
56  trace_enable_ = true;
57  }
58 
60  void TraceOff() {
61  trace_enable_ = false;
62  }
63 
65  bool IsTraceOn() {
66  return trace_enable_;
67  }
68 
71  size_t TraceBufSizeGet() {
72  return trace_buf_size_;
73  }
74 
78  return trace_buf_.capacity();
79  }
80 
82  void TraceBufCapacityReset(size_t size) {
83  trace_buf_.rset_capacity(size);
84  trace_buf_size_ = size;
85  }
86 
88  void TraceWrite(TraceEntryT *trace_entry) {
89  tbb::mutex::scoped_lock lock(mutex_);
90 
91  // Add the trace
92  trace_buf_.push_back(trace_entry);
93 
94  // Once the trace buffer is wrapped, increment the read index
95  if (wrap_) {
96  if (++read_index_ == trace_buf_size_) {
97  read_index_ = 0;
98  }
99  }
100 
101  // Increment the write_index_ and reset upon reaching trace_buf_size_
102  if (++write_index_ == trace_buf_size_) {
103  write_index_ = 0;
104  wrap_ = true;
105  }
106 
107  // Trace messages could be read in batches instead of reading
108  // the entire trace buffer in one shot. Therefore, trace messages
109  // could be added between subsequent read requests. If the
110  // read_index_ [points to the oldest message in the trace buffer]
111  // becomes same as the read index [points to the position in the
112  // trace buffer from where the next trace message should be read]
113  // stored in the read context, then there is no need to remember the
114  // read context.
115  ReadContextMap::iterator it = read_context_map_.begin();
116  ReadContextMap::iterator next = it;
117  for (size_t i = 0, cnt = read_context_map_.size(); i < cnt;
118  i++, it = next) {
119  ++next;
120  if (*it->second.get() == read_index_) {
121  read_context_map_.erase(it);
122  }
123  }
124  }
125 
127  uint32_t GetNextSeqNum() {
128  uint32_t nseqno(seqno_.fetch_and_increment());
129  // Reset seqno_ if it reaches max value
130  if (nseqno > kMaxSeqno) {
131  seqno_ = kMinSeqno;
132  }
133  return nseqno;
134  }
135 
138  void TraceRead(const std::string& context, const int count,
139  boost::function<void (TraceEntryT *, bool)> cb) {
140  tbb::mutex::scoped_lock lock(mutex_);
141  if (trace_buf_.empty()) {
142  // No message in the trace buffer
143  return;
144  }
145 
146  // if count = 0, then set the cnt equal to the size of trace_buf_
147  size_t cnt = count ? count : trace_buf_.size();
148 
149  size_t *read_index_ptr;
150  typename ContainerType::iterator it;
151  ReadContextMap::iterator context_it =
152  read_context_map_.find(context);
153  if (context_it != read_context_map_.end()) {
154  // If the read context is present, manipulate the position
155  // from where we wanna start
156  read_index_ptr = context_it->second.get();
157  size_t offset = *read_index_ptr - read_index_;
158  offset = offset > 0 ? offset : trace_buf_size_ + offset;
159  it = trace_buf_.begin() + offset;
160  } else {
161  // Create read context
162  boost::shared_ptr<size_t> read_context(new size_t(read_index_));
163  read_index_ptr = read_context.get();
164  read_context_map_.insert(std::make_pair(context, read_context));
165  it = trace_buf_.begin();
166  }
167 
168  size_t i;
169  typename ContainerType::iterator next = it;
170  for (i = 0; (it != trace_buf_.end()) && (i < cnt); i++, it = next) {
171  ++next;
172  cb(&(*it), next != trace_buf_.end());
173  }
174 
175  // Update the read index in the read context
176  size_t offset = *read_index_ptr + i;
177  *read_index_ptr = offset >= trace_buf_size_ ?
178  offset - trace_buf_size_ : offset;
179  }
180 
183  void TraceReadDone(const std::string& context) {
184  tbb::mutex::scoped_lock lock(mutex_);
185  ReadContextMap::iterator context_it =
186  read_context_map_.find(context);
187  if (context_it != read_context_map_.end()) {
188  read_context_map_.erase(context_it);
189  }
190  }
191 
192 private:
193 
195  typedef boost::ptr_circular_buffer<TraceEntryT> ContainerType;
196 
198  typedef std::map<const std::string, boost::shared_ptr<size_t> >
200 
202  std::string trace_buf_name_;
203 
206 
209 
212  tbb::atomic<bool> trace_enable_;
213 
216  size_t write_index_;
217 
220  size_t read_index_;
221 
223  bool wrap_;
224 
227 
229  tbb::atomic<uint32_t> seqno_;
230 
233  tbb::mutex mutex_;
234 
236  static const uint32_t kMaxSeqno = ((2 ^ 32) - 1) - 1;
237 
239  static const uint32_t kMinSeqno = 1;
240 
242 };
243 
245 template<typename TraceEntryT>
247 public:
248 
251 
254  explicit TraceBufferDeleter(TraceBufMap &trace_buf_map, tbb::mutex &mutex) :
255  trace_buf_map_(trace_buf_map),
256  mutex_(mutex) {
257  }
258 
260  void operator()(TraceBuffer<TraceEntryT> *trace_buffer) const {
261  tbb::mutex::scoped_lock lock(mutex_);
262  for (typename TraceBufMap::iterator it = trace_buf_map_.begin();
263  it != trace_buf_map_.end();
264  it++) {
265  if (it->second.lock() == NULL) {
266  trace_buf_map_.erase(it->first);
267  delete trace_buffer;
268  break;
269  }
270  }
271  }
272 
273 private:
274 
277 
279  tbb::mutex &mutex_;
280 };
281 
285 template<typename TraceEntryT>
286 class Trace {
287 public:
288 
291 
293  static Trace* GetInstance() {
294  if (!trace_) {
295  trace_ = new Trace;
296  }
297  return trace_;
298  }
299 
301  void TraceOn() {
302  trace_enable_ = true;
303  }
304 
306  void TraceOff() {
307  trace_enable_ = false;
308  }
309 
311  bool IsTraceOn() {
312  return trace_enable_;
313  }
314 
317  boost::shared_ptr<TraceBuffer<TraceEntryT> > TraceBufGet(const std::string& buf_name) {
318  tbb::mutex::scoped_lock lock(mutex_);
319  typename TraceBufMap::iterator it = trace_buf_map_.find(buf_name);
320  if (it != trace_buf_map_.end()) {
321  return it->second.lock();
322  }
323  return boost::shared_ptr<TraceBuffer<TraceEntryT> >();
324  }
325 
329  boost::shared_ptr<TraceBuffer<TraceEntryT> > TraceBufAdd(const std::string& buf_name, size_t size,
330  bool trace_enable) {
331  // should we have a default size for the buffer?
332  if (!size) {
333  return boost::shared_ptr<TraceBuffer<TraceEntryT> >();
334  }
335  tbb::mutex::scoped_lock lock(mutex_);
336  typename TraceBufMap::iterator it = trace_buf_map_.find(buf_name);
337  if (it == trace_buf_map_.end()) {
338  boost::shared_ptr<TraceBuffer<TraceEntryT> > trace_buf(
339  new TraceBuffer<TraceEntryT>(buf_name, size, trace_enable),
341  trace_buf_map_.insert(std::make_pair(buf_name, trace_buf));
342  return trace_buf;
343  }
344  return it->second.lock();
345  }
346 
348  void TraceBufListGet(std::vector<std::string>& trace_buf_list) {
349  tbb::mutex::scoped_lock lock(mutex_);
350  typename TraceBufMap::iterator it;
351  for (it = trace_buf_map_.begin(); it != trace_buf_map_.end(); ++it) {
352  trace_buf_list.push_back(it->first);
353  }
354  }
355 
357  size_t TraceBufCapacityGet(const std::string& buf_name) {
358  tbb::mutex::scoped_lock lock(mutex_);
359  typename TraceBufMap::iterator it = trace_buf_map_.find(buf_name);
360  if (it != trace_buf_map_.end()) {
361  boost::shared_ptr<TraceBuffer<TraceEntryT> > trace_buf =
362  it->second.lock();
363  return trace_buf->TraceBufCapacityGet();
364  } else {
365  return 0;
366  }
367  }
368 
372  boost::shared_ptr<TraceBuffer<TraceEntryT> > TraceBufCapacityReset(
373  const std::string& buf_name, size_t size) {
374  tbb::mutex::scoped_lock lock(mutex_);
375  typename TraceBufMap::iterator it = trace_buf_map_.find(buf_name);
376  if (it != trace_buf_map_.end()) {
377  boost::shared_ptr<TraceBuffer<TraceEntryT> > trace_buf =
378  it->second.lock();
379  trace_buf->TraceBufCapacityReset(size);
380  return trace_buf;
381  }
382  return boost::shared_ptr<TraceBuffer<TraceEntryT> >();
383  }
384 
385 private:
386 
388  Trace() {
389  trace_enable_ = true;
390  }
391 
393  ~Trace() {
394 
395  delete trace_;
396  }
397 
399  static Trace *trace_;
400 
402  tbb::atomic<bool> trace_enable_;
403 
406 
408  tbb::mutex mutex_;
409 
411 };
412 
413 #endif // __TRACE_H__
The class is responsible for the destruction of a trace buffer.
Definition: trace.h:246
TraceBufferDeleter(TraceBufMap &trace_buf_map, tbb::mutex &mutex)
Definition: trace.h:254
tbb::mutex & mutex_
A reference to the mutex object.
Definition: trace.h:279
TraceBufMap & trace_buf_map_
A reference to the trace buffers table.
Definition: trace.h:276
void operator()(TraceBuffer< TraceEntryT > *trace_buffer) const
Performs the deletion of the trace buffer from the given map.
Definition: trace.h:260
typename TraceBuffer< TraceEntryT >::TraceBufMap TraceBufMap
A link to the trace buffers table type.
Definition: trace.h:250
size_t TraceBufCapacityGet()
Definition: trace.h:77
size_t TraceBufSizeGet()
Definition: trace.h:71
tbb::atomic< uint32_t > seqno_
Stores the current sequence number.
Definition: trace.h:229
std::map< const std::string, boost::weak_ptr< TraceBuffer< TraceEntryT > > > TraceBufMap
The type defines how a map (a table) of trace buffers is stored.
Definition: trace.h:28
TraceBuffer(const std::string &buf_name, size_t size, bool trace_enable)
Definition: trace.h:32
size_t write_index_
Definition: trace.h:216
uint32_t GetNextSeqNum()
Returns the next sequence number.
Definition: trace.h:127
void TraceOff()
Disables the trace buffer.
Definition: trace.h:60
boost::ptr_circular_buffer< TraceEntryT > ContainerType
Specifies the data type for storing records of the trace buffer.
Definition: trace.h:195
tbb::mutex mutex_
Definition: trace.h:233
void TraceWrite(TraceEntryT *trace_entry)
Writes the provided data into the circular buffer.
Definition: trace.h:88
size_t read_index_
Definition: trace.h:220
bool wrap_
Indicates if the trace buffer is wrapped.
Definition: trace.h:223
static const uint32_t kMinSeqno
Reserves 0.
Definition: trace.h:239
ContainerType trace_buf_
Stores the records of the trace buffer.
Definition: trace.h:208
void TraceReadDone(const std::string &context)
Definition: trace.h:183
void TraceBufCapacityReset(size_t size)
Resets the size of the circular buffer.
Definition: trace.h:82
std::string trace_buf_name_
Stores the name of the trace buffer.
Definition: trace.h:202
void TraceOn()
Enables the trace buffer.
Definition: trace.h:55
void TraceRead(const std::string &context, const int count, boost::function< void(TraceEntryT *, bool)> cb)
Definition: trace.h:138
size_t trace_buf_size_
Stores the size of the trace buffer.
Definition: trace.h:205
std::string Name()
Returns the name of the trace buffer.
Definition: trace.h:50
~TraceBuffer()
Destroys a trace buffer.
Definition: trace.h:44
DISALLOW_COPY_AND_ASSIGN(TraceBuffer)
std::map< const std::string, boost::shared_ptr< size_t > > ReadContextMap
Specifies the read context for the trace buffer.
Definition: trace.h:199
tbb::atomic< bool > trace_enable_
Definition: trace.h:212
bool IsTraceOn()
Determines whether the trace buffer is enabled or not.
Definition: trace.h:65
static const uint32_t kMaxSeqno
Reserves max(uint32_t)
Definition: trace.h:236
ReadContextMap read_context_map_
Stores the read context.
Definition: trace.h:226
Definition: trace.h:286
TraceBufMap trace_buf_map_
Stores the table of trace buffers.
Definition: trace.h:405
~Trace()
Destroys the table.
Definition: trace.h:393
boost::shared_ptr< TraceBuffer< TraceEntryT > > TraceBufAdd(const std::string &buf_name, size_t size, bool trace_enable)
Definition: trace.h:329
boost::shared_ptr< TraceBuffer< TraceEntryT > > TraceBufGet(const std::string &buf_name)
Definition: trace.h:317
tbb::atomic< bool > trace_enable_
Determines if the tracing is enabled for the table.
Definition: trace.h:402
typename TraceBuffer< TraceEntryT >::TraceBufMap TraceBufMap
A link to the trace buffers table type.
Definition: trace.h:290
void TraceBufListGet(std::vector< std::string > &trace_buf_list)
Requests the list of trace buffers names from the table.
Definition: trace.h:348
boost::shared_ptr< TraceBuffer< TraceEntryT > > TraceBufCapacityReset(const std::string &buf_name, size_t size)
Definition: trace.h:372
tbb::mutex mutex_
A mutex to protect the table from data races.
Definition: trace.h:408
void TraceOff()
Disables tracing for the table.
Definition: trace.h:306
bool IsTraceOn()
Determines whether tracing is enabled for the table.
Definition: trace.h:311
Trace()
Forbids the default ctor.
Definition: trace.h:388
size_t TraceBufCapacityGet(const std::string &buf_name)
Returns the capacity of the trace buffer with the given name.
Definition: trace.h:357
static Trace * GetInstance()
Returns a pointer to the trace buffers table instance.
Definition: trace.h:293
DISALLOW_COPY_AND_ASSIGN(Trace)
void TraceOn()
Enables tracing for the table.
Definition: trace.h:301
static Trace * trace_
A pointer to the table (singleton) used in this program.
Definition: trace.h:399