blob: 579f336f52d51ee87a84ce3072fd1a66b79d29bb [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070016package org.onosproject.common;
alshabib339a3d92014-09-26 17:54:32 -070017
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070018import com.google.common.base.Supplier;
19import com.google.common.base.Suppliers;
20import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.ImmutableSetMultimap;
23import com.google.common.collect.ImmutableSetMultimap.Builder;
alshabib339a3d92014-09-26 17:54:32 -070024import org.onlab.graph.DijkstraGraphSearch;
25import org.onlab.graph.GraphPathSearch;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080026import org.onlab.graph.GraphPathSearch.Result;
alshabib339a3d92014-09-26 17:54:32 -070027import org.onlab.graph.TarjanGraphSearch;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080028import org.onlab.graph.TarjanGraphSearch.SCCResult;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.net.AbstractModel;
30import org.onosproject.net.ConnectPoint;
31import org.onosproject.net.DefaultPath;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.Link;
34import org.onosproject.net.Path;
35import org.onosproject.net.provider.ProviderId;
36import org.onosproject.net.topology.ClusterId;
37import org.onosproject.net.topology.DefaultTopologyCluster;
38import org.onosproject.net.topology.DefaultTopologyVertex;
39import org.onosproject.net.topology.GraphDescription;
40import org.onosproject.net.topology.LinkWeight;
41import org.onosproject.net.topology.Topology;
42import org.onosproject.net.topology.TopologyCluster;
43import org.onosproject.net.topology.TopologyEdge;
44import org.onosproject.net.topology.TopologyGraph;
45import org.onosproject.net.topology.TopologyVertex;
alshabib339a3d92014-09-26 17:54:32 -070046
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070047import java.util.ArrayList;
48import java.util.List;
49import java.util.Map;
50import java.util.Set;
alshabib339a3d92014-09-26 17:54:32 -070051
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070052import static com.google.common.base.MoreObjects.toStringHelper;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070053import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070054import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070055import static org.onlab.util.Tools.isNullOrEmpty;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070056import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
57import static org.onosproject.net.Link.State.ACTIVE;
58import static org.onosproject.net.Link.State.INACTIVE;
59import static org.onosproject.net.Link.Type.INDIRECT;
60
alshabib339a3d92014-09-26 17:54:32 -070061/**
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050062 * Default implementation of the topology descriptor. This carries the backing
63 * topology data.
alshabib339a3d92014-09-26 17:54:32 -070064 */
65public class DefaultTopology extends AbstractModel implements Topology {
66
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050067 private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>();
68 private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>();
alshabib339a3d92014-09-26 17:54:32 -070069
alshabib339a3d92014-09-26 17:54:32 -070070 private final long time;
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050071 private final long creationTime;
Thomas Vachuska6b7920d2014-11-25 19:48:39 -080072 private final long computeCost;
alshabib339a3d92014-09-26 17:54:32 -070073 private final TopologyGraph graph;
74
Thomas Vachuskac31d9f12015-01-22 12:33:27 -080075 private final LinkWeight weight;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080076 private final Supplier<SCCResult<TopologyVertex, TopologyEdge>> clusterResults;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080077 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
78 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
79 private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
alshabib339a3d92014-09-26 17:54:32 -070080
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080081 private final Supplier<ClusterIndexes> clusterIndexes;
alshabib339a3d92014-09-26 17:54:32 -070082
83 /**
84 * Creates a topology descriptor attributed to the specified provider.
85 *
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070086 * @param providerId identity of the provider
87 * @param description data describing the new topology
alshabib339a3d92014-09-26 17:54:32 -070088 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070089 public DefaultTopology(ProviderId providerId, GraphDescription description) {
alshabib339a3d92014-09-26 17:54:32 -070090 super(providerId);
91 this.time = description.timestamp();
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050092 this.creationTime = description.creationTime();
alshabib339a3d92014-09-26 17:54:32 -070093
94 // Build the graph
95 this.graph = new DefaultTopologyGraph(description.vertexes(),
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070096 description.edges());
alshabib339a3d92014-09-26 17:54:32 -070097
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080098 this.clusterResults = Suppliers.memoize(() -> searchForClusters());
99 this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
alshabib339a3d92014-09-26 17:54:32 -0700100
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800101 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
102
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800103 this.weight = new HopCountLinkWeight(graph.getVertexes().size());
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800104 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700105 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800106 this.computeCost = Math.max(0, System.nanoTime() - time);
alshabib339a3d92014-09-26 17:54:32 -0700107 }
108
109 @Override
110 public long time() {
111 return time;
112 }
113
114 @Override
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500115 public long creationTime() {
116 return creationTime;
117 }
118
119 @Override
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800120 public long computeCost() {
121 return computeCost;
122 }
123
124 @Override
alshabib339a3d92014-09-26 17:54:32 -0700125 public int clusterCount() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800126 return clusters.get().size();
alshabib339a3d92014-09-26 17:54:32 -0700127 }
128
129 @Override
130 public int deviceCount() {
131 return graph.getVertexes().size();
132 }
133
134 @Override
135 public int linkCount() {
136 return graph.getEdges().size();
137 }
138
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800139 private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
140 return clusterIndexes.get().clustersByDevice;
141 }
142
143 private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
144 return clusterIndexes.get().devicesByCluster;
145 }
146
147 private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
148 return clusterIndexes.get().linksByCluster;
alshabib339a3d92014-09-26 17:54:32 -0700149 }
150
151 /**
152 * Returns the backing topology graph.
153 *
154 * @return topology graph
155 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700156 public TopologyGraph getGraph() {
alshabib339a3d92014-09-26 17:54:32 -0700157 return graph;
158 }
159
160 /**
161 * Returns the set of topology clusters.
162 *
163 * @return set of clusters
164 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700165 public Set<TopologyCluster> getClusters() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800166 return ImmutableSet.copyOf(clusters.get().values());
alshabib339a3d92014-09-26 17:54:32 -0700167 }
168
169 /**
170 * Returns the specified topology cluster.
171 *
172 * @param clusterId cluster identifier
173 * @return topology cluster
174 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700175 public TopologyCluster getCluster(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800176 return clusters.get().get(clusterId);
alshabib339a3d92014-09-26 17:54:32 -0700177 }
178
179 /**
180 * Returns the topology cluster that contains the given device.
181 *
182 * @param deviceId device identifier
183 * @return topology cluster
184 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700185 public TopologyCluster getCluster(DeviceId deviceId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800186 return clustersByDevice().get(deviceId);
alshabib339a3d92014-09-26 17:54:32 -0700187 }
188
189 /**
190 * Returns the set of cluster devices.
191 *
192 * @param cluster topology cluster
193 * @return cluster devices
194 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700195 public Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800196 return devicesByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700197 }
198
199 /**
200 * Returns the set of cluster links.
201 *
202 * @param cluster topology cluster
203 * @return cluster links
204 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700205 public Set<Link> getClusterLinks(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800206 return linksByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700207 }
208
209 /**
210 * Indicates whether the given point is an infrastructure link end-point.
211 *
212 * @param connectPoint connection point
213 * @return true if infrastructure
214 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700215 public boolean isInfrastructure(ConnectPoint connectPoint) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800216 return infrastructurePoints.get().contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700217 }
218
219 /**
220 * Indicates whether the given point is part of a broadcast set.
221 *
222 * @param connectPoint connection point
223 * @return true if in broadcast set
224 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700225 public boolean isBroadcastPoint(ConnectPoint connectPoint) {
alshabib339a3d92014-09-26 17:54:32 -0700226 // Any non-infrastructure, i.e. edge points are assumed to be OK.
227 if (!isInfrastructure(connectPoint)) {
228 return true;
229 }
230
231 // Find the cluster to which the device belongs.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800232 TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700233 checkArgument(cluster != null, "No cluster found for device %s", connectPoint.deviceId());
alshabib339a3d92014-09-26 17:54:32 -0700234
235 // If the broadcast set is null or empty, or if the point explicitly
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700236 // belongs to it, return true.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800237 Set<ConnectPoint> points = broadcastSets.get().get(cluster.id());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700238 return isNullOrEmpty(points) || points.contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700239 }
240
241 /**
242 * Returns the size of the cluster broadcast set.
243 *
244 * @param clusterId cluster identifier
245 * @return size of the cluster broadcast set
246 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700247 public int broadcastSetSize(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800248 return broadcastSets.get().get(clusterId).size();
alshabib339a3d92014-09-26 17:54:32 -0700249 }
250
251 /**
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700252 * Returns the set of the cluster broadcast points.
253 *
254 * @param clusterId cluster identifier
255 * @return set of cluster broadcast points
256 */
257 public Set<ConnectPoint> broadcastPoints(ClusterId clusterId) {
258 return broadcastSets.get().get(clusterId);
259 }
260
261 /**
alshabib339a3d92014-09-26 17:54:32 -0700262 * Returns the set of pre-computed shortest paths between source and
263 * destination devices.
264 *
265 * @param src source device
266 * @param dst destination device
267 * @return set of shortest paths
268 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700269 public Set<Path> getPaths(DeviceId src, DeviceId dst) {
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800270 return getPaths(src, dst, null);
alshabib339a3d92014-09-26 17:54:32 -0700271 }
272
273 /**
274 * Computes on-demand the set of shortest paths between source and
275 * destination devices.
276 *
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700277 * @param src source device
278 * @param dst destination device
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800279 * @param weight link weight function
alshabib339a3d92014-09-26 17:54:32 -0700280 * @return set of shortest paths
281 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700282 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800283 final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
284 final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
285 Set<TopologyVertex> vertices = graph.getVertexes();
286 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
287 // src or dst not part of the current graph
288 return ImmutableSet.of();
289 }
290
alshabib339a3d92014-09-26 17:54:32 -0700291 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800292 DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS);
alshabib339a3d92014-09-26 17:54:32 -0700293 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
294 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
295 builder.add(networkPath(path));
296 }
297 return builder.build();
298 }
299
alshabib339a3d92014-09-26 17:54:32 -0700300 // Converts graph path to a network path with the same cost.
301 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
302 List<Link> links = new ArrayList<>();
303 for (TopologyEdge edge : path.edges()) {
304 links.add(edge.link());
305 }
Thomas Vachuska6acd3bb2014-11-09 23:44:22 -0800306 return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
alshabib339a3d92014-09-26 17:54:32 -0700307 }
308
alshabib339a3d92014-09-26 17:54:32 -0700309 // Searches for SCC clusters in the network topology graph using Tarjan
310 // algorithm.
311 private SCCResult<TopologyVertex, TopologyEdge> searchForClusters() {
312 return TARJAN.search(graph, new NoIndirectLinksWeight());
313 }
314
315 // Builds the topology clusters and returns the id-cluster bindings.
316 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
317 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800318 SCCResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
alshabib339a3d92014-09-26 17:54:32 -0700319 // Extract both vertexes and edges from the results; the lists form
320 // pairs along the same index.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800321 List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
322 List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
alshabib339a3d92014-09-26 17:54:32 -0700323
324 // Scan over the lists and create a cluster from the results.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800325 for (int i = 0, n = results.clusterCount(); i < n; i++) {
alshabib339a3d92014-09-26 17:54:32 -0700326 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
327 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
328
329 ClusterId cid = ClusterId.clusterId(i);
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500330 DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
331 vertexSet.size(),
332 edgeSet.size(),
333 findRoot(vertexSet));
alshabib339a3d92014-09-26 17:54:32 -0700334 clusterBuilder.put(cid, cluster);
335 }
336 return clusterBuilder.build();
337 }
338
339 // Finds the vertex whose device id is the lexicographical minimum in the
340 // specified set.
341 private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
342 TopologyVertex minVertex = null;
343 for (TopologyVertex vertex : vertexSet) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500344 if ((minVertex == null) || (minVertex.deviceId()
345 .toString().compareTo(minVertex.deviceId().toString()) < 0)) {
alshabib339a3d92014-09-26 17:54:32 -0700346 minVertex = vertex;
347 }
348 }
349 return minVertex;
350 }
351
352 // Processes a map of broadcast sets for each cluster.
353 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500354 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap
355 .builder();
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800356 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700357 addClusterBroadcastSet(cluster, builder);
358 }
359 return builder.build();
360 }
361
362 // Finds all broadcast points for the cluster. These are those connection
363 // points which lie along the shortest paths between the cluster root and
364 // all other devices within the cluster.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500365 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
alshabib339a3d92014-09-26 17:54:32 -0700366 // Use the graph root search results to build the broadcast set.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500367 Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, weight, 1);
alshabib339a3d92014-09-26 17:54:32 -0700368 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
369 TopologyVertex vertex = entry.getKey();
370
371 // Ignore any parents that lead outside the cluster.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800372 if (clustersByDevice().get(vertex.deviceId()) != cluster) {
alshabib339a3d92014-09-26 17:54:32 -0700373 continue;
374 }
375
376 // Ignore any back-link sets that are empty.
377 Set<TopologyEdge> parents = entry.getValue();
378 if (parents.isEmpty()) {
379 continue;
380 }
381
382 // Use the first back-link source and destinations to add to the
383 // broadcast set.
384 Link link = parents.iterator().next().link();
385 builder.put(cluster.id(), link.src());
386 builder.put(cluster.id(), link.dst());
387 }
388 }
389
390 // Collects and returns an set of all infrastructure link end-points.
391 private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
392 ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
393 for (TopologyEdge edge : graph.getEdges()) {
394 builder.add(edge.link().src());
395 builder.add(edge.link().dst());
396 }
397 return builder.build();
398 }
399
400 // Builds cluster-devices, cluster-links and device-cluster indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800401 private ClusterIndexes buildIndexes() {
alshabib339a3d92014-09-26 17:54:32 -0700402 // Prepare the index builders
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500403 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder =
404 ImmutableMap.builder();
405 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder =
406 ImmutableSetMultimap.builder();
407 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder =
408 ImmutableSetMultimap.builder();
alshabib339a3d92014-09-26 17:54:32 -0700409
410 // Now scan through all the clusters
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800411 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700412 int i = cluster.id().index();
413
414 // Scan through all the cluster vertexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800415 for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700416 devicesBuilder.put(cluster, vertex.deviceId());
417 clusterBuilder.put(vertex.deviceId(), cluster);
418 }
419
420 // Scan through all the cluster edges.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800421 for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700422 linksBuilder.put(cluster, edge.link());
423 }
424 }
425
426 // Finalize all indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800427 return new ClusterIndexes(clusterBuilder.build(),
428 devicesBuilder.build(),
429 linksBuilder.build());
alshabib339a3d92014-09-26 17:54:32 -0700430 }
431
432 // Link weight for measuring link cost as hop count with indirect links
433 // being as expensive as traversing the entire graph to assume the worst.
434 private static class HopCountLinkWeight implements LinkWeight {
435 private final int indirectLinkCost;
436
437 HopCountLinkWeight(int indirectLinkCost) {
438 this.indirectLinkCost = indirectLinkCost;
439 }
440
441 @Override
442 public double weight(TopologyEdge edge) {
443 // To force preference to use direct paths first, make indirect
444 // links as expensive as the linear vertex traversal.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500445 return edge.link().state() ==
446 ACTIVE ? (edge.link().type() ==
447 INDIRECT ? indirectLinkCost : 1) : -1;
alshabib339a3d92014-09-26 17:54:32 -0700448 }
449 }
450
451 // Link weight for preventing traversal over indirect links.
452 private static class NoIndirectLinksWeight implements LinkWeight {
453 @Override
454 public double weight(TopologyEdge edge) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500455 return (edge.link().state() == INACTIVE)
456 || (edge.link().type() == INDIRECT) ? -1 : 1;
alshabib339a3d92014-09-26 17:54:32 -0700457 }
458 }
459
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800460 static final class ClusterIndexes {
461 final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
462 final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
463 final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
464
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700465 public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
466 ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
467 ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800468 this.clustersByDevice = clustersByDevice;
469 this.devicesByCluster = devicesByCluster;
470 this.linksByCluster = linksByCluster;
471 }
472 }
473
alshabib339a3d92014-09-26 17:54:32 -0700474 @Override
475 public String toString() {
476 return toStringHelper(this)
477 .add("time", time)
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500478 .add("creationTime", creationTime)
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800479 .add("computeCost", computeCost)
alshabib339a3d92014-09-26 17:54:32 -0700480 .add("clusters", clusterCount())
481 .add("devices", deviceCount())
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500482 .add("links", linkCount()).toString();
alshabib339a3d92014-09-26 17:54:32 -0700483 }
484}