LCOV - code coverage report
Current view: top level - db - db_graph.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 141 162 87.0 %
Date: 2026-11-09 02:10:49 Functions: 29 31 93.5 %
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 "db/db_graph.h"
       7             : 
       8             : #ifdef __clang__
       9             : #pragma clang diagnostic push
      10             : #pragma clang diagnostic ignored "-Wunused-variable"
      11             : #pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
      12             : #endif
      13             : 
      14             : #include <boost/foreach.hpp>
      15             : #include <boost/scoped_ptr.hpp>
      16             : #include <boost/graph/breadth_first_search.hpp>
      17             : #include <boost/graph/filtered_graph.hpp>
      18             : 
      19             : #ifdef __clang__
      20             : #pragma clang diagnostic pop
      21             : #endif
      22             : 
      23             : #include "base/logging.h"
      24             : #include "base/time_util.h"
      25             : #include "db/db_graph_vertex.h"
      26             : #include "db/db_graph_edge.h"
      27             : 
      28             : using namespace std;
      29             : using namespace boost;
      30             : 
      31      190127 : void DBGraph::AddNode(DBGraphVertex *entry) {
      32      190127 :     entry->set_vertex(add_vertex(graph_));
      33      190127 :     DBGraphBase::VertexProperties &vertex = graph_[entry->vertex()];
      34      190127 :     vertex.entry = entry;
      35      190127 : }
      36             : 
      37      190117 : void DBGraph::RemoveNode(DBGraphVertex *entry) {
      38      190117 :     remove_vertex(entry->vertex(), graph_);
      39      190117 :     entry->VertexInvalidate();
      40      190117 : }
      41             : 
      42      161119 : DBGraph::Edge DBGraph::Link(DBGraphVertex *lhs, DBGraphVertex *rhs,
      43             :                             DBGraphEdge *edge) {
      44      161119 :     DBGraph::Edge edge_id;
      45             :     bool added;
      46      161119 :     boost::tie(edge_id, added) = add_edge(lhs->vertex(), rhs->vertex(),
      47      322238 :                                     EdgeProperties(edge->name(), edge), graph_);
      48      161119 :     assert(added);
      49      161119 :     edge->SetEdge(edge_id);
      50      322238 :     return edge_id;
      51             : }
      52             : 
      53      161111 : void DBGraph::Unlink(DBGraphEdge *edge) {
      54      161111 :     remove_edge(edge->edge_id(), graph_);
      55      161111 : }
      56             : 
      57             : template <typename GraphType>
      58             : class BFSVisitor : public default_bfs_visitor {
      59             : public:
      60             :     typedef DBGraphBase::VertexProperties Properties;
      61             : 
      62           5 :     BFSVisitor(DBGraph::VertexVisitor vertex_visit,
      63             :                DBGraph::EdgeVisitor edge_visit)
      64           5 :         : vertex_visit_(vertex_visit), edge_visit_(edge_visit) {
      65           5 :     }
      66             : 
      67           0 :     BFSVisitor(DBGraph::VertexVisitor vertex_visit,
      68             :                DBGraph::EdgeVisitor edge_visit,
      69             :                DBGraph::VertexFinish vertex_finish)
      70           0 :         : vertex_visit_(vertex_visit), edge_visit_(edge_visit),
      71           0 :           vertex_finish_(vertex_finish) {
      72           0 :     }
      73             : 
      74          21 :     void discover_vertex(DBGraph::Vertex u, const GraphType &graph) const {
      75          21 :         if (vertex_visit_) {
      76          21 :             vertex_visit_(graph[u].entry);
      77             :         }
      78          21 :     }
      79             : 
      80          21 :     void finish_vertex(DBGraph::Vertex u, const GraphType &graph) const {
      81          21 :         if (vertex_finish_) {
      82           0 :             vertex_finish_(graph[u].entry);
      83             :         }
      84          21 :     }
      85             : 
      86             :     // Edges are examined twice: once for the source and once for the target
      87             :     // node.
      88          34 :     void examine_edge(DBGraph::Edge e, const GraphType &graph) const {
      89          34 :         const DBGraphBase::EdgeProperties &properties = graph[e];
      90          34 :         if (edge_visit_) {
      91          18 :             edge_visit_(properties.edge);
      92             :         }
      93          34 :     }
      94             : 
      95             : private:
      96             :     DBGraph::VertexVisitor vertex_visit_;
      97             :     DBGraph::EdgeVisitor edge_visit_;
      98             :     DBGraph::VertexFinish vertex_finish_;
      99             : };
     100             : 
     101             : typedef std::map<DBGraph::Vertex, default_color_type> ColorMap;
     102             : 
     103           0 : void DBGraph::Visit(DBGraphVertex *start, VertexVisitor vertex_visit_fn,
     104             :                     EdgeVisitor edge_visit_fn, VertexFinish vertex_finish_fn) {
     105             :     const BFSVisitor<graph_t> vis(vertex_visit_fn, edge_visit_fn,
     106           0 :                                   vertex_finish_fn);
     107           0 :     ColorMap color_map;
     108           0 :     breadth_first_search(graph_, start->vertex(),
     109           0 :         visitor(vis).color_map(make_assoc_property_map(color_map)));
     110           0 : }
     111             : 
     112           5 : void DBGraph::Visit(DBGraphVertex *start, VertexVisitor vertex_visit_fn,
     113             :                     EdgeVisitor edge_visit_fn) {
     114          10 :     const BFSVisitor<graph_t> vis(vertex_visit_fn, edge_visit_fn);
     115           5 :     ColorMap color_map;
     116           5 :     breadth_first_search(graph_, start->vertex(),
     117          10 :         visitor(vis).color_map(make_assoc_property_map(color_map)));
     118           5 : }
     119             : 
     120             : struct DBGraph::EdgePredicate {
     121             :     EdgePredicate() : graph_(NULL), filter_(NULL) { }
     122         137 :     EdgePredicate(const DBGraph *graph, const VisitorFilter &filter)
     123         137 :         : graph_(graph), filter_(&filter) {
     124         137 :     }
     125             : 
     126         500 :     bool operator()(const DBGraphVertex *src, const DBGraphVertex *tgt,
     127             :                     const DBGraphEdge *edge) const {
     128         500 :         if (edge->IsDeleted()) {
     129           0 :             return false;
     130             :         }
     131         500 :         return filter_->EdgeFilter(src, tgt, edge);
     132             :     }
     133             : 
     134             : private:
     135             :     const DBGraph *graph_;
     136             :     const VisitorFilter *filter_;
     137             : };
     138             : 
     139             : struct DBGraph::VertexPredicate {
     140             :     VertexPredicate() : graph_(NULL), filter_(NULL) { }
     141         137 :     VertexPredicate(const DBGraph *graph, const VisitorFilter &filter)
     142         137 :         : graph_(graph), filter_(&filter) {
     143         137 :     }
     144         500 :     bool operator()(const DBGraphVertex *entry) const {
     145         500 :         if (entry->IsDeleted()) {
     146           0 :             return false;
     147             :         }
     148         500 :         return filter_->VertexFilter(entry);
     149             :     }
     150             : private:
     151             :     const DBGraph *graph_;
     152             :     const VisitorFilter *filter_;
     153             : };
     154             : 
     155         500 : DBGraphVertex *DBGraph::vertex_target(DBGraphVertex *current_vertex,
     156             :                                       DBGraphEdge *edge) {
     157         500 :     DBGraphVertex *adjacent_vertex = edge->target(this);
     158         500 :     if (adjacent_vertex == current_vertex) {
     159         228 :         adjacent_vertex = edge->source(this);
     160             :     }
     161         500 :     return adjacent_vertex;
     162             : }
     163             : 
     164             : 
     165        3410 : void DBGraph::IterateEdges(DBGraphVertex *current_vertex,
     166             :                    OutEdgeIterator &iter_begin, OutEdgeIterator &iter_end,
     167             :                    VertexVisitor vertex_visit_fn, EdgeVisitor edge_visit_fn,
     168             :                    EdgePredicate &edge_test, VertexPredicate &vertex_test,
     169             :                    ::uint64_t curr_walk, /* ::uint64_t because using namespace boost above */
     170             :                    VisitQ &visit_q,
     171             :                    bool match_name, const std::string &allowed_edge) {
     172        3910 :     for (; iter_begin != iter_end; ++iter_begin) {
     173        2964 :         const DBGraph::EdgeProperties &e_prop = get(edge_bundle, *iter_begin);
     174        2964 :         DBGraphEdge *edge = e_prop.edge;
     175        2964 :         if (match_name && e_prop.name() != allowed_edge) break;
     176         500 :         DBGraphVertex *adjacent_vertex = vertex_target(current_vertex, edge);
     177         500 :         if (edge_visit_fn) edge_visit_fn(edge);
     178         511 :         if (!edge_test(current_vertex, adjacent_vertex, edge)) continue;
     179         374 :         if (adjacent_vertex->visited(curr_walk)) continue;
     180         363 :         if (vertex_test(adjacent_vertex)) {
     181         357 :             vertex_visit_fn(adjacent_vertex);
     182         357 :             visit_q.push(adjacent_vertex);
     183             :         }
     184         363 :         adjacent_vertex->set_visited(curr_walk);
     185             :     }
     186        3410 : }
     187             : 
     188         137 : void DBGraph::Visit(DBGraphVertex *start, VertexVisitor vertex_visit_fn,
     189             :                     EdgeVisitor edge_visit_fn, const VisitorFilter &filter) {
     190             :     // uint64_t t = ClockMonotonicUsec();
     191         137 :     ::uint64_t curr_walk = get_graph_walk_num(); /* ::uint64_t because using namespace boost above */
     192         137 :     EdgePredicate edge_test(this, filter);
     193         137 :     VertexPredicate vertex_test(this, filter);
     194             : 
     195         137 :     VisitQ visit_q;
     196             : 
     197         137 :     visit_q.push(start);
     198         137 :     start->set_visited(curr_walk);
     199         137 :     if (vertex_test(start)) {
     200         137 :         vertex_visit_fn(start);
     201             :     }
     202         631 :     while (!visit_q.empty()) {
     203         494 :         DBGraphVertex *vertex = visit_q.front();
     204         494 :         visit_q.pop();
     205             :         // Get All out-edges from the node
     206         494 :         OutEdgeListType &out_edge_set = graph_.out_edge_list(vertex->vertex());
     207         494 :         if (out_edge_set.empty()) continue;
     208             : 
     209         490 :         OutEdgeListType::iterator it = out_edge_set.begin();
     210         490 :         OutEdgeListType::iterator it_end = out_edge_set.end();
     211             : 
     212             :         // Collect all allowed edges to visit
     213             :         DBGraph::VisitorFilter::AllowedEdgeRetVal allowed_edge_ret =
     214         490 :             filter.AllowedEdges(vertex);
     215             : 
     216         490 :         if (!allowed_edge_ret.first) {
     217        3860 :             for (auto allowed_edge : allowed_edge_ret.second) {
     218        3390 :                 EdgeContainer fake_container;
     219        3390 :                 fake_container.push_back(
     220        6780 :                          EdgeType(0, 0, EdgeProperties(allowed_edge, NULL)));
     221        3390 :                 StoredEdge es(vertex->vertex(), fake_container.begin());
     222             :                 // Call lower_bound on out edge list and walk on selected edges
     223        3390 :                 it = out_edge_set.lower_bound(es);
     224        3390 :                 IterateEdges(vertex, it, it_end, vertex_visit_fn, edge_visit_fn,
     225             :                 edge_test, vertex_test, curr_walk, visit_q, true, allowed_edge);
     226        3390 :             }
     227             :         } else {
     228          20 :             IterateEdges(vertex, it, it_end, vertex_visit_fn, edge_visit_fn,
     229             :                          edge_test, vertex_test, curr_walk, visit_q);
     230             :         }
     231         490 :     }
     232             :     // uint64_t end_t = ClockMonotonicUsec();
     233             :     // std::cout << "Graph Walk time(in usec) " <<  (end_t-t) << std::endl;
     234         137 : }
     235             : 
     236         167 : DBGraph::edge_iterator::edge_iterator(DBGraph *graph) : graph_(graph) {
     237         167 :     if (graph_) {
     238          80 :         boost::tie(iter_, end_) = edges(*graph_->graph());
     239             :     }
     240         167 : }
     241             : 
     242          45 : DBGraph::DBEdgeInfo DBGraph::edge_iterator::dereference() const {
     243          45 :     Vertex src = source(*iter_, *graph_->graph());
     244          45 :     Vertex tgt = target(*iter_, *graph_->graph());
     245          45 :     return boost::make_tuple(graph_->vertex_data(src), graph_->vertex_data(tgt),
     246         135 :                              graph_->edge_data(*iter_));
     247             : }
     248             : 
     249          87 : bool DBGraph::edge_iterator::equal(const edge_iterator &rhs) const {
     250          87 :     if (graph_ != NULL) {
     251          87 :         if (rhs.graph_ == NULL) {
     252          87 :             return (iter_ == end_);
     253             :         }
     254           0 :         return iter_ == rhs.iter_;
     255             :     } else {
     256           0 :         if (rhs.graph_ != NULL) {
     257           0 :             return (rhs.iter_ == rhs.end_);
     258             :         }
     259           0 :         return true;
     260             :     }
     261             : }
     262             : 
     263          42 : DBGraph::edge_iterator DBGraph::edge_list_begin() {
     264          42 :     return edge_iterator(this);
     265             : }
     266             : 
     267          87 : DBGraph::edge_iterator DBGraph::edge_list_end() {
     268          87 :     return edge_iterator(NULL);
     269             : }
     270             : 
     271         355 : DBGraph::vertex_iterator::vertex_iterator(DBGraph *graph)
     272         355 :     : graph_(graph) {
     273         355 :     if (graph_ != NULL) {
     274          77 :         boost::tie(iter_, end_) = vertices(*graph_->graph());
     275             :     }
     276         355 : }
     277             : 
     278         278 : bool DBGraph::vertex_iterator::equal(const vertex_iterator &rhs) const {
     279         278 :     if (graph_ != NULL) {
     280         278 :         if (rhs.graph_ != NULL) {
     281           0 :             return iter_ == rhs.iter_;
     282             :         } else {
     283         278 :             return (iter_ == end_);
     284             :         }
     285             :     } else {
     286           0 :         if (rhs.graph_ != NULL) {
     287           0 :             return rhs.iter_ == rhs.end_;
     288             :         } else {
     289           0 :             return true;
     290             :         }
     291             :     }
     292             : }
     293             : 
     294          39 : DBGraph::vertex_iterator DBGraph::vertex_list_begin() {
     295          39 :     return vertex_iterator(this);
     296             : }
     297             : 
     298         278 : DBGraph::vertex_iterator DBGraph::vertex_list_end() {
     299         278 :     return vertex_iterator(NULL);
     300             : }
     301             : 
     302           3 : void DBGraph::clear() {
     303           3 :     graph_.clear();
     304           3 : }
     305             : 
     306         585 : size_t DBGraph::vertex_count() const {
     307         585 :     return num_vertices(graph_);
     308             : }
     309             : 
     310         536 : size_t DBGraph::edge_count() const {
     311         536 :     return num_edges(graph_);
     312             : }
     313             : 
     314             : template <class StoredEdge>
     315      304301 : bool order_by_name<StoredEdge>::operator()(const StoredEdge& e1, const StoredEdge& e2) const {
     316      304301 :     const DBGraph::EdgeProperties &edge1 = get(edge_bundle, e1);
     317      304301 :     const DBGraph::EdgeProperties &edge2 = get(edge_bundle, e2);
     318      304301 :     return edge1.name() < edge2.name();
     319             : }

Generated by: LCOV version 1.14