Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <vector>
6 : #include <atomic>
7 :
8 : #include <tbb/spin_rw_mutex.h>
9 :
10 : #include <boost/bind/bind.hpp>
11 : #include <boost/foreach.hpp>
12 : #include <boost/dynamic_bitset.hpp>
13 : #include <boost/type_traits.hpp>
14 :
15 : #include "base/compiler.h"
16 : #include "base/logging.h"
17 : #include "base/task_annotations.h"
18 : #include "base/time_util.h"
19 : #include "db/db.h"
20 : #include "db/db_partition.h"
21 : #include "db/db_table.h"
22 : #include "db/db_table_partition.h"
23 : #include "db/db_table_walk_mgr.h"
24 : #include "db/db_types.h"
25 :
26 : class DBEntry;
27 : class DBEntryBase;
28 :
29 : using namespace std;
30 : using namespace boost::placeholders;
31 :
32 1378536 : DBRequest::DBRequest() : oper(static_cast<DBOperation>(0)) {
33 1378493 : }
34 :
35 1435141 : DBRequest::~DBRequest() {
36 : #if defined(__GNUC__)
37 : #if (__GNUC_PREREQ(4, 2) > 0)
38 : boost::has_virtual_destructor<DBRequestKey>::type key_has_destructor;
39 : boost::has_virtual_destructor<DBRequestData>::type data_has_destructor;
40 1435141 : assert(key_has_destructor && data_has_destructor);
41 : #endif
42 : #endif
43 1435001 : }
44 :
45 690218 : void DBRequest::Swap(DBRequest *rhs) {
46 690218 : swap(oper, rhs->oper);
47 690217 : swap(key, rhs->key);
48 690214 : swap(data, rhs->data);
49 690204 : }
50 :
51 : // we need copy to be able to resize vector of atomics
52 : // therefore we don't need the same value in both instances
53 : template<typename _Tp>
54 : struct AtomicWithCopy : public std::atomic<_Tp> {
55 : // Inherit constructors
56 : using std::atomic<_Tp>::atomic;
57 :
58 : // Bring in base class operators and methods
59 : using std::atomic<_Tp>::operator=;
60 : using std::atomic<_Tp>::load;
61 : using std::atomic<_Tp>::store;
62 :
63 : // Custom constructor to handle copy from another AtomicWithCopy (must perform a load/store)
64 1020107 : AtomicWithCopy(const AtomicWithCopy& other) : std::atomic<_Tp>(other.load()) {}
65 :
66 : // Custom assignment operator
67 796551 : AtomicWithCopy& operator=(const AtomicWithCopy& other) {
68 1593113 : this->store(other.load());
69 796554 : return *this;
70 : }
71 : };
72 :
73 : class DBTableBase::ListenerInfo {
74 : public:
75 : typedef vector<ChangeCallback> CallbackList;
76 : typedef vector<string> NameList;
77 : typedef vector<AtomicWithCopy<uint64_t>> StateCountList;
78 :
79 1531297 : explicit ListenerInfo(const string &table_name) :
80 1531297 : db_state_accounting_(true) {
81 1531198 : if (table_name.find("__ifmap_") != string::npos) {
82 : // TODO need to have unconditional DB state accounting
83 : // for now skipp DB State accounting for ifmap tables
84 1233301 : db_state_accounting_ = false;
85 : }
86 1531215 : }
87 :
88 797146 : DBTableBase::ListenerId Register(ChangeCallback callback,
89 : const string &name) {
90 797146 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
91 797300 : size_t i = bmap_.find_first();
92 796905 : if (i == bmap_.npos) {
93 796493 : i = callbacks_.size();
94 796488 : callbacks_.push_back(callback);
95 796610 : names_.push_back(name);
96 796649 : state_count_.resize(i + 1);
97 796619 : state_count_[i] = AtomicWithCopy<uint64_t>(0);
98 : } else {
99 412 : bmap_.reset(i);
100 410 : if (bmap_.none()) {
101 313 : bmap_.clear();
102 : }
103 410 : callbacks_[i] = callback;
104 410 : names_[i] = name;
105 410 : state_count_[i] = 0;
106 : }
107 797274 : return i;
108 797419 : }
109 :
110 797289 : void Unregister(ListenerId listener) {
111 797289 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
112 797291 : callbacks_[listener] = NULL;
113 797287 : names_[listener] = "";
114 : // During Unregister Listener should have cleaned up,
115 : // DB states from all the entries in this table.
116 797287 : assert(state_count_[listener] == 0);
117 797285 : if ((size_t) listener == callbacks_.size() - 1) {
118 1262729 : while (!callbacks_.empty() && callbacks_.back() == NULL) {
119 796698 : callbacks_.pop_back();
120 796698 : names_.pop_back();
121 796700 : state_count_.pop_back();
122 : }
123 466029 : if (bmap_.size() > callbacks_.size()) {
124 226944 : bmap_.resize(callbacks_.size());
125 : }
126 : } else {
127 331256 : if ((size_t) listener >= bmap_.size()) {
128 328750 : bmap_.resize(listener + 1);
129 : }
130 331258 : bmap_.set(listener);
131 : }
132 797289 : }
133 :
134 : // concurrency: called from DBPartition task.
135 2569431 : void RunNotify(DBTablePartBase *tpart, DBEntryBase *entry) {
136 2569431 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
137 2569951 : for (CallbackList::iterator iter = callbacks_.begin();
138 9035558 : iter != callbacks_.end(); ++iter) {
139 6465075 : if (*iter != NULL) {
140 6438241 : ChangeCallback cb = *iter;
141 6437990 : (cb)(tpart, entry);
142 6438849 : }
143 : }
144 2569227 : }
145 :
146 3977342 : void AddToDBStateCount(ListenerId listener, int count) {
147 3977342 : if (db_state_accounting_ && listener != DBTableBase::kInvalidId) {
148 3759763 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
149 3761071 : state_count_[listener] += count;
150 3762058 : }
151 3979084 : }
152 :
153 1301446 : uint64_t GetDBStateCount(ListenerId listener) {
154 1301446 : assert(db_state_accounting_ && listener != DBTableBase::kInvalidId);
155 1301547 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
156 2603718 : return state_count_[listener];
157 1301711 : }
158 :
159 7007 : void FillListeners(vector<ShowTableListener> *listeners) const {
160 7007 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
161 7107 : ListenerId id = 0;
162 7107 : for (CallbackList::const_iterator iter = callbacks_.begin();
163 16901 : iter != callbacks_.end(); ++iter, ++id) {
164 9857 : if (*iter != NULL) {
165 9840 : ShowTableListener item;
166 9829 : item.id = id;
167 9829 : item.name = names_[id];
168 9843 : item.state_count = state_count_[id];
169 9835 : listeners->push_back(item);
170 9807 : }
171 : }
172 7056 : }
173 :
174 3783973 : bool empty() const {
175 3783973 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
176 7568634 : return callbacks_.empty();
177 3784042 : }
178 :
179 10317 : size_t size() const {
180 10317 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
181 20634 : return (callbacks_.size() - bmap_.count());
182 10317 : }
183 :
184 : private:
185 : bool db_state_accounting_;
186 : CallbackList callbacks_;
187 : NameList names_;
188 : StateCountList state_count_;
189 : mutable tbb::spin_rw_mutex rw_mutex_;
190 : boost::dynamic_bitset<> bmap_; // free list.
191 : };
192 :
193 1531300 : DBTableBase::DBTableBase(DB *db, const string &name)
194 1531278 : : db_(db), name_(name), info_(new ListenerInfo(name)),
195 1531300 : enqueue_count_(0), input_count_(0), notify_count_(0) {
196 1531198 : walker_count_ = 0;
197 1531411 : walk_request_count_ = 0;
198 1531398 : walk_complete_count_ = 0;
199 1531411 : walk_cancel_count_ = 0;
200 1531408 : walk_again_count_ = 0;
201 1531416 : walk_count_ = 0;
202 1531388 : }
203 :
204 1531422 : DBTableBase::~DBTableBase() {
205 1531422 : }
206 :
207 797266 : DBTableBase::ListenerId DBTableBase::Register(ChangeCallback callback,
208 : const string &name) {
209 797266 : return info_->Register(callback, name);
210 : }
211 :
212 797292 : void DBTableBase::Unregister(ListenerId listener) {
213 797292 : info_->Unregister(listener);
214 : // If a table is marked for deletion, then we may trigger the deletion
215 : // process when the last client is removed
216 797290 : if (info_->empty())
217 361852 : RetryDelete();
218 797291 : }
219 :
220 679806 : bool DBTableBase::Enqueue(DBRequest *req) {
221 679806 : DBTablePartBase *tpart = GetTablePartition(req->key.get());
222 679792 : DBPartition *partition = db_->GetPartition(tpart->index());
223 679791 : enqueue_count_++;
224 679791 : return partition->EnqueueRequest(tpart, NULL, req);
225 : }
226 :
227 379450 : void DBTableBase::EnqueueRemove(DBEntryBase *db_entry) {
228 379450 : DBTablePartBase *tpart = GetTablePartition(db_entry);
229 379406 : DBPartition *partition = db_->GetPartition(tpart->index());
230 379396 : partition->EnqueueRemove(tpart, db_entry);
231 379508 : }
232 :
233 2569584 : void DBTableBase::RunNotify(DBTablePartBase *tpart, DBEntryBase *entry) {
234 2569584 : notify_count_++;
235 2569584 : info_->RunNotify(tpart, entry);
236 2569992 : }
237 :
238 3977687 : void DBTableBase::AddToDBStateCount(ListenerId listener, int count) {
239 3977687 : info_->AddToDBStateCount(listener, count);
240 3979026 : }
241 :
242 1301645 : uint64_t DBTableBase::GetDBStateCount(ListenerId listener) {
243 1301645 : return info_->GetDBStateCount(listener);
244 : }
245 :
246 289629 : bool DBTableBase::MayDelete() const {
247 289629 : if (HasListeners()) {
248 0 : return false;
249 : }
250 289629 : if (HasWalkers()) {
251 0 : return false;
252 : }
253 289629 : if (!empty()) {
254 0 : return false;
255 : }
256 :
257 289629 : return true;
258 : }
259 :
260 2986853 : bool DBTableBase::HasListeners() const {
261 2986853 : return !info_->empty();
262 : }
263 :
264 10317 : size_t DBTableBase::GetListenerCount() const {
265 10317 : return info_->size();
266 : }
267 :
268 7016 : void DBTableBase::FillListeners(vector<ShowTableListener> *listeners) const {
269 7016 : info_->FillListeners(listeners);
270 7135 : }
271 :
272 : class DBTable::WalkWorker : public Task {
273 : public:
274 : WalkWorker(TableWalker *walker, int db_partition_id);
275 :
276 : virtual bool Run();
277 :
278 0 : std::string Description() const { return "DBTable::WalkWorker"; }
279 :
280 : private:
281 : // Store the last visited node to continue walk
282 : std::unique_ptr<DBRequestKey> walk_ctx_;
283 :
284 : // Table partition for which this worker was created
285 : DBTablePartition *tbl_partition_;
286 :
287 : TableWalker *walker_;
288 : };
289 :
290 : class DBTable::TableWalker {
291 : public:
292 1531358 : TableWalker(DBTable *table) : table_(table) {
293 1531277 : pending_workers_ = 0;
294 1531419 : }
295 :
296 : void StartWalk();
297 :
298 1065620 : DBTable *table() {
299 1065620 : return table_;
300 : }
301 :
302 231285 : void ClearWalkWorks() {
303 231285 : worker_tasks_.clear();
304 231285 : }
305 :
306 : DBTable *table_;
307 : // check whether iteration is completed on all Table Partition
308 : std::atomic<uint16_t> pending_workers_;
309 : // For debugging purpose. Few of the tasks in this list could has finished
310 : // executing and destroyed. List of workers are useful in debugging with
311 : // gdb/gcore to see the current state of the walk and walk_context
312 : std::list<Task *> worker_tasks_;
313 : };
314 :
315 798774 : bool DBTable::WalkWorker::Run() {
316 798774 : int count = 0;
317 798774 : DBRequestKey *key_resume = walk_ctx_.get();
318 798774 : DBTable *table = walker_->table();
319 798768 : int max_walk_entry_count = table->GetWalkIterationToYield();
320 : DBEntry *entry;
321 :
322 798780 : if (key_resume != NULL) {
323 665384 : std::unique_ptr<const DBEntryBase> start;
324 665384 : start = table->AllocEntry(key_resume);
325 : // Find matching or next in sort order
326 665179 : entry = tbl_partition_->lower_bound(start.get());
327 665472 : } else {
328 133396 : entry = tbl_partition_->GetFirst();
329 : }
330 798633 : if (entry == NULL) {
331 586 : goto walk_done;
332 : }
333 :
334 1596069 : for (DBEntry *next = NULL; entry; entry = next) {
335 1463224 : next = tbl_partition_->GetNext(entry);
336 1463188 : if (count == max_walk_entry_count) {
337 : // store the context
338 665331 : walk_ctx_ = entry->GetDBRequestKey();
339 664633 : return false;
340 : }
341 :
342 : // Invoke walker function
343 797857 : bool more = table->InvokeWalkCb(tbl_partition_, entry);
344 798046 : if (!more) {
345 94 : break;
346 : }
347 :
348 797952 : db_walker_wait();
349 798022 : count++;
350 : }
351 :
352 132845 : walk_done:
353 : // Check whether all other walks on the table is completed
354 133525 : long num_walkers_on_tpart = walker_->pending_workers_.fetch_sub(1);
355 133525 : if (num_walkers_on_tpart == 1) {
356 109027 : table->WalkDone();
357 : }
358 133425 : return true;
359 : }
360 :
361 133425 : DBTable::WalkWorker::WalkWorker(TableWalker *walker, int db_partition_id)
362 133425 : : Task(walker->table()->GetWalkerTaskId(), db_partition_id), walker_(walker) {
363 133425 : tbl_partition_ = static_cast<DBTablePartition *>
364 133425 : (walker_->table()->GetTablePartition(db_partition_id));
365 133425 : }
366 :
367 231285 : void DBTable::TableWalker::StartWalk() {
368 231285 : CHECK_CONCURRENCY("db::Walker");
369 231285 : assert(pending_workers_ == 0);
370 747942 : for (int i = 0; i < table_->PartitionCount(); i++) {
371 : DBTablePartition *partition = static_cast<DBTablePartition *>(
372 516657 : table_->GetTablePartition(i));
373 516657 : if (!partition->size()) continue;
374 133425 : worker_tasks_.push_back(new WalkWorker(this, i));
375 133425 : pending_workers_++;
376 : }
377 231285 : if (pending_workers_ == 0) {
378 122258 : table_->WalkDone();
379 : } else {
380 109027 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
381 242452 : for (auto *task : worker_tasks_) scheduler->Enqueue(task);
382 : }
383 231285 : }
384 :
385 : ///////////////////////////////////////////////////////////
386 : // Implementation of DBTable methods
387 : ///////////////////////////////////////////////////////////
388 1531294 : DBTable::DBTable(DB *db, const string &name)
389 : : DBTableBase(db, name),
390 1531376 : walker_(new TableWalker(this)),
391 3062511 : walker_task_id_(db->task_id()) {
392 :
393 : static bool init_ = false;
394 : static int iter_to_yield_env_ = 0;
395 :
396 1531183 : if (!init_) {
397 : // XXX To be used for testing purposes only.
398 161 : char *count_str = getenv("DB_ITERATION_TO_YIELD");
399 161 : if (count_str) {
400 161 : iter_to_yield_env_ = strtol(count_str, NULL, 0);
401 : } else {
402 0 : iter_to_yield_env_ = kIterationToYield;
403 : }
404 161 : init_ = true;
405 : }
406 1531183 : max_walk_iteration_to_yield_ = iter_to_yield_env_;
407 1531183 : }
408 :
409 1531422 : DBTable::~DBTable() {
410 1531422 : STLDeleteValues(&partitions_);
411 1531422 : }
412 :
413 1523217 : void DBTable::Init() {
414 3599577 : for (int i = 0; i < PartitionCount(); i++) {
415 2076530 : partitions_.push_back(AllocPartition(i));
416 : }
417 1522886 : }
418 :
419 2076420 : DBTablePartition *DBTable::AllocPartition(int index) {
420 2076420 : return new DBTablePartition(this, index);
421 : }
422 :
423 231285 : void DBTable::StartWalk() {
424 231285 : CHECK_CONCURRENCY("db::Walker");
425 231285 : incr_walk_count();
426 231285 : walker_->StartWalk();
427 231285 : }
428 :
429 212819 : DBEntry *DBTable::Add(const DBRequest *req) {
430 212819 : return AllocEntry(req->key.get()).release();
431 : }
432 :
433 1439 : void DBTable::Change(DBEntryBase *entry) {
434 1439 : DBTablePartBase *tpart = GetTablePartition(entry);
435 1439 : tpart->Notify(entry);
436 1439 : }
437 :
438 0 : bool DBTable::OnChange(DBEntry *entry, const DBRequest *req) {
439 0 : return true;
440 : }
441 :
442 4 : bool DBTable::Delete(DBEntry *entry, const DBRequest *req) {
443 4 : return true;
444 : }
445 :
446 1412791 : int DBTable::PartitionCount() const {
447 1412791 : return DB::PartitionCount();
448 : }
449 :
450 16961239 : static size_t HashToPartition(size_t hash) {
451 16961239 : return hash % DB::PartitionCount();
452 : }
453 :
454 20445644 : DBTablePartBase *DBTable::GetTablePartition(const int index) {
455 20445644 : return partitions_[index];
456 : }
457 :
458 24101 : const DBTablePartBase *DBTable::GetTablePartition(const int index) const {
459 24101 : return partitions_[index];
460 : }
461 :
462 810593 : DBTablePartBase *DBTable::GetTablePartition(const DBRequestKey *key) {
463 810593 : int id = HashToPartition(Hash(key));
464 810563 : return GetTablePartition(id);
465 : }
466 :
467 0 : const DBTablePartBase *DBTable::GetTablePartition(
468 : const DBRequestKey *key) const {
469 0 : int id = HashToPartition(Hash(key));
470 0 : return GetTablePartition(id);
471 : }
472 :
473 15426938 : DBTablePartBase *DBTable::GetTablePartition(const DBEntryBase *entry) {
474 15426938 : const DBEntry *gentry = static_cast<const DBEntry *>(entry);
475 15426938 : size_t id = HashToPartition(Hash(gentry));
476 15421034 : return GetTablePartition(id);
477 : }
478 :
479 24101 : const DBTablePartBase *DBTable::GetTablePartition(
480 : const DBEntryBase *entry) const {
481 24101 : const DBEntry *gentry = static_cast<const DBEntry *>(entry);
482 24101 : size_t id = HashToPartition(Hash(gentry));
483 24101 : return GetTablePartition(id);
484 : }
485 :
486 : // Find DB Entry without taking lock. Calling routine must ensure its
487 : // running in exclusion with DB task
488 144 : DBEntry *DBTable::FindNoLock(const DBEntry *entry) {
489 144 : size_t id = HashToPartition(Hash(entry));
490 : DBTablePartition *tbl_partition =
491 144 : static_cast<DBTablePartition *>(GetTablePartition(id));
492 144 : return tbl_partition->FindNoLock(entry);
493 : }
494 :
495 415856 : DBEntry *DBTable::Find(const DBEntry *entry) {
496 415856 : size_t id = HashToPartition(Hash(entry));
497 : DBTablePartition *tbl_partition =
498 415854 : static_cast<DBTablePartition *>(GetTablePartition(id));
499 415853 : return tbl_partition->Find(entry);
500 : }
501 :
502 0 : const DBEntry *DBTable::Find(const DBEntry *entry) const {
503 0 : return const_cast<DBTable *>(this)->Find(entry);
504 : }
505 :
506 : // Find DB Entry without taking lock. Calling routine must ensure its
507 : // running in exclusion with DB task
508 93 : DBEntry *DBTable::FindNoLock(const DBRequestKey *key) {
509 93 : int id = HashToPartition(Hash(key));
510 : DBTablePartition *tbl_partition =
511 93 : static_cast<DBTablePartition *>(GetTablePartition(id));
512 93 : return tbl_partition->FindNoLock(key);
513 : }
514 :
515 290184 : DBEntry *DBTable::Find(const DBRequestKey *key, int id) {
516 290184 : if (id == -1)
517 290156 : id = HashToPartition(Hash(key));
518 : DBTablePartition *tbl_partition =
519 290184 : static_cast<DBTablePartition *>(GetTablePartition(id));
520 290184 : return tbl_partition->Find(key);
521 : }
522 :
523 260 : const DBEntry *DBTable::Find(const DBRequestKey *key, int id) const {
524 260 : return const_cast<DBTable *>(this)->Find(key, id);
525 : }
526 :
527 : //
528 : // Concurrency: called from task that's mutually exclusive with db::DBTable
529 : // or db::IFMapTable as applicable.
530 : //
531 : // Calculate the size across all partitions.
532 : //
533 1927883 : size_t DBTable::Size() const {
534 1927883 : size_t total = 0;
535 1927883 : for (vector<DBTablePartition *>::const_iterator iter = partitions_.begin();
536 7066186 : iter != partitions_.end(); iter++) {
537 5138386 : total += (*iter)->size();
538 : }
539 1927860 : return total;
540 : }
541 :
542 49720 : void DBTable::Input(DBTablePartition *tbl_partition, DBClient *client,
543 : DBRequest *req) {
544 : DBRequestKey *key =
545 49720 : static_cast<DBRequestKey *>(req->key.get());
546 49720 : DBEntry *entry = NULL;
547 :
548 49720 : entry = tbl_partition->Find(key);
549 49720 : if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
550 31312 : if (entry) {
551 18144 : if (OnChange(entry, req) || entry->IsDeleted()) {
552 : // The entry may currently be marked as deleted.
553 1983 : entry->ClearDelete();
554 1983 : tbl_partition->Change(entry);
555 : }
556 : } else {
557 13168 : if ((entry = Add(req)) != NULL) {
558 13168 : tbl_partition->Add(entry);
559 : }
560 : }
561 18408 : } else if (req->oper == DBRequest::DB_ENTRY_DELETE) {
562 14390 : if (entry) {
563 14344 : if (Delete(entry, req)) {
564 14344 : tbl_partition->Delete(entry);
565 : }
566 : }
567 4018 : } else if (req->oper == DBRequest::DB_ENTRY_NOTIFY) {
568 4018 : if (entry) {
569 4000 : tbl_partition->Notify(entry);
570 : }
571 : } else {
572 0 : assert(0);
573 : }
574 49720 : }
575 :
576 4 : void DBTable::DBStateClear(DBTable *table, ListenerId id) {
577 4 : DBEntryBase *next = NULL;
578 :
579 8 : for (int i = 0; i < table->PartitionCount(); ++i) {
580 : DBTablePartition *partition = static_cast<DBTablePartition *>(
581 4 : table->GetTablePartition(i));
582 :
583 4 : for (DBEntryBase *entry = partition->GetFirst(); entry; entry = next) {
584 0 : next = partition->GetNext(entry);
585 0 : DBState *state = entry->GetState(table, id);
586 0 : if (state) {
587 0 : entry->ClearState(table, id);
588 0 : delete state;
589 : }
590 : }
591 : }
592 4 : }
593 :
594 : //
595 : // Callback for table walk triggered by NotifyAllEntries.
596 : //
597 129684 : bool DBTable::WalkCallback(DBTablePartBase *tpart, DBEntryBase *entry) {
598 129684 : tpart->Notify(entry);
599 129688 : return true;
600 : }
601 :
602 : //
603 : // Callback for completion of table walk triggered by NotifyAllEntries.
604 : //
605 61308 : void DBTable::WalkCompleteCallback(DBTableBase *tbl_base) {
606 61308 : walk_ref_.reset();
607 61308 : }
608 :
609 : //
610 : // Concurrency: called from task that's mutually exclusive with db::DBTable
611 : // or db::IFMapTable as applicable.
612 : //
613 : // Trigger notification of all entries to all listeners.
614 : // Should be used sparingly e.g. to handle significant configuration change.
615 : //
616 : // The walk callback just turns around and puts the DBentryBase on the change
617 : // list.
618 : //
619 : // If the walk is already running, it is allowed to complete and WalkAgain API
620 : // is invoked to trigger walk on current walk completion.
621 : //
622 63148 : void DBTable::NotifyAllEntries() {
623 63148 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper", "bgp::RTFilter",
624 : "db::DBTable");
625 :
626 63151 : if (empty())
627 1840 : return;
628 :
629 61311 : if (walk_ref_ == NULL) {
630 : walk_ref_ =
631 122616 : AllocWalker(boost::bind(&DBTable::WalkCallback, this, _1, _2),
632 61308 : boost::bind(&DBTable::WalkCompleteCallback, this, _2));
633 61308 : WalkTable(walk_ref_);
634 : } else {
635 3 : WalkAgain(walk_ref_);
636 : }
637 : }
638 :
639 228937 : DBTable::DBTableWalkRef DBTable::AllocWalker(WalkFn walk_fn,
640 : WalkCompleteFn walk_complete) {
641 228937 : DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
642 228936 : return walk_mgr->AllocWalker(this, walk_fn, walk_complete);
643 : }
644 :
645 162430 : void DBTable::ReleaseWalker(DBTable::DBTableWalkRef &walk) {
646 162430 : DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
647 162430 : walk_mgr->ReleaseWalker(walk);
648 162430 : return;
649 : }
650 :
651 228536 : void DBTable::WalkTable(DBTable::DBTableWalkRef walk) {
652 228536 : DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
653 228535 : walk_mgr->WalkTable(walk);
654 228536 : return;
655 : }
656 :
657 36562 : void DBTable::WalkAgain(DBTable::DBTableWalkRef walk) {
658 36562 : DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
659 36562 : walk_mgr->WalkAgain(walk);
660 36562 : return;
661 : }
662 :
663 798133 : bool DBTable::InvokeWalkCb(DBTablePartBase *part, DBEntryBase *entry) {
664 798133 : DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
665 797977 : return walk_mgr->InvokeWalkCb(part, entry);
666 : }
667 :
668 231285 : void DBTable::WalkDone() {
669 231285 : incr_walk_complete_count();
670 231285 : walker_->ClearWalkWorks();
671 231285 : DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
672 231285 : return walk_mgr->WalkDone();
673 : }
|