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())), | ... | ... |
-
Please register or login to post a comment