Yuta HIGUCHI
Committed by Gerrit Code Review

Lazily compute SCC, etc. on demand

- TODO computeCost does not correspond to actual computation cost now

Change-Id: Iffe3093c81bbb51d5feb46117fae8be092cf9288
...@@ -15,12 +15,17 @@ ...@@ -15,12 +15,17 @@
15 */ 15 */
16 package org.onlab.onos.store.topology.impl; 16 package org.onlab.onos.store.topology.impl;
17 17
18 +import com.google.common.base.Supplier;
19 +import com.google.common.base.Suppliers;
18 import com.google.common.collect.ImmutableMap; 20 import com.google.common.collect.ImmutableMap;
19 import com.google.common.collect.ImmutableSet; 21 import com.google.common.collect.ImmutableSet;
20 import com.google.common.collect.ImmutableSetMultimap; 22 import com.google.common.collect.ImmutableSetMultimap;
23 +
21 import org.onlab.graph.DijkstraGraphSearch; 24 import org.onlab.graph.DijkstraGraphSearch;
22 import org.onlab.graph.GraphPathSearch; 25 import org.onlab.graph.GraphPathSearch;
26 +import org.onlab.graph.GraphPathSearch.Result;
23 import org.onlab.graph.TarjanGraphSearch; 27 import org.onlab.graph.TarjanGraphSearch;
28 +import org.onlab.graph.TarjanGraphSearch.SCCResult;
24 import org.onlab.onos.net.AbstractModel; 29 import org.onlab.onos.net.AbstractModel;
25 import org.onlab.onos.net.ConnectPoint; 30 import org.onlab.onos.net.ConnectPoint;
26 import org.onlab.onos.net.DefaultPath; 31 import org.onlab.onos.net.DefaultPath;
...@@ -46,8 +51,6 @@ import java.util.Set; ...@@ -46,8 +51,6 @@ import java.util.Set;
46 51
47 import static com.google.common.base.MoreObjects.toStringHelper; 52 import static com.google.common.base.MoreObjects.toStringHelper;
48 import static com.google.common.collect.ImmutableSetMultimap.Builder; 53 import static com.google.common.collect.ImmutableSetMultimap.Builder;
49 -import static org.onlab.graph.GraphPathSearch.Result;
50 -import static org.onlab.graph.TarjanGraphSearch.SCCResult;
51 import static org.onlab.onos.core.CoreService.CORE_PROVIDER_ID; 54 import static org.onlab.onos.core.CoreService.CORE_PROVIDER_ID;
52 import static org.onlab.onos.net.Link.State.ACTIVE; 55 import static org.onlab.onos.net.Link.State.ACTIVE;
53 import static org.onlab.onos.net.Link.State.INACTIVE; 56 import static org.onlab.onos.net.Link.State.INACTIVE;
...@@ -68,18 +71,15 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -68,18 +71,15 @@ public class DefaultTopology extends AbstractModel implements Topology {
68 private final long computeCost; 71 private final long computeCost;
69 private final TopologyGraph graph; 72 private final TopologyGraph graph;
70 73
71 - private final SCCResult<TopologyVertex, TopologyEdge> clusterResults; 74 + private final Supplier<SCCResult<TopologyVertex, TopologyEdge>> clusterResults;
72 - private final ImmutableMap<DeviceId, Result<TopologyVertex, TopologyEdge>> results; 75 + private final Supplier<ImmutableMap<DeviceId, Result<TopologyVertex, TopologyEdge>>> results;
73 - private final ImmutableSetMultimap<PathKey, Path> paths; 76 + private final Supplier<ImmutableSetMultimap<PathKey, Path>> paths;
74 -
75 - private final ImmutableMap<ClusterId, TopologyCluster> clusters;
76 - private final ImmutableSet<ConnectPoint> infrastructurePoints;
77 - private final ImmutableSetMultimap<ClusterId, ConnectPoint> broadcastSets;
78 77
79 - private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice; 78 + private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
80 - private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster; 79 + private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
81 - private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster; 80 + private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets;
82 81
82 + private final Supplier<ClusterIndexes> clusterIndexes;
83 83
84 /** 84 /**
85 * Creates a topology descriptor attributed to the specified provider. 85 * Creates a topology descriptor attributed to the specified provider.
...@@ -95,16 +95,17 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -95,16 +95,17 @@ public class DefaultTopology extends AbstractModel implements Topology {
95 this.graph = new DefaultTopologyGraph(description.vertexes(), 95 this.graph = new DefaultTopologyGraph(description.vertexes(),
96 description.edges()); 96 description.edges());
97 97
98 - this.results = searchForShortestPaths();
99 - this.paths = buildPaths();
100 98
101 - this.clusterResults = searchForClusters(); 99 + this.results = Suppliers.memoize(() -> searchForShortestPaths());
102 - this.clusters = buildTopologyClusters(); 100 + this.paths = Suppliers.memoize(() -> buildPaths());
101 +
102 + this.clusterResults = Suppliers.memoize(() -> searchForClusters());
103 + this.clusters = Suppliers.memoize(() -> buildTopologyClusters());
103 104
104 - buildIndexes(); 105 + this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
105 106
106 - this.broadcastSets = buildBroadcastSets(); 107 + this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
107 - this.infrastructurePoints = findInfrastructurePoints(); 108 + this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
108 this.computeCost = Math.max(0, System.nanoTime() - time); 109 this.computeCost = Math.max(0, System.nanoTime() - time);
109 } 110 }
110 111
...@@ -120,7 +121,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -120,7 +121,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
120 121
121 @Override 122 @Override
122 public int clusterCount() { 123 public int clusterCount() {
123 - return clusters.size(); 124 + return clusters.get().size();
124 } 125 }
125 126
126 @Override 127 @Override
...@@ -135,7 +136,19 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -135,7 +136,19 @@ public class DefaultTopology extends AbstractModel implements Topology {
135 136
136 @Override 137 @Override
137 public int pathCount() { 138 public int pathCount() {
138 - return paths.size(); 139 + return paths.get().size();
140 + }
141 +
142 + private ImmutableMap<DeviceId, TopologyCluster> clustersByDevice() {
143 + return clusterIndexes.get().clustersByDevice;
144 + }
145 +
146 + private ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster() {
147 + return clusterIndexes.get().devicesByCluster;
148 + }
149 +
150 + private ImmutableSetMultimap<TopologyCluster, Link> linksByCluster() {
151 + return clusterIndexes.get().linksByCluster;
139 } 152 }
140 153
141 /** 154 /**
...@@ -153,7 +166,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -153,7 +166,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
153 * @return set of clusters 166 * @return set of clusters
154 */ 167 */
155 Set<TopologyCluster> getClusters() { 168 Set<TopologyCluster> getClusters() {
156 - return ImmutableSet.copyOf(clusters.values()); 169 + return ImmutableSet.copyOf(clusters.get().values());
157 } 170 }
158 171
159 /** 172 /**
...@@ -163,7 +176,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -163,7 +176,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
163 * @return topology cluster 176 * @return topology cluster
164 */ 177 */
165 TopologyCluster getCluster(ClusterId clusterId) { 178 TopologyCluster getCluster(ClusterId clusterId) {
166 - return clusters.get(clusterId); 179 + return clusters.get().get(clusterId);
167 } 180 }
168 181
169 /** 182 /**
...@@ -173,7 +186,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -173,7 +186,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
173 * @return topology cluster 186 * @return topology cluster
174 */ 187 */
175 TopologyCluster getCluster(DeviceId deviceId) { 188 TopologyCluster getCluster(DeviceId deviceId) {
176 - return clustersByDevice.get(deviceId); 189 + return clustersByDevice().get(deviceId);
177 } 190 }
178 191
179 /** 192 /**
...@@ -183,7 +196,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -183,7 +196,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
183 * @return cluster devices 196 * @return cluster devices
184 */ 197 */
185 Set<DeviceId> getClusterDevices(TopologyCluster cluster) { 198 Set<DeviceId> getClusterDevices(TopologyCluster cluster) {
186 - return devicesByCluster.get(cluster); 199 + return devicesByCluster().get(cluster);
187 } 200 }
188 201
189 /** 202 /**
...@@ -193,7 +206,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -193,7 +206,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
193 * @return cluster links 206 * @return cluster links
194 */ 207 */
195 Set<Link> getClusterLinks(TopologyCluster cluster) { 208 Set<Link> getClusterLinks(TopologyCluster cluster) {
196 - return linksByCluster.get(cluster); 209 + return linksByCluster().get(cluster);
197 } 210 }
198 211
199 /** 212 /**
...@@ -203,7 +216,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -203,7 +216,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
203 * @return true if infrastructure 216 * @return true if infrastructure
204 */ 217 */
205 boolean isInfrastructure(ConnectPoint connectPoint) { 218 boolean isInfrastructure(ConnectPoint connectPoint) {
206 - return infrastructurePoints.contains(connectPoint); 219 + return infrastructurePoints.get().contains(connectPoint);
207 } 220 }
208 221
209 /** 222 /**
...@@ -219,14 +232,14 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -219,14 +232,14 @@ public class DefaultTopology extends AbstractModel implements Topology {
219 } 232 }
220 233
221 // Find the cluster to which the device belongs. 234 // Find the cluster to which the device belongs.
222 - TopologyCluster cluster = clustersByDevice.get(connectPoint.deviceId()); 235 + TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId());
223 if (cluster == null) { 236 if (cluster == null) {
224 throw new IllegalArgumentException("No cluster found for device " + connectPoint.deviceId()); 237 throw new IllegalArgumentException("No cluster found for device " + connectPoint.deviceId());
225 } 238 }
226 239
227 // If the broadcast set is null or empty, or if the point explicitly 240 // If the broadcast set is null or empty, or if the point explicitly
228 // belongs to it, return true; 241 // belongs to it, return true;
229 - Set<ConnectPoint> points = broadcastSets.get(cluster.id()); 242 + Set<ConnectPoint> points = broadcastSets.get().get(cluster.id());
230 return points == null || points.isEmpty() || points.contains(connectPoint); 243 return points == null || points.isEmpty() || points.contains(connectPoint);
231 } 244 }
232 245
...@@ -237,7 +250,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -237,7 +250,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
237 * @return size of the cluster broadcast set 250 * @return size of the cluster broadcast set
238 */ 251 */
239 int broadcastSetSize(ClusterId clusterId) { 252 int broadcastSetSize(ClusterId clusterId) {
240 - return broadcastSets.get(clusterId).size(); 253 + return broadcastSets.get().get(clusterId).size();
241 } 254 }
242 255
243 /** 256 /**
...@@ -249,7 +262,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -249,7 +262,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
249 * @return set of shortest paths 262 * @return set of shortest paths
250 */ 263 */
251 Set<Path> getPaths(DeviceId src, DeviceId dst) { 264 Set<Path> getPaths(DeviceId src, DeviceId dst) {
252 - return paths.get(new PathKey(src, dst)); 265 + return paths.get().get(new PathKey(src, dst));
253 } 266 }
254 267
255 /** 268 /**
...@@ -295,8 +308,8 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -295,8 +308,8 @@ public class DefaultTopology extends AbstractModel implements Topology {
295 // Builds network paths from the graph path search results 308 // Builds network paths from the graph path search results
296 private ImmutableSetMultimap<PathKey, Path> buildPaths() { 309 private ImmutableSetMultimap<PathKey, Path> buildPaths() {
297 Builder<PathKey, Path> builder = ImmutableSetMultimap.builder(); 310 Builder<PathKey, Path> builder = ImmutableSetMultimap.builder();
298 - for (DeviceId deviceId : results.keySet()) { 311 + for (DeviceId deviceId : results.get().keySet()) {
299 - Result<TopologyVertex, TopologyEdge> result = results.get(deviceId); 312 + Result<TopologyVertex, TopologyEdge> result = results.get().get(deviceId);
300 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) { 313 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
301 builder.put(new PathKey(path.src().deviceId(), path.dst().deviceId()), 314 builder.put(new PathKey(path.src().deviceId(), path.dst().deviceId()),
302 networkPath(path)); 315 networkPath(path));
...@@ -363,7 +376,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -363,7 +376,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
363 // Processes a map of broadcast sets for each cluster. 376 // Processes a map of broadcast sets for each cluster.
364 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() { 377 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
365 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder(); 378 Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder();
366 - for (TopologyCluster cluster : clusters.values()) { 379 + for (TopologyCluster cluster : clusters.get().values()) {
367 addClusterBroadcastSet(cluster, builder); 380 addClusterBroadcastSet(cluster, builder);
368 } 381 }
369 return builder.build(); 382 return builder.build();
...@@ -375,12 +388,12 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -375,12 +388,12 @@ public class DefaultTopology extends AbstractModel implements Topology {
375 private void addClusterBroadcastSet(TopologyCluster cluster, 388 private void addClusterBroadcastSet(TopologyCluster cluster,
376 Builder<ClusterId, ConnectPoint> builder) { 389 Builder<ClusterId, ConnectPoint> builder) {
377 // Use the graph root search results to build the broadcast set. 390 // Use the graph root search results to build the broadcast set.
378 - Result<TopologyVertex, TopologyEdge> result = results.get(cluster.root()); 391 + Result<TopologyVertex, TopologyEdge> result = results.get().get(cluster.root());
379 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) { 392 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
380 TopologyVertex vertex = entry.getKey(); 393 TopologyVertex vertex = entry.getKey();
381 394
382 // Ignore any parents that lead outside the cluster. 395 // Ignore any parents that lead outside the cluster.
383 - if (clustersByDevice.get(vertex.deviceId()) != cluster) { 396 + if (clustersByDevice().get(vertex.deviceId()) != cluster) {
384 continue; 397 continue;
385 } 398 }
386 399
...@@ -409,32 +422,32 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -409,32 +422,32 @@ public class DefaultTopology extends AbstractModel implements Topology {
409 } 422 }
410 423
411 // Builds cluster-devices, cluster-links and device-cluster indexes. 424 // Builds cluster-devices, cluster-links and device-cluster indexes.
412 - private void buildIndexes() { 425 + private ClusterIndexes buildIndexes() {
413 // Prepare the index builders 426 // Prepare the index builders
414 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder = ImmutableMap.builder(); 427 ImmutableMap.Builder<DeviceId, TopologyCluster> clusterBuilder = ImmutableMap.builder();
415 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder = ImmutableSetMultimap.builder(); 428 ImmutableSetMultimap.Builder<TopologyCluster, DeviceId> devicesBuilder = ImmutableSetMultimap.builder();
416 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder = ImmutableSetMultimap.builder(); 429 ImmutableSetMultimap.Builder<TopologyCluster, Link> linksBuilder = ImmutableSetMultimap.builder();
417 430
418 // Now scan through all the clusters 431 // Now scan through all the clusters
419 - for (TopologyCluster cluster : clusters.values()) { 432 + for (TopologyCluster cluster : clusters.get().values()) {
420 int i = cluster.id().index(); 433 int i = cluster.id().index();
421 434
422 // Scan through all the cluster vertexes. 435 // Scan through all the cluster vertexes.
423 - for (TopologyVertex vertex : clusterResults.clusterVertexes().get(i)) { 436 + for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) {
424 devicesBuilder.put(cluster, vertex.deviceId()); 437 devicesBuilder.put(cluster, vertex.deviceId());
425 clusterBuilder.put(vertex.deviceId(), cluster); 438 clusterBuilder.put(vertex.deviceId(), cluster);
426 } 439 }
427 440
428 // Scan through all the cluster edges. 441 // Scan through all the cluster edges.
429 - for (TopologyEdge edge : clusterResults.clusterEdges().get(i)) { 442 + for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) {
430 linksBuilder.put(cluster, edge.link()); 443 linksBuilder.put(cluster, edge.link());
431 } 444 }
432 } 445 }
433 446
434 // Finalize all indexes. 447 // Finalize all indexes.
435 - clustersByDevice = clusterBuilder.build(); 448 + return new ClusterIndexes(clusterBuilder.build(),
436 - devicesByCluster = devicesBuilder.build(); 449 + devicesBuilder.build(),
437 - linksByCluster = linksBuilder.build(); 450 + linksBuilder.build());
438 } 451 }
439 452
440 // Link weight for measuring link cost as hop count with indirect links 453 // Link weight for measuring link cost as hop count with indirect links
...@@ -463,6 +476,20 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -463,6 +476,20 @@ public class DefaultTopology extends AbstractModel implements Topology {
463 } 476 }
464 } 477 }
465 478
479 + static final class ClusterIndexes {
480 + final ImmutableMap<DeviceId, TopologyCluster> clustersByDevice;
481 + final ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster;
482 + final ImmutableSetMultimap<TopologyCluster, Link> linksByCluster;
483 +
484 + public ClusterIndexes(ImmutableMap<DeviceId, TopologyCluster> clustersByDevice,
485 + ImmutableSetMultimap<TopologyCluster, DeviceId> devicesByCluster,
486 + ImmutableSetMultimap<TopologyCluster, Link> linksByCluster) {
487 + this.clustersByDevice = clustersByDevice;
488 + this.devicesByCluster = devicesByCluster;
489 + this.linksByCluster = linksByCluster;
490 + }
491 + }
492 +
466 @Override 493 @Override
467 public String toString() { 494 public String toString() {
468 return toStringHelper(this) 495 return toStringHelper(this)
......