LCOV - code coverage report
Current view: top level - ifmap - ifmap_dependency_tracker.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 96 98 98.0 %
Date: 2026-06-04 02:06:09 Functions: 11 11 100.0 %
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_dependency_tracker.h"
       6             : 
       7             : #include <sstream>
       8             : #include <boost/assign/list_of.hpp>
       9             : 
      10             : #include "ifmap/ifmap_link.h"
      11             : #include "ifmap/ifmap_node.h"
      12             : #include "ifmap/ifmap_table.h"
      13             : 
      14             : using namespace boost::assign;
      15             : using namespace std;
      16             : 
      17        8199 : IFMapDependencyTracker::IFMapDependencyTracker(
      18        8199 :     DB *db, DBGraph *graph, ChangeObserver observer)
      19        8199 :         : database_(db), graph_(graph), observer_(observer) {
      20        8199 : }
      21             : 
      22             : //
      23             : // Add an IFMapNode to the NodeList for further propagation if it's an
      24             : // interesting node. It's interesting if there's an entry for self in the
      25             : // ReactionMap.
      26             : //
      27             : // Node event is added based on "add_node_event" flag
      28             : //
      29      196587 : void IFMapDependencyTracker::NodeEvent(IFMapNode *node, bool add_node_event) {
      30      196587 :     if (add_node_event)
      31      190948 :         AddChangeEvent(node);
      32      196587 :     if (IsInterestingEvent(node, "self")) {
      33      145822 :         node_list_.push_back(
      34      291644 :             make_pair(node->table()->Typename(), node->name()));
      35             :     }
      36      196587 : }
      37             : 
      38             : //
      39             : // Add an IFMapNode to the NodeList for further propagation if it's an
      40             : // interesting node. It's interesting if there's an entry for self in the
      41             : // ReactionMap.
      42             : //
      43             : // The node is always added to the ChangeList even if it's not interesting.
      44             : //
      45      190948 : void IFMapDependencyTracker::NodeEvent(IFMapNode *node) {
      46      190948 :     NodeEvent(node, true);
      47      190948 : }
      48             : 
      49             : //
      50             : // Check both the edges corresponding to the IFMapLink and add them to the
      51             : // EdgeDescriptorList if interesting. An edge is considered interesting if
      52             : // there's an entry for the metadata in the ReactionMap for the IFMapNode's
      53             : // identifier type.
      54             : //
      55      251983 : bool IFMapDependencyTracker::LinkEvent(const string metadata,
      56             :     IFMapNode *left, IFMapNode *right) {
      57      251983 :     bool interest = false;
      58             : 
      59      251983 :     if ((left != NULL) && IsInterestingEvent(left, metadata)) {
      60      108442 :         const char *type_left = left->table()->Typename();
      61      108442 :         edge_list_.push_back(
      62      216884 :             EdgeDescriptor(metadata, type_left, left->name()));
      63      108442 :         interest = true;
      64             :     }
      65      251983 :     if ((right != NULL) && IsInterestingEvent(right, metadata)) {
      66       76976 :         const char *type_right = right->table()->Typename();
      67       76976 :         edge_list_.push_back(
      68      153952 :             EdgeDescriptor(metadata, type_right, right->name()));
      69       76976 :         interest = true;
      70             :     }
      71             : 
      72      251983 :     return interest;
      73             : }
      74             : 
      75             : //
      76             : // Walk the NodeList and EdgeDescriptorList and evaluate the NodeEventPolicy
      77             : // to build up the change list. The InEdgeSet is used to avoid evaluating the
      78             : // same EdgeDescriptor more than once, hence avoiding any loops in the graph.
      79             : //
      80       68933 : void IFMapDependencyTracker::PropagateChanges() {
      81       68933 :     InEdgeSet in_edges;
      82             : 
      83       68933 :     for (NodeList::iterator iter = node_list_.begin();
      84      214755 :          iter != node_list_.end(); ++iter) {
      85             :         IFMapTable *table =
      86      145822 :             IFMapTable::FindTable(database_, iter->first);
      87      145822 :         if (table == NULL) {
      88           0 :             continue;
      89             :         }
      90      145822 :         IFMapNode *node = table->FindNode(iter->second);
      91      145822 :         if ((node == NULL) || node->IsDeleted()) {
      92           4 :             continue;
      93             :         }
      94      145818 :         PropagateNode(node, &in_edges);
      95             :     }
      96             : 
      97       68933 :     for (EdgeDescriptorList::iterator iter = edge_list_.begin();
      98      254351 :          iter != edge_list_.end(); ++iter) {
      99      185418 :         const EdgeDescriptor &edge = *iter;
     100             :         IFMapTable *table =
     101      185418 :             IFMapTable::FindTable(database_, edge.id_type);
     102      185418 :         if (table == NULL) {
     103           0 :             continue;
     104             :         }
     105      185418 :         IFMapNode *node = table->FindNode(edge.id_name);
     106      185418 :         if ((node == NULL) || node->IsDeleted()) {
     107           4 :             continue;
     108             :         }
     109      185414 :         PropagateEdge(node, edge.metadata, &in_edges);
     110             :     }
     111       68933 : }
     112             : 
     113             : //
     114             : // Clear all intermediate state used during propagation. This is called after
     115             : // we're done propagating all accumulated node and edge triggers to the change
     116             : // list.
     117             : //
     118       68933 : void IFMapDependencyTracker::Clear() {
     119       68933 :     node_list_.clear();
     120       68933 :     edge_list_.clear();
     121       68933 : }
     122             : 
     123             : //
     124             : // Get the PropagateList for the given identifier type and metadata.
     125             : //
     126             : const IFMapDependencyTracker::PropagateList *
     127     1053593 : IFMapDependencyTracker::GetPropagateList(
     128             :     const string &type, const string &metadata) const {
     129             : 
     130     1053593 :     NodeEventPolicy::const_iterator ploc = policy_.find(type);
     131     1053593 :     if (ploc == policy_.end()) {
     132      159340 :         return NULL;
     133             :     }
     134      894253 :     ReactionMap::const_iterator rloc = ploc->second.find(metadata);
     135      894253 :     if (rloc == ploc->second.end()) {
     136       66885 :         return NULL;
     137             :     }
     138      827368 :     return &rloc->second;
     139             : }
     140             : 
     141             : //
     142             : // Determine if the event specified by the node and metadata is interesting.
     143             : // It's interesting if the NodeEventPolicy has non-empty propagate list for
     144             : // the event.
     145             : //
     146      660077 : bool IFMapDependencyTracker::IsInterestingEvent(
     147             :     const IFMapNode *node, const string &metadata) const {
     148      660077 :     if (node->IsDeleted()) {
     149      102612 :         return false;
     150             :     }
     151      557465 :     return GetPropagateList(node->table()->Typename(), metadata) != NULL;
     152             : }
     153             : 
     154             : //
     155             : // Propagate changes for a IFMapNode on the NodeList.  The fact that it's on
     156             : // the NodeList means that the node must have been deemed interesting and so
     157             : // it's PropagateList must be non-empty.
     158             : //
     159      145818 : void IFMapDependencyTracker::PropagateNode(
     160             :     IFMapNode *node, InEdgeSet *in_edges) {
     161             : 
     162             :     const PropagateList *plist =
     163      145818 :         GetPropagateList(node->table()->Typename(), "self");
     164      145818 :     assert(plist);
     165             : 
     166             :     // Iterate through the edges of node. If the metadata for an edge is in
     167             :     // the PropagateList, we need to propagate changes for the edge itself.
     168      145818 :     for (DBGraphVertex::edge_iterator iter =
     169      145818 :          node->edge_list_begin(graph_);
     170      355138 :          iter != node->edge_list_end(graph_); ++iter) {
     171      209320 :         IFMapLink *link = static_cast<IFMapLink *>(iter.operator->());
     172      209320 :         IFMapNode *target = static_cast<IFMapNode *>(iter.target());
     173      209320 :         if (plist->find(link->metadata()) == plist->end()) {
     174      119333 :             continue;
     175             :         }
     176       89987 :         PropagateEdge(target, link->metadata(), in_edges);
     177             :     }
     178      145818 : }
     179             : 
     180             : //
     181             : // Propagate changes for an edge on the EdgeDescriptorList.
     182             : //
     183      350310 : void IFMapDependencyTracker::PropagateEdge(
     184             :     IFMapNode *node, const string &metadata, InEdgeSet *in_edges) {
     185      350310 :     assert(!node->IsDeleted());
     186             : 
     187             :     // Make a bidirectional check i.e. policy terms that apply to the two
     188             :     // edges for a link must be symmetrical.
     189             :     const PropagateList *plist =
     190      350310 :         GetPropagateList(node->table()->Typename(), metadata);
     191      350310 :     assert(plist);
     192             : 
     193             :     // Skip if this edge in already in the InEdgeSet i.e. it's a duplicate.
     194      350310 :     if (in_edges->count(make_pair(node, metadata)) > 0) {
     195      138422 :         return;
     196             :     }
     197             : 
     198             :     // Add entry to InEdgeSet for loop prevention.
     199      211888 :     in_edges->insert(make_pair(node, metadata));
     200             : 
     201             :     // Add the node corresponding to this edge to the change list if there's
     202             :     // an entry for self in the PropagateList.
     203      211888 :     PropagateList::const_iterator self = plist->find("self");
     204      211888 :     if (self != plist->end()) {
     205      141403 :         AddChangeEvent(node);
     206             :     }
     207             : 
     208             :     // Iterate through the edges of node. If the metadata for an edge is in
     209             :     // the PropagateList, we need to propagate changes for the edge itself.
     210      211888 :     for (DBGraphVertex::edge_iterator iter =
     211      211888 :          node->edge_list_begin(graph_);
     212     1086286 :          iter != node->edge_list_end(graph_); ++iter) {
     213      874398 :         IFMapLink *link = static_cast<IFMapLink *>(iter.operator->());
     214      874398 :         if (plist->find(link->metadata()) == plist->end()) {
     215      799489 :             continue;
     216             :         }
     217       74909 :         IFMapNode *target = static_cast<IFMapNode *>(iter.target());
     218       74909 :         PropagateEdge(target, link->metadata(), in_edges);
     219             :     }
     220             : }
     221             : 
     222             : //
     223             : // Add the IFMapNode to the change list.
     224             : //
     225      332351 : void IFMapDependencyTracker::AddChangeEvent(IFMapNode *node) {
     226      332351 :     observer_(node);
     227      332351 : }
     228             : 

Generated by: LCOV version 1.14