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 8197 : IFMapDependencyTracker::IFMapDependencyTracker( 18 8197 : DB *db, DBGraph *graph, ChangeObserver observer) 19 8197 : : database_(db), graph_(graph), observer_(observer) { 20 8197 : } 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 196015 : void IFMapDependencyTracker::NodeEvent(IFMapNode *node, bool add_node_event) { 30 196015 : if (add_node_event) 31 190396 : AddChangeEvent(node); 32 196015 : if (IsInterestingEvent(node, "self")) { 33 145497 : node_list_.push_back( 34 290994 : make_pair(node->table()->Typename(), node->name())); 35 : } 36 196015 : } 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 190396 : void IFMapDependencyTracker::NodeEvent(IFMapNode *node) { 46 190396 : NodeEvent(node, true); 47 190396 : } 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 251652 : bool IFMapDependencyTracker::LinkEvent(const string metadata, 56 : IFMapNode *left, IFMapNode *right) { 57 251652 : bool interest = false; 58 : 59 251652 : if ((left != NULL) && IsInterestingEvent(left, metadata)) { 60 108168 : const char *type_left = left->table()->Typename(); 61 108168 : edge_list_.push_back( 62 216336 : EdgeDescriptor(metadata, type_left, left->name())); 63 108168 : interest = true; 64 : } 65 251652 : if ((right != NULL) && IsInterestingEvent(right, metadata)) { 66 76643 : const char *type_right = right->table()->Typename(); 67 76643 : edge_list_.push_back( 68 153286 : EdgeDescriptor(metadata, type_right, right->name())); 69 76643 : interest = true; 70 : } 71 : 72 251652 : 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 68363 : void IFMapDependencyTracker::PropagateChanges() { 81 68363 : InEdgeSet in_edges; 82 : 83 68363 : for (NodeList::iterator iter = node_list_.begin(); 84 213860 : iter != node_list_.end(); ++iter) { 85 : IFMapTable *table = 86 145497 : IFMapTable::FindTable(database_, iter->first); 87 145497 : if (table == NULL) { 88 0 : continue; 89 : } 90 145497 : IFMapNode *node = table->FindNode(iter->second); 91 145497 : if ((node == NULL) || node->IsDeleted()) { 92 7 : continue; 93 : } 94 145490 : PropagateNode(node, &in_edges); 95 : } 96 : 97 68363 : for (EdgeDescriptorList::iterator iter = edge_list_.begin(); 98 253174 : iter != edge_list_.end(); ++iter) { 99 184811 : const EdgeDescriptor &edge = *iter; 100 : IFMapTable *table = 101 184811 : IFMapTable::FindTable(database_, edge.id_type); 102 184811 : if (table == NULL) { 103 0 : continue; 104 : } 105 184811 : IFMapNode *node = table->FindNode(edge.id_name); 106 184811 : if ((node == NULL) || node->IsDeleted()) { 107 3 : continue; 108 : } 109 184808 : PropagateEdge(node, edge.metadata, &in_edges); 110 : } 111 68363 : } 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 68363 : void IFMapDependencyTracker::Clear() { 119 68363 : node_list_.clear(); 120 68363 : edge_list_.clear(); 121 68363 : } 122 : 123 : // 124 : // Get the PropagateList for the given identifier type and metadata. 125 : // 126 : const IFMapDependencyTracker::PropagateList * 127 1051612 : IFMapDependencyTracker::GetPropagateList( 128 : const string &type, const string &metadata) const { 129 : 130 1051612 : NodeEventPolicy::const_iterator ploc = policy_.find(type); 131 1051612 : if (ploc == policy_.end()) { 132 159386 : return NULL; 133 : } 134 892226 : ReactionMap::const_iterator rloc = ploc->second.find(metadata); 135 892226 : if (rloc == ploc->second.end()) { 136 66773 : return NULL; 137 : } 138 825453 : 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 659008 : bool IFMapDependencyTracker::IsInterestingEvent( 147 : const IFMapNode *node, const string &metadata) const { 148 659008 : if (node->IsDeleted()) { 149 102541 : return false; 150 : } 151 556467 : 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 145490 : void IFMapDependencyTracker::PropagateNode( 160 : IFMapNode *node, InEdgeSet *in_edges) { 161 : 162 : const PropagateList *plist = 163 145490 : GetPropagateList(node->table()->Typename(), "self"); 164 145490 : 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 145490 : for (DBGraphVertex::edge_iterator iter = 169 145490 : node->edge_list_begin(graph_); 170 354931 : iter != node->edge_list_end(graph_); ++iter) { 171 209441 : IFMapLink *link = static_cast<IFMapLink *>(iter.operator->()); 172 209441 : IFMapNode *target = static_cast<IFMapNode *>(iter.target()); 173 209441 : if (plist->find(link->metadata()) == plist->end()) { 174 119205 : continue; 175 : } 176 90236 : PropagateEdge(target, link->metadata(), in_edges); 177 : } 178 145490 : } 179 : 180 : // 181 : // Propagate changes for an edge on the EdgeDescriptorList. 182 : // 183 349655 : void IFMapDependencyTracker::PropagateEdge( 184 : IFMapNode *node, const string &metadata, InEdgeSet *in_edges) { 185 349655 : 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 349655 : GetPropagateList(node->table()->Typename(), metadata); 191 349655 : assert(plist); 192 : 193 : // Skip if this edge in already in the InEdgeSet i.e. it's a duplicate. 194 349655 : if (in_edges->count(make_pair(node, metadata)) > 0) { 195 138550 : return; 196 : } 197 : 198 : // Add entry to InEdgeSet for loop prevention. 199 211105 : 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 211105 : PropagateList::const_iterator self = plist->find("self"); 204 211105 : if (self != plist->end()) { 205 141163 : 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 211105 : for (DBGraphVertex::edge_iterator iter = 211 211105 : node->edge_list_begin(graph_); 212 1084417 : iter != node->edge_list_end(graph_); ++iter) { 213 873312 : IFMapLink *link = static_cast<IFMapLink *>(iter.operator->()); 214 873312 : if (plist->find(link->metadata()) == plist->end()) { 215 798701 : continue; 216 : } 217 74611 : IFMapNode *target = static_cast<IFMapNode *>(iter.target()); 218 74611 : PropagateEdge(target, link->metadata(), in_edges); 219 : } 220 : } 221 : 222 : // 223 : // Add the IFMapNode to the change list. 224 : // 225 331559 : void IFMapDependencyTracker::AddChangeEvent(IFMapNode *node) { 226 331559 : observer_(node); 227 331559 : } 228 :