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 :