LCOV - code coverage report
Current view: top level - db - db_table.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 334 354 94.4 %
Date: 2026-06-04 02:06:09 Functions: 64 71 90.1 %
Legend: Lines: hit not hit

          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     1284267 : DBRequest::DBRequest() : oper(static_cast<DBOperation>(0)) {
      33     1284236 : }
      34             : 
      35     1287855 : 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     1287855 :     assert(key_has_destructor && data_has_destructor);
      41             : #endif
      42             : #endif
      43     1287748 : }
      44             : 
      45      649930 : void DBRequest::Swap(DBRequest *rhs) {
      46      649930 :     swap(oper, rhs->oper);
      47      649930 :     swap(key, rhs->key);
      48      649924 :     swap(data, rhs->data);
      49      649916 : }
      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     1012183 :     AtomicWithCopy(const AtomicWithCopy& other) : std::atomic<_Tp>(other.load()) {}
      65             :     
      66             :     // Custom assignment operator
      67      792719 :     AtomicWithCopy& operator=(const AtomicWithCopy& other) {
      68     1585433 :         this->store(other.load());
      69      792714 :         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     1530279 :     explicit ListenerInfo(const string &table_name) :
      80     1530279 :         db_state_accounting_(true) {
      81     1530245 :         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     1233151 :             db_state_accounting_ = false;
      85             :         }
      86     1530252 :     }
      87             : 
      88      793257 :     DBTableBase::ListenerId Register(ChangeCallback callback,
      89             :         const string &name) {
      90      793257 :         tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
      91      793390 :         size_t i = bmap_.find_first();
      92      793104 :         if (i == bmap_.npos) {
      93      792655 :             i = callbacks_.size();
      94      792655 :             callbacks_.push_back(callback);
      95      792758 :             names_.push_back(name);
      96      792730 :             state_count_.resize(i + 1);
      97      792729 :             state_count_[i] = AtomicWithCopy<uint64_t>(0);
      98             :         } else {
      99         449 :             bmap_.reset(i);
     100         449 :             if (bmap_.none()) {
     101         337 :                 bmap_.clear();
     102             :             }
     103         449 :             callbacks_[i] = callback;
     104         449 :             names_[i] = name;
     105         449 :             state_count_[i] = 0;
     106             :         }
     107      793403 :         return i;
     108      793431 :     }
     109             : 
     110      793367 :     void Unregister(ListenerId listener) {
     111      793367 :         tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
     112      793367 :         callbacks_[listener] = NULL;
     113      793366 :         names_[listener] = "";
     114             :         // During Unregister Listener should have cleaned up,
     115             :         // DB states from all the entries in this table.
     116      793362 :         assert(state_count_[listener] == 0);
     117      793362 :         if ((size_t) listener == callbacks_.size() - 1) {
     118     1257377 :             while (!callbacks_.empty() && callbacks_.back() == NULL) {
     119      792810 :                 callbacks_.pop_back();
     120      792810 :                 names_.pop_back();
     121      792810 :                 state_count_.pop_back();
     122             :             }
     123      464568 :             if (bmap_.size() > callbacks_.size()) {
     124      225885 :                 bmap_.resize(callbacks_.size());
     125             :             }
     126             :         } else {
     127      328795 :             if ((size_t) listener >= bmap_.size()) {
     128      326902 :                 bmap_.resize(listener + 1);
     129             :             }
     130      328797 :             bmap_.set(listener);
     131             :         }
     132      793365 :     }
     133             : 
     134             :     // concurrency: called from DBPartition task.
     135     2503654 :     void RunNotify(DBTablePartBase *tpart, DBEntryBase *entry) {
     136     2503654 :         tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     137     2504407 :         for (CallbackList::iterator iter = callbacks_.begin();
     138     8658612 :              iter != callbacks_.end(); ++iter) {
     139     6154273 :             if (*iter != NULL) {
     140     6123508 :                 ChangeCallback cb = *iter;
     141     6122645 :                 (cb)(tpart, entry);
     142     6124885 :             }
     143             :         }
     144     2502905 :     }
     145             : 
     146     3830342 :     void AddToDBStateCount(ListenerId listener, int count) {
     147     3830342 :         if (db_state_accounting_ && listener != DBTableBase::kInvalidId) {
     148     3613598 :             tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     149     3614704 :             state_count_[listener] += count;
     150     3615591 :         }
     151     3832124 :     }
     152             : 
     153     1285315 :     uint64_t GetDBStateCount(ListenerId listener) {
     154     1285315 :         assert(db_state_accounting_ && listener != DBTableBase::kInvalidId);
     155     1285332 :         tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     156     2571502 :         return state_count_[listener];
     157     1285554 :     }
     158             : 
     159        6626 :     void FillListeners(vector<ShowTableListener> *listeners) const {
     160        6626 :         tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     161        6724 :         ListenerId id = 0;
     162        6724 :         for (CallbackList::const_iterator iter = callbacks_.begin();
     163       16061 :              iter != callbacks_.end(); ++iter, ++id) {
     164        9408 :             if (*iter != NULL) {
     165        9397 :                 ShowTableListener item;
     166        9388 :                 item.id = id;
     167        9388 :                 item.name = names_[id];
     168        9400 :                 item.state_count = state_count_[id];
     169        9391 :                 listeners->push_back(item);
     170        9342 :             }
     171             :         }
     172        6662 :     }
     173             : 
     174     3757183 :     bool empty() const {
     175     3757183 :         tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
     176     7515216 :         return callbacks_.empty();
     177     3757283 :     }
     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     1530277 : DBTableBase::DBTableBase(DB *db, const string &name)
     194     1530270 :         : db_(db), name_(name), info_(new ListenerInfo(name)),
     195     1530277 :           enqueue_count_(0), input_count_(0), notify_count_(0) {
     196     1530238 :     walker_count_ = 0;
     197     1530330 :     walk_request_count_ = 0;
     198     1530307 :     walk_complete_count_ = 0;
     199     1530326 :     walk_cancel_count_ = 0;
     200     1530327 :     walk_again_count_ = 0;
     201     1530322 :     walk_count_ = 0;
     202     1530316 : }
     203             : 
     204     1530331 : DBTableBase::~DBTableBase() {
     205     1530331 : }
     206             : 
     207      793345 : DBTableBase::ListenerId DBTableBase::Register(ChangeCallback callback,
     208             :     const string &name) {
     209      793345 :     return info_->Register(callback, name);
     210             : }
     211             : 
     212      793367 : void DBTableBase::Unregister(ListenerId listener) {
     213      793367 :     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      793367 :     if (info_->empty())
     217      360862 :         RetryDelete();
     218      793367 : }
     219             : 
     220      648612 : bool DBTableBase::Enqueue(DBRequest *req) {
     221      648612 :     DBTablePartBase *tpart = GetTablePartition(req->key.get());
     222      648610 :     DBPartition *partition = db_->GetPartition(tpart->index());
     223      648607 :     enqueue_count_++;
     224      648607 :     return partition->EnqueueRequest(tpart, NULL, req);
     225             : }
     226             : 
     227      367983 : void DBTableBase::EnqueueRemove(DBEntryBase *db_entry) {
     228      367983 :     DBTablePartBase *tpart = GetTablePartition(db_entry);
     229      367910 :     DBPartition *partition = db_->GetPartition(tpart->index());
     230      367908 :     partition->EnqueueRemove(tpart, db_entry);
     231      368045 : }
     232             : 
     233     2503813 : void DBTableBase::RunNotify(DBTablePartBase *tpart, DBEntryBase *entry) {
     234     2503813 :     notify_count_++;
     235     2503813 :     info_->RunNotify(tpart, entry);
     236     2504411 : }
     237             : 
     238     3830882 : void DBTableBase::AddToDBStateCount(ListenerId listener, int count) {
     239     3830882 :     info_->AddToDBStateCount(listener, count);
     240     3832013 : }
     241             : 
     242     1285440 : uint64_t DBTableBase::GetDBStateCount(ListenerId listener) {
     243     1285440 :     return info_->GetDBStateCount(listener);
     244             : }
     245             : 
     246      288738 : bool DBTableBase::MayDelete() const {
     247      288738 :     if (HasListeners()) {
     248           2 :         return false;
     249             :     }
     250      288736 :     if (HasWalkers()) {
     251           0 :         return false;
     252             :     }
     253      288736 :     if (!empty()) {
     254           0 :         return false;
     255             :     }
     256             : 
     257      288736 :     return true;
     258             : }
     259             : 
     260     2963964 : bool DBTableBase::HasListeners() const {
     261     2963964 :     return !info_->empty();
     262             : }
     263             : 
     264       10317 : size_t DBTableBase::GetListenerCount() const {
     265       10317 :     return info_->size();
     266             : }
     267             : 
     268        6628 : void DBTableBase::FillListeners(vector<ShowTableListener> *listeners) const {
     269        6628 :     info_->FillListeners(listeners);
     270        6732 : }
     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     1530314 :     TableWalker(DBTable *table) : table_(table) {
     293     1530295 :         pending_workers_ = 0;
     294     1530326 :     }
     295             : 
     296             :     void StartWalk();
     297             : 
     298     1060233 :     DBTable *table() {
     299     1060233 :         return table_;
     300             :     }
     301             : 
     302      227479 :     void ClearWalkWorks() {
     303      227479 :         worker_tasks_.clear();
     304      227479 :     }
     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      797843 : bool DBTable::WalkWorker::Run() {
     316      797843 :     int count = 0;
     317      797843 :     DBRequestKey *key_resume = walk_ctx_.get();
     318      797852 :     DBTable *table = walker_->table();
     319      797841 :     int max_walk_entry_count = table->GetWalkIterationToYield();
     320             :     DBEntry *entry;
     321             : 
     322      797848 :     if (key_resume != NULL) {
     323      666729 :         std::unique_ptr<const DBEntryBase> start;
     324      666729 :         start = table->AllocEntry(key_resume);
     325             :         // Find matching or next in sort order
     326      666582 :         entry = tbl_partition_->lower_bound(start.get());
     327      666798 :     } else {
     328      131119 :         entry = tbl_partition_->GetFirst();
     329             :     }
     330      797785 :     if (entry == NULL) {
     331         676 :         goto walk_done;
     332             :     }
     333             : 
     334     1594240 :     for (DBEntry *next = NULL; entry; entry = next) {
     335     1463715 :         next = tbl_partition_->GetNext(entry);
     336     1463754 :         if (count == max_walk_entry_count) {
     337             :             // store the context
     338      666773 :             walk_ctx_ = entry->GetDBRequestKey();
     339      666213 :             return false;
     340             :         }
     341             : 
     342             :         // Invoke walker function
     343      796981 :         bool more = table->InvokeWalkCb(tbl_partition_, entry);
     344      797236 :         if (!more) {
     345         124 :             break;
     346             :         }
     347             : 
     348      797112 :         db_walker_wait();
     349      797131 :         count++;
     350             :     }
     351             : 
     352      130525 : walk_done:
     353             :     // Check whether all other walks on the table is completed
     354      131325 :     long num_walkers_on_tpart = walker_->pending_workers_.fetch_sub(1);
     355      131325 :     if (num_walkers_on_tpart == 1) {
     356      107240 :         table->WalkDone();
     357             :     }
     358      131197 :     return true;
     359             : }
     360             : 
     361      131197 : DBTable::WalkWorker::WalkWorker(TableWalker *walker, int db_partition_id)
     362      131197 :     : Task(walker->table()->GetWalkerTaskId(), db_partition_id), walker_(walker) {
     363      131197 :     tbl_partition_ = static_cast<DBTablePartition *>
     364      131197 :         (walker_->table()->GetTablePartition(db_partition_id));
     365      131197 : }
     366             : 
     367      227479 : void DBTable::TableWalker::StartWalk() {
     368      227479 :     CHECK_CONCURRENCY("db::Walker");
     369      227479 :     assert(pending_workers_ == 0);
     370      741329 :     for (int i = 0; i < table_->PartitionCount(); i++) {
     371             :         DBTablePartition *partition = static_cast<DBTablePartition *>(
     372      513850 :             table_->GetTablePartition(i));
     373      513850 :         if (!partition->size()) continue;
     374      131197 :         worker_tasks_.push_back(new WalkWorker(this, i));
     375      131197 :         pending_workers_++;
     376             :     }
     377      227479 :     if (pending_workers_ == 0) {
     378      120239 :         table_->WalkDone();
     379             :     } else {
     380      107240 :         TaskScheduler *scheduler = TaskScheduler::GetInstance();
     381      238437 :         for (auto *task : worker_tasks_) scheduler->Enqueue(task);
     382             :     }
     383      227479 : }
     384             : 
     385             : ///////////////////////////////////////////////////////////
     386             : // Implementation of DBTable methods
     387             : ///////////////////////////////////////////////////////////
     388     1530277 : DBTable::DBTable(DB *db, const string &name)
     389             :     : DBTableBase(db, name),
     390     1530317 :       walker_(new TableWalker(this)),
     391     3060534 :       walker_task_id_(db->task_id()) {
     392             : 
     393             :     static bool init_ = false;
     394             :     static int iter_to_yield_env_ = 0;
     395             : 
     396     1530241 :     if (!init_) {
     397             :         // XXX To be used for testing purposes only.
     398         159 :         char *count_str = getenv("DB_ITERATION_TO_YIELD");
     399         159 :         if (count_str) {
     400         159 :             iter_to_yield_env_ = strtol(count_str, NULL, 0);
     401             :         } else {
     402           0 :             iter_to_yield_env_ = kIterationToYield;
     403             :         }
     404         159 :         init_ = true;
     405             :     }
     406     1530241 :     max_walk_iteration_to_yield_ = iter_to_yield_env_;
     407     1530241 : }
     408             : 
     409     1530331 : DBTable::~DBTable() {
     410     1530331 :     STLDeleteValues(&partitions_);
     411     1530331 : }
     412             : 
     413     1522189 : void DBTable::Init() {
     414     3597843 :     for (int i = 0; i < PartitionCount(); i++) {
     415     2075845 :         partitions_.push_back(AllocPartition(i));
     416             :     }
     417     1521940 : }
     418             : 
     419     2075776 : DBTablePartition *DBTable::AllocPartition(int index) {
     420     2075776 :     return new DBTablePartition(this, index);
     421             : }
     422             : 
     423      227479 : void DBTable::StartWalk() {
     424      227479 :     CHECK_CONCURRENCY("db::Walker");
     425      227479 :     incr_walk_count();
     426      227479 :     walker_->StartWalk();
     427      227479 : }
     428             : 
     429      212711 : DBEntry *DBTable::Add(const DBRequest *req) {
     430      212711 :     return AllocEntry(req->key.get()).release();
     431             : }
     432             : 
     433        1474 : void DBTable::Change(DBEntryBase *entry) {
     434        1474 :     DBTablePartBase *tpart = GetTablePartition(entry);
     435        1474 :     tpart->Notify(entry);
     436        1474 : }
     437             : 
     438           0 : bool DBTable::OnChange(DBEntry *entry, const DBRequest *req) {
     439           0 :     return true;
     440             : }
     441             : 
     442           0 : bool DBTable::Delete(DBEntry *entry, const DBRequest *req) {
     443           0 :     return true;
     444             : }
     445             : 
     446     1414690 : int DBTable::PartitionCount() const {
     447     1414690 :     return DB::PartitionCount();
     448             : }
     449             : 
     450    16186406 : static size_t HashToPartition(size_t hash) {
     451    16186406 :     return hash % DB::PartitionCount();
     452             : }
     453             : 
     454    19648604 : DBTablePartBase *DBTable::GetTablePartition(const int index) {
     455    19648604 :     return partitions_[index];
     456             : }
     457             : 
     458       24094 : const DBTablePartBase *DBTable::GetTablePartition(const int index) const {
     459       24094 :     return partitions_[index];
     460             : }
     461             : 
     462      711571 : DBTablePartBase *DBTable::GetTablePartition(const DBRequestKey *key) {
     463      711571 :     int id = HashToPartition(Hash(key));
     464      711561 :     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    14989241 : DBTablePartBase *DBTable::GetTablePartition(const DBEntryBase *entry) {
     474    14989241 :     const DBEntry *gentry = static_cast<const DBEntry *>(entry);
     475    14989241 :     size_t id = HashToPartition(Hash(gentry));
     476    14979528 :     return GetTablePartition(id);
     477             : }
     478             : 
     479       24094 : const DBTablePartBase *DBTable::GetTablePartition(
     480             :         const DBEntryBase *entry) const {
     481       24094 :     const DBEntry *gentry = static_cast<const DBEntry *>(entry);
     482       24094 :     size_t id = HashToPartition(Hash(gentry));
     483       24094 :     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          98 : DBEntry *DBTable::FindNoLock(const DBEntry *entry) {
     489          98 :     size_t id = HashToPartition(Hash(entry));
     490             :     DBTablePartition *tbl_partition =
     491          98 :         static_cast<DBTablePartition *>(GetTablePartition(id));
     492          98 :     return tbl_partition->FindNoLock(entry);
     493             : }
     494             : 
     495      384899 : DBEntry *DBTable::Find(const DBEntry *entry) {
     496      384899 :     size_t id = HashToPartition(Hash(entry));
     497             :     DBTablePartition *tbl_partition =
     498      384899 :         static_cast<DBTablePartition *>(GetTablePartition(id));
     499      384899 :     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          17 : DBEntry *DBTable::FindNoLock(const DBRequestKey *key) {
     509          17 :     int id = HashToPartition(Hash(key));
     510             :     DBTablePartition *tbl_partition =
     511          17 :     static_cast<DBTablePartition *>(GetTablePartition(id));
     512          17 :     return tbl_partition->FindNoLock(key);
     513             : }
     514             : 
     515       87492 : DBEntry *DBTable::Find(const DBRequestKey *key, int id) {
     516       87492 :     if (id == -1)
     517       87464 :         id = HashToPartition(Hash(key));
     518             :     DBTablePartition *tbl_partition =
     519       87492 :     static_cast<DBTablePartition *>(GetTablePartition(id));
     520       87492 :     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     1909358 : size_t DBTable::Size() const {
     534     1909358 :     size_t total = 0;
     535     1909358 :     for (vector<DBTablePartition *>::const_iterator iter = partitions_.begin();
     536     7028723 :          iter != partitions_.end(); iter++) {
     537     5119411 :         total += (*iter)->size();
     538             :     }
     539     1909321 :     return total;
     540             : }
     541             : 
     542        2363 : void DBTable::Input(DBTablePartition *tbl_partition, DBClient *client,
     543             :                     DBRequest *req) {
     544             :     DBRequestKey *key =
     545        2363 :         static_cast<DBRequestKey *>(req->key.get());
     546        2363 :     DBEntry *entry = NULL;
     547             : 
     548        2363 :     entry = tbl_partition->Find(key);
     549        2363 :     if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
     550        1170 :         if (entry) {
     551         582 :             if (OnChange(entry, req) || entry->IsDeleted()) {
     552             :                 // The entry may currently be marked as deleted.
     553         120 :                 entry->ClearDelete();
     554         120 :                 tbl_partition->Change(entry);
     555             :             }
     556             :         } else {
     557         588 :             if ((entry = Add(req)) != NULL) {
     558         588 :                 tbl_partition->Add(entry);
     559             :             }
     560             :         }
     561        1193 :     } else if (req->oper == DBRequest::DB_ENTRY_DELETE) {
     562         650 :         if (entry) {
     563         637 :             if (Delete(entry, req)) {
     564         637 :                 tbl_partition->Delete(entry);
     565             :             }
     566             :         }
     567         543 :     } else if (req->oper == DBRequest::DB_ENTRY_NOTIFY) {
     568         543 :         if (entry) {
     569         543 :             tbl_partition->Notify(entry);
     570             :         }
     571             :     } else {
     572           0 :         assert(0);
     573             :     }
     574        2363 : }
     575             : 
     576           2 : void DBTable::DBStateClear(DBTable *table, ListenerId id) {
     577           2 :     DBEntryBase *next = NULL;
     578             : 
     579           4 :     for (int i = 0; i < table->PartitionCount(); ++i) {
     580             :         DBTablePartition *partition = static_cast<DBTablePartition *>(
     581           2 :             table->GetTablePartition(i));
     582             : 
     583           2 :         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           2 : }
     593             : 
     594             : //
     595             : // Callback for table walk triggered by NotifyAllEntries.
     596             : //
     597      129444 : bool DBTable::WalkCallback(DBTablePartBase *tpart, DBEntryBase *entry) {
     598      129444 :     tpart->Notify(entry);
     599      129448 :     return true;
     600             : }
     601             : 
     602             : //
     603             : // Callback for completion of table walk triggered by NotifyAllEntries.
     604             : //
     605       61317 : void DBTable::WalkCompleteCallback(DBTableBase *tbl_base) {
     606       61317 :     walk_ref_.reset();
     607       61317 : }
     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       64044 : void DBTable::NotifyAllEntries() {
     623       64044 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper", "bgp::RTFilter",
     624             :                       "db::DBTable");
     625             : 
     626       64043 :     if (empty())
     627        2728 :         return;
     628             : 
     629       61317 :     if (walk_ref_ == NULL) {
     630             :         walk_ref_ =
     631      122634 :             AllocWalker(boost::bind(&DBTable::WalkCallback, this, _1, _2),
     632       61317 :                     boost::bind(&DBTable::WalkCompleteCallback, this, _2));
     633       61317 :         WalkTable(walk_ref_);
     634             :     } else {
     635           0 :         WalkAgain(walk_ref_);
     636             :     }
     637             : }
     638             : 
     639      220650 : DBTable::DBTableWalkRef DBTable::AllocWalker(WalkFn walk_fn,
     640             :                                              WalkCompleteFn walk_complete) {
     641      220650 :     DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
     642      220650 :     return walk_mgr->AllocWalker(this, walk_fn, walk_complete);
     643             : }
     644             : 
     645      158467 : void DBTable::ReleaseWalker(DBTable::DBTableWalkRef &walk) {
     646      158467 :     DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
     647      158467 :     walk_mgr->ReleaseWalker(walk);
     648      158467 :     return;
     649             : }
     650             : 
     651      227381 : void DBTable::WalkTable(DBTable::DBTableWalkRef walk) {
     652      227381 :     DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
     653      227381 :     walk_mgr->WalkTable(walk);
     654      227381 :     return;
     655             : }
     656             : 
     657       30233 : void DBTable::WalkAgain(DBTable::DBTableWalkRef walk) {
     658       30233 :     DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
     659       30233 :     walk_mgr->WalkAgain(walk);
     660       30233 :     return;
     661             : }
     662             : 
     663      797240 : bool DBTable::InvokeWalkCb(DBTablePartBase *part, DBEntryBase *entry) {
     664      797240 :     DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
     665      797117 :     return walk_mgr->InvokeWalkCb(part, entry);
     666             : }
     667             : 
     668      227479 : void DBTable::WalkDone() {
     669      227479 :     incr_walk_complete_count();
     670      227479 :     walker_->ClearWalkWorks();
     671      227479 :     DBTableWalkMgr *walk_mgr = database()->GetWalkMgr();
     672      227479 :     return walk_mgr->WalkDone();
     673             : }

Generated by: LCOV version 1.14