OpenSDN source code
db_table_walk_mgr.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #ifndef ctrlplane_db_table_walk_mgr_h
6 #define ctrlplane_db_table_walk_mgr_h
7 
8 #include <list>
9 #include <set>
10 #include <mutex>
11 
12 #include <boost/assign.hpp>
13 #include <boost/function.hpp>
14 #include <boost/scoped_ptr.hpp>
15 #include <boost/shared_ptr.hpp>
16 
17 
18 #include "base/logging.h"
19 #include "base/task_trigger.h"
20 #include "base/util.h"
21 
22 #include "db/db_table.h"
23 
24 //
25 // DBTableWalkMgr:
26 // ==============
27 // DBTableWalkMgr provides infrastructure to walk DBTable.
28 //
29 // DBTable class provides API for walking DBTable. Following APIs are provided
30 //
31 // 1. AllocWalker: This API allocates a walk handle and returns to the caller
32 // Application is suppose to release the walker using ReleaseWalker.
33 //
34 // AllocWalker API can be called from any task context.
35 //
36 // Application provides two callback function as input to for this API.
37 //
38 // DBTable::WalkFn : Callback invoked by walk infra while traversing each
39 // DBEntry in DBTable. This API is invoked in db::DBTable task context
40 // by default. Application can configure the task id in which
41 // DBTable walk is performed using DBTable::SetWalkTaskId
42 //
43 // DBTable::WalkCompleteFn: Callback invoked by walk infra on completion of
44 // ongoing walk request. This API is invoked in db::Walker task
45 // context irrespective of the task id set with DBTable::SetWalkTaskId
46 // This callback is not invoked in cases where application
47 // calls ReleaseWalker on ongoing walker. Also, WalkCompleteFn is
48 // called only after handling all WalkAgain requests on the walker.
49 //
50 // 2. ReleaseWalker: This API releases the walker. After invoking this API,
51 // application will stop getting Walk callback for the ongoing Walk request.
52 // Application should not refer to the DBTableWalkRef after invoking this API
53 //
54 // ReleaseWalker API can be called from any task context.
55 //
56 // 3. WalkTable: This API starts the table walk. This API should be called
57 // from a task which is mutually exclusive from db::Walker task.
58 //
59 // 4. WalkAgain: To re-trigger/restart current walk request from application.
60 // Callback for WalkFn is no longer invoked for ongoing walk and walk is
61 // restarted from beginning of DBTable. This API should be called from a task
62 // which is mutually exclusive from db::Walker task.
63 //
64 // DBTableWalkMgr ensures that not more than one DBTable is walked at any point
65 // in time. All other DBTable walk requests are queued and taken up only after
66 // current walk completes.
67 // Actual DBTable walk (i.e. iterating the DBTablePartition) is performed in
68 // db::DBTable task or task id configured with DBTable::SetWalkTaskId with
69 // instance id set as partition index.
70 // The advantage of running DBTable walk in serial manner is in clubbing
71 // multiple walk requests on a given table and serving such requests in one
72 // iteration of DBTable walk
73 //
74 // WalkReqList holds list of DBTableWalkRef(i.e. walkers created by multiple
75 // application modules) that requested for DBTable walk on a specific table.
76 // InvokeWalkCb notifies all such walkers stored in current_table_walk_, while
77 // iterating through DBTable entries
78 //
79 // WalkRequestInfo:
80 // ===============
81 // WalkRequestInfo is a per table Walk request structure. It also holds
82 // DBTableWalkRef which requested for DBTable walk.
83 //
84 // WalkRequestInfoList
85 // ===================
86 // walk_request_list_ holds list of WalkRequestInfo. This list is keyed by
87 // DBTable. Additional walk_request_set_ is maintained for easy search of
88 // WalkRequestInfo for a given DBTable.
89 // Current table on which walk is going on will not be present in the
90 // walk_request_list_. If caller requests for WalkAgain(), it is added back to
91 // the walk_request_list_ (in the end of the list).
92 //
93 // Task Triggers:
94 // walk_request_trigger_ : Task trigger which evaluate walk_request_list_.
95 // It removes the WalkRequestInfo on top of this list and starts walk on the
96 // table. This task trigger runs in "db::Walker" task context.
97 //
98 // walk_done_trigger_ : Task trigger ensures that WalkCompleteFn is triggered
99 // in db::Walker task context for all DBTableWalkRef which requested for
100 // current DBTable walk. At the end of ProcessWalkDone, walk_request_trigger_ is
101 // triggered to evaluate walk request from top of walk_request_list_.
102 //
104 public:
105  DBTableWalkMgr();
106 
108  walk_request_trigger_->set_disable();
109  }
110 
112  walk_request_trigger_->set_enable();
113  }
114 
116  walk_done_trigger_->set_disable();
117  }
118 
120  walk_done_trigger_->set_enable();
121  }
122 
123 private:
124  friend class DBTable;
125  typedef std::set<DBTable::DBTableWalkRef> WalkReqList;
126 
129  }
130 
132  pending_requests.insert(ref);
133  }
134 
136  pending_requests.erase(ref);
137  }
138 
139  bool WalkPending() {
140  return !pending_requests.empty();
141  }
144  };
145 
147  bool operator()(const WalkRequestInfo *lhs,
148  const WalkRequestInfo *rhs) const {
149  return lhs->table < rhs->table;
150  }
151  };
152  typedef boost::shared_ptr<WalkRequestInfo> WalkRequestInfoPtr;
153  typedef std::list<WalkRequestInfoPtr> WalkRequestInfoList;
154  typedef std::set<WalkRequestInfo *, WalkRequestCompare> WalkRequestInfoSet;
155 
156  // Create a DBTable Walker
158  DBTable::WalkCompleteFn walk_complete);
159 
160  // Release the Walker
162 
163  // Start a walk on the table.
165 
166  // DBTable finished walking
167  void WalkDone();
168 
169  // Walk the table again
171 
172  bool ProcessWalkRequestList();
173 
174  bool ProcessWalkDone();
175 
176  bool InvokeWalkCb(DBTablePartBase *part, DBEntryBase *entry);
177 
178  boost::scoped_ptr<TaskTrigger> walk_request_trigger_;
179  boost::scoped_ptr<TaskTrigger> walk_done_trigger_;
180 
181  // Mutex to protect walk_request_list_ and walk_request_set_ as
182  // Walk can be requested from task which may run concurrently
183  std::mutex mutex_;
186 
188 
190 };
191 
192 #endif
void DisableWalkDoneTrigger()
std::set< WalkRequestInfo *, WalkRequestCompare > WalkRequestInfoSet
WalkRequestInfoSet walk_request_set_
void ReleaseWalker(DBTable::DBTableWalkRef &walk)
DBTable::DBTableWalkRef AllocWalker(DBTable *table, DBTable::WalkFn walk_fn, DBTable::WalkCompleteFn walk_complete)
void EnableWalkDoneTrigger()
boost::scoped_ptr< TaskTrigger > walk_request_trigger_
std::set< DBTable::DBTableWalkRef > WalkReqList
std::list< WalkRequestInfoPtr > WalkRequestInfoList
void WalkTable(DBTable::DBTableWalkRef walk)
void DisableWalkProcessing()
boost::scoped_ptr< TaskTrigger > walk_done_trigger_
WalkReqList current_table_walk_
bool InvokeWalkCb(DBTablePartBase *part, DBEntryBase *entry)
bool ProcessWalkRequestList()
DISALLOW_COPY_AND_ASSIGN(DBTableWalkMgr)
void WalkAgain(DBTable::DBTableWalkRef walk)
WalkRequestInfoList walk_request_list_
boost::shared_ptr< WalkRequestInfo > WalkRequestInfoPtr
boost::function< void(DBTableWalkRef, DBTableBase *)> WalkCompleteFn
Definition: db_table.h:179
boost::intrusive_ptr< DBTableWalk > DBTableWalkRef
Definition: db_table.h:169
boost::function< bool(DBTablePartBase *, DBEntryBase *)> WalkFn
Definition: db_table.h:176
bool operator()(const WalkRequestInfo *lhs, const WalkRequestInfo *rhs) const
void AppendWalkReq(DBTable::DBTableWalkRef ref)
void DeleteWalkReq(DBTable::DBTableWalkRef ref)