OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ifmap_dependency_tracker.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
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 
18  DB *db, DBGraph *graph, ChangeObserver observer)
19  : database_(db), graph_(graph), observer_(observer) {
20 }
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 void IFMapDependencyTracker::NodeEvent(IFMapNode *node, bool add_node_event) {
30  if (add_node_event)
31  AddChangeEvent(node);
32  if (IsInterestingEvent(node, "self")) {
33  node_list_.push_back(
34  make_pair(node->table()->Typename(), node->name()));
35  }
36 }
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 //
46  NodeEvent(node, true);
47 }
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 bool IFMapDependencyTracker::LinkEvent(const string metadata,
56  IFMapNode *left, IFMapNode *right) {
57  bool interest = false;
58 
59  if ((left != NULL) && IsInterestingEvent(left, metadata)) {
60  const char *type_left = left->table()->Typename();
61  edge_list_.push_back(
62  EdgeDescriptor(metadata, type_left, left->name()));
63  interest = true;
64  }
65  if ((right != NULL) && IsInterestingEvent(right, metadata)) {
66  const char *type_right = right->table()->Typename();
67  edge_list_.push_back(
68  EdgeDescriptor(metadata, type_right, right->name()));
69  interest = true;
70  }
71 
72  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 //
81  InEdgeSet in_edges;
82 
83  for (NodeList::iterator iter = node_list_.begin();
84  iter != node_list_.end(); ++iter) {
85  IFMapTable *table =
86  IFMapTable::FindTable(database_, iter->first);
87  if (table == NULL) {
88  continue;
89  }
90  IFMapNode *node = table->FindNode(iter->second);
91  if ((node == NULL) || node->IsDeleted()) {
92  continue;
93  }
94  PropagateNode(node, &in_edges);
95  }
96 
97  for (EdgeDescriptorList::iterator iter = edge_list_.begin();
98  iter != edge_list_.end(); ++iter) {
99  const EdgeDescriptor &edge = *iter;
100  IFMapTable *table =
102  if (table == NULL) {
103  continue;
104  }
105  IFMapNode *node = table->FindNode(edge.id_name);
106  if ((node == NULL) || node->IsDeleted()) {
107  continue;
108  }
109  PropagateEdge(node, edge.metadata, &in_edges);
110  }
111 }
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 //
119  node_list_.clear();
120  edge_list_.clear();
121 }
122 
123 //
124 // Get the PropagateList for the given identifier type and metadata.
125 //
128  const string &type, const string &metadata) const {
129 
130  NodeEventPolicy::const_iterator ploc = policy_.find(type);
131  if (ploc == policy_.end()) {
132  return NULL;
133  }
134  ReactionMap::const_iterator rloc = ploc->second.find(metadata);
135  if (rloc == ploc->second.end()) {
136  return NULL;
137  }
138  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 //
147  const IFMapNode *node, const string &metadata) const {
148  if (node->IsDeleted()) {
149  return false;
150  }
151  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 //
160  IFMapNode *node, InEdgeSet *in_edges) {
161 
162  const PropagateList *plist =
163  GetPropagateList(node->table()->Typename(), "self");
164  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  for (DBGraphVertex::edge_iterator iter =
169  node->edge_list_begin(graph_);
170  iter != node->edge_list_end(graph_); ++iter) {
171  IFMapLink *link = static_cast<IFMapLink *>(iter.operator->());
172  IFMapNode *target = static_cast<IFMapNode *>(iter.target());
173  if (plist->find(link->metadata()) == plist->end()) {
174  continue;
175  }
176  PropagateEdge(target, link->metadata(), in_edges);
177  }
178 }
179 
180 //
181 // Propagate changes for an edge on the EdgeDescriptorList.
182 //
184  IFMapNode *node, const string &metadata, InEdgeSet *in_edges) {
185  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  GetPropagateList(node->table()->Typename(), metadata);
191  assert(plist);
192 
193  // Skip if this edge in already in the InEdgeSet i.e. it's a duplicate.
194  if (in_edges->count(make_pair(node, metadata)) > 0) {
195  return;
196  }
197 
198  // Add entry to InEdgeSet for loop prevention.
199  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  PropagateList::const_iterator self = plist->find("self");
204  if (self != plist->end()) {
205  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  for (DBGraphVertex::edge_iterator iter =
211  node->edge_list_begin(graph_);
212  iter != node->edge_list_end(graph_); ++iter) {
213  IFMapLink *link = static_cast<IFMapLink *>(iter.operator->());
214  if (plist->find(link->metadata()) == plist->end()) {
215  continue;
216  }
217  IFMapNode *target = static_cast<IFMapNode *>(iter.target());
218  PropagateEdge(target, link->metadata(), in_edges);
219  }
220 }
221 
222 //
223 // Add the IFMapNode to the change list.
224 //
226  observer_(node);
227 }
228 
bool IsInterestingEvent(const IFMapNode *node, const std::string &metadata) const
boost::function< void(IFMapNode *node)> ChangeObserver
bool IsDeleted() const
Definition: db_entry.h:49
std::set< std::string > PropagateList
virtual const char * Typename() const =0
void PropagateEdge(IFMapNode *node, const std::string &metadata, InEdgeSet *in_edges)
IFMapTable * table()
Definition: ifmap_node.h:29
Definition: db.h:24
uint8_t type
Definition: load_balance.h:109
const PropagateList * GetPropagateList(const std::string &type, const std::string &metadata) const
IFMapNode * FindNode(const std::string &name)
Definition: ifmap_table.cc:23
void AddChangeEvent(IFMapNode *node)
const std::string & name() const
Definition: ifmap_node.h:48
std::set< std::pair< IFMapNode *, std::string > > InEdgeSet
void PropagateNode(IFMapNode *node, InEdgeSet *in_edges)
static IFMapTable * FindTable(DB *db, const std::string &element_type)
Definition: ifmap_table.cc:39
edge_iterator edge_list_end(DBGraph *graph)
bool LinkEvent(const std::string metadata, IFMapNode *left, IFMapNode *right)
IFMapDependencyTracker(DB *db, DBGraph *graph, ChangeObserver observer)
void NodeEvent(IFMapNode *node)
edge_iterator edge_list_begin(DBGraph *graph)