LCOV - code coverage report
Current view: top level - ifmap - ifmap_exporter.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 479 495 96.8 %
Date: 2026-06-18 01:51:13 Functions: 50 52 96.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "ifmap/ifmap_exporter.h"
       6             : 
       7             : #include <boost/bind/bind.hpp>
       8             : #include <boost/checked_delete.hpp>
       9             : 
      10             : #include "db/db.h"
      11             : #include "db/db_table_partition.h"
      12             : #include "ifmap/ifmap_client.h"
      13             : #include "ifmap/ifmap_graph_walker.h"
      14             : #include "ifmap/ifmap_link.h"
      15             : #include "ifmap/ifmap_log.h"
      16             : #include "ifmap/ifmap_server.h"
      17             : #include "ifmap/ifmap_log_types.h"
      18             : #include "ifmap/ifmap_table.h"
      19             : #include "ifmap/ifmap_update.h"
      20             : #include "ifmap/ifmap_update_queue.h"
      21             : #include "ifmap/ifmap_update_sender.h"
      22             : #include "ifmap/ifmap_util.h"
      23             : 
      24             : using namespace std;
      25             : using namespace boost::algorithm;
      26             : using namespace boost::placeholders;
      27             : 
      28             : class IFMapExporter::TableInfo {
      29             : public:
      30        7924 :     TableInfo(DBTable::ListenerId id)
      31        7924 :             : id_(id) {
      32        7924 :     }
      33       40240 :     DBTableBase::ListenerId id() const { return id_; }
      34             : 
      35             : private:
      36             :     DBTableBase::ListenerId id_;
      37             : };
      38             : 
      39         179 : IFMapExporter::IFMapExporter(IFMapServer *server)
      40         537 :         : server_(server), link_table_(NULL) {
      41         179 : }
      42             : 
      43         537 : IFMapExporter::~IFMapExporter() {
      44         179 :     Shutdown();
      45         895 : }
      46             : 
      47          53 : void IFMapExporter::Initialize(DB *db) {
      48          53 :     for (DB::iterator iter = db->lower_bound("__ifmap__");
      49        7924 :          iter != db->end(); ++iter) {
      50        7924 :         DBTable *table = static_cast<DBTable *>(iter->second);
      51        7924 :         if (table->name().find("__ifmap__") != 0) {
      52          53 :             break;
      53             :         }
      54             :         DBTable::ListenerId id =
      55        7871 :                 table->Register(
      56             :                     boost::bind(&IFMapExporter::NodeTableExport, this, _1, _2));
      57        7871 :         table_map_.insert(make_pair(table, new TableInfo(id)));
      58             :     }
      59             : 
      60          53 :     link_table_ = static_cast<DBTable *>(
      61          53 :         db->FindTable("__ifmap_metadata__.0"));
      62          53 :     assert(link_table_);
      63             :     DBTable::ListenerId id =
      64          53 :             link_table_->Register(
      65             :                 boost::bind(&IFMapExporter::LinkTableExport, this, _1, _2));
      66          53 :     table_map_.insert(make_pair(link_table_, new TableInfo(id)));
      67             : 
      68          53 :     walker_.reset(new IFMapGraphWalker(server_->graph(), this));
      69          53 : }
      70             : 
      71         338 : void IFMapExporter::Shutdown() {
      72        1014 :     for (int i = 0; i < TT_END; ++i) {
      73         964 :         for (size_t index = 0; index < client_config_tracker_[i].size(); ++index) {
      74         288 :             ConfigSet *set = client_config_tracker_[i][index];
      75         288 :             if (set) {
      76         136 :                 set->clear();
      77         136 :                 delete set;
      78         136 :                 client_config_tracker_[i][index] = NULL;
      79             :             }
      80             :         }
      81             :     }
      82        8262 :     for (TableMap::iterator iter = table_map_.begin(); iter != table_map_.end();
      83        7924 :          ++iter) {
      84        7924 :         DBTable *table = iter->first;
      85        7924 :         TableInfo *info = iter->second;
      86        7924 :         table->Unregister(info->id());
      87        7924 :         TableStateClear(table, info->id());
      88        7924 :         delete info;
      89             :     }
      90         338 :     table_map_.clear();
      91         338 : }
      92             : 
      93       19211 : const IFMapExporter::TableInfo *IFMapExporter::Find(
      94             :     const DBTable *table) const {
      95             :     TableMap::const_iterator loc =
      96       19211 :             table_map_.find(const_cast<DBTable *>(table));
      97       19211 :     if (loc != table_map_.end()) {
      98       19211 :         return loc->second;
      99             :     }
     100           0 :     return NULL;
     101             : }
     102             : 
     103        1792 : DBTableBase::ListenerId IFMapExporter::TableListenerId(
     104             :     const DBTable *table) const {
     105        1792 :     const IFMapExporter::TableInfo *tinfo = Find(table);
     106        1792 :     if (tinfo == NULL) {
     107           0 :         return DBTableBase::kInvalidId;
     108             :     }
     109        1792 :     return tinfo->id();
     110             : }
     111             : 
     112       10645 : bool IFMapExporter::IsFeasible(const IFMapNode *node) {
     113       10645 :     if (node->IsDeleted()) {
     114          83 :         return false;
     115             :     }
     116       10562 :     return true;
     117             : }
     118             : 
     119        6956 : const BitSet *IFMapExporter::MergeClientInterest(
     120             :     IFMapNode * node, IFMapNodeState *state, std::unique_ptr<BitSet> *ptr) {
     121             : 
     122        6956 :     const BitSet *set = &state->interest();
     123        6956 :     IFMapTable *table = node->table();
     124             : 
     125        6956 :     if (table->name() == "__ifmap__.virtual_router.0") {
     126         174 :         IFMapClient *client = server_->FindClient(node->name());
     127         174 :         if (!client) {
     128          42 :             return set;
     129             :         }
     130         132 :         BitSet *merged_set = new BitSet(*set);
     131         132 :         merged_set->set(client->index());
     132         132 :         ptr->reset(merged_set);
     133         132 :         StateInterestSet(state, *merged_set);
     134         132 :         return merged_set;
     135             :     }
     136             : 
     137        6782 :     return set;
     138             : }
     139             : 
     140        3831 : IFMapNodeState *IFMapExporter::NodeStateLookup(IFMapNode *node){
     141        3831 :     const TableInfo *tinfo = Find(node->table());
     142             :     IFMapNodeState *state = static_cast<IFMapNodeState *>(
     143        3831 :         node->GetState(node->table(), tinfo ? tinfo->id() : 0));
     144        3831 :     return state;
     145             : }
     146             : 
     147        6023 : IFMapNodeState *IFMapExporter::NodeStateLocate(IFMapNode *node){
     148        6023 :     const TableInfo *tinfo = Find(node->table());
     149             :     IFMapNodeState *state = static_cast<IFMapNodeState *>(
     150        6023 :         node->GetState(node->table(), tinfo->id()));
     151        6023 :     if (state == NULL) {
     152        1790 :         state = new IFMapNodeState(node);
     153        1790 :         node->SetState(node->table(), tinfo->id(), state);
     154             :     }
     155        6023 :     return state;
     156             : }
     157             : 
     158        9569 : IFMapUpdateQueue *IFMapExporter::queue() {
     159        9569 :     return server_->queue();
     160             : }
     161             : 
     162        1423 : IFMapUpdateSender *IFMapExporter::sender() {
     163        1423 :     return server_->sender();
     164             : }
     165             : 
     166             : template <class ObjectType>
     167        7084 : bool IFMapExporter::UpdateAddChange(ObjectType *obj, IFMapState *state,
     168             :                                     const BitSet &add_set, const BitSet &rm_set,
     169             :                                     bool change) {
     170             :     // Remove any bit in "advertise" from the positive update.
     171             :     // This is a NOP in case the interest set is non empty and this is change.
     172        7084 :     IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
     173        7084 :     if (update != NULL) {
     174         582 :         update->AdvertiseReset(rm_set);
     175             :     }
     176             : 
     177        7084 :     if (state->interest().empty()) {
     178        5326 :         if (update != NULL) {
     179          14 :             queue()->Dequeue(update);
     180          14 :             state->Remove(update);
     181          14 :             delete update;
     182             :         }
     183        5326 :         return false;
     184             :     }
     185             : 
     186        1758 :     if (!change && add_set.empty()) {
     187          79 :         return false;
     188             :     }
     189             : 
     190        1679 :     bool is_move = false;
     191        1679 :     if (update != NULL) {
     192         568 :         if (!change) {
     193         568 :             if (update->advertise().Contains(add_set)) {
     194         508 :                 return false;
     195             :             }
     196             :         } else {
     197           0 :             if (state->interest() == update->advertise()) {
     198           0 :                 return false;
     199             :             }
     200             :         }
     201          60 :         is_move = true;
     202          60 :         queue()->Dequeue(update);
     203             :     } else {
     204        1111 :         update = new IFMapUpdate(obj, true);
     205        1111 :         state->Insert(update);
     206             :     }
     207             : 
     208        1171 :     if (!change) {
     209        1162 :         update->AdvertiseOr(add_set);
     210             :     } else {
     211           9 :         update->SetAdvertise(state->interest());
     212             :     }
     213        1171 :     queue()->Enqueue(update);
     214        1171 :     sender()->QueueActive();
     215        1171 :     return is_move;
     216             : }
     217             : 
     218             : template <class ObjectType>
     219        7084 : bool IFMapExporter::UpdateRemove(ObjectType *obj, IFMapState *state,
     220             :                                  const BitSet &rm_set) {
     221             :     // Remove any bit in "interest" from the delete update.
     222        7084 :     IFMapUpdate *update = state->GetUpdate(IFMapListEntry::DEL);
     223        7084 :     if (update != NULL) {
     224         166 :         update->AdvertiseReset(state->interest());
     225             :     }
     226             : 
     227        7084 :     if (rm_set.empty()) {
     228        6840 :         if (update != NULL) {
     229          19 :             queue()->Dequeue(update);
     230          19 :             state->Remove(update);
     231          19 :             delete update;
     232             :         }
     233        6840 :         return false;
     234             :     }
     235             : 
     236         244 :     bool is_move = false;
     237         244 :     if (update != NULL) {
     238         147 :         if (rm_set == update->advertise()) {
     239         127 :             return false;
     240             :         }
     241          20 :         is_move = true;
     242          20 :         queue()->Dequeue(update);
     243             :     } else {
     244          97 :         update = new IFMapUpdate(obj, false);
     245          97 :         state->Insert(update);
     246             :     }
     247             : 
     248         117 :     update->SetAdvertise(rm_set);
     249         117 :     queue()->Enqueue(update);
     250         117 :     sender()->QueueActive();
     251         117 :     return is_move;
     252             : }
     253             : 
     254             : template <class ObjectType>
     255         149 : void IFMapExporter::EnqueueDelete(ObjectType *obj, IFMapState *state) {
     256         149 :     IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
     257         149 :     if (update != NULL) {
     258           4 :         queue()->Dequeue(update);
     259           4 :         state->Remove(update);
     260           4 :         delete update;
     261             :     }
     262             : 
     263         149 :     update = state->GetUpdate(IFMapListEntry::DEL);
     264         149 :     if (update != NULL) {
     265           0 :         queue()->Dequeue(update);
     266             :     }
     267         149 :     if (state->advertised().empty()) {
     268         119 :         assert(update == NULL);
     269         119 :         return;
     270             :     }
     271             : 
     272          30 :     if (update == NULL) {
     273          30 :         update = new IFMapUpdate(obj, false);
     274          30 :         state->Insert(update);
     275             :     }
     276          30 :     update->SetAdvertise(state->advertised());
     277          30 :     queue()->Enqueue(update);
     278          30 :     sender()->QueueActive();
     279             : }
     280             : 
     281         320 : IFMapLinkState *IFMapExporter::LinkStateLookup(IFMapLink *link) {
     282         320 :     const TableInfo *tinfo = Find(link_table_);
     283         320 :     if (!tinfo)
     284           0 :         return NULL;
     285             :     IFMapLinkState *state = static_cast<IFMapLinkState *>(
     286         320 :         link->GetState(link_table_, tinfo->id()));
     287         320 :     return state;
     288             : }
     289             : 
     290          54 : void IFMapExporter::MoveDependentLinks(IFMapNodeState *state) {
     291         215 :     for (IFMapNodeState::iterator iter = state->begin(); iter != state->end();
     292         161 :          ++iter) {
     293         161 :         IFMapLink *link = iter.operator->();
     294         161 :         IFMapLinkState *ls = LinkStateLookup(link);
     295         161 :         if (ls == NULL) {
     296           0 :             continue;
     297             :         }
     298         161 :         IFMapUpdate *update = ls->GetUpdate(IFMapListEntry::UPDATE);
     299         161 :         if (update == NULL) {
     300          68 :             continue;
     301             :         }
     302          93 :         assert(!update->advertise().empty());
     303          93 :         queue()->Dequeue(update);
     304          93 :         queue()->Enqueue(update);
     305          93 :         sender()->QueueActive();
     306             :     }
     307          54 : }
     308             : 
     309          12 : void IFMapExporter::MoveAdjacentNode(IFMapNodeState *state) {
     310          12 :     IFMapUpdate *update = state->GetUpdate(IFMapListEntry::DEL);
     311          12 :     if (update != NULL) {
     312          12 :         assert(!update->advertise().empty());
     313          12 :         queue()->Dequeue(update);
     314          12 :         queue()->Enqueue(update);
     315          12 :         sender()->QueueActive();
     316             :     }
     317          12 : }
     318             : 
     319          67 : void IFMapExporter::RemoveDependentLinks(IFMapNodeState *state,
     320             :                                          const BitSet &rm_set) {
     321          67 :     for (IFMapNodeState::iterator iter = state->begin(), next = state->begin();
     322         222 :          iter != state->end(); iter = next) {
     323         155 :         IFMapLink *link = iter.operator->();
     324         155 :         next = ++iter;
     325         155 :         IFMapLinkState *ls = LinkStateLookup(link);
     326         155 :         if (ls == NULL) {
     327           0 :             continue;
     328             :         }
     329         155 :         BitSet common = ls->advertised() & rm_set;
     330         155 :         if (!common.empty()) {
     331         113 :             LinkTableExport(link->get_table_partition(), link);
     332             :         }
     333         155 :     }
     334          67 : }
     335             : 
     336        1164 : void IFMapExporter::ProcessAdjacentNode(IFMapNode *node, const BitSet &add_set,
     337             :         IFMapNodeState *state, bool force_process) {
     338        1164 :     BitSet current = state->advertised();
     339        1164 :     IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
     340        1164 :     if (update) {
     341         612 :         current |= update->advertise();
     342             :     }
     343        1164 :     if (!current.Contains(add_set)) {
     344         548 :         NodeTableExport(node->get_table_partition(), node);
     345             :     } else {
     346         616 :         if (force_process) {
     347          52 :             if (update) {
     348          40 :                 update->AdvertiseReset(update->advertise());
     349             :             }
     350          52 :             state->AdvertisedReset(state->advertised());
     351          52 :             NodeTableExport(node->get_table_partition(), node);
     352             :         }
     353             :     }
     354        1164 : }
     355             : 
     356         209 : void IFMapExporter::DeleteStateIfAppropriate(DBTable *table, DBEntryBase *entry,
     357             :                                              IFMapState *state) {
     358         209 :     if (state->CanDelete()) {
     359         141 :         assert(state->advertised().empty());
     360         141 :         assert(state->interest().empty());
     361         141 :         entry->ClearState(table, TableListenerId(table));
     362         141 :         delete state;
     363             :     }
     364         209 : }
     365             : 
     366             : // Propagate changes to all the interested peers.
     367             : //
     368             : // Update order:
     369             : // link updates (adds) should only be advertised after the corresponding nodes
     370             : // are advertised.
     371             : // node membership removal (deletes) should only be advertised after all the
     372             : // refering links are removed.
     373             : // When enqueuing a link add, the code forces node processing of adjacent links
     374             : // before the link update is added to the queue.
     375             : // When enqueueing a node removal, the corresponding link removals are placed
     376             : // in the queue before the node.
     377             : // When a node update moves, any dependent (positive) link update moves also.
     378             : // When a (negative) link update moves the corresponding node removals move
     379             : // also.
     380        3689 : void IFMapExporter::NodeTableExport(DBTablePartBase *partition,
     381             :                                     DBEntryBase *entry) {
     382        3689 :     IFMapNode *node = static_cast<IFMapNode *>(entry);
     383        3689 :     DBTable *table = static_cast<DBTablePartition *>(partition)->table();
     384             : 
     385        3689 :     const TableInfo *tinfo = Find(table);
     386        3689 :     DBState *entry_state = entry->GetState(table, tinfo->id());
     387        3689 :     IFMapNodeState *state = static_cast<IFMapNodeState *>(entry_state);
     388             : 
     389        3689 :     if (IsFeasible(node)) {
     390        3606 :         if (state == NULL) {
     391         634 :             state = new IFMapNodeState(node);
     392         634 :             entry->SetState(table, tinfo->id(), state);
     393             :         }
     394        3606 :         state->SetValid(node);
     395             : 
     396             :         // This is an add operation for nodes that are interested and
     397             :         // have not seen the advertisement.
     398        3606 :         BitSet add_set;
     399        3606 :         add_set.BuildComplement(state->interest(), state->advertised());
     400             : 
     401             :         // This is a delete operation for nodes that have seen it but are no
     402             :         // longer interested.
     403        3606 :         BitSet rm_set;
     404        3606 :         rm_set.BuildComplement(state->advertised(), state->interest());
     405             : 
     406        3606 :         bool change = ConfigChanged(node);
     407             : 
     408             :         // enqueue update
     409             :         // If there is a previous update in the queue, if that update has
     410             :         // been seen by any of receivers, we need to move the update to
     411             :         // the tail of the list. When that happens, dependent updates
     412             :         // moved also.
     413        3606 :         bool move = UpdateAddChange(node, state, add_set, rm_set, change);
     414        3606 :         if (move) {
     415          54 :             MoveDependentLinks(state);
     416             :         }
     417             : 
     418             :         // For the subset of clients being removed, make sure that all
     419             :         // dependent links are removed before.
     420        3606 :         if (!rm_set.empty()) {
     421          67 :             RemoveDependentLinks(state, rm_set);
     422             :         }
     423        3606 :         UpdateRemove(node, state, rm_set);
     424        3689 :     } else if (state != NULL) {
     425             :         // Link deletes must preceed node deletes.
     426          80 :         ConfigChanged(node);
     427          80 :         state->ClearValid();
     428          80 :         if (!state->HasDependents()) {
     429             :             // enqueue delete.
     430          73 :             StateInterestReset(state, state->interest());
     431          73 :             EnqueueDelete(node, state);
     432          73 :             if (state->update_list().empty()) {
     433          61 :                 DeleteStateIfAppropriate(table, entry, state);
     434             :             }
     435             :         }
     436             :     }
     437        3689 : }
     438             : 
     439         152 : static void MaybeNotifyOnLinkDelete(IFMapNode *node, IFMapNodeState *state) {
     440         152 :     if (node->IsDeleted() && !state->HasDependents()) {
     441          73 :         IFMapTable *table = node->table();
     442          73 :         table->Change(node);
     443             :     }
     444         152 : }
     445             : 
     446             : // When a link is created or deleted this may affect the interest graph for
     447             : // the agents.
     448             : // Link changes should only be propagated after the respective nodes are
     449             : // feasible.
     450        3556 : void IFMapExporter::LinkTableExport(DBTablePartBase *partition,
     451             :                                     DBEntryBase *entry) {
     452        3556 :     IFMapLink *link = static_cast<IFMapLink *>(entry);
     453        3556 :     DBTable *table = static_cast<DBTablePartition *>(partition)->table();
     454        3556 :     const TableInfo *tinfo = Find(table);
     455        3556 :     DBState *entry_state = entry->GetState(table, tinfo->id());
     456        3556 :     IFMapLinkState *state = static_cast<IFMapLinkState *>(entry_state);
     457             : 
     458        3556 :     if (!entry->IsDeleted()) {
     459        3478 :         IFMapNodeState *s_left = NULL;
     460        3478 :         IFMapNodeState *s_right = NULL;
     461             : 
     462        3478 :         bool add_link = false;
     463        3478 :         bool force_update = false;
     464        3478 :         if (state == NULL) {
     465        2757 :             state = new IFMapLinkState(link);
     466        2757 :             entry->SetState(table, tinfo->id(), state);
     467        2757 :             s_left = NodeStateLocate(link->left());
     468        2757 :             s_right = NodeStateLocate(link->right());
     469        2757 :             add_link = true;
     470             :             // This is special as internally generated
     471             :             // We can end up  in this situation where add comes just after
     472             :             // delete but processing of delete happens just before
     473             :             // Delete for link comes and link is marked for deletion
     474             :             // Delete event gets picked up, state gets deleted and delete
     475             :             //  event is raised to send updates
     476             :             // Add event comes in and revives the link since it is only
     477             :             //  marked for deletion, add event is enqueued
     478             :             // Send update gets picked up but CleanupInterest does not
     479             :             //  do anything because old interest is same as new one
     480             :             // Add event gets picked up but state was deleted earlier
     481             :             // This is a corner case and should not happen for other
     482             :             // config based events
     483        5640 :             if (starts_with(link->left()->ToString(), "virtual-router") &&
     484        2883 :                (starts_with(link->right()->ToString(), "virtual-machine:"))) {
     485          86 :                 if (!s_right->advertised().empty())
     486           0 :                     s_right->AdvertisedReset(s_right->advertised());
     487          86 :                 force_update = true;
     488             :             }
     489             :         } else {
     490         721 :             if (state->IsValid() && !link->link_revival()) {
     491             :                 // Link change
     492         717 :                 assert(state->HasDependency());
     493         717 :                 s_left = state->left();
     494         717 :                 s_right = state->right();
     495           4 :             } else if (state->IsValid() && link->link_revival()) {
     496           2 :                 link->SetLinkRevival(false);
     497           2 :                 assert(state->HasDependency());
     498           2 :                 s_left = state->left();
     499           2 :                 s_right = state->right();
     500           2 :                 force_update = true;
     501           2 :                 state->AdvertisedReset(state->advertised());
     502           2 :                 if (s_left->advertised().Contains(state->interest()))
     503           2 :                     s_left->AdvertisedReset(state->interest());
     504           2 :                 if (s_right->advertised().Contains(state->interest()))
     505           2 :                     s_right->AdvertisedReset(state->interest());
     506             :             } else {
     507             :                 // Link revival i.e. delete quickly followed by add
     508           2 :                 assert(!state->HasDependency());
     509           2 :                 s_left = NodeStateLocate(link->left());
     510           2 :                 s_right = NodeStateLocate(link->right());
     511           2 :                 add_link = true;
     512           2 :                 force_update = true;
     513           2 :                 state->AdvertisedReset(state->advertised());
     514           2 :                 link->SetLinkRevival(false);
     515           2 :                 if (s_left->advertised().Contains(state->interest()))
     516           2 :                     s_left->AdvertisedReset(state->interest());
     517           2 :                 if (s_right->advertised().Contains(state->interest()))
     518           2 :                     s_right->AdvertisedReset(state->interest());
     519             :             }
     520             :         }
     521             : 
     522             :         // If one of the nodes is a vswitch node, then the interest mask
     523             :         // is the corresponding peer bit.
     524        3478 :         std::unique_ptr<BitSet> ml, mr;
     525        3478 :         const BitSet *lset = MergeClientInterest(link->left(), s_left, &ml);
     526        3478 :         const BitSet *rset = MergeClientInterest(link->right(), s_right, &mr);
     527        3478 :         if (*lset != *rset) {
     528         243 :             walker_->LinkAdd(link, link->left(), *lset, link->right(), *rset);
     529             :         }
     530             : 
     531        3478 :         if (add_link) {
     532             :             // Establish dependency.
     533        2759 :             state->SetDependency(s_left, s_right);
     534        2759 :             state->SetValid();
     535             :         }
     536             : 
     537        3478 :         if (IsFeasible(link->left()) && IsFeasible(link->right())) {
     538             :             // Interest mask is the intersection of left and right nodes.
     539        3478 :             StateInterestSet(state, (s_left->interest() & s_right->interest()));
     540             :         } else {
     541           0 :             StateInterestSet(state, BitSet());
     542             :         }
     543             : 
     544             :         // This is an add operation for nodes that are interested and
     545             :         // have not seen the advertisement.
     546        3478 :         BitSet add_set;
     547        3478 :         add_set.BuildComplement(state->interest(), state->advertised());
     548             : 
     549        3478 :         BitSet rm_set;
     550        3478 :         rm_set.BuildComplement(state->advertised(), state->interest());
     551             : 
     552        3478 :         if (!add_set.empty()) {
     553         582 :             ProcessAdjacentNode(link->left(), add_set, s_left, force_update);
     554         582 :             ProcessAdjacentNode(link->right(), add_set, s_right, force_update);
     555             :         }
     556             : 
     557        3478 :         UpdateAddChange(link, state, add_set, rm_set, false);
     558             : 
     559        3478 :         bool move = UpdateRemove(link, state, rm_set);
     560        3478 :         if (move) {
     561           6 :             MoveAdjacentNode(s_left);
     562           6 :             MoveAdjacentNode(s_right);
     563             :         }
     564        3556 :     } else if ((state != NULL) && state->IsValid()) {
     565          76 :         IFMapNode *left = link->LeftNode(server_->database());
     566          76 :         IFMapNodeState *s_left = state->left();
     567          76 :         assert((left != NULL) && (s_left != NULL));
     568          76 :         IFMapNode *right = link->RightNode(server_->database());
     569          76 :         IFMapNodeState *s_right = state->right();
     570          76 :         assert((right != NULL) && (s_right != NULL));
     571          76 :         BitSet interest = s_left->interest() & s_right->interest();
     572          76 :         StateInterestReset(state, state->interest());
     573             : 
     574          76 :         IFMAP_DEBUG(LinkOper, "LinkRemove", left->ToString(), right->ToString(),
     575             :             s_left->interest().ToString(), s_right->interest().ToString());
     576          76 :         walker_->LinkRemove(interest);
     577             : 
     578          76 :         state->RemoveDependency();
     579          76 :         state->ClearValid();
     580             : 
     581             :         // enqueue update.
     582          76 :         EnqueueDelete(link, state);
     583          76 :         if (state->update_list().empty()) {
     584          58 :             DeleteStateIfAppropriate(table, entry, state);
     585             :         }
     586             : 
     587          76 :         MaybeNotifyOnLinkDelete(left, s_left);
     588          76 :         MaybeNotifyOnLinkDelete(right, s_right);
     589          76 :     }
     590        3556 : }
     591             : 
     592        1159 : void IFMapExporter::StateUpdateOnDequeue(IFMapUpdate *update,
     593             :                                          const BitSet &dequeue_set,
     594             :                                          bool is_delete) {
     595        1159 :     DBTable *table = NULL;
     596        1159 :     DBEntry *db_entry = NULL;
     597             : 
     598        1159 :     IFMapState *state = NULL;
     599        1159 :     if (update->data().type == IFMapObjectPtr::NODE) {
     600         567 :         IFMapNode *node = update->data().u.node;
     601         567 :         db_entry = node;
     602         567 :         table = node->table();
     603         592 :     } else if (update->data().type == IFMapObjectPtr::LINK) {
     604         592 :         db_entry = update->data().u.link;
     605         592 :         table = link_table_;
     606             :     }
     607             :     state = static_cast<IFMapState *>(
     608        1159 :         db_entry->GetState(table, TableListenerId(table)));
     609        1159 :     if (is_delete) {
     610             :         // For any bit in dequeue_set, its possible that advertised is not set.
     611             :         // EG: update is UPDATE and we are called from UpdateQ.Leave(). Reset
     612             :         // only the bits that are really set.
     613          90 :         BitSet adv_bits = state->advertised() & dequeue_set;
     614          90 :         StateAdvertisedReset(state, adv_bits);
     615          90 :     } else {
     616        1069 :         StateAdvertisedOr(state, dequeue_set);
     617             :     }
     618             : 
     619        1159 :     if (update->advertise().empty()) {
     620        1159 :         state->Remove(update);
     621        1159 :         if (update->IsDelete()) {
     622          90 :             DeleteStateIfAppropriate(table, db_entry, state);
     623             :         }
     624        1159 :         delete update;
     625             :     }
     626        1159 : }
     627             : 
     628             : struct IFMapUpdateDisposer {
     629        7924 :     explicit IFMapUpdateDisposer(IFMapUpdateQueue *queue) : queue_(queue) { }
     630          42 :     void operator()(IFMapUpdate *ptr) {
     631          42 :         queue_->Dequeue(ptr);
     632          42 :         boost::checked_delete(ptr);
     633          42 :     }
     634             : 
     635             :   private:
     636             :     IFMapUpdateQueue *queue_;
     637             : };
     638             : 
     639        7924 : void IFMapExporter::TableStateClear(DBTable *table,
     640             :                                     DBTable::ListenerId tsid) {
     641             :     DBTablePartition *partition = static_cast<DBTablePartition *>(
     642        7924 :         table->GetTablePartition(0));
     643             : 
     644        7924 :     IFMapUpdateDisposer disposer(queue());
     645        7924 :     for (DBEntry *entry = static_cast<DBEntry *>(partition->GetFirst()),
     646       12964 :                  *next = NULL; entry != NULL; entry = next) {
     647        5040 :         next = static_cast<DBEntry *>(partition->GetNext(entry));
     648             :         IFMapState *state = static_cast<IFMapState *>(
     649        5040 :             entry->GetState(table, tsid));
     650        5040 :         if (state == NULL) {
     651           0 :             continue;
     652             :         }
     653        5040 :         entry->ClearState(table, tsid);
     654        5040 :         state->ClearAndDispose(disposer);
     655        5040 :         boost::checked_delete(state);
     656             :     }
     657             : 
     658        7924 : }
     659             : 
     660         168 : bool IFMapExporter::FilterNeighbor(IFMapNode *lnode, IFMapLink *link) {
     661         168 :     return walker_->FilterNeighbor(lnode, link);
     662             : }
     663             : 
     664        3686 : bool IFMapExporter::ConfigChanged(IFMapNode *node) {
     665        3686 :     IFMapNodeState *state = NodeStateLookup(node);
     666        3686 :     bool changed = false;
     667        3686 :     assert(state);
     668             : 
     669        3686 :     IFMapExporter::crc32type node_crc = node->GetConfigCrc();
     670        3686 :     if (state->crc() != node_crc) {
     671        2212 :         changed = true;
     672        2212 :         state->SetCrc(node_crc);
     673             :     }
     674             : 
     675        3686 :     return changed;
     676             : }
     677             : 
     678          74 : void IFMapExporter::AddClientConfigTracker(int index) {
     679         222 :     for (int tracker_type = 0; tracker_type < TT_END; ++tracker_type) {
     680         148 :         if (index >= (int)client_config_tracker_[tracker_type].size()) {
     681         144 :             client_config_tracker_[tracker_type].resize(index + 1, NULL);
     682             :         }
     683         148 :         assert(client_config_tracker_[tracker_type][index] == NULL);
     684         148 :         ConfigSet *set = new ConfigSet();
     685         148 :         client_config_tracker_[tracker_type][index] = set;
     686             :     }
     687          74 : }
     688             : 
     689           6 : void IFMapExporter::DeleteClientConfigTracker(int index) {
     690          18 :     for (int tracker_type = 0; tracker_type < TT_END; ++tracker_type) {
     691          12 :         ConfigSet *set = client_config_tracker_[tracker_type].at(index);
     692          12 :         assert(set);
     693          12 :         delete set;
     694          12 :         client_config_tracker_[tracker_type][index] = NULL;
     695             :     }
     696           6 : }
     697             : 
     698        2574 : void IFMapExporter::UpdateClientConfigTracker(IFMapState *state,
     699             :         const BitSet& client_bits, bool add, TrackerType tracker_type) {
     700        5083 :     for (size_t pos = client_bits.find_first(); pos != BitSet::npos;
     701        2509 :             pos = client_bits.find_next(pos)) {
     702        2509 :         ConfigSet *set = client_config_tracker_[tracker_type].at(pos);
     703        2509 :         assert(set);
     704        2509 :         if (add) {
     705        2234 :             set->insert(state);
     706             :         } else {
     707         275 :             CsSz_t num = set->erase(state);
     708         275 :             assert(num == 1);
     709             :         }
     710             :     }
     711        2574 : }
     712             : 
     713           6 : void IFMapExporter::CleanupClientConfigTrackedEntries(int index) {
     714           6 :     BitSet rm_bs;
     715           6 :     rm_bs.set(index);
     716             : 
     717           6 :     ConfigSet *set = client_config_tracker_[INTEREST].at(index);
     718           6 :     assert(set);
     719          48 :     for (ConfigSet::iterator iter = set->begin(); iter != set->end(); ++iter) {
     720          42 :         IFMapState *state = *iter;
     721          42 :         state->InterestReset(rm_bs);
     722             :     }
     723             : 
     724           6 :     set = client_config_tracker_[ADVERTISED].at(index);
     725           6 :     assert(set);
     726          48 :     for (ConfigSet::iterator iter = set->begin(); iter != set->end(); ++iter) {
     727          42 :         IFMapState *state = *iter;
     728          42 :         state->AdvertisedReset(rm_bs);
     729             :     }
     730           6 : }
     731             : 
     732           0 : bool IFMapExporter::ClientHasConfigTracker(TrackerType tracker_type,
     733             :         int index) {
     734           0 :     ConfigSet *set = client_config_tracker_[tracker_type].at(index);
     735           0 :     return ((set != NULL) ? true : false);
     736             : }
     737             : 
     738          24 : bool IFMapExporter::ClientConfigTrackerHasState(TrackerType tracker_type,
     739             :                                                 int index, IFMapState *state) {
     740          24 :     ConfigSet *set = client_config_tracker_[tracker_type].at(index);
     741          24 :     assert(set);
     742          24 :     ConfigSet::iterator iter = set->find(state);
     743          24 :     return (iter == set->end() ? false : true);
     744             : }
     745             : 
     746          16 : bool IFMapExporter::ClientConfigTrackerEmpty(TrackerType tracker_type,
     747             :         int index) {
     748          16 :     ConfigSet *set = client_config_tracker_[tracker_type].at(index);
     749          16 :     assert(set);
     750          16 :     return set->empty();
     751             : }
     752             : 
     753           8 : size_t IFMapExporter::ClientConfigTrackerSize(TrackerType tracker_type,
     754             :         int index) {
     755           8 :     ConfigSet *set = client_config_tracker_[tracker_type].at(index);
     756           8 :     assert(set);
     757           8 :     return set->size();
     758             : }
     759             : 
     760          20 : IFMapExporter::Cs_citer IFMapExporter::ClientConfigTrackerBegin(
     761             :         TrackerType tracker_type, int index) const {
     762          20 :     ConfigSet *set = client_config_tracker_[tracker_type].at(index);
     763          20 :     assert(set);
     764          20 :     return set->begin();
     765             : }
     766             : 
     767          20 : IFMapExporter::Cs_citer IFMapExporter::ClientConfigTrackerEnd(
     768             :         TrackerType tracker_type, int index) const {
     769          20 :     ConfigSet *set = client_config_tracker_[tracker_type].at(index);
     770          20 :     assert(set);
     771          20 :     return set->end();
     772             : }
     773             : 
     774        3685 : void IFMapExporter::StateInterestSet(IFMapState *state,
     775             :                                      const BitSet& interest_bits) {
     776             :     // Add the node to the config-tracker of all clients that just became
     777             :     // interested in this node.
     778        3685 :     bool add = true;
     779        3685 :     BitSet new_clients;
     780        3685 :     new_clients.BuildComplement(interest_bits, state->interest());
     781        3685 :     if (!new_clients.empty()) {
     782         642 :         UpdateClientConfigTracker(state, new_clients, add, INTEREST);
     783             :     }
     784             : 
     785             :     // Remove the node from the config-tracker of all clients that are no longer
     786             :     // interested in this node.
     787        3685 :     add = false;
     788        3685 :     BitSet old_clients;
     789        3685 :     old_clients.BuildComplement(state->interest(), interest_bits);
     790        3685 :     if (!old_clients.empty()) {
     791         131 :         UpdateClientConfigTracker(state, old_clients, add, INTEREST);
     792             :     }
     793             : 
     794        3685 :     state->SetInterest(interest_bits);
     795        3685 : }
     796             : 
     797             : // Add the node to the config-tracker of all clients that just became interested
     798             : // in this node.
     799         493 : void IFMapExporter::StateInterestOr(IFMapState *state,
     800             :                                     const BitSet& interest_bits) {
     801         493 :     bool add = true;
     802         493 :     UpdateClientConfigTracker(state, interest_bits, add, INTEREST);
     803         493 :     state->InterestOr(interest_bits);
     804         493 : }
     805             : 
     806             : // Remove the node from the config-tracker of all clients that are no longer
     807             : // interested in this node.
     808         149 : void IFMapExporter::StateInterestReset(IFMapState *state,
     809             :                                        const BitSet& interest_bits) {
     810         149 :     bool add = false;
     811         149 :     UpdateClientConfigTracker(state, interest_bits, add, INTEREST);
     812         149 :     state->InterestReset(interest_bits);
     813         149 : }
     814             : 
     815             : // Add the node to the config-tracker of all clients that just sent this node.
     816        1069 : void IFMapExporter::StateAdvertisedOr(IFMapState *state,
     817             :                                       const BitSet& advertised_bits) {
     818        1069 :     bool add = true;
     819        1069 :     UpdateClientConfigTracker(state, advertised_bits, add, ADVERTISED);
     820        1069 :     state->AdvertisedOr(advertised_bits);
     821        1069 : }
     822             : 
     823             : // Remove the node from the config-tracker of all clients from whom the node
     824             : // was withdrawn.
     825          90 : void IFMapExporter::StateAdvertisedReset(IFMapState *state,
     826             :                                          const BitSet& advertised_bits) {
     827          90 :     bool add = false;
     828          90 :     UpdateClientConfigTracker(state, advertised_bits, add, ADVERTISED);
     829          90 :     state->AdvertisedReset(advertised_bits);
     830          90 : }
     831             : 
     832           0 : const IFMapTypenameWhiteList &IFMapExporter::get_traversal_white_list() const {
     833           0 :     return walker_->get_traversal_white_list();
     834             : }
     835             : 
     836           6 : void IFMapExporter::ResetLinkDeleteClients(const BitSet &bset) {
     837           6 :     walker_->ResetLinkDeleteClients(bset);
     838           6 : }
     839             : 

Generated by: LCOV version 1.14