Thomas Vachuska

ONOS-745 Refactoring topology to compute only broadcast tree and not pre-compute paths.

ONOS-744 Refactoring graph search to allow requesting max number of paths.

Change-Id: I28467246b92df32ebb3155c45774ecc051fdd3dd
Showing 23 changed files with 186 additions and 213 deletions
...@@ -69,20 +69,18 @@ public class SummaryCommand extends AbstractShellCommand { ...@@ -69,20 +69,18 @@ public class SummaryCommand extends AbstractShellCommand {
69 .put("links", topology.linkCount()) 69 .put("links", topology.linkCount())
70 .put("hosts", get(HostService.class).getHostCount()) 70 .put("hosts", get(HostService.class).getHostCount())
71 .put("SCC(s)", topology.clusterCount()) 71 .put("SCC(s)", topology.clusterCount())
72 - .put("paths", topology.pathCount())
73 .put("flows", get(FlowRuleService.class).getFlowRuleCount()) 72 .put("flows", get(FlowRuleService.class).getFlowRuleCount())
74 .put("intents", get(IntentService.class).getIntentCount())); 73 .put("intents", get(IntentService.class).getIntentCount()));
75 } else { 74 } else {
76 print("node=%s, version=%s", 75 print("node=%s, version=%s",
77 get(ClusterService.class).getLocalNode().ip(), 76 get(ClusterService.class).getLocalNode().ip(),
78 get(CoreService.class).version().toString()); 77 get(CoreService.class).version().toString());
79 - print("nodes=%d, devices=%d, links=%d, hosts=%d, SCC(s)=%s, paths=%d, flows=%d, intents=%d", 78 + print("nodes=%d, devices=%d, links=%d, hosts=%d, SCC(s)=%s, flows=%d, intents=%d",
80 activeNodes(get(ClusterService.class).getNodes()), 79 activeNodes(get(ClusterService.class).getNodes()),
81 get(DeviceService.class).getDeviceCount(), 80 get(DeviceService.class).getDeviceCount(),
82 get(LinkService.class).getLinkCount(), 81 get(LinkService.class).getLinkCount(),
83 get(HostService.class).getHostCount(), 82 get(HostService.class).getHostCount(),
84 topologyService.getClusters(topology).size(), 83 topologyService.getClusters(topology).size(),
85 - topology.pathCount(),
86 get(FlowRuleService.class).getFlowRuleCount(), 84 get(FlowRuleService.class).getFlowRuleCount(),
87 get(IntentService.class).getIntentCount()); 85 get(IntentService.class).getIntentCount());
88 } 86 }
......
...@@ -31,7 +31,7 @@ import org.onosproject.net.topology.TopologyService; ...@@ -31,7 +31,7 @@ import org.onosproject.net.topology.TopologyService;
31 public class TopologyCommand extends AbstractShellCommand { 31 public class TopologyCommand extends AbstractShellCommand {
32 32
33 private static final String FMT = 33 private static final String FMT =
34 - "time=%s, devices=%d, links=%d, clusters=%d, paths=%d"; 34 + "time=%s, devices=%d, links=%d, clusters=%d";
35 35
36 @Option(name = "-r", aliases = "--recompute", description = "Trigger topology re-computation", 36 @Option(name = "-r", aliases = "--recompute", description = "Trigger topology re-computation",
37 required = false, multiValued = false) 37 required = false, multiValued = false)
...@@ -59,11 +59,10 @@ public class TopologyCommand extends AbstractShellCommand { ...@@ -59,11 +59,10 @@ public class TopologyCommand extends AbstractShellCommand {
59 .put("time", topology.time()) 59 .put("time", topology.time())
60 .put("deviceCount", topology.deviceCount()) 60 .put("deviceCount", topology.deviceCount())
61 .put("linkCount", topology.linkCount()) 61 .put("linkCount", topology.linkCount())
62 - .put("clusterCount", topology.clusterCount()) 62 + .put("clusterCount", topology.clusterCount()));
63 - .put("pathCount", topology.pathCount()));
64 } else { 63 } else {
65 print(FMT, topology.time(), topology.deviceCount(), topology.linkCount(), 64 print(FMT, topology.time(), topology.deviceCount(), topology.linkCount(),
66 - topology.clusterCount(), topology.pathCount()); 65 + topology.clusterCount());
67 } 66 }
68 } 67 }
69 68
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
15 */ 15 */
16 package org.onosproject.net.topology; 16 package org.onosproject.net.topology;
17 17
18 -import org.onosproject.net.DeviceId;
19 -
20 import java.util.Objects; 18 import java.util.Objects;
21 19
22 import static com.google.common.base.MoreObjects.toStringHelper; 20 import static com.google.common.base.MoreObjects.toStringHelper;
...@@ -29,7 +27,7 @@ public class DefaultTopologyCluster implements TopologyCluster { ...@@ -29,7 +27,7 @@ public class DefaultTopologyCluster implements TopologyCluster {
29 private final ClusterId id; 27 private final ClusterId id;
30 private final int deviceCount; 28 private final int deviceCount;
31 private final int linkCount; 29 private final int linkCount;
32 - private final DeviceId root; 30 + private final TopologyVertex root;
33 31
34 /** 32 /**
35 * Creates a new topology cluster descriptor with the specified attributes. 33 * Creates a new topology cluster descriptor with the specified attributes.
...@@ -40,7 +38,7 @@ public class DefaultTopologyCluster implements TopologyCluster { ...@@ -40,7 +38,7 @@ public class DefaultTopologyCluster implements TopologyCluster {
40 * @param root cluster root node 38 * @param root cluster root node
41 */ 39 */
42 public DefaultTopologyCluster(ClusterId id, int deviceCount, int linkCount, 40 public DefaultTopologyCluster(ClusterId id, int deviceCount, int linkCount,
43 - DeviceId root) { 41 + TopologyVertex root) {
44 this.id = id; 42 this.id = id;
45 this.deviceCount = deviceCount; 43 this.deviceCount = deviceCount;
46 this.linkCount = linkCount; 44 this.linkCount = linkCount;
...@@ -63,7 +61,7 @@ public class DefaultTopologyCluster implements TopologyCluster { ...@@ -63,7 +61,7 @@ public class DefaultTopologyCluster implements TopologyCluster {
63 } 61 }
64 62
65 @Override 63 @Override
66 - public DeviceId root() { 64 + public TopologyVertex root() {
67 return root; 65 return root;
68 } 66 }
69 67
......
...@@ -61,13 +61,4 @@ public interface Topology extends Provided { ...@@ -61,13 +61,4 @@ public interface Topology extends Provided {
61 */ 61 */
62 int linkCount(); 62 int linkCount();
63 63
64 - /**
65 - * Returns the number of infrastructure paths computed between devices
66 - * in the topology. This means the number of all the shortest paths
67 - * (hop-count) between all device pairs.
68 - *
69 - * @return number of paths
70 - */
71 - int pathCount();
72 -
73 } 64 }
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
15 */ 15 */
16 package org.onosproject.net.topology; 16 package org.onosproject.net.topology;
17 17
18 -import org.onosproject.net.DeviceId;
19 -
20 /** 18 /**
21 * Representation of an SCC (strongly-connected component) in a network topology. 19 * Representation of an SCC (strongly-connected component) in a network topology.
22 */ 20 */
...@@ -44,10 +42,10 @@ public interface TopologyCluster { ...@@ -44,10 +42,10 @@ public interface TopologyCluster {
44 int linkCount(); 42 int linkCount();
45 43
46 /** 44 /**
47 - * Returns the device identifier of the cluster root device. 45 + * Returns the cluster root vertex.
48 * 46 *
49 - * @return cluster root device identifier 47 + * @return cluster root vertex
50 */ 48 */
51 - DeviceId root(); 49 + TopologyVertex root();
52 50
53 } 51 }
......
...@@ -43,11 +43,12 @@ public class DefaultTopologyClusterTest { ...@@ -43,11 +43,12 @@ public class DefaultTopologyClusterTest {
43 assertEquals("incorrect id", clusterId(6), cluster.id()); 43 assertEquals("incorrect id", clusterId(6), cluster.id());
44 assertEquals("incorrect id", 5, cluster.deviceCount()); 44 assertEquals("incorrect id", 5, cluster.deviceCount());
45 assertEquals("incorrect id", 4, cluster.linkCount()); 45 assertEquals("incorrect id", 4, cluster.linkCount());
46 - assertEquals("incorrect id", deviceId("of:111"), cluster.root()); 46 + assertEquals("incorrect id", deviceId("of:111"), cluster.root().deviceId());
47 47
48 } 48 }
49 49
50 private TopologyCluster cluster(int id, int dc, int lc, String root) { 50 private TopologyCluster cluster(int id, int dc, int lc, String root) {
51 - return new DefaultTopologyCluster(clusterId(id), dc, lc, deviceId(root)); 51 + return new DefaultTopologyCluster(clusterId(id), dc, lc,
52 + new DefaultTopologyVertex(deviceId(root)));
52 } 53 }
53 } 54 }
......
...@@ -31,7 +31,6 @@ import org.onosproject.net.topology.GraphDescription; ...@@ -31,7 +31,6 @@ import org.onosproject.net.topology.GraphDescription;
31 import org.onosproject.net.topology.LinkWeight; 31 import org.onosproject.net.topology.LinkWeight;
32 import org.onosproject.net.topology.Topology; 32 import org.onosproject.net.topology.Topology;
33 import org.onosproject.net.topology.TopologyCluster; 33 import org.onosproject.net.topology.TopologyCluster;
34 -import org.onosproject.net.topology.TopologyEdge;
35 import org.onosproject.net.topology.TopologyEvent; 34 import org.onosproject.net.topology.TopologyEvent;
36 import org.onosproject.net.topology.TopologyGraph; 35 import org.onosproject.net.topology.TopologyGraph;
37 import org.onosproject.net.topology.TopologyListener; 36 import org.onosproject.net.topology.TopologyListener;
...@@ -127,7 +126,6 @@ public class TopologyManagerTest { ...@@ -127,7 +126,6 @@ public class TopologyManagerTest {
127 assertEquals("wrong cluster count", 2, topology.clusterCount()); 126 assertEquals("wrong cluster count", 2, topology.clusterCount());
128 assertEquals("wrong device count", 6, topology.deviceCount()); 127 assertEquals("wrong device count", 6, topology.deviceCount());
129 assertEquals("wrong link count", 10, topology.linkCount()); 128 assertEquals("wrong link count", 10, topology.linkCount());
130 - assertEquals("wrong path count", 18, topology.pathCount());
131 129
132 assertEquals("wrong cluster count", 2, service.getClusters(topology).size()); 130 assertEquals("wrong cluster count", 2, service.getClusters(topology).size());
133 131
...@@ -148,12 +146,6 @@ public class TopologyManagerTest { ...@@ -148,12 +146,6 @@ public class TopologyManagerTest {
148 assertFalse("should not be infrastructure point", 146 assertFalse("should not be infrastructure point",
149 service.isInfrastructure(topology, new ConnectPoint(did("a"), portNumber(3)))); 147 service.isInfrastructure(topology, new ConnectPoint(did("a"), portNumber(3))));
150 148
151 - // One of these cannot be a broadcast point... or we have a loop...
152 -// assertFalse("should not be broadcast point",
153 -// service.isBroadcastPoint(topology, new ConnectPoint(did("a"), portNumber(1))) &&
154 -// service.isBroadcastPoint(topology, new ConnectPoint(did("b"), portNumber(1))) &&
155 -// service.isBroadcastPoint(topology, new ConnectPoint(did("c"), portNumber(1))) &&
156 -// service.isBroadcastPoint(topology, new ConnectPoint(did("d"), portNumber(1))));
157 assertTrue("should be broadcast point", 149 assertTrue("should be broadcast point",
158 service.isBroadcastPoint(topology, new ConnectPoint(did("a"), portNumber(3)))); 150 service.isBroadcastPoint(topology, new ConnectPoint(did("a"), portNumber(3))));
159 } 151 }
...@@ -182,12 +174,7 @@ public class TopologyManagerTest { ...@@ -182,12 +174,7 @@ public class TopologyManagerTest {
182 public void onDemandPath() { 174 public void onDemandPath() {
183 submitTopologyGraph(); 175 submitTopologyGraph();
184 Topology topology = service.currentTopology(); 176 Topology topology = service.currentTopology();
185 - LinkWeight weight = new LinkWeight() { 177 + LinkWeight weight = edge -> 3.3;
186 - @Override
187 - public double weight(TopologyEdge edge) {
188 - return 3.3;
189 - }
190 - };
191 178
192 Set<Path> paths = service.getPaths(topology, did("a"), did("c"), weight); 179 Set<Path> paths = service.getPaths(topology, did("a"), did("c"), weight);
193 assertEquals("wrong path count", 2, paths.size()); 180 assertEquals("wrong path count", 2, paths.size());
......
...@@ -20,7 +20,6 @@ import com.google.common.base.Suppliers; ...@@ -20,7 +20,6 @@ import com.google.common.base.Suppliers;
20 import com.google.common.collect.ImmutableMap; 20 import com.google.common.collect.ImmutableMap;
21 import com.google.common.collect.ImmutableSet; 21 import com.google.common.collect.ImmutableSet;
22 import com.google.common.collect.ImmutableSetMultimap; 22 import com.google.common.collect.ImmutableSetMultimap;
23 -
24 import org.onlab.graph.DijkstraGraphSearch; 23 import org.onlab.graph.DijkstraGraphSearch;
25 import org.onlab.graph.GraphPathSearch; 24 import org.onlab.graph.GraphPathSearch;
26 import org.onlab.graph.GraphPathSearch.Result; 25 import org.onlab.graph.GraphPathSearch.Result;
...@@ -51,11 +50,13 @@ import java.util.Set; ...@@ -51,11 +50,13 @@ import java.util.Set;
51 50
52 import static com.google.common.base.MoreObjects.toStringHelper; 51 import static com.google.common.base.MoreObjects.toStringHelper;
53 import static com.google.common.collect.ImmutableSetMultimap.Builder; 52 import static com.google.common.collect.ImmutableSetMultimap.Builder;
53 +import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
54 import static org.onosproject.core.CoreService.CORE_PROVIDER_ID; 54 import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
55 import static org.onosproject.net.Link.State.ACTIVE; 55 import static org.onosproject.net.Link.State.ACTIVE;
56 import static org.onosproject.net.Link.State.INACTIVE; 56 import static org.onosproject.net.Link.State.INACTIVE;
57 import static org.onosproject.net.Link.Type.INDIRECT; 57 import static org.onosproject.net.Link.Type.INDIRECT;
58 58
59 +// FIXME: Move to onos-core-common when ready
59 /** 60 /**
60 * Default implementation of the topology descriptor. This carries the 61 * Default implementation of the topology descriptor. This carries the
61 * backing topology data. 62 * backing topology data.
...@@ -71,10 +72,8 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -71,10 +72,8 @@ public class DefaultTopology extends AbstractModel implements Topology {
71 private final long computeCost; 72 private final long computeCost;
72 private final TopologyGraph graph; 73 private final TopologyGraph graph;
73 74
75 + private final LinkWeight weight;
74 private final Supplier<SCCResult<TopologyVertex, TopologyEdge>> clusterResults; 76 private final Supplier<SCCResult<TopologyVertex, TopologyEdge>> clusterResults;
75 - private final Supplier<ImmutableMap<DeviceId, Result<TopologyVertex, TopologyEdge>>> results;
76 - private final Supplier<ImmutableSetMultimap<PathKey, Path>> paths;
77 -
78 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters; 77 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
79 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints; 78 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
80 private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets; 79 private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
...@@ -95,15 +94,12 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -95,15 +94,12 @@ public class DefaultTopology extends AbstractModel implements Topology {
95 this.graph = new DefaultTopologyGraph(description.vertexes(), 94 this.graph = new DefaultTopologyGraph(description.vertexes(),
96 description.edges()); 95 description.edges());
97 96
98 -
99 - this.results = Suppliers.memoize(() -> searchForShortestPaths());
100 - this.paths = Suppliers.memoize(() -> buildPaths());
101 -
102 this.clusterResults = Suppliers.memoize(() -> searchForClusters()); 97 this.clusterResults = Suppliers.memoize(() -> searchForClusters());
103 this.clusters = Suppliers.memoize(() -> buildTopologyClusters()); 98 this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
104 99
105 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes()); 100 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
106 101
102 + this.weight = new HopCountLinkWeight(graph.getVertexes().size());
107 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets()); 103 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
108 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints()); 104 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
109 this.computeCost = Math.max(0, System.nanoTime() - time); 105 this.computeCost = Math.max(0, System.nanoTime() - time);
...@@ -134,11 +130,6 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -134,11 +130,6 @@ public class DefaultTopology extends AbstractModel implements Topology {
134 return graph.getEdges().size(); 130 return graph.getEdges().size();
135 } 131 }
136 132
137 - @Override
138 - public int pathCount() {
139 - return paths.get().size();
140 - }
141 -
142 private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() { 133 private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
143 return clusterIndexes.get().clustersByDevice; 134 return clusterIndexes.get().clustersByDevice;
144 } 135 }
...@@ -262,7 +253,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -262,7 +253,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
262 * @return set of shortest paths 253 * @return set of shortest paths
263 */ 254 */
264 Set<Path> getPaths(DeviceId src, DeviceId dst) { 255 Set<Path> getPaths(DeviceId src, DeviceId dst) {
265 - return paths.get().get(new PathKey(src, dst)); 256 + return getPaths(src, dst, null);
266 } 257 }
267 258
268 /** 259 /**
...@@ -284,7 +275,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -284,7 +275,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
284 } 275 }
285 276
286 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result = 277 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
287 - DIJKSTRA.search(graph, srcV, dstV, weight); 278 + DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS);
288 ImmutableSet.Builder<Path> builder = ImmutableSet.builder(); 279 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
289 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) { 280 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
290 builder.add(networkPath(path)); 281 builder.add(networkPath(path));
...@@ -293,31 +284,6 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -293,31 +284,6 @@ public class DefaultTopology extends AbstractModel implements Topology {
293 } 284 }
294 285
295 286
296 - // Searches the graph for all shortest paths and returns the search results.
297 - private ImmutableMap<DeviceId, Result<TopologyVertex, TopologyEdge>> searchForShortestPaths() {
298 - ImmutableMap.Builder<DeviceId, Result<TopologyVertex, TopologyEdge>> builder = ImmutableMap.builder();
299 -
300 - // Search graph paths for each source to all destinations.
301 - LinkWeight weight = new HopCountLinkWeight(graph.getVertexes().size());
302 - for (TopologyVertex src : graph.getVertexes()) {
303 - builder.put(src.deviceId(), DIJKSTRA.search(graph, src, null, weight));
304 - }
305 - return builder.build();
306 - }
307 -
308 - // Builds network paths from the graph path search results
309 - private ImmutableSetMultimap<PathKey, Path> buildPaths() {
310 - Builder<PathKey, Path> builder = ImmutableSetMultimap.builder();
311 - for (DeviceId deviceId : results.get().keySet()) {
312 - Result<TopologyVertex, TopologyEdge> result = results.get().get(deviceId);
313 - for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
314 - builder.put(new PathKey(path.src().deviceId(), path.dst().deviceId()),
315 - networkPath(path));
316 - }
317 - }
318 - return builder.build();
319 - }
320 -
321 // Converts graph path to a network path with the same cost. 287 // Converts graph path to a network path with the same cost.
322 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) { 288 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
323 List<Link> links = new ArrayList<>(); 289 List<Link> links = new ArrayList<>();
...@@ -337,23 +303,21 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -337,23 +303,21 @@ public class DefaultTopology extends AbstractModel implements Topology {
337 // Builds the topology clusters and returns the id-cluster bindings. 303 // Builds the topology clusters and returns the id-cluster bindings.
338 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() { 304 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
339 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder(); 305 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
340 - SCCResult<TopologyVertex, TopologyEdge> result = 306 + SCCResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
341 - TARJAN.search(graph, new NoIndirectLinksWeight());
342 -
343 // Extract both vertexes and edges from the results; the lists form 307 // Extract both vertexes and edges from the results; the lists form
344 // pairs along the same index. 308 // pairs along the same index.
345 - List<Set<TopologyVertex>> clusterVertexes = result.clusterVertexes(); 309 + List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
346 - List<Set<TopologyEdge>> clusterEdges = result.clusterEdges(); 310 + List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
347 311
348 // Scan over the lists and create a cluster from the results. 312 // Scan over the lists and create a cluster from the results.
349 - for (int i = 0, n = result.clusterCount(); i < n; i++) { 313 + for (int i = 0, n = results.clusterCount(); i < n; i++) {
350 Set<TopologyVertex> vertexSet = clusterVertexes.get(i); 314 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
351 Set<TopologyEdge> edgeSet = clusterEdges.get(i); 315 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
352 316
353 ClusterId cid = ClusterId.clusterId(i); 317 ClusterId cid = ClusterId.clusterId(i);
354 DefaultTopologyCluster cluster = 318 DefaultTopologyCluster cluster =
355 new DefaultTopologyCluster(cid, vertexSet.size(), edgeSet.size(), 319 new DefaultTopologyCluster(cid, vertexSet.size(), edgeSet.size(),
356 - findRoot(vertexSet).deviceId()); 320 + findRoot(vertexSet));
357 clusterBuilder.put(cid, cluster); 321 clusterBuilder.put(cid, cluster);
358 } 322 }
359 return clusterBuilder.build(); 323 return clusterBuilder.build();
...@@ -388,7 +352,8 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -388,7 +352,8 @@ public class DefaultTopology extends AbstractModel implements Topology {
388 private void addClusterBroadcastSet(TopologyCluster cluster, 352 private void addClusterBroadcastSet(TopologyCluster cluster,
389 Builder<ClusterId, ConnectPoint> builder) { 353 Builder<ClusterId, ConnectPoint> builder) {
390 // Use the graph root search results to build the broadcast set. 354 // Use the graph root search results to build the broadcast set.
391 - Result<TopologyVertex, TopologyEdge> result = results.get().get(cluster.root()); 355 + Result<TopologyVertex, TopologyEdge> result =
356 + DIJKSTRA.search(graph, cluster.root(), null, weight, 1);
392 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) { 357 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
393 TopologyVertex vertex = entry.getKey(); 358 TopologyVertex vertex = entry.getKey();
394 359
...@@ -498,7 +463,6 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -498,7 +463,6 @@ public class DefaultTopology extends AbstractModel implements Topology {
498 .add("clusters", clusterCount()) 463 .add("clusters", clusterCount())
499 .add("devices", deviceCount()) 464 .add("devices", deviceCount())
500 .add("links", linkCount()) 465 .add("links", linkCount())
501 - .add("pathCount", pathCount())
502 .toString(); 466 .toString();
503 } 467 }
504 } 468 }
......
...@@ -15,12 +15,16 @@ ...@@ -15,12 +15,16 @@
15 */ 15 */
16 package org.onosproject.store.trivial.impl; 16 package org.onosproject.store.trivial.impl;
17 17
18 +import com.google.common.base.Supplier;
19 +import com.google.common.base.Suppliers;
18 import com.google.common.collect.ImmutableMap; 20 import com.google.common.collect.ImmutableMap;
19 import com.google.common.collect.ImmutableSet; 21 import com.google.common.collect.ImmutableSet;
20 import com.google.common.collect.ImmutableSetMultimap; 22 import com.google.common.collect.ImmutableSetMultimap;
21 import org.onlab.graph.DijkstraGraphSearch; 23 import org.onlab.graph.DijkstraGraphSearch;
22 import org.onlab.graph.GraphPathSearch; 24 import org.onlab.graph.GraphPathSearch;
25 +import org.onlab.graph.GraphPathSearch.Result;
23 import org.onlab.graph.TarjanGraphSearch; 26 import org.onlab.graph.TarjanGraphSearch;
27 +import org.onlab.graph.TarjanGraphSearch.SCCResult;
24 import org.onosproject.net.AbstractModel; 28 import org.onosproject.net.AbstractModel;
25 import org.onosproject.net.ConnectPoint; 29 import org.onosproject.net.ConnectPoint;
26 import org.onosproject.net.DefaultPath; 30 import org.onosproject.net.DefaultPath;
...@@ -46,13 +50,13 @@ import java.util.Set; ...@@ -46,13 +50,13 @@ import java.util.Set;
46 50
47 import static com.google.common.base.MoreObjects.toStringHelper; 51 import static com.google.common.base.MoreObjects.toStringHelper;
48 import static com.google.common.collect.ImmutableSetMultimap.Builder; 52 import static com.google.common.collect.ImmutableSetMultimap.Builder;
49 -import static org.onlab.graph.GraphPathSearch.Result; 53 +import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
50 -import static org.onlab.graph.TarjanGraphSearch.SCCResult;
51 import static org.onosproject.core.CoreService.CORE_PROVIDER_ID; 54 import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
52 import static org.onosproject.net.Link.State.ACTIVE; 55 import static org.onosproject.net.Link.State.ACTIVE;
53 import static org.onosproject.net.Link.State.INACTIVE; 56 import static org.onosproject.net.Link.State.INACTIVE;
54 import static org.onosproject.net.Link.Type.INDIRECT; 57 import static org.onosproject.net.Link.Type.INDIRECT;
55 58
59 +// FIXME: Move to onos-core-common when ready
56 /** 60 /**
57 * Default implementation of the topology descriptor. This carries the 61 * Default implementation of the topology descriptor. This carries the
58 * backing topology data. 62 * backing topology data.
...@@ -68,18 +72,13 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -68,18 +72,13 @@ public class DefaultTopology extends AbstractModel implements Topology {
68 private final long computeCost; 72 private final long computeCost;
69 private final TopologyGraph graph; 73 private final TopologyGraph graph;
70 74
71 - private final SCCResult<TopologyVertex, TopologyEdge> clusterResults; 75 + private final LinkWeight weight;
72 - private final ImmutableMap<DeviceId, Result<TopologyVertex, TopologyEdge>> results; 76 + private final Supplier<SCCResult<TopologyVertex, TopologyEdge>> clusterResults;
73 - private final ImmutableSetMultimap<PathKey, Path> paths; 77 + private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
74 - 78 + private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
75 - private final ImmutableMap<ClusterId, TopologyCluster> clusters; 79 + private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
76 - private final ImmutableSet<ConnectPoint> infrastructurePoints;
77 - private final ImmutableSetMultimap<ClusterId, ConnectPoint> broadcastSets;
78 -
79 - private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
80 - private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
81 - private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
82 80
81 + private final Supplier<ClusterIndexes> clusterIndexes;
83 82
84 /** 83 /**
85 * Creates a topology descriptor attributed to the specified provider. 84 * Creates a topology descriptor attributed to the specified provider.
...@@ -95,16 +94,14 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -95,16 +94,14 @@ public class DefaultTopology extends AbstractModel implements Topology {
95 this.graph = new DefaultTopologyGraph(description.vertexes(), 94 this.graph = new DefaultTopologyGraph(description.vertexes(),
96 description.edges()); 95 description.edges());
97 96
98 - this.results = searchForShortestPaths(); 97 + this.clusterResults = Suppliers.memoize(() -> searchForClusters());
99 - this.paths = buildPaths(); 98 + this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
100 -
101 - this.clusterResults = searchForClusters();
102 - this.clusters = buildTopologyClusters();
103 99
104 - buildIndexes(); 100 + this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
105 101
106 - this.broadcastSets = buildBroadcastSets(); 102 + this.weight = new HopCountLinkWeight(graph.getVertexes().size());
107 - this.infrastructurePoints = findInfrastructurePoints(); 103 + this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
104 + this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
108 this.computeCost = Math.max(0, System.nanoTime() - time); 105 this.computeCost = Math.max(0, System.nanoTime() - time);
109 } 106 }
110 107
...@@ -120,7 +117,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -120,7 +117,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
120 117
121 @Override 118 @Override
122 public int clusterCount() { 119 public int clusterCount() {
123 - return clusters.size(); 120 + return clusters.get().size();
124 } 121 }
125 122
126 @Override 123 @Override
...@@ -133,9 +130,16 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -133,9 +130,16 @@ public class DefaultTopology extends AbstractModel implements Topology {
133 return graph.getEdges().size(); 130 return graph.getEdges().size();
134 } 131 }
135 132
136 - @Override 133 + private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
137 - public int pathCount() { 134 + return clusterIndexes.get().clustersByDevice;
138 - return paths.size(); 135 + }
136 +
137 + private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
138 + return clusterIndexes.get().devicesByCluster;
139 + }
140 +
141 + private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
142 + return clusterIndexes.get().linksByCluster;
139 } 143 }
140 144
141 /** 145 /**
...@@ -153,7 +157,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -153,7 +157,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
153 * @return set of clusters 157 * @return set of clusters
154 */ 158 */
155 Set<TopologyCluster> getClusters() { 159 Set<TopologyCluster> getClusters() {
156 - return ImmutableSet.copyOf(clusters.values()); 160 + return ImmutableSet.copyOf(clusters.get().values());
157 } 161 }
158 162
159 /** 163 /**
...@@ -163,7 +167,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -163,7 +167,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
163 * @return topology cluster 167 * @return topology cluster
164 */ 168 */
165 TopologyCluster getCluster(ClusterId clusterId) { 169 TopologyCluster getCluster(ClusterId clusterId) {
166 - return clusters.get(clusterId); 170 + return clusters.get().get(clusterId);
167 } 171 }
168 172
169 /** 173 /**
...@@ -173,7 +177,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -173,7 +177,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
173 * @return topology cluster 177 * @return topology cluster
174 */ 178 */
175 TopologyCluster getCluster(DeviceId deviceId) { 179 TopologyCluster getCluster(DeviceId deviceId) {
176 - return clustersByDevice.get(deviceId); 180 + return clustersByDevice().get(deviceId);
177 } 181 }
178 182
179 /** 183 /**
...@@ -183,7 +187,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -183,7 +187,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
183 * @return cluster devices 187 * @return cluster devices
184 */ 188 */
185 Set<DeviceId> getClusterDevices(TopologyCluster cluster) { 189 Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
186 - return devicesByCluster.get(cluster); 190 + return devicesByCluster().get(cluster);
187 } 191 }
188 192
189 /** 193 /**
...@@ -193,7 +197,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -193,7 +197,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
193 * @return cluster links 197 * @return cluster links
194 */ 198 */
195 Set<Link> getClusterLinks(TopologyCluster cluster) { 199 Set<Link> getClusterLinks(TopologyCluster cluster) {
196 - return linksByCluster.get(cluster); 200 + return linksByCluster().get(cluster);
197 } 201 }
198 202
199 /** 203 /**
...@@ -203,7 +207,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -203,7 +207,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
203 * @return true if infrastructure 207 * @return true if infrastructure
204 */ 208 */
205 boolean isInfrastructure(ConnectPoint connectPoint) { 209 boolean isInfrastructure(ConnectPoint connectPoint) {
206 - return infrastructurePoints.contains(connectPoint); 210 + return infrastructurePoints.get().contains(connectPoint);
207 } 211 }
208 212
209 /** 213 /**
...@@ -219,14 +223,14 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -219,14 +223,14 @@ public class DefaultTopology extends AbstractModel implements Topology {
219 } 223 }
220 224
221 // Find the cluster to which the device belongs. 225 // Find the cluster to which the device belongs.
222 - TopologyCluster cluster = clustersByDevice.get(connectPoint.deviceId()); 226 + TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
223 if (cluster == null) { 227 if (cluster == null) {
224 throw new IllegalArgumentException("No cluster found for device " + connectPoint.deviceId()); 228 throw new IllegalArgumentException("No cluster found for device " + connectPoint.deviceId());
225 } 229 }
226 230
227 // If the broadcast set is null or empty, or if the point explicitly 231 // If the broadcast set is null or empty, or if the point explicitly
228 // belongs to it, return true; 232 // belongs to it, return true;
229 - Set<ConnectPoint> points = broadcastSets.get(cluster.id()); 233 + Set<ConnectPoint> points = broadcastSets.get().get(cluster.id());
230 return points == null || points.isEmpty() || points.contains(connectPoint); 234 return points == null || points.isEmpty() || points.contains(connectPoint);
231 } 235 }
232 236
...@@ -237,7 +241,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -237,7 +241,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
237 * @return size of the cluster broadcast set 241 * @return size of the cluster broadcast set
238 */ 242 */
239 int broadcastSetSize(ClusterId clusterId) { 243 int broadcastSetSize(ClusterId clusterId) {
240 - return broadcastSets.get(clusterId).size(); 244 + return broadcastSets.get().get(clusterId).size();
241 } 245 }
242 246
243 /** 247 /**
...@@ -249,7 +253,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -249,7 +253,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
249 * @return set of shortest paths 253 * @return set of shortest paths
250 */ 254 */
251 Set<Path> getPaths(DeviceId src, DeviceId dst) { 255 Set<Path> getPaths(DeviceId src, DeviceId dst) {
252 - return paths.get(new PathKey(src, dst)); 256 + return getPaths(src, dst, null);
253 } 257 }
254 258
255 /** 259 /**
...@@ -258,7 +262,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -258,7 +262,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
258 * 262 *
259 * @param src source device 263 * @param src source device
260 * @param dst destination device 264 * @param dst destination device
261 - * @param weight edge weight function 265 + * @param weight link weight function
262 * @return set of shortest paths 266 * @return set of shortest paths
263 */ 267 */
264 Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) { 268 Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
...@@ -271,7 +275,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -271,7 +275,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
271 } 275 }
272 276
273 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result = 277 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
274 - DIJKSTRA.search(graph, srcV, dstV, weight); 278 + DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS);
275 ImmutableSet.Builder<Path> builder = ImmutableSet.builder(); 279 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
276 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) { 280 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
277 builder.add(networkPath(path)); 281 builder.add(networkPath(path));
...@@ -280,31 +284,6 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -280,31 +284,6 @@ public class DefaultTopology extends AbstractModel implements Topology {
280 } 284 }
281 285
282 286
283 - // Searches the graph for all shortest paths and returns the search results.
284 - private ImmutableMap<DeviceId, Result<TopologyVertex, TopologyEdge>> searchForShortestPaths() {
285 - ImmutableMap.Builder<DeviceId, Result<TopologyVertex, TopologyEdge>> builder = ImmutableMap.builder();
286 -
287 - // Search graph paths for each source to all destinations.
288 - LinkWeight weight = new HopCountLinkWeight(graph.getVertexes().size());
289 - for (TopologyVertex src : graph.getVertexes()) {
290 - builder.put(src.deviceId(), DIJKSTRA.search(graph, src, null, weight));
291 - }
292 - return builder.build();
293 - }
294 -
295 - // Builds network paths from the graph path search results
296 - private ImmutableSetMultimap<PathKey, Path> buildPaths() {
297 - Builder<PathKey, Path> builder = ImmutableSetMultimap.builder();
298 - for (DeviceId deviceId : results.keySet()) {
299 - Result<TopologyVertex, TopologyEdge> result = results.get(deviceId);
300 - for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
301 - builder.put(new PathKey(path.src().deviceId(), path.dst().deviceId()),
302 - networkPath(path));
303 - }
304 - }
305 - return builder.build();
306 - }
307 -
308 // Converts graph path to a network path with the same cost. 287 // Converts graph path to a network path with the same cost.
309 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) { 288 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
310 List<Link> links = new ArrayList<>(); 289 List<Link> links = new ArrayList<>();
...@@ -324,23 +303,21 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -324,23 +303,21 @@ public class DefaultTopology extends AbstractModel implements Topology {
324 // Builds the topology clusters and returns the id-cluster bindings. 303 // Builds the topology clusters and returns the id-cluster bindings.
325 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() { 304 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
326 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder(); 305 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
327 - SCCResult<TopologyVertex, TopologyEdge> result = 306 + SCCResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
328 - TARJAN.search(graph, new NoIndirectLinksWeight());
329 -
330 // Extract both vertexes and edges from the results; the lists form 307 // Extract both vertexes and edges from the results; the lists form
331 // pairs along the same index. 308 // pairs along the same index.
332 - List<Set<TopologyVertex>> clusterVertexes = result.clusterVertexes(); 309 + List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
333 - List<Set<TopologyEdge>> clusterEdges = result.clusterEdges(); 310 + List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
334 311
335 // Scan over the lists and create a cluster from the results. 312 // Scan over the lists and create a cluster from the results.
336 - for (int i = 0, n = result.clusterCount(); i < n; i++) { 313 + for (int i = 0, n = results.clusterCount(); i < n; i++) {
337 Set<TopologyVertex> vertexSet = clusterVertexes.get(i); 314 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
338 Set<TopologyEdge> edgeSet = clusterEdges.get(i); 315 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
339 316
340 ClusterId cid = ClusterId.clusterId(i); 317 ClusterId cid = ClusterId.clusterId(i);
341 DefaultTopologyCluster cluster = 318 DefaultTopologyCluster cluster =
342 new DefaultTopologyCluster(cid, vertexSet.size(), edgeSet.size(), 319 new DefaultTopologyCluster(cid, vertexSet.size(), edgeSet.size(),
343 - findRoot(vertexSet).deviceId()); 320 + findRoot(vertexSet));
344 clusterBuilder.put(cid, cluster); 321 clusterBuilder.put(cid, cluster);
345 } 322 }
346 return clusterBuilder.build(); 323 return clusterBuilder.build();
...@@ -363,7 +340,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -363,7 +340,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
363 // Processes a map of broadcast sets for each cluster. 340 // Processes a map of broadcast sets for each cluster.
364 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() { 341 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
365 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder(); 342 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder();
366 - for (TopologyCluster cluster : clusters.values()) { 343 + for (TopologyCluster cluster : clusters.get().values()) {
367 addClusterBroadcastSet(cluster, builder); 344 addClusterBroadcastSet(cluster, builder);
368 } 345 }
369 return builder.build(); 346 return builder.build();
...@@ -375,12 +352,13 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -375,12 +352,13 @@ public class DefaultTopology extends AbstractModel implements Topology {
375 private void addClusterBroadcastSet(TopologyCluster cluster, 352 private void addClusterBroadcastSet(TopologyCluster cluster,
376 Builder<ClusterId, ConnectPoint> builder) { 353 Builder<ClusterId, ConnectPoint> builder) {
377 // Use the graph root search results to build the broadcast set. 354 // Use the graph root search results to build the broadcast set.
378 - Result<TopologyVertex, TopologyEdge> result = results.get(cluster.root()); 355 + Result<TopologyVertex, TopologyEdge> result =
356 + DIJKSTRA.search(graph, cluster.root(), null, weight, 1);
379 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) { 357 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
380 TopologyVertex vertex = entry.getKey(); 358 TopologyVertex vertex = entry.getKey();
381 359
382 // Ignore any parents that lead outside the cluster. 360 // Ignore any parents that lead outside the cluster.
383 - if (clustersByDevice.get(vertex.deviceId()) != cluster) { 361 + if (clustersByDevice().get(vertex.deviceId()) != cluster) {
384 continue; 362 continue;
385 } 363 }
386 364
...@@ -409,32 +387,32 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -409,32 +387,32 @@ public class DefaultTopology extends AbstractModel implements Topology {
409 } 387 }
410 388
411 // Builds cluster-devices, cluster-links and device-cluster indexes. 389 // Builds cluster-devices, cluster-links and device-cluster indexes.
412 - private void buildIndexes() { 390 + private ClusterIndexes buildIndexes() {
413 // Prepare the index builders 391 // Prepare the index builders
414 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder = ImmutableMap.builder(); 392 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
415 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder = ImmutableSetMultimap.builder(); 393 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder = ImmutableSetMultimap.builder();
416 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder = ImmutableSetMultimap.builder(); 394 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder = ImmutableSetMultimap.builder();
417 395
418 // Now scan through all the clusters 396 // Now scan through all the clusters
419 - for (TopologyCluster cluster : clusters.values()) { 397 + for (TopologyCluster cluster : clusters.get().values()) {
420 int i = cluster.id().index(); 398 int i = cluster.id().index();
421 399
422 // Scan through all the cluster vertexes. 400 // Scan through all the cluster vertexes.
423 - for (TopologyVertex vertex : clusterResults.clusterVertexes().get(i)) { 401 + for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
424 devicesBuilder.put(cluster, vertex.deviceId()); 402 devicesBuilder.put(cluster, vertex.deviceId());
425 clusterBuilder.put(vertex.deviceId(), cluster); 403 clusterBuilder.put(vertex.deviceId(), cluster);
426 } 404 }
427 405
428 // Scan through all the cluster edges. 406 // Scan through all the cluster edges.
429 - for (TopologyEdge edge : clusterResults.clusterEdges().get(i)) { 407 + for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
430 linksBuilder.put(cluster, edge.link()); 408 linksBuilder.put(cluster, edge.link());
431 } 409 }
432 } 410 }
433 411
434 // Finalize all indexes. 412 // Finalize all indexes.
435 - clustersByDevice = clusterBuilder.build(); 413 + return new ClusterIndexes(clusterBuilder.build(),
436 - devicesByCluster = devicesBuilder.build(); 414 + devicesBuilder.build(),
437 - linksByCluster = linksBuilder.build(); 415 + linksBuilder.build());
438 } 416 }
439 417
440 // Link weight for measuring link cost as hop count with indirect links 418 // Link weight for measuring link cost as hop count with indirect links
...@@ -463,6 +441,20 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -463,6 +441,20 @@ public class DefaultTopology extends AbstractModel implements Topology {
463 } 441 }
464 } 442 }
465 443
444 + static final class ClusterIndexes {
445 + final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
446 + final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
447 + final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
448 +
449 + public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
450 + ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
451 + ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
452 + this.clustersByDevice = clustersByDevice;
453 + this.devicesByCluster = devicesByCluster;
454 + this.linksByCluster = linksByCluster;
455 + }
456 + }
457 +
466 @Override 458 @Override
467 public String toString() { 459 public String toString() {
468 return toStringHelper(this) 460 return toStringHelper(this)
...@@ -471,7 +463,6 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -471,7 +463,6 @@ public class DefaultTopology extends AbstractModel implements Topology {
471 .add("clusters", clusterCount()) 463 .add("clusters", clusterCount())
472 .add("devices", deviceCount()) 464 .add("devices", deviceCount())
473 .add("links", linkCount()) 465 .add("links", linkCount())
474 - .add("pathCount", pathCount())
475 .toString(); 466 .toString();
476 } 467 }
477 } 468 }
......
...@@ -17,6 +17,7 @@ package org.onosproject.store.trivial.impl; ...@@ -17,6 +17,7 @@ package org.onosproject.store.trivial.impl;
17 17
18 import org.junit.Before; 18 import org.junit.Before;
19 import org.junit.Test; 19 import org.junit.Test;
20 +import org.onlab.packet.ChassisId;
20 import org.onosproject.net.ConnectPoint; 21 import org.onosproject.net.ConnectPoint;
21 import org.onosproject.net.DefaultDevice; 22 import org.onosproject.net.DefaultDevice;
22 import org.onosproject.net.DefaultLink; 23 import org.onosproject.net.DefaultLink;
...@@ -31,8 +32,6 @@ import org.onosproject.net.topology.DefaultGraphDescription; ...@@ -31,8 +32,6 @@ import org.onosproject.net.topology.DefaultGraphDescription;
31 import org.onosproject.net.topology.GraphDescription; 32 import org.onosproject.net.topology.GraphDescription;
32 import org.onosproject.net.topology.LinkWeight; 33 import org.onosproject.net.topology.LinkWeight;
33 import org.onosproject.net.topology.TopologyCluster; 34 import org.onosproject.net.topology.TopologyCluster;
34 -import org.onosproject.net.topology.TopologyEdge;
35 -import org.onlab.packet.ChassisId;
36 35
37 import java.util.Set; 36 import java.util.Set;
38 37
...@@ -57,13 +56,9 @@ public class DefaultTopologyTest { ...@@ -57,13 +56,9 @@ public class DefaultTopologyTest {
57 public static final PortNumber P1 = portNumber(1); 56 public static final PortNumber P1 = portNumber(1);
58 public static final PortNumber P2 = portNumber(2); 57 public static final PortNumber P2 = portNumber(2);
59 58
60 - public static final LinkWeight WEIGHT = new LinkWeight() { 59 + public static final LinkWeight WEIGHT = edge ->
61 - @Override 60 + edge.src().deviceId().equals(D4) || edge.dst().deviceId().equals(D4)
62 - public double weight(TopologyEdge edge) { 61 + ? 2.0 : 1.0;
63 - return edge.src().deviceId().equals(D4) ||
64 - edge.dst().deviceId().equals(D4) ? 2.0 : 1.0;
65 - }
66 - };
67 62
68 private DefaultTopology dt; 63 private DefaultTopology dt;
69 64
......
...@@ -65,17 +65,31 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V ...@@ -65,17 +65,31 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V
65 protected final Set<Path<V, E>> paths = new HashSet<>(); 65 protected final Set<Path<V, E>> paths = new HashSet<>();
66 protected final Map<V, Double> costs = new HashMap<>(); 66 protected final Map<V, Double> costs = new HashMap<>();
67 protected final Map<V, Set<E>> parents = new HashMap<>(); 67 protected final Map<V, Set<E>> parents = new HashMap<>();
68 + protected final int maxPaths;
68 69
69 /** 70 /**
70 - * Creates the result of path search. 71 + * Creates the result of a single-path search.
71 * 72 *
72 * @param src path source 73 * @param src path source
73 * @param dst optional path destination 74 * @param dst optional path destination
74 */ 75 */
75 public DefaultResult(V src, V dst) { 76 public DefaultResult(V src, V dst) {
77 + this(src, dst, 1);
78 + }
79 +
80 + /**
81 + * Creates the result of path search.
82 + *
83 + * @param src path source
84 + * @param dst optional path destination
85 + * @param maxPaths optional limit of number of paths;
86 + * {@link GraphPathSearch#ALL_PATHS} if no limit
87 + */
88 + public DefaultResult(V src, V dst, int maxPaths) {
76 checkNotNull(src, "Source cannot be null"); 89 checkNotNull(src, "Source cannot be null");
77 this.src = src; 90 this.src = src;
78 this.dst = dst; 91 this.dst = dst;
92 + this.maxPaths = maxPaths;
79 } 93 }
80 94
81 @Override 95 @Override
...@@ -126,7 +140,8 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V ...@@ -126,7 +140,8 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V
126 140
127 /** 141 /**
128 * Updates the cost of the vertex using its existing cost plus the 142 * Updates the cost of the vertex using its existing cost plus the
129 - * cost to traverse the specified edge. 143 + * cost to traverse the specified edge. If the search is in single
144 + * path mode, only one path will be accrued.
130 * 145 *
131 * @param vertex vertex to update 146 * @param vertex vertex to update
132 * @param edge edge through which vertex is reached 147 * @param edge edge through which vertex is reached
...@@ -147,9 +162,11 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V ...@@ -147,9 +162,11 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V
147 if (replace) { 162 if (replace) {
148 edges.clear(); 163 edges.clear();
149 } 164 }
165 + if (maxPaths == ALL_PATHS || edges.size() < maxPaths) {
150 edges.add(edge); 166 edges.add(edge);
151 } 167 }
152 } 168 }
169 + }
153 170
154 /** 171 /**
155 * Removes the set of parent edges for the specified vertex. 172 * Removes the set of parent edges for the specified vertex.
...@@ -203,7 +220,7 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V ...@@ -203,7 +220,7 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V
203 for (V v : destinations) { 220 for (V v : destinations) {
204 // Ignore the source, if it is among the destinations. 221 // Ignore the source, if it is among the destinations.
205 if (!v.equals(src)) { 222 if (!v.equals(src)) {
206 - buildAllPaths(this, src, v); 223 + buildAllPaths(this, src, v, maxPaths);
207 } 224 }
208 } 225 }
209 } 226 }
...@@ -218,15 +235,18 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V ...@@ -218,15 +235,18 @@ public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V
218 * @param result graph search result 235 * @param result graph search result
219 * @param src source vertex 236 * @param src source vertex
220 * @param dst destination vertex 237 * @param dst destination vertex
238 + * @param maxPaths limit on the number of paths built;
239 + * {@link GraphPathSearch#ALL_PATHS} if no limit
221 */ 240 */
222 - private void buildAllPaths(DefaultResult result, V src, V dst) { 241 + private void buildAllPaths(DefaultResult result, V src, V dst, int maxPaths) {
223 DefaultMutablePath<V, E> basePath = new DefaultMutablePath<>(); 242 DefaultMutablePath<V, E> basePath = new DefaultMutablePath<>();
224 basePath.setCost(result.cost(dst)); 243 basePath.setCost(result.cost(dst));
225 244
226 Set<DefaultMutablePath<V, E>> pendingPaths = new HashSet<>(); 245 Set<DefaultMutablePath<V, E>> pendingPaths = new HashSet<>();
227 pendingPaths.add(basePath); 246 pendingPaths.add(basePath);
228 247
229 - while (!pendingPaths.isEmpty()) { 248 + while (!pendingPaths.isEmpty() &&
249 + (maxPaths == ALL_PATHS || result.paths.size() < maxPaths)) {
230 Set<DefaultMutablePath<V, E>> frontier = new HashSet<>(); 250 Set<DefaultMutablePath<V, E>> frontier = new HashSet<>();
231 251
232 for (DefaultMutablePath<V, E> path : pendingPaths) { 252 for (DefaultMutablePath<V, E> path : pendingPaths) {
......
...@@ -24,11 +24,11 @@ public class BellmanFordGraphSearch<V extends Vertex, E extends Edge<V>> ...@@ -24,11 +24,11 @@ public class BellmanFordGraphSearch<V extends Vertex, E extends Edge<V>>
24 24
25 @Override 25 @Override
26 public Result<V, E> search(Graph<V, E> graph, V src, V dst, 26 public Result<V, E> search(Graph<V, E> graph, V src, V dst,
27 - EdgeWeight<V, E> weight) { 27 + EdgeWeight<V, E> weight, int maxPaths) {
28 checkArguments(graph, src, dst); 28 checkArguments(graph, src, dst);
29 29
30 // Prepare the graph search result. 30 // Prepare the graph search result.
31 - DefaultResult result = new DefaultResult(src, dst); 31 + DefaultResult result = new DefaultResult(src, dst, maxPaths);
32 32
33 // The source vertex has cost 0, of course. 33 // The source vertex has cost 0, of course.
34 result.updateVertex(src, null, 0.0, true); 34 result.updateVertex(src, null, 0.0, true);
......
...@@ -26,11 +26,11 @@ public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>> ...@@ -26,11 +26,11 @@ public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>>
26 26
27 @Override 27 @Override
28 public Result<V, E> search(Graph<V, E> graph, V src, V dst, 28 public Result<V, E> search(Graph<V, E> graph, V src, V dst,
29 - EdgeWeight<V, E> weight) { 29 + EdgeWeight<V, E> weight, int maxPaths) {
30 checkArguments(graph, src, dst); 30 checkArguments(graph, src, dst);
31 31
32 // Prepare the graph result. 32 // Prepare the graph result.
33 - DefaultResult result = new DefaultResult(src, dst); 33 + DefaultResult result = new DefaultResult(src, dst, maxPaths);
34 34
35 // Setup the starting frontier with the source as the sole vertex. 35 // Setup the starting frontier with the source as the sole vertex.
36 Set<V> frontier = new HashSet<>(); 36 Set<V> frontier = new HashSet<>();
......
...@@ -36,11 +36,11 @@ public class DepthFirstSearch<V extends Vertex, E extends Edge<V>> ...@@ -36,11 +36,11 @@ public class DepthFirstSearch<V extends Vertex, E extends Edge<V>>
36 36
37 @Override 37 @Override
38 public SpanningTreeResult search(Graph<V, E> graph, V src, V dst, 38 public SpanningTreeResult search(Graph<V, E> graph, V src, V dst,
39 - EdgeWeight<V, E> weight) { 39 + EdgeWeight<V, E> weight, int maxPaths) {
40 checkArguments(graph, src, dst); 40 checkArguments(graph, src, dst);
41 41
42 // Prepare the search result. 42 // Prepare the search result.
43 - SpanningTreeResult result = new SpanningTreeResult(src, dst); 43 + SpanningTreeResult result = new SpanningTreeResult(src, dst, maxPaths);
44 44
45 // The source vertex has cost 0, of course. 45 // The source vertex has cost 0, of course.
46 result.updateVertex(src, null, 0.0, true); 46 result.updateVertex(src, null, 0.0, true);
...@@ -143,9 +143,10 @@ public class DepthFirstSearch<V extends Vertex, E extends Edge<V>> ...@@ -143,9 +143,10 @@ public class DepthFirstSearch<V extends Vertex, E extends Edge<V>>
143 * 143 *
144 * @param src search source 144 * @param src search source
145 * @param dst optional search destination 145 * @param dst optional search destination
146 + * @param maxPaths limit on the number of paths
146 */ 147 */
147 - public SpanningTreeResult(V src, V dst) { 148 + public SpanningTreeResult(V src, V dst, int maxPaths) {
148 - super(src, dst); 149 + super(src, dst, maxPaths);
149 } 150 }
150 151
151 /** 152 /**
......
...@@ -28,12 +28,12 @@ public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>> ...@@ -28,12 +28,12 @@ public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>>
28 28
29 @Override 29 @Override
30 public Result<V, E> search(Graph<V, E> graph, V src, V dst, 30 public Result<V, E> search(Graph<V, E> graph, V src, V dst,
31 - EdgeWeight<V, E> weight) { 31 + EdgeWeight<V, E> weight, int maxPaths) {
32 checkArguments(graph, src, dst); 32 checkArguments(graph, src, dst);
33 33
34 // Use the default result to remember cumulative costs and parent 34 // Use the default result to remember cumulative costs and parent
35 // edges to each each respective vertex. 35 // edges to each each respective vertex.
36 - DefaultResult result = new DefaultResult(src, dst); 36 + DefaultResult result = new DefaultResult(src, dst, maxPaths);
37 37
38 // Cost to reach the source vertex is 0 of course. 38 // Cost to reach the source vertex is 0 of course.
39 result.updateVertex(src, null, 0.0, false); 39 result.updateVertex(src, null, 0.0, false);
......
...@@ -26,6 +26,8 @@ import java.util.Set; ...@@ -26,6 +26,8 @@ import java.util.Set;
26 */ 26 */
27 public interface GraphPathSearch<V extends Vertex, E extends Edge<V>> { 27 public interface GraphPathSearch<V extends Vertex, E extends Edge<V>> {
28 28
29 + public static int ALL_PATHS = -1;
30 +
29 /** 31 /**
30 * Abstraction of a path search result. 32 * Abstraction of a path search result.
31 */ 33 */
...@@ -68,7 +70,7 @@ public interface GraphPathSearch<V extends Vertex, E extends Edge<V>> { ...@@ -68,7 +70,7 @@ public interface GraphPathSearch<V extends Vertex, E extends Edge<V>> {
68 } 70 }
69 71
70 /** 72 /**
71 - * Searches the specified graph. 73 + * Searches the specified graph for paths between vertices.
72 * 74 *
73 * @param graph graph to be searched 75 * @param graph graph to be searched
74 * @param src optional source vertex 76 * @param src optional source vertex
...@@ -76,8 +78,10 @@ public interface GraphPathSearch<V extends Vertex, E extends Edge<V>> { ...@@ -76,8 +78,10 @@ public interface GraphPathSearch<V extends Vertex, E extends Edge<V>> {
76 * destinations will be searched 78 * destinations will be searched
77 * @param weight optional edge-weight; if null cost of each edge will be 79 * @param weight optional edge-weight; if null cost of each edge will be
78 * assumed to be 1.0 80 * assumed to be 1.0
81 + * @param maxPaths limit on number of paths; {@link GraphPathSearch#ALL_PATHS} if no limit
79 * @return search results 82 * @return search results
80 */ 83 */
81 - Result<V, E> search(Graph<V, E> graph, V src, V dst, EdgeWeight<V, E> weight); 84 + Result<V, E> search(Graph<V, E> graph, V src, V dst,
85 + EdgeWeight<V, E> weight, int maxPaths);
82 86
83 } 87 }
......
...@@ -23,6 +23,8 @@ import java.util.List; ...@@ -23,6 +23,8 @@ import java.util.List;
23 //import java.util.PriorityQueue; 23 //import java.util.PriorityQueue;
24 import java.util.Set; 24 import java.util.Set;
25 25
26 +import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
27 +
26 /** 28 /**
27 * K-shortest-path graph search algorithm capable of finding not just one, 29 * K-shortest-path graph search algorithm capable of finding not just one,
28 * but K shortest paths with ascending order between the source and destinations. 30 * but K shortest paths with ascending order between the source and destinations.
...@@ -137,7 +139,7 @@ public class KshortestPathSearch<V extends Vertex, E extends Edge<V>> { ...@@ -137,7 +139,7 @@ public class KshortestPathSearch<V extends Vertex, E extends Edge<V>> {
137 private List<E> searchShortestPath(Graph<V, E> graph, V src, V dst) { 139 private List<E> searchShortestPath(Graph<V, E> graph, V src, V dst) {
138 // Determine the shortest path from the source to the destination by using the Dijkstra algorithm. 140 // Determine the shortest path from the source to the destination by using the Dijkstra algorithm.
139 DijkstraGraphSearch dijkstraAlg = new DijkstraGraphSearch(); 141 DijkstraGraphSearch dijkstraAlg = new DijkstraGraphSearch();
140 - Set<Path> paths = dijkstraAlg.search(graph, src, dst, weight).paths(); 142 + Set<Path> paths = dijkstraAlg.search(graph, src, dst, weight, ALL_PATHS).paths();
141 Iterator<Path> itr = paths.iterator(); 143 Iterator<Path> itr = paths.iterator();
142 if (!itr.hasNext()) { 144 if (!itr.hasNext()) {
143 return null; 145 return null;
......
...@@ -36,19 +36,19 @@ public abstract class AbstractGraphPathSearchTest extends GraphTest { ...@@ -36,19 +36,19 @@ public abstract class AbstractGraphPathSearchTest extends GraphTest {
36 public void noSuchSourceArgument() { 36 public void noSuchSourceArgument() {
37 graphSearch().search(new AdjacencyListsGraph<>(of(B, C), 37 graphSearch().search(new AdjacencyListsGraph<>(of(B, C),
38 of(new TestEdge(B, C, 1))), 38 of(new TestEdge(B, C, 1))),
39 - A, H, weight); 39 + A, H, weight, 1);
40 } 40 }
41 41
42 @Test(expected = NullPointerException.class) 42 @Test(expected = NullPointerException.class)
43 public void nullGraphArgument() { 43 public void nullGraphArgument() {
44 - graphSearch().search(null, A, H, weight); 44 + graphSearch().search(null, A, H, weight, 1);
45 } 45 }
46 46
47 @Test(expected = NullPointerException.class) 47 @Test(expected = NullPointerException.class)
48 public void nullSourceArgument() { 48 public void nullSourceArgument() {
49 graphSearch().search(new AdjacencyListsGraph<>(of(B, C), 49 graphSearch().search(new AdjacencyListsGraph<>(of(B, C),
50 of(new TestEdge(B, C, 1))), 50 of(new TestEdge(B, C, 1))),
51 - null, H, weight); 51 + null, H, weight, 1);
52 } 52 }
53 53
54 @Test 54 @Test
......
...@@ -21,6 +21,7 @@ import java.util.HashSet; ...@@ -21,6 +21,7 @@ import java.util.HashSet;
21 import java.util.Set; 21 import java.util.Set;
22 22
23 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertEquals;
24 +import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
24 25
25 /** 26 /**
26 * Test of the Bellman-Ford algorithm. 27 * Test of the Bellman-Ford algorithm.
...@@ -56,7 +57,7 @@ public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest { ...@@ -56,7 +57,7 @@ public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest {
56 graph = new AdjacencyListsGraph<>(vertexes, edges); 57 graph = new AdjacencyListsGraph<>(vertexes, edges);
57 58
58 GraphPathSearch<TestVertex, TestEdge> search = graphSearch(); 59 GraphPathSearch<TestVertex, TestEdge> search = graphSearch();
59 - Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, H, weight).paths(); 60 + Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, H, weight, ALL_PATHS).paths();
60 assertEquals("incorrect paths count", 1, paths.size()); 61 assertEquals("incorrect paths count", 1, paths.size());
61 62
62 Path p = paths.iterator().next(); 63 Path p = paths.iterator().next();
...@@ -65,10 +66,10 @@ public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest { ...@@ -65,10 +66,10 @@ public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest {
65 assertEquals("incorrect path length", 5, p.edges().size()); 66 assertEquals("incorrect path length", 5, p.edges().size());
66 assertEquals("incorrect path cost", 5.0, p.cost(), 0.1); 67 assertEquals("incorrect path cost", 5.0, p.cost(), 0.1);
67 68
68 - paths = search.search(graph, A, G, weight).paths(); 69 + paths = search.search(graph, A, G, weight, ALL_PATHS).paths();
69 assertEquals("incorrect paths count", 0, paths.size()); 70 assertEquals("incorrect paths count", 0, paths.size());
70 71
71 - paths = search.search(graph, A, null, weight).paths(); 72 + paths = search.search(graph, A, null, weight, ALL_PATHS).paths();
72 printPaths(paths); 73 printPaths(paths);
73 assertEquals("incorrect paths count", 6, paths.size()); 74 assertEquals("incorrect paths count", 6, paths.size());
74 } 75 }
......
...@@ -20,6 +20,7 @@ import org.junit.Test; ...@@ -20,6 +20,7 @@ import org.junit.Test;
20 import java.util.Set; 20 import java.util.Set;
21 21
22 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertEquals;
23 +import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
23 24
24 /** 25 /**
25 * Test of the BFS and similar path search algorithms. 26 * Test of the BFS and similar path search algorithms.
...@@ -47,7 +48,8 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest { ...@@ -47,7 +48,8 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest {
47 graph = new AdjacencyListsGraph<>(vertexes(), edges()); 48 graph = new AdjacencyListsGraph<>(vertexes(), edges());
48 49
49 GraphPathSearch<TestVertex, TestEdge> search = graphSearch(); 50 GraphPathSearch<TestVertex, TestEdge> search = graphSearch();
50 - Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, H, weight).paths(); 51 + Set<Path<TestVertex, TestEdge>> paths =
52 + search.search(graph, A, H, weight, ALL_PATHS).paths();
51 assertEquals("incorrect paths count", 1, paths.size()); 53 assertEquals("incorrect paths count", 1, paths.size());
52 54
53 Path p = paths.iterator().next(); 55 Path p = paths.iterator().next();
...@@ -56,7 +58,7 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest { ...@@ -56,7 +58,7 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest {
56 assertEquals("incorrect path length", pathLength, p.edges().size()); 58 assertEquals("incorrect path length", pathLength, p.edges().size());
57 assertEquals("incorrect path cost", pathCost, p.cost(), 0.1); 59 assertEquals("incorrect path cost", pathCost, p.cost(), 0.1);
58 60
59 - paths = search.search(graph, A, null, weight).paths(); 61 + paths = search.search(graph, A, null, weight, ALL_PATHS).paths();
60 printPaths(paths); 62 printPaths(paths);
61 assertEquals("incorrect paths count", pathCount, paths.size()); 63 assertEquals("incorrect paths count", pathCount, paths.size());
62 } 64 }
...@@ -68,7 +70,7 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest { ...@@ -68,7 +70,7 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest {
68 EdgeWeight<TestVertex, TestEdge> weight, 70 EdgeWeight<TestVertex, TestEdge> weight,
69 int pathCount, double pathCost) { 71 int pathCount, double pathCost) {
70 GraphPathSearch.Result<TestVertex, TestEdge> result = 72 GraphPathSearch.Result<TestVertex, TestEdge> result =
71 - search.search(graph, src, dst, weight); 73 + search.search(graph, src, dst, weight, ALL_PATHS);
72 Set<Path<TestVertex, TestEdge>> paths = result.paths(); 74 Set<Path<TestVertex, TestEdge>> paths = result.paths();
73 printPaths(paths); 75 printPaths(paths);
74 assertEquals("incorrect paths count", pathCount, paths.size()); 76 assertEquals("incorrect paths count", pathCount, paths.size());
...@@ -78,4 +80,21 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest { ...@@ -78,4 +80,21 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest {
78 } 80 }
79 } 81 }
80 82
83 + // Executes the single-path search and validates its results.
84 + protected void executeSinglePathSearch(GraphPathSearch<TestVertex, TestEdge> search,
85 + Graph<TestVertex, TestEdge> graph,
86 + TestVertex src, TestVertex dst,
87 + EdgeWeight<TestVertex, TestEdge> weight,
88 + int pathCount, double pathCost) {
89 + GraphPathSearch.Result<TestVertex, TestEdge> result =
90 + search.search(graph, src, dst, weight, 1);
91 + Set<Path<TestVertex, TestEdge>> paths = result.paths();
92 + printPaths(paths);
93 + assertEquals("incorrect paths count", Math.min(pathCount, 1), paths.size());
94 + if (pathCount > 0) {
95 + Path<TestVertex, TestEdge> path = paths.iterator().next();
96 + assertEquals("incorrect path cost", pathCost, path.cost(), 0.1);
97 + }
98 + }
99 +
81 } 100 }
......
...@@ -22,6 +22,7 @@ import java.util.Set; ...@@ -22,6 +22,7 @@ import java.util.Set;
22 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.assertTrue;
24 import static org.onlab.graph.DepthFirstSearch.EdgeType; 24 import static org.onlab.graph.DepthFirstSearch.EdgeType;
25 +import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
25 26
26 /** 27 /**
27 * Test of the DFS algorithm. 28 * Test of the DFS algorithm.
...@@ -52,7 +53,7 @@ public class DepthFirstSearchTest extends AbstractGraphPathSearchTest { ...@@ -52,7 +53,7 @@ public class DepthFirstSearchTest extends AbstractGraphPathSearchTest {
52 DepthFirstSearch<TestVertex, TestEdge> search = graphSearch(); 53 DepthFirstSearch<TestVertex, TestEdge> search = graphSearch();
53 54
54 DepthFirstSearch<TestVertex, TestEdge>.SpanningTreeResult result = 55 DepthFirstSearch<TestVertex, TestEdge>.SpanningTreeResult result =
55 - search.search(graph, A, H, weight); 56 + search.search(graph, A, H, weight, 1);
56 Set<Path<TestVertex, TestEdge>> paths = result.paths(); 57 Set<Path<TestVertex, TestEdge>> paths = result.paths();
57 assertEquals("incorrect path count", 1, paths.size()); 58 assertEquals("incorrect path count", 1, paths.size());
58 59
...@@ -77,7 +78,7 @@ public class DepthFirstSearchTest extends AbstractGraphPathSearchTest { ...@@ -77,7 +78,7 @@ public class DepthFirstSearchTest extends AbstractGraphPathSearchTest {
77 78
78 // Perform narrow path search to a specific destination. 79 // Perform narrow path search to a specific destination.
79 DepthFirstSearch<TestVertex, TestEdge>.SpanningTreeResult result = 80 DepthFirstSearch<TestVertex, TestEdge>.SpanningTreeResult result =
80 - search.search(graph, A, null, weight); 81 + search.search(graph, A, null, weight, ALL_PATHS);
81 assertEquals("incorrect paths count", 7, result.paths().size()); 82 assertEquals("incorrect paths count", 7, result.paths().size());
82 83
83 int[] types = new int[]{0, 0, 0, 0}; 84 int[] types = new int[]{0, 0, 0, 0};
......
...@@ -55,16 +55,16 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { ...@@ -55,16 +55,16 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
55 new TestEdge(C, D, 1), 55 new TestEdge(C, D, 1),
56 new TestEdge(D, C, 1))); 56 new TestEdge(D, C, 1)));
57 GraphPathSearch<TestVertex, TestEdge> gs = graphSearch(); 57 GraphPathSearch<TestVertex, TestEdge> gs = graphSearch();
58 - Set<Path<TestVertex, TestEdge>> paths = gs.search(graph, A, B, weight).paths(); 58 + Set<Path<TestVertex, TestEdge>> paths = gs.search(graph, A, B, weight, 1).paths();
59 printPaths(paths); 59 printPaths(paths);
60 assertEquals("incorrect paths count", 1, paths.size()); 60 assertEquals("incorrect paths count", 1, paths.size());
61 assertEquals("incorrect path cost", 1.0, paths.iterator().next().cost(), 0.1); 61 assertEquals("incorrect path cost", 1.0, paths.iterator().next().cost(), 0.1);
62 62
63 - paths = gs.search(graph, A, D, weight).paths(); 63 + paths = gs.search(graph, A, D, weight, 1).paths();
64 printPaths(paths); 64 printPaths(paths);
65 assertEquals("incorrect paths count", 0, paths.size()); 65 assertEquals("incorrect paths count", 0, paths.size());
66 66
67 - paths = gs.search(graph, A, null, weight).paths(); 67 + paths = gs.search(graph, A, null, weight, 1).paths();
68 printPaths(paths); 68 printPaths(paths);
69 assertEquals("incorrect paths count", 1, paths.size()); 69 assertEquals("incorrect paths count", 1, paths.size());
70 assertEquals("incorrect path cost", 1.0, paths.iterator().next().cost(), 0.1); 70 assertEquals("incorrect path cost", 1.0, paths.iterator().next().cost(), 0.1);
...@@ -78,6 +78,7 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { ...@@ -78,6 +78,7 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
78 new TestEdge(B, D, 1), 78 new TestEdge(B, D, 1),
79 new TestEdge(C, D, 1))); 79 new TestEdge(C, D, 1)));
80 executeSearch(graphSearch(), graph, A, D, weight, 2, 2.0); 80 executeSearch(graphSearch(), graph, A, D, weight, 2, 2.0);
81 + executeSinglePathSearch(graphSearch(), graph, A, D, weight, 1, 2.0);
81 } 82 }
82 83
83 @Test 84 @Test
...@@ -93,6 +94,7 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { ...@@ -93,6 +94,7 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
93 new TestEdge(F, G, 1), 94 new TestEdge(F, G, 1),
94 new TestEdge(A, G, 4))); 95 new TestEdge(A, G, 4)));
95 executeSearch(graphSearch(), graph, A, G, weight, 5, 4.0); 96 executeSearch(graphSearch(), graph, A, G, weight, 5, 4.0);
97 + executeSinglePathSearch(graphSearch(), graph, A, G, weight, 1, 4.0);
96 } 98 }
97 99
98 @Test 100 @Test
...@@ -106,6 +108,7 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { ...@@ -106,6 +108,7 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
106 new TestEdge(F, G, 1), new TestEdge(F, H, 1), 108 new TestEdge(F, G, 1), new TestEdge(F, H, 1),
107 new TestEdge(A, E, 3), new TestEdge(B, D, 1))); 109 new TestEdge(A, E, 3), new TestEdge(B, D, 1)));
108 executeSearch(graphSearch(), graph, A, E, weight, 3, 3.0); 110 executeSearch(graphSearch(), graph, A, E, weight, 3, 3.0);
111 + executeSinglePathSearch(graphSearch(), graph, A, E, weight, 1, 3.0);
109 } 112 }
110 113
111 @Test 114 @Test
...@@ -123,6 +126,7 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { ...@@ -123,6 +126,7 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
123 new TestEdge(G, A, -5), 126 new TestEdge(G, A, -5),
124 new TestEdge(A, G, 4))); 127 new TestEdge(A, G, 4)));
125 executeSearch(graphSearch(), graph, A, G, weight, 3, 4.0); 128 executeSearch(graphSearch(), graph, A, G, weight, 3, 4.0);
129 + executeSinglePathSearch(graphSearch(), graph, A, G, weight, 1, 4.0);
126 } 130 }
127 131
128 @Test 132 @Test
......
...@@ -454,7 +454,6 @@ public abstract class TopologyViewMessages { ...@@ -454,7 +454,6 @@ public abstract class TopologyViewMessages {
454 new Prop("Links", format(topology.linkCount())), 454 new Prop("Links", format(topology.linkCount())),
455 new Prop("Hosts", format(hostService.getHostCount())), 455 new Prop("Hosts", format(hostService.getHostCount())),
456 new Prop("Topology SCCs", format(topology.clusterCount())), 456 new Prop("Topology SCCs", format(topology.clusterCount())),
457 - new Prop("Paths", format(topology.pathCount())),
458 new Separator(), 457 new Separator(),
459 new Prop("Intents", format(intentService.getIntentCount())), 458 new Prop("Intents", format(intentService.getIntentCount())),
460 new Prop("Flows", format(flowService.getFlowRuleCount())), 459 new Prop("Flows", format(flowService.getFlowRuleCount())),
......