OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
db_table.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #ifndef ctrlplane_db_table_h
6 #define ctrlplane_db_table_h
7 
8 #include <memory>
9 #include <vector>
10 #include <unistd.h>
11 #include <boost/function.hpp>
12 #include <boost/intrusive_ptr.hpp>
13 #include <tbb/atomic.h>
14 
15 #include "base/util.h"
16 
17 class DB;
18 class DBClient;
19 class DBEntryBase;
20 class DBEntry;
21 class DBTablePartBase;
22 class DBTablePartition;
23 class DBTableWalk;
24 class ShowTableListener;
25 
26 class DBRequestKey {
27 public:
28  virtual ~DBRequestKey() { }
29 };
31 public:
32  virtual ~DBRequestData() { }
33 };
34 
35 struct DBRequest {
36  typedef enum {
41  } DBOperation;
43 
44  DBRequest();
45  DBRequest(DBOperation op) : oper(op) { }
46  ~DBRequest();
47 
48  std::unique_ptr<DBRequestKey> key;
49  std::unique_ptr<DBRequestData> data;
50 
51  // Swap contents between two DBRequest entries.
52  void Swap(DBRequest *rhs);
53 
54 private:
56 };
57 
58 // Database table interface.
59 class DBTableBase {
60 public:
61  typedef boost::function<void(DBTablePartBase *, DBEntryBase *)> ChangeCallback;
62  typedef int ListenerId;
63 
64  static const int kInvalidId = -1;
65 
66  DBTableBase(DB *db, const std::string &name);
67  virtual ~DBTableBase();
68 
69  // Enqueue a request to the table. Takes ownership of the data.
70  bool Enqueue(DBRequest *req);
71  void EnqueueRemove(DBEntryBase *db_entry);
72 
73  // Determine the table partition depending on the record key.
74  virtual DBTablePartBase *GetTablePartition(const DBRequestKey *key) = 0;
75  // Determine the table partition depending on the Entry
76  virtual DBTablePartBase *GetTablePartition(const DBEntryBase *entry) = 0;
77  // Determine the table partition for given index
78  virtual DBTablePartBase *GetTablePartition(const int index) = 0;
79 
80  // Record has been modified.
81  virtual void Change(DBEntryBase *) = 0;
82 
83  // Callback from table partition for entry add/remove.
84  virtual void AddRemoveCallback(const DBEntryBase *entry, bool add) const { }
85 
86  // Register a DB listener.
88  const std::string &name = "unspecified");
89  void Unregister(ListenerId listener);
90 
91  void RunNotify(DBTablePartBase *tpart, DBEntryBase *entry);
92 
93  // Manage db state count for a listener.
94  void AddToDBStateCount(ListenerId listener, int count);
95 
96  uint64_t GetDBStateCount(ListenerId listener);
97 
98  // Calculate the size across all partitions.
99  // Must be called from Task which is mutually exclusive with db::DBTable.
100  virtual size_t Size() const { return 0; }
101  bool empty() const { return (Size() == 0); }
102 
103  // Suspended deletion resume hook for user function
104  virtual void RetryDelete() { }
105  virtual bool MayDelete() const;
106 
107  DB *database() { return db_; }
108  const DB *database() const { return db_; }
109 
110  const std::string &name() const { return name_; }
111 
112  bool HasListeners() const;
113  size_t GetListenerCount() const;
114  void FillListeners(std::vector<ShowTableListener> *listeners) const;
115 
116  uint64_t enqueue_count() const { return enqueue_count_; }
119 
120  uint64_t input_count() const { return input_count_; }
123 
124  uint64_t notify_count() const { return notify_count_; }
127 
128  bool HasWalkers() const { return walker_count_ != 0; }
129  uint64_t walker_count() const { return walker_count_; }
131  uint64_t decr_walker_count() { return --walker_count_; }
132 
133  uint64_t walk_request_count() const { return walk_request_count_; }
134  uint64_t walk_complete_count() const { return walk_complete_count_; }
135  uint64_t walk_cancel_count() const { return walk_cancel_count_; }
136  uint64_t walk_again_count() const { return walk_again_count_; }
137  uint64_t walk_count() const { return walk_count_; }
143 
144 private:
146  DB *db_;
147  std::string name_;
148  std::unique_ptr<ListenerInfo> info_;
149  uint64_t enqueue_count_;
150  uint64_t input_count_;
151  uint64_t notify_count_;
152  tbb::atomic<uint64_t> walker_count_;
153  tbb::atomic<uint64_t> walk_count_;
154  tbb::atomic<uint64_t> walk_request_count_;
155  tbb::atomic<uint64_t> walk_complete_count_;
156  tbb::atomic<uint64_t> walk_cancel_count_;
157  tbb::atomic<uint64_t> walk_again_count_;
158 };
159 
160 // An implementation of DBTableBase that uses boost::set as data-store
161 // Most of the DB Table implementations should derive from here instead of
162 // DBTableBase directly.
163 // Derive directly from DBTableBase only if there is a strong reason to do so
164 //
165 // Additionally, provides a set of virtual functions to override the default
166 // functionality
167 class DBTable : public DBTableBase {
168 public:
169  typedef boost::intrusive_ptr<DBTableWalk> DBTableWalkRef;
170 
171  // Walker function:
172  // Called for each DBEntry under a db::DBTable task that corresponds to the
173  // specific partition.
174  // arguments: DBTable partition and DBEntry.
175  // returns: true (continue); false (stop).
176  typedef boost::function<bool(DBTablePartBase *, DBEntryBase *)> WalkFn;
177 
178  // Called when all partitions are done iterating.
179  typedef boost::function<void(DBTableWalkRef, DBTableBase *)> WalkCompleteFn;
180 
181  static const int kIterationToYield = 256;
182 
183  DBTable(DB *db, const std::string &name);
184  virtual ~DBTable();
185  void Init();
186 
188  // virtual functions to be implemented by derived class
190 
191  // Alloc a derived DBEntry
192  virtual std::unique_ptr<DBEntry> AllocEntry(const DBRequestKey *key) const = 0;
193 
194  // Hash for an entry. Used to identify partition
195  virtual size_t Hash(const DBEntry *entry) const {return 0;};
196 
197  // Hash for key. Used to identify partition
198  virtual size_t Hash(const DBRequestKey *key) const {return 0;};
199 
200  // Alloc a derived DBTablePartBase entry. The default implementation
201  // allocates DBTablePart should be good for most common cases.
202  // Override if *really* necessary
203  virtual DBTablePartition *AllocPartition(int index);
204 
205  // Input processing implemented by derived class. Default
206  // implementation takes care of Add/Delete/Change.
207  // Override if *really* necessary
208  virtual void Input(DBTablePartition *tbl_partition, DBClient *client,
209  DBRequest *req);
210 
211  // Add hook for user function. Must return entry to be inserted into tree
212  // Must return NULL if no entry is to be added into tree
213  virtual DBEntry *Add(const DBRequest *req);
214  // Change hook for user function. Return 'true' if clients need to be
215  // notified of the change
216  virtual bool OnChange(DBEntry *entry, const DBRequest *req);
217  // Delete hook for user function
218  virtual bool Delete(DBEntry *entry, const DBRequest *req);
219 
220  void NotifyAllEntries();
221 
223  // Utility methods for table
225  // Find DB Entry. Get key from from argument
226  DBEntry *Find(const DBEntry *entry);
227  const DBEntry *Find(const DBEntry *entry) const;
228 
229  DBEntry *Find(const DBRequestKey *key, int id = -1);
230  const DBEntry *Find(const DBRequestKey *key, int id = -1) const;
231 
232  // Find DB Entry without taking lock. Calling routine must ensure its
233  // running in exclusion with DB task
234  DBEntry *FindNoLock(const DBEntry *entry);
235  DBEntry *FindNoLock(const DBRequestKey *key);
236 
238  // Virtual functions from DBTableBase implemented by DBTable
240 
241  // Return the table partition for a specific request.
242  virtual DBTablePartBase *GetTablePartition(const DBRequestKey *key);
243  virtual const DBTablePartBase *GetTablePartition(
244  const DBRequestKey *key) const;
245  // Return the table partition for a DBEntryBase
246  virtual DBTablePartBase *GetTablePartition(const DBEntryBase *entry);
247  virtual const DBTablePartBase *GetTablePartition(
248  const DBEntryBase *entry) const;
249  // Return the table partition for a index
250  virtual DBTablePartBase *GetTablePartition(const int index);
251  virtual const DBTablePartBase *GetTablePartition(const int index) const;
252 
253  // Change notification handler.
254  virtual void Change(DBEntryBase *entry);
255 
256  virtual int PartitionCount() const;
257 
258  // Calculate the size across all partitions.
259  virtual size_t Size() const;
260 
261  // helper functions
262 
263  // Delete all the state entries of a specific listener.
264  // Not thread-safe. Used to shutdown and cleanup the process.
265  static void DBStateClear(DBTable *table, ListenerId id);
266 
267 
268  // Walk APIs
269  // Create a DBTable Walker
270  // Concurrency : can be invoked from any task
271  DBTableWalkRef AllocWalker(WalkFn walk_fn, WalkCompleteFn walk_complete);
272 
273  // Release the Walker
274  // Concurrency : can be invoked from any task
275  void ReleaseWalker(DBTableWalkRef &walk);
276 
277  // Start a walk on the table.
278  // Concurrency : should be invoked from a task which is mutually exclusive
279  // "db::Walker" task
280  void WalkTable(DBTableWalkRef walk);
281 
282  // Walk the table again
283  // Concurrency : should be invoked from a task which is mutually exclusive
284  // "db::Walker" task
285  void WalkAgain(DBTableWalkRef walk);
286 
287  void SetWalkIterationToYield(int count) {
289  }
290 
293  }
294 
295  void SetWalkTaskId(int task_id) {
296  walker_task_id_ = task_id;
297  }
298 
300  return walker_task_id_;
301  }
302 private:
303  friend class DBTableWalkMgr;
304  class TableWalker;
305  // A Job for walking through the DBTablePartition
306  class WalkWorker;
307 
308  static void db_walker_wait() {
309  static unsigned int walk_sleep_usecs_;
310  static bool once;
311 
312  if (!once) {
313  once = true;
314 
315  char *wait = getenv("DB_WALKER_WAIT_USECS");
316  if (wait) {
317  walk_sleep_usecs_ = (unsigned int) strtoul(wait, NULL, 0);
318  if (walk_sleep_usecs_ > 1000000)
319  walk_sleep_usecs_ = 1000000;
320  }
321 
322  }
323 
324  if (walk_sleep_usecs_) {
325  usleep(walk_sleep_usecs_);
326  }
327  }
328 
330  // Utility methods
332  // Hash key to a partition id
333  int GetPartitionId(const DBRequestKey *key);
334  // Hash entry to a partition id
335  int GetPartitionId(const DBEntry *entry);
336 
337  // Called from DBTableWalkMgr to start the walk
338  void StartWalk();
339 
340  // Call DBTableWalkMgr to notify the walkers
341  bool InvokeWalkCb(DBTablePartBase *part, DBEntryBase *entry);
342 
343  // Call DBTableWalkMgr::WalkDone
344  void WalkDone();
345 
346  // Walker callback for NotifyAllEntries()
347  bool WalkCallback(DBTablePartBase *tpart, DBEntryBase *entry);
348  void WalkCompleteCallback(DBTableBase *tbl_base);
349 
350  std::unique_ptr<TableWalker> walker_;
351  std::vector<DBTablePartition *> partitions_;
355 
357 };
358 
359 class DBTableWalk {
360 public:
361  enum WalkState {
362  INIT = 1,
367  };
368 
371  : table_(table), walk_fn_(walk_fn), walk_complete_(walk_complete) {
372  walk_state_ = INIT;
373  walk_again_ = false;
374  refcount_ = 0;
375  }
376 
377  DBTable *table() const { return table_;}
378  DBTable::WalkFn walk_fn() const { return walk_fn_;}
380 
381  bool requested() const { return (walk_state_ == WALK_REQUESTED);}
382  bool in_progress() const { return (walk_state_ == WALK_IN_PROGRESS);}
383  bool done() const { return (walk_state_ == WALK_DONE);}
384  bool stopped() const { return (walk_state_ == WALK_STOPPED);}
385  bool walk_again() const { return walk_again_;}
386  bool walk_is_active() const {
387  return ((walk_state_ == WALK_REQUESTED) ||
389  }
390 
391  WalkState walk_state() const { return walk_state_;}
392 
393 private:
394  friend class DBTableWalkMgr;
395 
396  friend void intrusive_ptr_add_ref(DBTableWalk *walker);
397  friend void intrusive_ptr_release(DBTableWalk *walker);
398 
399  void set_walk_again() { walk_again_ = true;}
400  void reset_walk_again() { walk_again_ = false;}
401 
406 
410  tbb::atomic<WalkState> walk_state_;
411  tbb::atomic<bool> walk_again_;
412  tbb::atomic<int> refcount_;
413 
415 };
416 
417 inline void intrusive_ptr_add_ref(DBTableWalk *walker) {
418  walker->refcount_.fetch_and_increment();
419 }
420 
421 inline void intrusive_ptr_release(DBTableWalk *walker) {
422  int prev = walker->refcount_.fetch_and_decrement();
423  if (prev == 1) {
424  DBTable *table = walker->table();
425  delete walker;
426  table->decr_walker_count();
427  table->RetryDelete();
428  }
429 }
430 #endif
bool HasWalkers() const
Definition: db_table.h:128
uint64_t walk_again_count() const
Definition: db_table.h:136
friend void intrusive_ptr_add_ref(DBTableWalk *walker)
Definition: db_table.h:417
static const int kIterationToYield
Definition: db_table.h:181
tbb::atomic< uint64_t > walk_request_count_
Definition: db_table.h:154
DB * db_
Definition: db_table.h:145
int intrusive_ptr_add_ref(const AsPath *cpath)
Definition: bgp_aspath.h:147
const DB * database() const
Definition: db_table.h:108
uint64_t walk_request_count() const
Definition: db_table.h:133
void WalkTable(DBTableWalkRef walk)
Definition: db_table.cc:625
bool WalkCallback(DBTablePartBase *tpart, DBEntryBase *entry)
Definition: db_table.cc:571
uint64_t enqueue_count() const
Definition: db_table.h:116
void RunNotify(DBTablePartBase *tpart, DBEntryBase *entry)
Definition: db_table.cc:207
uint64_t enqueue_count_
Definition: db_table.h:149
uint64_t walk_count() const
Definition: db_table.h:137
DISALLOW_COPY_AND_ASSIGN(DBRequest)
virtual ~DBTableBase()
Definition: db_table.cc:178
virtual bool OnChange(DBEntry *entry, const DBRequest *req)
Definition: db_table.cc:412
void AddToDBStateCount(ListenerId listener, int count)
Definition: db_table.cc:212
int walker_task_id_
Definition: db_table.h:353
void incr_walk_cancel_count()
Definition: db_table.h:140
void set_walk_done()
Definition: db_table.h:402
std::vector< DBTablePartition * > partitions_
Definition: db_table.h:351
virtual void RetryDelete()
Definition: db_table.h:104
DBTableBase(DB *db, const std::string &name)
Definition: db_table.cc:167
tbb::atomic< bool > walk_again_
Definition: db_table.h:411
uint64_t input_count() const
Definition: db_table.h:120
int ListenerId
Definition: db_table.h:62
DBTable::WalkCompleteFn walk_complete() const
Definition: db_table.h:379
std::unique_ptr< DBRequestData > data
Definition: db_table.h:49
DBTableWalkRef AllocWalker(WalkFn walk_fn, WalkCompleteFn walk_complete)
Definition: db_table.cc:613
~DBRequest()
Definition: db_table.cc:33
boost::function< void(DBTablePartBase *, DBEntryBase *)> ChangeCallback
Definition: db_table.h:61
virtual DBEntry * Add(const DBRequest *req)
Definition: db_table.cc:403
virtual size_t Size() const
Definition: db_table.h:100
bool Enqueue(DBRequest *req)
Definition: db_table.cc:194
virtual void Change(DBEntryBase *entry)
Definition: db_table.cc:407
bool in_progress() const
Definition: db_table.h:382
void incr_walk_count()
Definition: db_table.h:142
tbb::atomic< uint64_t > walk_count_
Definition: db_table.h:153
void set_walk_again()
Definition: db_table.h:399
void NotifyAllEntries()
Definition: db_table.cc:596
DB * database()
Definition: db_table.h:107
void reset_notify_count()
Definition: db_table.h:126
virtual ~DBRequestData()
Definition: db_table.h:32
WalkState walk_state() const
Definition: db_table.h:391
tbb::atomic< uint64_t > walk_again_count_
Definition: db_table.h:157
uint64_t GetDBStateCount(ListenerId listener)
Definition: db_table.cc:216
DBTable::WalkFn walk_fn_
Definition: db_table.h:408
int GetPartitionId(const DBRequestKey *key)
void Swap(DBRequest *rhs)
Definition: db_table.cc:43
virtual size_t Hash(const DBEntry *entry) const
Definition: db_table.h:195
void FillListeners(std::vector< ShowTableListener > *listeners) const
Definition: db_table.cc:242
void Unregister(ListenerId listener)
Definition: db_table.cc:186
static void db_walker_wait()
Definition: db_table.h:308
void ReleaseWalker(DBTableWalkRef &walk)
Definition: db_table.cc:619
boost::function< void(DBTableWalkRef, DBTableBase *)> WalkCompleteFn
Definition: db_table.h:179
tbb::atomic< int > refcount_
Definition: db_table.h:412
DISALLOW_COPY_AND_ASSIGN(DBTableWalk)
DBTable::WalkCompleteFn walk_complete_
Definition: db_table.h:409
ListenerId Register(ChangeCallback callback, const std::string &name="unspecified")
Definition: db_table.cc:181
std::string name_
Definition: db_table.h:147
void incr_walker_count()
Definition: db_table.h:130
uint64_t notify_count() const
Definition: db_table.h:124
Definition: db.h:24
std::unique_ptr< TableWalker > walker_
Definition: db_table.h:350
tbb::atomic< uint64_t > walk_complete_count_
Definition: db_table.h:155
virtual size_t Hash(const DBRequestKey *key) const
Definition: db_table.h:198
void WalkAgain(DBTableWalkRef walk)
Definition: db_table.cc:631
uint64_t walk_complete_count() const
Definition: db_table.h:134
virtual size_t Size() const
Definition: db_table.cc:507
void Init()
Definition: db_table.cc:387
bool done() const
Definition: db_table.h:383
DBTable(DB *db, const std::string &name)
Definition: db_table.cc:362
virtual bool Delete(DBEntry *entry, const DBRequest *req)
Definition: db_table.cc:416
virtual void Change(DBEntryBase *)=0
void incr_enqueue_count()
Definition: db_table.h:117
friend void intrusive_ptr_release(DBTableWalk *walker)
Definition: db_table.h:421
void SetWalkIterationToYield(int count)
Definition: db_table.h:287
std::unique_ptr< DBRequestKey > key
Definition: db_table.h:48
uint64_t walk_cancel_count() const
Definition: db_table.h:135
DBOperation oper
Definition: db_table.h:42
DBTable * table() const
Definition: db_table.h:377
virtual void AddRemoveCallback(const DBEntryBase *entry, bool add) const
Definition: db_table.h:84
DISALLOW_COPY_AND_ASSIGN(DBTable)
bool requested() const
Definition: db_table.h:381
virtual std::unique_ptr< DBEntry > AllocEntry(const DBRequestKey *key) const =0
std::unique_ptr< ListenerInfo > info_
Definition: db_table.h:148
bool walk_again() const
Definition: db_table.h:385
DBEntry * FindNoLock(const DBEntry *entry)
Definition: db_table.cc:462
int GetWalkerTaskId()
Definition: db_table.h:299
DBTable * table_
Definition: db_table.h:407
void incr_walk_complete_count()
Definition: db_table.h:139
const std::string & name() const
Definition: db_table.h:110
void EnqueueRemove(DBEntryBase *db_entry)
Definition: db_table.cc:201
virtual DBTablePartition * AllocPartition(int index)
Definition: db_table.cc:393
DBRequest()
Definition: db_table.cc:30
void StartWalk()
Definition: db_table.cc:397
uint64_t decr_walker_count()
Definition: db_table.h:131
void WalkDone()
Definition: db_table.cc:642
virtual bool MayDelete() const
Definition: db_table.cc:220
bool walk_is_active() const
Definition: db_table.h:386
virtual DBTablePartBase * GetTablePartition(const DBRequestKey *key)
Definition: db_table.cc:436
void incr_input_count()
Definition: db_table.h:121
DBTableWalk(DBTable *table, DBTable::WalkFn walk_fn, DBTable::WalkCompleteFn walk_complete)
Definition: db_table.h:369
void set_walk_stopped()
Definition: db_table.h:405
tbb::atomic< WalkState > walk_state_
Definition: db_table.h:410
bool InvokeWalkCb(DBTablePartBase *part, DBEntryBase *entry)
Definition: db_table.cc:637
virtual ~DBRequestKey()
Definition: db_table.h:28
size_t GetListenerCount() const
Definition: db_table.cc:238
void incr_notify_count()
Definition: db_table.h:125
int max_walk_iteration_to_yield_
Definition: db_table.h:354
static void DBStateClear(DBTable *table, ListenerId id)
Definition: db_table.cc:550
bool HasListeners() const
Definition: db_table.cc:234
DBTable::WalkFn walk_fn() const
Definition: db_table.h:378
static const int kInvalidId
Definition: db_table.h:64
DBEntry * Find(const DBEntry *entry)
Definition: db_table.cc:469
bool stopped() const
Definition: db_table.h:384
bool empty() const
Definition: db_table.h:101
void WalkCompleteCallback(DBTableBase *tbl_base)
Definition: db_table.cc:579
boost::function< bool(DBTablePartBase *, DBEntryBase *)> WalkFn
Definition: db_table.h:176
void reset_enqueue_count()
Definition: db_table.h:118
uint64_t walker_count() const
Definition: db_table.h:129
void intrusive_ptr_release(const AsPath *cpath)
Definition: bgp_aspath.h:155
boost::intrusive_ptr< DBTableWalk > DBTableWalkRef
Definition: db_table.h:169
tbb::atomic< uint64_t > walk_cancel_count_
Definition: db_table.h:156
uint64_t input_count_
Definition: db_table.h:150
DBTable::DBTableWalkRef walk_ref_
Definition: db_table.h:352
virtual int PartitionCount() const
Definition: db_table.cc:420
uint64_t notify_count_
Definition: db_table.h:151
void set_walk_requested()
Definition: db_table.h:403
void reset_input_count()
Definition: db_table.h:122
int GetWalkIterationToYield()
Definition: db_table.h:291
tbb::atomic< uint64_t > walker_count_
Definition: db_table.h:152
void incr_walk_again_count()
Definition: db_table.h:141
void SetWalkTaskId(int task_id)
Definition: db_table.h:295
void reset_walk_again()
Definition: db_table.h:400
void incr_walk_request_count()
Definition: db_table.h:138
DBRequest(DBOperation op)
Definition: db_table.h:45
virtual DBTablePartBase * GetTablePartition(const DBRequestKey *key)=0
void set_in_progress()
Definition: db_table.h:404
virtual void Input(DBTablePartition *tbl_partition, DBClient *client, DBRequest *req)
Definition: db_table.cc:516
virtual ~DBTable()
Definition: db_table.cc:383