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;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -117,8 +118,10 @@ public class ECLinkStore
private final Logger log = getLogger(getClass());
private final Map<LinkKey, Link> links = Maps.newConcurrentMap();
private final Map<LinkKey, Set<ProviderId>> linkProviders = Maps.newConcurrentMap();
private EventuallyConsistentMap<Provided<LinkKey>, LinkDescription> linkDescriptions;
private ApplicationId appId;
private static final MessageSubject LINK_INJECT_MESSAGE = new MessageSubject("inject-link-request");
......@@ -202,6 +205,7 @@ public class ECLinkStore
public void deactivate() {
linkDescriptions.removeListener(linkTracker);
linkDescriptions.destroy();
linkProviders.clear();
links.clear();
clusterCommunicator.removeSubscriber(LINK_INJECT_MESSAGE);
netCfgService.removeListener(cfgListener);
......@@ -305,6 +309,14 @@ public class ECLinkStore
return updated;
}
private Set<ProviderId> createOrUpdateLinkProviders(Set<ProviderId> current, ProviderId providerId) {
if (current == null) {
current = Sets.newConcurrentHashSet();
}
current.add(providerId);
return current;
}
private LinkEvent refreshLinkCache(LinkKey linkKey) {
AtomicReference<LinkEvent.Type> eventType = new AtomicReference<>();
Link link = links.compute(linkKey, (key, existingLink) -> {
......@@ -326,11 +338,7 @@ public class ECLinkStore
}
private Set<ProviderId> getAllProviders(LinkKey linkKey) {
return linkDescriptions.keySet()
.stream()
.filter(key -> key.key().equals(linkKey))
.map(key -> key.providerId())
.collect(Collectors.toSet());
return linkProviders.getOrDefault(linkKey, Sets.newConcurrentHashSet());
}
private ProviderId getBaseProviderId(LinkKey linkKey) {
......@@ -358,8 +366,11 @@ public class ECLinkStore
getAllProviders(linkKey).stream()
.map(p -> new Provided<>(linkKey, p))
.forEach(key -> {
LinkDescription linkDescription = linkDescriptions.get(key);
if (linkDescription != null) {
annotations.set(merge(annotations.get(),
linkDescriptions.get(key).annotations()));
linkDescription.annotations()));
}
});
Link.State initialLinkState;
......@@ -375,8 +386,6 @@ public class ECLinkStore
}
return DefaultLink.builder()
.providerId(baseProviderId)
.src(src)
......@@ -447,6 +456,7 @@ public class ECLinkStore
Link removedLink = links.remove(linkKey);
if (removedLink != null) {
getAllProviders(linkKey).forEach(p -> linkDescriptions.remove(new Provided<>(linkKey, p)));
linkProviders.remove(linkKey);
return new LinkEvent(LINK_REMOVED, removedLink);
}
return null;
......@@ -475,9 +485,12 @@ public class ECLinkStore
@Override
public void event(EventuallyConsistentMapEvent<Provided<LinkKey>, LinkDescription> event) {
if (event.type() == PUT) {
linkProviders.compute(event.key().key(), (k, v) ->
createOrUpdateLinkProviders(v, event.key().providerId()));
notifyDelegate(refreshLinkCache(event.key().key()));
} else if (event.type() == REMOVE) {
notifyDelegate(purgeLinkCache(event.key().key()));
linkProviders.remove(event.key().key());
}
}
}
......