blob: bdf7d732cc27299ed76e37bfd933a682d7c23091 [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 Vachuskab2c47a72015-08-05 14:22:54 -070018import com.google.common.base.Function;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070019import com.google.common.base.Supplier;
20import com.google.common.base.Suppliers;
21import com.google.common.collect.ImmutableMap;
22import com.google.common.collect.ImmutableSet;
23import com.google.common.collect.ImmutableSetMultimap;
24import com.google.common.collect.ImmutableSetMultimap.Builder;
alshabib339a3d92014-09-26 17:54:32 -070025import org.onlab.graph.DijkstraGraphSearch;
26import org.onlab.graph.GraphPathSearch;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080027import org.onlab.graph.GraphPathSearch.Result;
alshabib339a3d92014-09-26 17:54:32 -070028import org.onlab.graph.TarjanGraphSearch;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080029import org.onlab.graph.TarjanGraphSearch.SCCResult;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.net.AbstractModel;
31import org.onosproject.net.ConnectPoint;
32import org.onosproject.net.DefaultPath;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.Link;
35import org.onosproject.net.Path;
36import org.onosproject.net.provider.ProviderId;
37import org.onosproject.net.topology.ClusterId;
38import org.onosproject.net.topology.DefaultTopologyCluster;
39import org.onosproject.net.topology.DefaultTopologyVertex;
40import org.onosproject.net.topology.GraphDescription;
41import org.onosproject.net.topology.LinkWeight;
42import org.onosproject.net.topology.Topology;
43import org.onosproject.net.topology.TopologyCluster;
44import org.onosproject.net.topology.TopologyEdge;
45import org.onosproject.net.topology.TopologyGraph;
46import org.onosproject.net.topology.TopologyVertex;
alshabib339a3d92014-09-26 17:54:32 -070047
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070048import java.util.ArrayList;
49import java.util.List;
50import java.util.Map;
51import java.util.Set;
alshabib339a3d92014-09-26 17:54:32 -070052
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070053import static com.google.common.base.MoreObjects.toStringHelper;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070054import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070055import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
Thomas Vachuska320c58f2015-08-05 10:42:32 -070056import static org.onlab.util.Tools.isNullOrEmpty;
Thomas Vachuska930a8ee2015-08-04 18:49:36 -070057import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
58import static org.onosproject.net.Link.State.ACTIVE;
59import static org.onosproject.net.Link.State.INACTIVE;
60import static org.onosproject.net.Link.Type.INDIRECT;
61
alshabib339a3d92014-09-26 17:54:32 -070062/**
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050063 * Default implementation of the topology descriptor. This carries the backing
64 * topology data.
alshabib339a3d92014-09-26 17:54:32 -070065 */
66public class DefaultTopology extends AbstractModel implements Topology {
67
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050068 private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>();
69 private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>();
alshabib339a3d92014-09-26 17:54:32 -070070
alshabib339a3d92014-09-26 17:54:32 -070071 private final long time;
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050072 private final long creationTime;
Thomas Vachuska6b7920d2014-11-25 19:48:39 -080073 private final long computeCost;
alshabib339a3d92014-09-26 17:54:32 -070074 private final TopologyGraph graph;
75
Thomas Vachuskac31d9f12015-01-22 12:33:27 -080076 private final LinkWeight weight;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080077 private final Supplier<SCCResult<TopologyVertex, TopologyEdge>> clusterResults;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080078 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
79 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
80 private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070081 private final Function<ConnectPoint, Boolean> broadcastFunction;
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -080082 private final Supplier<ClusterIndexes> clusterIndexes;
alshabib339a3d92014-09-26 17:54:32 -070083
84 /**
85 * Creates a topology descriptor attributed to the specified provider.
86 *
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070087 * @param providerId identity of the provider
88 * @param description data describing the new topology
89 * @param broadcastFunction broadcast point function
alshabib339a3d92014-09-26 17:54:32 -070090 */
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070091 public DefaultTopology(ProviderId providerId, GraphDescription description,
92 Function<ConnectPoint, Boolean> broadcastFunction) {
alshabib339a3d92014-09-26 17:54:32 -070093 super(providerId);
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070094 this.broadcastFunction = broadcastFunction;
alshabib339a3d92014-09-26 17:54:32 -070095 this.time = description.timestamp();
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -050096 this.creationTime = description.creationTime();
alshabib339a3d92014-09-26 17:54:32 -070097
98 // Build the graph
99 this.graph = new DefaultTopologyGraph(description.vertexes(),
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700100 description.edges());
alshabib339a3d92014-09-26 17:54:32 -0700101
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800102 this.clusterResults = Suppliers.memoize(() -> searchForClusters());
103 this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
alshabib339a3d92014-09-26 17:54:32 -0700104
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800105 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
106
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800107 this.weight = new HopCountLinkWeight(graph.getVertexes().size());
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800108 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700109 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800110 this.computeCost = Math.max(0, System.nanoTime() - time);
alshabib339a3d92014-09-26 17:54:32 -0700111 }
112
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700113 /**
114 * Creates a topology descriptor attributed to the specified provider.
115 *
116 * @param providerId identity of the provider
117 * @param description data describing the new topology
118 */
119 public DefaultTopology(ProviderId providerId, GraphDescription description) {
120 this(providerId, description, null);
121 }
122
alshabib339a3d92014-09-26 17:54:32 -0700123 @Override
124 public long time() {
125 return time;
126 }
127
128 @Override
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500129 public long creationTime() {
130 return creationTime;
131 }
132
133 @Override
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800134 public long computeCost() {
135 return computeCost;
136 }
137
138 @Override
alshabib339a3d92014-09-26 17:54:32 -0700139 public int clusterCount() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800140 return clusters.get().size();
alshabib339a3d92014-09-26 17:54:32 -0700141 }
142
143 @Override
144 public int deviceCount() {
145 return graph.getVertexes().size();
146 }
147
148 @Override
149 public int linkCount() {
150 return graph.getEdges().size();
151 }
152
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800153 private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
154 return clusterIndexes.get().clustersByDevice;
155 }
156
157 private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
158 return clusterIndexes.get().devicesByCluster;
159 }
160
161 private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
162 return clusterIndexes.get().linksByCluster;
alshabib339a3d92014-09-26 17:54:32 -0700163 }
164
165 /**
166 * Returns the backing topology graph.
167 *
168 * @return topology graph
169 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700170 public TopologyGraph getGraph() {
alshabib339a3d92014-09-26 17:54:32 -0700171 return graph;
172 }
173
174 /**
175 * Returns the set of topology clusters.
176 *
177 * @return set of clusters
178 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700179 public Set<TopologyCluster> getClusters() {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800180 return ImmutableSet.copyOf(clusters.get().values());
alshabib339a3d92014-09-26 17:54:32 -0700181 }
182
183 /**
184 * Returns the specified topology cluster.
185 *
186 * @param clusterId cluster identifier
187 * @return topology cluster
188 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700189 public TopologyCluster getCluster(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800190 return clusters.get().get(clusterId);
alshabib339a3d92014-09-26 17:54:32 -0700191 }
192
193 /**
194 * Returns the topology cluster that contains the given device.
195 *
196 * @param deviceId device identifier
197 * @return topology cluster
198 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700199 public TopologyCluster getCluster(DeviceId deviceId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800200 return clustersByDevice().get(deviceId);
alshabib339a3d92014-09-26 17:54:32 -0700201 }
202
203 /**
204 * Returns the set of cluster devices.
205 *
206 * @param cluster topology cluster
207 * @return cluster devices
208 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700209 public Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800210 return devicesByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700211 }
212
213 /**
214 * Returns the set of cluster links.
215 *
216 * @param cluster topology cluster
217 * @return cluster links
218 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700219 public Set<Link> getClusterLinks(TopologyCluster cluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800220 return linksByCluster().get(cluster);
alshabib339a3d92014-09-26 17:54:32 -0700221 }
222
223 /**
224 * Indicates whether the given point is an infrastructure link end-point.
225 *
226 * @param connectPoint connection point
227 * @return true if infrastructure
228 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700229 public boolean isInfrastructure(ConnectPoint connectPoint) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800230 return infrastructurePoints.get().contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700231 }
232
233 /**
234 * Indicates whether the given point is part of a broadcast set.
235 *
236 * @param connectPoint connection point
237 * @return true if in broadcast set
238 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700239 public boolean isBroadcastPoint(ConnectPoint connectPoint) {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700240 if (broadcastFunction != null) {
241 return broadcastFunction.apply(connectPoint);
242 }
243
alshabib339a3d92014-09-26 17:54:32 -0700244 // Any non-infrastructure, i.e. edge points are assumed to be OK.
245 if (!isInfrastructure(connectPoint)) {
246 return true;
247 }
248
249 // Find the cluster to which the device belongs.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800250 TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700251 checkArgument(cluster != null, "No cluster found for device %s", connectPoint.deviceId());
alshabib339a3d92014-09-26 17:54:32 -0700252
253 // If the broadcast set is null or empty, or if the point explicitly
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700254 // belongs to it, return true.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800255 Set<ConnectPoint> points = broadcastSets.get().get(cluster.id());
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700256 return isNullOrEmpty(points) || points.contains(connectPoint);
alshabib339a3d92014-09-26 17:54:32 -0700257 }
258
259 /**
260 * Returns the size of the cluster broadcast set.
261 *
262 * @param clusterId cluster identifier
263 * @return size of the cluster broadcast set
264 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700265 public int broadcastSetSize(ClusterId clusterId) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800266 return broadcastSets.get().get(clusterId).size();
alshabib339a3d92014-09-26 17:54:32 -0700267 }
268
269 /**
Thomas Vachuska320c58f2015-08-05 10:42:32 -0700270 * Returns the set of the cluster broadcast points.
271 *
272 * @param clusterId cluster identifier
273 * @return set of cluster broadcast points
274 */
275 public Set<ConnectPoint> broadcastPoints(ClusterId clusterId) {
276 return broadcastSets.get().get(clusterId);
277 }
278
279 /**
alshabib339a3d92014-09-26 17:54:32 -0700280 * Returns the set of pre-computed shortest paths between source and
281 * destination devices.
282 *
283 * @param src source device
284 * @param dst destination device
285 * @return set of shortest paths
286 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700287 public Set<Path> getPaths(DeviceId src, DeviceId dst) {
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800288 return getPaths(src, dst, null);
alshabib339a3d92014-09-26 17:54:32 -0700289 }
290
291 /**
292 * Computes on-demand the set of shortest paths between source and
293 * destination devices.
294 *
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700295 * @param src source device
296 * @param dst destination device
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800297 * @param weight link weight function
alshabib339a3d92014-09-26 17:54:32 -0700298 * @return set of shortest paths
299 */
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700300 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800301 final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
302 final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
303 Set<TopologyVertex> vertices = graph.getVertexes();
304 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
305 // src or dst not part of the current graph
306 return ImmutableSet.of();
307 }
308
alshabib339a3d92014-09-26 17:54:32 -0700309 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800310 DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS);
alshabib339a3d92014-09-26 17:54:32 -0700311 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
312 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
313 builder.add(networkPath(path));
314 }
315 return builder.build();
316 }
317
alshabib339a3d92014-09-26 17:54:32 -0700318 // Converts graph path to a network path with the same cost.
319 private Path networkPath(org.onlab.graph.Path<TopologyVertex, TopologyEdge> path) {
320 List<Link> links = new ArrayList<>();
321 for (TopologyEdge edge : path.edges()) {
322 links.add(edge.link());
323 }
Thomas Vachuska6acd3bb2014-11-09 23:44:22 -0800324 return new DefaultPath(CORE_PROVIDER_ID, links, path.cost());
alshabib339a3d92014-09-26 17:54:32 -0700325 }
326
alshabib339a3d92014-09-26 17:54:32 -0700327 // Searches for SCC clusters in the network topology graph using Tarjan
328 // algorithm.
329 private SCCResult<TopologyVertex, TopologyEdge> searchForClusters() {
330 return TARJAN.search(graph, new NoIndirectLinksWeight());
331 }
332
333 // Builds the topology clusters and returns the id-cluster bindings.
334 private ImmutableMap<ClusterId, TopologyCluster> buildTopologyClusters() {
335 ImmutableMap.Builder<ClusterId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800336 SCCResult<TopologyVertex, TopologyEdge> results = clusterResults.get();
alshabib339a3d92014-09-26 17:54:32 -0700337 // Extract both vertexes and edges from the results; the lists form
338 // pairs along the same index.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800339 List<Set<TopologyVertex>> clusterVertexes = results.clusterVertexes();
340 List<Set<TopologyEdge>> clusterEdges = results.clusterEdges();
alshabib339a3d92014-09-26 17:54:32 -0700341
342 // Scan over the lists and create a cluster from the results.
Thomas Vachuskac31d9f12015-01-22 12:33:27 -0800343 for (int i = 0, n = results.clusterCount(); i < n; i++) {
alshabib339a3d92014-09-26 17:54:32 -0700344 Set<TopologyVertex> vertexSet = clusterVertexes.get(i);
345 Set<TopologyEdge> edgeSet = clusterEdges.get(i);
346
347 ClusterId cid = ClusterId.clusterId(i);
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500348 DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid,
349 vertexSet.size(),
350 edgeSet.size(),
351 findRoot(vertexSet));
alshabib339a3d92014-09-26 17:54:32 -0700352 clusterBuilder.put(cid, cluster);
353 }
354 return clusterBuilder.build();
355 }
356
357 // Finds the vertex whose device id is the lexicographical minimum in the
358 // specified set.
359 private TopologyVertex findRoot(Set<TopologyVertex> vertexSet) {
360 TopologyVertex minVertex = null;
361 for (TopologyVertex vertex : vertexSet) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500362 if ((minVertex == null) || (minVertex.deviceId()
363 .toString().compareTo(minVertex.deviceId().toString()) < 0)) {
alshabib339a3d92014-09-26 17:54:32 -0700364 minVertex = vertex;
365 }
366 }
367 return minVertex;
368 }
369
370 // Processes a map of broadcast sets for each cluster.
371 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500372 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap
373 .builder();
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800374 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700375 addClusterBroadcastSet(cluster, builder);
376 }
377 return builder.build();
378 }
379
380 // Finds all broadcast points for the cluster. These are those connection
381 // points which lie along the shortest paths between the cluster root and
382 // all other devices within the cluster.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500383 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
alshabib339a3d92014-09-26 17:54:32 -0700384 // Use the graph root search results to build the broadcast set.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500385 Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, weight, 1);
alshabib339a3d92014-09-26 17:54:32 -0700386 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
387 TopologyVertex vertex = entry.getKey();
388
389 // Ignore any parents that lead outside the cluster.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800390 if (clustersByDevice().get(vertex.deviceId()) != cluster) {
alshabib339a3d92014-09-26 17:54:32 -0700391 continue;
392 }
393
394 // Ignore any back-link sets that are empty.
395 Set<TopologyEdge> parents = entry.getValue();
396 if (parents.isEmpty()) {
397 continue;
398 }
399
400 // Use the first back-link source and destinations to add to the
401 // broadcast set.
402 Link link = parents.iterator().next().link();
403 builder.put(cluster.id(), link.src());
404 builder.put(cluster.id(), link.dst());
405 }
406 }
407
408 // Collects and returns an set of all infrastructure link end-points.
409 private ImmutableSet<ConnectPoint> findInfrastructurePoints() {
410 ImmutableSet.Builder<ConnectPoint> builder = ImmutableSet.builder();
411 for (TopologyEdge edge : graph.getEdges()) {
412 builder.add(edge.link().src());
413 builder.add(edge.link().dst());
414 }
415 return builder.build();
416 }
417
418 // Builds cluster-devices, cluster-links and device-cluster indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800419 private ClusterIndexes buildIndexes() {
alshabib339a3d92014-09-26 17:54:32 -0700420 // Prepare the index builders
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500421 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder =
422 ImmutableMap.builder();
423 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder =
424 ImmutableSetMultimap.builder();
425 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder =
426 ImmutableSetMultimap.builder();
alshabib339a3d92014-09-26 17:54:32 -0700427
428 // Now scan through all the clusters
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800429 for (TopologyCluster cluster : clusters.get().values()) {
alshabib339a3d92014-09-26 17:54:32 -0700430 int i = cluster.id().index();
431
432 // Scan through all the cluster vertexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800433 for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700434 devicesBuilder.put(cluster, vertex.deviceId());
435 clusterBuilder.put(vertex.deviceId(), cluster);
436 }
437
438 // Scan through all the cluster edges.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800439 for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
alshabib339a3d92014-09-26 17:54:32 -0700440 linksBuilder.put(cluster, edge.link());
441 }
442 }
443
444 // Finalize all indexes.
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800445 return new ClusterIndexes(clusterBuilder.build(),
446 devicesBuilder.build(),
447 linksBuilder.build());
alshabib339a3d92014-09-26 17:54:32 -0700448 }
449
450 // Link weight for measuring link cost as hop count with indirect links
451 // being as expensive as traversing the entire graph to assume the worst.
452 private static class HopCountLinkWeight implements LinkWeight {
453 private final int indirectLinkCost;
454
455 HopCountLinkWeight(int indirectLinkCost) {
456 this.indirectLinkCost = indirectLinkCost;
457 }
458
459 @Override
460 public double weight(TopologyEdge edge) {
461 // To force preference to use direct paths first, make indirect
462 // links as expensive as the linear vertex traversal.
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500463 return edge.link().state() ==
464 ACTIVE ? (edge.link().type() ==
465 INDIRECT ? indirectLinkCost : 1) : -1;
alshabib339a3d92014-09-26 17:54:32 -0700466 }
467 }
468
469 // Link weight for preventing traversal over indirect links.
470 private static class NoIndirectLinksWeight implements LinkWeight {
471 @Override
472 public double weight(TopologyEdge edge) {
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500473 return (edge.link().state() == INACTIVE)
474 || (edge.link().type() == INDIRECT) ? -1 : 1;
alshabib339a3d92014-09-26 17:54:32 -0700475 }
476 }
477
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800478 static final class ClusterIndexes {
479 final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
480 final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
481 final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
482
Thomas Vachuska930a8ee2015-08-04 18:49:36 -0700483 public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
484 ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
485 ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
Yuta HIGUCHIb2e74a02014-11-30 13:54:38 -0800486 this.clustersByDevice = clustersByDevice;
487 this.devicesByCluster = devicesByCluster;
488 this.linksByCluster = linksByCluster;
489 }
490 }
491
alshabib339a3d92014-09-26 17:54:32 -0700492 @Override
493 public String toString() {
494 return toStringHelper(this)
495 .add("time", time)
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500496 .add("creationTime", creationTime)
Thomas Vachuska6b7920d2014-11-25 19:48:39 -0800497 .add("computeCost", computeCost)
alshabib339a3d92014-09-26 17:54:32 -0700498 .add("clusters", clusterCount())
499 .add("devices", deviceCount())
Abhishek Dwaraki1e5873e2015-03-08 00:01:17 -0500500 .add("links", linkCount()).toString();
alshabib339a3d92014-09-26 17:54:32 -0700501 }
502}