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 <atomic>
9 #include <mutex>
10 #include <map>
11 #include <vector>
12 #include <stdexcept>
13 
14 #include <boost/function.hpp>
15 #include <boost/ptr_container/ptr_circular_buffer.hpp>
16 #include <boost/weak_ptr.hpp>
17 #include <boost/shared_ptr.hpp>
18 #include "base/util.h"
19 
24 template<typename TraceEntryT>
25 class TraceBuffer {
26 public:
27 
29  typedef std::map<const std::string,
30  boost::weak_ptr<TraceBuffer<TraceEntryT> > > TraceBufMap;
31 
34  TraceBuffer(const std::string& buf_name, size_t size, bool trace_enable)
35  : trace_buf_name_(buf_name),
36  trace_buf_size_(size),
38  write_index_(0),
39  read_index_(0),
40  wrap_(false) {
41  seqno_ = 0;
42  trace_enable_ = trace_enable;
43  }
44 
47  read_context_map_.clear();
48  trace_buf_.clear();
49  }
50 
52  std::string Name() {
53  return trace_buf_name_;
54  }
55 
57  void TraceOn() {
58  trace_enable_ = true;
59  }
60 
62  void TraceOff() {
63  trace_enable_ = false;
64  }
65 
67  bool IsTraceOn() {
68  return trace_enable_;
69  }
70 
73  size_t TraceBufSizeGet() {
74  return trace_buf_size_;
75  }
76 
80  return trace_buf_.capacity();
81  }
82 
84  void TraceBufCapacityReset(size_t size) {
85  trace_buf_.rset_capacity(size);
86  trace_buf_size_ = size;
87  }
88 
90  void TraceWrite(TraceEntryT *trace_entry) {
91  std::scoped_lock lock(mutex_);
92 
93  // Add the trace
94  trace_buf_.push_back(trace_entry);
95 
96  // Once the trace buffer is wrapped, increment the read index
97  if (wrap_) {
98  if (++read_index_ == trace_buf_size_) {
99  read_index_ = 0;
100  }
101  }
102 
103  // Increment the write_index_ and reset upon reaching trace_buf_size_
104  if (++write_index_ == trace_buf_size_) {
105  write_index_ = 0;
106  wrap_ = true;
107  }
108 
109  // Trace messages could be read in batches instead of reading
110  // the entire trace buffer in one shot. Therefore, trace messages
111  // could be added between subsequent read requests. If the
112  // read_index_ [points to the oldest message in the trace buffer]
113  // becomes same as the read index [points to the position in the
114  // trace buffer from where the next trace message should be read]
115  // stored in the read context, then there is no need to remember the
116  // read context.
117  ReadContextMap::iterator it = read_context_map_.begin();
118  ReadContextMap::iterator next = it;
119  for (size_t i = 0, cnt = read_context_map_.size(); i < cnt;
120  i++, it = next) {
121  ++next;
122  if (*it->second.get() == read_index_) {
123  read_context_map_.erase(it);
124  }
125  }
126  }
127 
129  uint32_t GetNextSeqNum() {
130  uint32_t nseqno(seqno_.fetch_add(1));
131  // Reset seqno_ if it reaches max value
132  if (nseqno+1 >= kMaxSeqno) {
133  seqno_ = kMinSeqno;
134  }
135  return nseqno;
136  }
137 
140  void TraceRead(const std::string& context, const int count,
141  boost::function<void (TraceEntryT *, bool)> cb) {
142  std::scoped_lock lock(mutex_);
143  if (trace_buf_.empty()) {
144  // No message in the trace buffer
145  return;
146  }
147 
148  // if count = 0, then set the cnt equal to the size of trace_buf_
149  size_t cnt = count ? count : trace_buf_.size();
150 
151  size_t *read_index_ptr;
152  typename ContainerType::iterator it;
153  ReadContextMap::iterator context_it =
154  read_context_map_.find(context);
155  if (context_it != read_context_map_.end()) {
156  // If the read context is present, manipulate the position
157  // from where we wanna start
158  read_index_ptr = context_it->second.get();
159  size_t offset = *read_index_ptr - read_index_;
160  offset = offset > 0 ? offset : trace_buf_size_ + offset;
161  it = trace_buf_.begin() + offset;
162  } else {
163  // Create read context
164  boost::shared_ptr<size_t> read_context(new size_t(read_index_));
165  read_index_ptr = read_context.get();
166  read_context_map_.insert(std::make_pair(context, read_context));
167  it = trace_buf_.begin();
168  }
169 
170  size_t i;
171  typename ContainerType::iterator next = it;
172  for (i = 0; (it != trace_buf_.end()) && (i < cnt); i++, it = next) {
173  ++next;
174  cb(&(*it), next != trace_buf_.end());
175  }
176 
177  // Update the read index in the read context
178  size_t offset = *read_index_ptr + i;
179  *read_index_ptr = offset >= trace_buf_size_ ?
180  offset - trace_buf_size_ : offset;
181  }
182 
185  void TraceReadDone(const std::string& context) {
186  std::scoped_lock lock(mutex_);
187  ReadContextMap::iterator context_it =
188  read_context_map_.find(context);
189  if (context_it != read_context_map_.end()) {
190  read_context_map_.erase(context_it);
191  }
192  }
193 
194 private:
195 
197  typedef boost::ptr_circular_buffer<TraceEntryT> ContainerType;
198 
200  typedef std::map<const std::string, boost::shared_ptr<size_t> >
202 
204  std::string trace_buf_name_;
205 
208 
211 
214  std::atomic<bool> trace_enable_;
215 
218  size_t write_index_;
219 
222  size_t read_index_;
223 
225  bool wrap_;
226 
229 
231  std::atomic<uint32_t> seqno_;
232 
235  std::mutex mutex_;
236 
238  static const uint32_t kMaxSeqno = ((2 ^ 32) - 1) - 1;
239 
241  static const uint32_t kMinSeqno = 1;
242 
244 };
245 
247 template<typename TraceEntryT>
249 public:
250 
253 
256  explicit TraceBufferDeleter(TraceBufMap &trace_buf_map, std::mutex &mutex) :
257  trace_buf_map_(trace_buf_map),
258  mutex_(mutex) {
259  }
260 
262  void operator()(TraceBuffer<TraceEntryT> *trace_buffer) const {
263  std::scoped_lock lock(mutex_);
264  for (typename TraceBufMap::iterator it = trace_buf_map_.begin();
265  it != trace_buf_map_.end();
266  it++) {
267  if (it->second.lock() == NULL) {
268  trace_buf_map_.erase(it->first);
269  delete trace_buffer;
270  break;
271  }
272  }
273  }
274 
275 private:
276 
279 
281  std::mutex &mutex_;
282 };
283 
287 template<typename TraceEntryT>
288 class Trace {
289 public:
290 
293 
295  static Trace* GetInstance() {
296  if (!trace_) {
297  trace_ = new Trace;
298  }
299  return trace_;
300  }
301 
303  void TraceOn() {
304  trace_enable_ = true;
305  }
306 
308  void TraceOff() {
309  trace_enable_ = false;
310  }
311 
313  bool IsTraceOn() {
314  return trace_enable_;
315  }
316 
319  boost::shared_ptr<TraceBuffer<TraceEntryT> > TraceBufGet(const std::string& buf_name) {
320  std::scoped_lock lock(mutex_);
321  typename TraceBufMap::iterator it = trace_buf_map_.find(buf_name);
322  if (it != trace_buf_map_.end()) {
323  return it->second.lock();
324  }
325  return boost::shared_ptr<TraceBuffer<TraceEntryT> >();
326  }
327 
331  boost::shared_ptr<TraceBuffer<TraceEntryT> > TraceBufAdd(const std::string& buf_name, size_t size,
332  bool trace_enable) {
333  // should we have a default size for the buffer?
334  if (!size) {
335  return boost::shared_ptr<TraceBuffer<TraceEntryT> >();
336  }
337  std::scoped_lock lock(mutex_);
338  typename TraceBufMap::iterator it = trace_buf_map_.find(buf_name);
339  if (it == trace_buf_map_.end()) {
340  boost::shared_ptr<TraceBuffer<TraceEntryT> > trace_buf(
341  new TraceBuffer<TraceEntryT>(buf_name, size, trace_enable),
343  trace_buf_map_.insert(std::make_pair(buf_name, trace_buf));
344  return trace_buf;
345  }
346  return it->second.lock();
347  }
348 
350  void TraceBufListGet(std::vector<std::string>& trace_buf_list) {
351  std::scoped_lock lock(mutex_);
352  typename TraceBufMap::iterator it;
353  for (it = trace_buf_map_.begin(); it != trace_buf_map_.end(); ++it) {
354  trace_buf_list.push_back(it->first);
355  }
356  }
357 
359  size_t TraceBufCapacityGet(const std::string& buf_name) {
360  std::scoped_lock lock(mutex_);
361  typename TraceBufMap::iterator it = trace_buf_map_.find(buf_name);
362  if (it != trace_buf_map_.end()) {
363  boost::shared_ptr<TraceBuffer<TraceEntryT> > trace_buf =
364  it->second.lock();
365  return trace_buf->TraceBufCapacityGet();
366  } else {
367  return 0;
368  }
369  }
370 
374  boost::shared_ptr<TraceBuffer<TraceEntryT> > TraceBufCapacityReset(
375  const std::string& buf_name, size_t size) {
376  std::scoped_lock lock(mutex_);
377  typename TraceBufMap::iterator it = trace_buf_map_.find(buf_name);
378  if (it != trace_buf_map_.end()) {
379  boost::shared_ptr<TraceBuffer<TraceEntryT> > trace_buf =
380  it->second.lock();
381  trace_buf->TraceBufCapacityReset(size);
382  return trace_buf;
383  }
384  return boost::shared_ptr<TraceBuffer<TraceEntryT> >();
385  }
386 
387 private:
388 
390  Trace() {
391  trace_enable_ = true;
392  }
393 
395  ~Trace() {
396 
397  delete trace_;
398  }
399 
401  static Trace *trace_;
402 
404  std::atomic<bool> trace_enable_;
405 
408 
410  std::mutex mutex_;
411 
413 };
414 
415 #endif // __TRACE_H__
The class is responsible for the destruction of a trace buffer.
Definition: trace.h:248
std::mutex & mutex_
A reference to the mutex object.
Definition: trace.h:281
TraceBufferDeleter(TraceBufMap &trace_buf_map, std::mutex &mutex)
Definition: trace.h:256
TraceBufMap & trace_buf_map_
A reference to the trace buffers table.
Definition: trace.h:278
void operator()(TraceBuffer< TraceEntryT > *trace_buffer) const
Performs the deletion of the trace buffer from the given map.
Definition: trace.h:262
typename TraceBuffer< TraceEntryT >::TraceBufMap TraceBufMap
A link to the trace buffers table type.
Definition: trace.h:252
size_t TraceBufCapacityGet()
Definition: trace.h:79
size_t TraceBufSizeGet()
Definition: trace.h:73
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:30
TraceBuffer(const std::string &buf_name, size_t size, bool trace_enable)
Definition: trace.h:34
size_t write_index_
Definition: trace.h:218
uint32_t GetNextSeqNum()
Returns the next sequence number.
Definition: trace.h:129
void TraceOff()
Disables the trace buffer.
Definition: trace.h:62
boost::ptr_circular_buffer< TraceEntryT > ContainerType
Specifies the data type for storing records of the trace buffer.
Definition: trace.h:197
void TraceWrite(TraceEntryT *trace_entry)
Writes the provided data into the circular buffer.
Definition: trace.h:90
std::mutex mutex_
Definition: trace.h:235
size_t read_index_
Definition: trace.h:222
bool wrap_
Indicates if the trace buffer is wrapped.
Definition: trace.h:225
static const uint32_t kMinSeqno
Reserves 0.
Definition: trace.h:241
ContainerType trace_buf_
Stores the records of the trace buffer.
Definition: trace.h:210
void TraceReadDone(const std::string &context)
Definition: trace.h:185
void TraceBufCapacityReset(size_t size)
Resets the size of the circular buffer.
Definition: trace.h:84
std::string trace_buf_name_
Stores the name of the trace buffer.
Definition: trace.h:204
void TraceOn()
Enables the trace buffer.
Definition: trace.h:57
void TraceRead(const std::string &context, const int count, boost::function< void(TraceEntryT *, bool)> cb)
Definition: trace.h:140
size_t trace_buf_size_
Stores the size of the trace buffer.
Definition: trace.h:207
std::string Name()
Returns the name of the trace buffer.
Definition: trace.h:52
~TraceBuffer()
Destroys a trace buffer.
Definition: trace.h:46
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:201
bool IsTraceOn()
Determines whether the trace buffer is enabled or not.
Definition: trace.h:67
static const uint32_t kMaxSeqno
Reserves max(uint32_t)
Definition: trace.h:238
std::atomic< bool > trace_enable_
Definition: trace.h:214
ReadContextMap read_context_map_
Stores the read context.
Definition: trace.h:228
std::atomic< uint32_t > seqno_
Stores the current sequence number.
Definition: trace.h:231
Definition: trace.h:288
TraceBufMap trace_buf_map_
Stores the table of trace buffers.
Definition: trace.h:407
~Trace()
Destroys the table.
Definition: trace.h:395
boost::shared_ptr< TraceBuffer< TraceEntryT > > TraceBufAdd(const std::string &buf_name, size_t size, bool trace_enable)
Definition: trace.h:331
boost::shared_ptr< TraceBuffer< TraceEntryT > > TraceBufGet(const std::string &buf_name)
Definition: trace.h:319
typename TraceBuffer< TraceEntryT >::TraceBufMap TraceBufMap
A link to the trace buffers table type.
Definition: trace.h:292
void TraceBufListGet(std::vector< std::string > &trace_buf_list)
Requests the list of trace buffers names from the table.
Definition: trace.h:350
boost::shared_ptr< TraceBuffer< TraceEntryT > > TraceBufCapacityReset(const std::string &buf_name, size_t size)
Definition: trace.h:374
std::mutex mutex_
A mutex to protect the table from data races.
Definition: trace.h:410
void TraceOff()
Disables tracing for the table.
Definition: trace.h:308
bool IsTraceOn()
Determines whether tracing is enabled for the table.
Definition: trace.h:313
Trace()
Forbids the default ctor.
Definition: trace.h:390
size_t TraceBufCapacityGet(const std::string &buf_name)
Returns the capacity of the trace buffer with the given name.
Definition: trace.h:359
static Trace * GetInstance()
Returns a pointer to the trace buffers table instance.
Definition: trace.h:295
DISALLOW_COPY_AND_ASSIGN(Trace)
void TraceOn()
Enables tracing for the table.
Definition: trace.h:303
static Trace * trace_
A pointer to the table (singleton) used in this program.
Definition: trace.h:401
std::atomic< bool > trace_enable_
Determines if the tracing is enabled for the table.
Definition: trace.h:404