kircaali
Committed by Gerrit Code Review

Fix for ONOS-3183

Stream processes by Lambda queries in collection objects has a known performance bottleneck. For each create and update link data operations, this  kind of queries are frequently used and this causes inefficient topology discovery operation. For to solve that problem i analize thread dump during discovery process and i saw that especially getAllProviders method uses high cpu. than i change the provider search operation with additional map data which holds linkkey and its providers. by this way provider search operation not only gets faster but also uses minimum resource. Before that change, i can discover only 4XX number of switches at one controller, but later number grows to 15XX switches

Change-Id: I65ed71b7f295917c818b2f9227d0fc070aa4a29b
...@@ -71,6 +71,7 @@ import org.slf4j.Logger; ...@@ -71,6 +71,7 @@ import org.slf4j.Logger;
71 71
72 import com.google.common.collect.Iterables; 72 import com.google.common.collect.Iterables;
73 import com.google.common.collect.Maps; 73 import com.google.common.collect.Maps;
74 +import com.google.common.collect.Sets;
74 import com.google.common.util.concurrent.Futures; 75 import com.google.common.util.concurrent.Futures;
75 76
76 import static com.google.common.base.Preconditions.checkNotNull; 77 import static com.google.common.base.Preconditions.checkNotNull;
...@@ -95,8 +96,8 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -95,8 +96,8 @@ import static org.slf4j.LoggerFactory.getLogger;
95 @Component(immediate = true, enabled = true) 96 @Component(immediate = true, enabled = true)
96 @Service 97 @Service
97 public class ECLinkStore 98 public class ECLinkStore
98 - extends AbstractStore<LinkEvent, LinkStoreDelegate> 99 + extends AbstractStore<LinkEvent, LinkStoreDelegate>
99 - implements LinkStore { 100 + implements LinkStore {
100 101
101 /** 102 /**
102 * Modes for dealing with newly discovered links. 103 * Modes for dealing with newly discovered links.
...@@ -117,8 +118,10 @@ public class ECLinkStore ...@@ -117,8 +118,10 @@ public class ECLinkStore
117 private final Logger log = getLogger(getClass()); 118 private final Logger log = getLogger(getClass());
118 119
119 private final Map<LinkKey, Link> links = Maps.newConcurrentMap(); 120 private final Map<LinkKey, Link> links = Maps.newConcurrentMap();
121 + private final Map<LinkKey, Set<ProviderId>> linkProviders = Maps.newConcurrentMap();
120 private EventuallyConsistentMap<Provided<LinkKey>, LinkDescription> linkDescriptions; 122 private EventuallyConsistentMap<Provided<LinkKey>, LinkDescription> linkDescriptions;
121 123
124 +
122 private ApplicationId appId; 125 private ApplicationId appId;
123 126
124 private static final MessageSubject LINK_INJECT_MESSAGE = new MessageSubject("inject-link-request"); 127 private static final MessageSubject LINK_INJECT_MESSAGE = new MessageSubject("inject-link-request");
...@@ -188,10 +191,10 @@ public class ECLinkStore ...@@ -188,10 +191,10 @@ public class ECLinkStore
188 }).build(); 191 }).build();
189 192
190 clusterCommunicator.addSubscriber(LINK_INJECT_MESSAGE, 193 clusterCommunicator.addSubscriber(LINK_INJECT_MESSAGE,
191 - SERIALIZER::decode, 194 + SERIALIZER::decode,
192 - this::injectLink, 195 + this::injectLink,
193 - SERIALIZER::encode, 196 + SERIALIZER::encode,
194 - SharedExecutors.getPoolThreadExecutor()); 197 + SharedExecutors.getPoolThreadExecutor());
195 198
196 linkDescriptions.addListener(linkTracker); 199 linkDescriptions.addListener(linkTracker);
197 200
...@@ -202,6 +205,7 @@ public class ECLinkStore ...@@ -202,6 +205,7 @@ public class ECLinkStore
202 public void deactivate() { 205 public void deactivate() {
203 linkDescriptions.removeListener(linkTracker); 206 linkDescriptions.removeListener(linkTracker);
204 linkDescriptions.destroy(); 207 linkDescriptions.destroy();
208 + linkProviders.clear();
205 links.clear(); 209 links.clear();
206 clusterCommunicator.removeSubscriber(LINK_INJECT_MESSAGE); 210 clusterCommunicator.removeSubscriber(LINK_INJECT_MESSAGE);
207 netCfgService.removeListener(cfgListener); 211 netCfgService.removeListener(cfgListener);
...@@ -273,10 +277,10 @@ public class ECLinkStore ...@@ -273,10 +277,10 @@ public class ECLinkStore
273 return null; 277 return null;
274 } 278 }
275 return Futures.getUnchecked(clusterCommunicator.sendAndReceive(new Provided<>(linkDescription, providerId), 279 return Futures.getUnchecked(clusterCommunicator.sendAndReceive(new Provided<>(linkDescription, providerId),
276 - LINK_INJECT_MESSAGE, 280 + LINK_INJECT_MESSAGE,
277 - SERIALIZER::encode, 281 + SERIALIZER::encode,
278 - SERIALIZER::decode, 282 + SERIALIZER::decode,
279 - dstNodeId)); 283 + dstNodeId));
280 } 284 }
281 } 285 }
282 286
...@@ -295,16 +299,24 @@ public class ECLinkStore ...@@ -295,16 +299,24 @@ public class ECLinkStore
295 private LinkDescription createOrUpdateLinkInternal(LinkDescription current, LinkDescription updated) { 299 private LinkDescription createOrUpdateLinkInternal(LinkDescription current, LinkDescription updated) {
296 if (current != null) { 300 if (current != null) {
297 // we only allow transition from INDIRECT -> DIRECT 301 // we only allow transition from INDIRECT -> DIRECT
298 - return new DefaultLinkDescription( 302 + return new DefaultLinkDescription(
299 - current.src(), 303 + current.src(),
300 - current.dst(), 304 + current.dst(),
301 - current.type() == DIRECT ? DIRECT : updated.type(), 305 + current.type() == DIRECT ? DIRECT : updated.type(),
302 - current.isExpected(), 306 + current.isExpected(),
303 - union(current.annotations(), updated.annotations())); 307 + union(current.annotations(), updated.annotations()));
304 } 308 }
305 return updated; 309 return updated;
306 } 310 }
307 311
312 + private Set<ProviderId> createOrUpdateLinkProviders(Set<ProviderId> current, ProviderId providerId) {
313 + if (current == null) {
314 + current = Sets.newConcurrentHashSet();
315 + }
316 + current.add(providerId);
317 + return current;
318 + }
319 +
308 private LinkEvent refreshLinkCache(LinkKey linkKey) { 320 private LinkEvent refreshLinkCache(LinkKey linkKey) {
309 AtomicReference<LinkEvent.Type> eventType = new AtomicReference<>(); 321 AtomicReference<LinkEvent.Type> eventType = new AtomicReference<>();
310 Link link = links.compute(linkKey, (key, existingLink) -> { 322 Link link = links.compute(linkKey, (key, existingLink) -> {
...@@ -313,11 +325,11 @@ public class ECLinkStore ...@@ -313,11 +325,11 @@ public class ECLinkStore
313 eventType.set(LINK_ADDED); 325 eventType.set(LINK_ADDED);
314 return newLink; 326 return newLink;
315 } else if (existingLink.state() != newLink.state() || 327 } else if (existingLink.state() != newLink.state() ||
316 - existingLink.isExpected() != newLink.isExpected() || 328 + existingLink.isExpected() != newLink.isExpected() ||
317 - (existingLink.type() == INDIRECT && newLink.type() == DIRECT) || 329 + (existingLink.type() == INDIRECT && newLink.type() == DIRECT) ||
318 - !AnnotationsUtil.isEqual(existingLink.annotations(), newLink.annotations())) { 330 + !AnnotationsUtil.isEqual(existingLink.annotations(), newLink.annotations())) {
319 - eventType.set(LINK_UPDATED); 331 + eventType.set(LINK_UPDATED);
320 - return newLink; 332 + return newLink;
321 } else { 333 } else {
322 return existingLink; 334 return existingLink;
323 } 335 }
...@@ -326,20 +338,16 @@ public class ECLinkStore ...@@ -326,20 +338,16 @@ public class ECLinkStore
326 } 338 }
327 339
328 private Set<ProviderId> getAllProviders(LinkKey linkKey) { 340 private Set<ProviderId> getAllProviders(LinkKey linkKey) {
329 - return linkDescriptions.keySet() 341 + return linkProviders.getOrDefault(linkKey, Sets.newConcurrentHashSet());
330 - .stream()
331 - .filter(key -> key.key().equals(linkKey))
332 - .map(key -> key.providerId())
333 - .collect(Collectors.toSet());
334 } 342 }
335 343
336 private ProviderId getBaseProviderId(LinkKey linkKey) { 344 private ProviderId getBaseProviderId(LinkKey linkKey) {
337 Set<ProviderId> allProviders = getAllProviders(linkKey); 345 Set<ProviderId> allProviders = getAllProviders(linkKey);
338 if (allProviders.size() > 0) { 346 if (allProviders.size() > 0) {
339 return allProviders.stream() 347 return allProviders.stream()
340 - .filter(p -> !p.isAncillary()) 348 + .filter(p -> !p.isAncillary())
341 - .findFirst() 349 + .findFirst()
342 - .orElse(Iterables.getFirst(allProviders, null)); 350 + .orElse(Iterables.getFirst(allProviders, null));
343 } 351 }
344 return null; 352 return null;
345 } 353 }
...@@ -356,11 +364,14 @@ public class ECLinkStore ...@@ -356,11 +364,14 @@ public class ECLinkStore
356 annotations.set(merge(annotations.get(), base.annotations())); 364 annotations.set(merge(annotations.get(), base.annotations()));
357 365
358 getAllProviders(linkKey).stream() 366 getAllProviders(linkKey).stream()
359 - .map(p -> new Provided<>(linkKey, p)) 367 + .map(p -> new Provided<>(linkKey, p))
360 - .forEach(key -> { 368 + .forEach(key -> {
361 - annotations.set(merge(annotations.get(), 369 + LinkDescription linkDescription = linkDescriptions.get(key);
362 - linkDescriptions.get(key).annotations())); 370 + if (linkDescription != null) {
363 - }); 371 + annotations.set(merge(annotations.get(),
372 + linkDescription.annotations()));
373 + }
374 + });
364 375
365 Link.State initialLinkState; 376 Link.State initialLinkState;
366 377
...@@ -375,8 +386,6 @@ public class ECLinkStore ...@@ -375,8 +386,6 @@ public class ECLinkStore
375 } 386 }
376 387
377 388
378 -
379 -
380 return DefaultLink.builder() 389 return DefaultLink.builder()
381 .providerId(baseProviderId) 390 .providerId(baseProviderId)
382 .src(src) 391 .src(src)
...@@ -394,8 +403,8 @@ public class ECLinkStore ...@@ -394,8 +403,8 @@ public class ECLinkStore
394 // Note: INDIRECT -> DIRECT transition only 403 // Note: INDIRECT -> DIRECT transition only
395 // so that BDDP discovered Link will not overwrite LDDP Link 404 // so that BDDP discovered Link will not overwrite LDDP Link
396 if (oldLink.state() != newLink.state() || 405 if (oldLink.state() != newLink.state() ||
397 - (oldLink.type() == INDIRECT && newLink.type() == DIRECT) || 406 + (oldLink.type() == INDIRECT && newLink.type() == DIRECT) ||
398 - !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) { 407 + !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) {
399 408
400 links.put(key, newLink); 409 links.put(key, newLink);
401 return new LinkEvent(LINK_UPDATED, newLink); 410 return new LinkEvent(LINK_UPDATED, newLink);
...@@ -447,6 +456,7 @@ public class ECLinkStore ...@@ -447,6 +456,7 @@ public class ECLinkStore
447 Link removedLink = links.remove(linkKey); 456 Link removedLink = links.remove(linkKey);
448 if (removedLink != null) { 457 if (removedLink != null) {
449 getAllProviders(linkKey).forEach(p -> linkDescriptions.remove(new Provided<>(linkKey, p))); 458 getAllProviders(linkKey).forEach(p -> linkDescriptions.remove(new Provided<>(linkKey, p)));
459 + linkProviders.remove(linkKey);
450 return new LinkEvent(LINK_REMOVED, removedLink); 460 return new LinkEvent(LINK_REMOVED, removedLink);
451 } 461 }
452 return null; 462 return null;
...@@ -475,9 +485,12 @@ public class ECLinkStore ...@@ -475,9 +485,12 @@ public class ECLinkStore
475 @Override 485 @Override
476 public void event(EventuallyConsistentMapEvent<Provided<LinkKey>, LinkDescription> event) { 486 public void event(EventuallyConsistentMapEvent<Provided<LinkKey>, LinkDescription> event) {
477 if (event.type() == PUT) { 487 if (event.type() == PUT) {
488 + linkProviders.compute(event.key().key(), (k, v) ->
489 + createOrUpdateLinkProviders(v, event.key().providerId()));
478 notifyDelegate(refreshLinkCache(event.key().key())); 490 notifyDelegate(refreshLinkCache(event.key().key()));
479 } else if (event.type() == REMOVE) { 491 } else if (event.type() == REMOVE) {
480 notifyDelegate(purgeLinkCache(event.key().key())); 492 notifyDelegate(purgeLinkCache(event.key().key()));
493 + linkProviders.remove(event.key().key());
481 } 494 }
482 } 495 }
483 } 496 }
...@@ -521,8 +534,8 @@ public class ECLinkStore ...@@ -521,8 +534,8 @@ public class ECLinkStore
521 // Configuration properties factory 534 // Configuration properties factory
522 private final ConfigFactory factory = 535 private final ConfigFactory factory =
523 new ConfigFactory<ApplicationId, CoreConfig>(APP_SUBJECT_FACTORY, 536 new ConfigFactory<ApplicationId, CoreConfig>(APP_SUBJECT_FACTORY,
524 - CoreConfig.class, 537 + CoreConfig.class,
525 - "core") { 538 + "core") {
526 @Override 539 @Override
527 public CoreConfig createConfig() { 540 public CoreConfig createConfig() {
528 return new CoreConfig(); 541 return new CoreConfig();
......