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

Generated by: LCOV version 1.14