Line data Source code
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 : // 103 : class DBTableWalkMgr { 104 : public: 105 : DBTableWalkMgr(); 106 : 107 22 : void DisableWalkProcessing() { 108 22 : walk_request_trigger_->set_disable(); 109 22 : } 110 : 111 22 : void EnableWalkProcessing() { 112 22 : walk_request_trigger_->set_enable(); 113 22 : } 114 : 115 : void DisableWalkDoneTrigger() { 116 : walk_done_trigger_->set_disable(); 117 : } 118 : 119 : void EnableWalkDoneTrigger() { 120 : walk_done_trigger_->set_enable(); 121 : } 122 : 123 : private: 124 : friend class DBTable; 125 : typedef std::set<DBTable::DBTableWalkRef> WalkReqList; 126 : 127 : struct WalkRequestInfo { 128 482247 : WalkRequestInfo(DBTable *table) : table(table) { 129 482247 : } 130 : 131 255992 : void AppendWalkReq(DBTable::DBTableWalkRef ref) { 132 255992 : pending_requests.insert(ref); 133 255992 : } 134 : 135 : void DeleteWalkReq(DBTable::DBTableWalkRef ref) { 136 : pending_requests.erase(ref); 137 : } 138 : 139 : bool WalkPending() { 140 : return !pending_requests.empty(); 141 : } 142 : DBTable *table; 143 : WalkReqList pending_requests; 144 : }; 145 : 146 : struct WalkRequestCompare { 147 1237494 : bool operator()(const WalkRequestInfo *lhs, 148 : const WalkRequestInfo *rhs) const { 149 1237494 : 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 157 : DBTable::DBTableWalkRef AllocWalker(DBTable *table, DBTable::WalkFn walk_fn, 158 : DBTable::WalkCompleteFn walk_complete); 159 : 160 : // Release the Walker 161 : void ReleaseWalker(DBTable::DBTableWalkRef &walk); 162 : 163 : // Start a walk on the table. 164 : void WalkTable(DBTable::DBTableWalkRef walk); 165 : 166 : // DBTable finished walking 167 : void WalkDone(); 168 : 169 : // Walk the table again 170 : void WalkAgain(DBTable::DBTableWalkRef walk); 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_; 184 : WalkRequestInfoList walk_request_list_; 185 : WalkRequestInfoSet walk_request_set_; 186 : 187 : WalkReqList current_table_walk_; 188 : 189 : DISALLOW_COPY_AND_ASSIGN(DBTableWalkMgr); 190 : }; 191 : 192 : #endif