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: 469 495 94.7 %
Date: 2026-11-09 02:10:49 Functions: 49 52 94.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14