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
115 additions
and
133 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 | } | ... | ... |
This diff is collapsed. Click to expand it.
| ... | @@ -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