[AETHER-72] Refactoring RouteService
- to use bulk updates interface
- to use new getRoutesForNextHops API
- to use multi-thread resolver
- to use multi-thread hostexec
- to use a concurrent hashmap instead of synchronized
- to use a non-blocking resolved store
Additionally updates unit tests
Change-Id: Id960abd0f2a1b03066ce34b6a2f72b76566bb58c
diff --git a/apps/route-service/app/src/main/java/org/onosproject/routeservice/store/LocalRouteStore.java b/apps/route-service/app/src/main/java/org/onosproject/routeservice/store/LocalRouteStore.java
index 04b0f38..c286ab1 100644
--- a/apps/route-service/app/src/main/java/org/onosproject/routeservice/store/LocalRouteStore.java
+++ b/apps/route-service/app/src/main/java/org/onosproject/routeservice/store/LocalRouteStore.java
@@ -16,6 +16,7 @@
package org.onosproject.routeservice.store;
+import com.google.common.collect.Sets;
import com.googlecode.concurrenttrees.common.KeyValuePair;
import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
@@ -35,6 +36,7 @@
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -82,11 +84,27 @@
}
@Override
+ public void updateRoutes(Collection<Route> routes) {
+ Map<RouteTableId, Set<Route>> computedTables = computeRouteTablesFromRoutes(routes);
+ computedTables.forEach(
+ ((routeTableId, routesToAdd) -> getDefaultRouteTable(routeTableId).update(routesToAdd))
+ );
+ }
+
+ @Override
public void removeRoute(Route route) {
getDefaultRouteTable(route).remove(route);
}
@Override
+ public void removeRoutes(Collection<Route> routes) {
+ Map<RouteTableId, Set<Route>> computedTables = computeRouteTablesFromRoutes(routes);
+ computedTables.forEach(
+ ((routeTableId, routesToRemove) -> getDefaultRouteTable(routeTableId).remove(routesToRemove))
+ );
+ }
+
+ @Override
public void replaceRoute(Route route) {
getDefaultRouteTable(route).replace(route);
}
@@ -111,6 +129,15 @@
}
@Override
+ public Collection<RouteSet> getRoutesForNextHops(Collection<IpAddress> nextHops) {
+ Map<RouteTableId, Set<IpAddress>> computedTables = computeRouteTablesFromIps(nextHops);
+ return computedTables.entrySet().stream()
+ .map(entry -> getDefaultRouteTable(entry.getKey()).getRoutesForNextHops(entry.getValue()))
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList());
+ }
+
+ @Override
public RouteSet getRoutes(IpPrefix prefix) {
return getDefaultRouteTable(prefix.address()).getRoutes(prefix);
}
@@ -124,6 +151,30 @@
return routeTables.get(routeTableId);
}
+ private RouteTable getDefaultRouteTable(RouteTableId routeTableId) {
+ return routeTables.get(routeTableId);
+ }
+
+ private Map<RouteTableId, Set<Route>> computeRouteTablesFromRoutes(Collection<Route> routes) {
+ Map<RouteTableId, Set<Route>> computedTables = new HashMap<>();
+ routes.forEach(route -> {
+ RouteTableId routeTableId = (route.prefix().address().isIp4()) ? IPV4 : IPV6;
+ Set<Route> tempRoutes = computedTables.computeIfAbsent(routeTableId, k -> Sets.newHashSet());
+ tempRoutes.add(route);
+ });
+ return computedTables;
+ }
+
+ private Map<RouteTableId, Set<IpAddress>> computeRouteTablesFromIps(Collection<IpAddress> ipAddresses) {
+ Map<RouteTableId, Set<IpAddress>> computedTables = new HashMap<>();
+ ipAddresses.forEach(ipAddress -> {
+ RouteTableId routeTableId = (ipAddress.isIp4()) ? IPV4 : IPV6;
+ Set<IpAddress> tempIpAddresses = computedTables.computeIfAbsent(routeTableId, k -> Sets.newHashSet());
+ tempIpAddresses.add(ipAddress);
+ });
+ return computedTables;
+ }
+
/**
* Route table into which routes can be placed.
*/
@@ -163,6 +214,17 @@
}
/**
+ * Adds or updates the routes in the route table.
+ *
+ * @param routes routes to update
+ */
+ public void update(Collection<Route> routes) {
+ synchronized (this) {
+ routes.forEach(this::update);
+ }
+ }
+
+ /**
* Removes the route from the route table.
*
* @param route route to remove
@@ -180,6 +242,17 @@
}
/**
+ * Adds or updates the routes in the route table.
+ *
+ * @param routes routes to update
+ */
+ public void remove(Collection<Route> routes) {
+ synchronized (this) {
+ routes.forEach(this::remove);
+ }
+ }
+
+ /**
* Replace the route in the route table.
*/
public void replace(Route route) {
@@ -199,6 +272,28 @@
.collect(Collectors.toSet());
}
+ /**
+ * Returns the routes pointing to the next hops.
+ *
+ * @param ips next hops IP addresses
+ * @return routes for the next hop
+ */
+ public Collection<RouteSet> getRoutesForNextHops(Collection<IpAddress> ips) {
+ // First create a reduced snapshot of the store iterating one time the map
+ Map<IpPrefix, Set<Route>> filteredRouteStore = new HashMap<>();
+ routes.values().stream()
+ .filter(r -> ips.contains(r.nextHop()))
+ .forEach(r -> {
+ Collection<Route> tempRoutes = filteredRouteStore.computeIfAbsent(
+ r.prefix(), k -> Sets.newHashSet());
+ tempRoutes.add(r);
+ });
+ // Return the collection of the routeSet we have to resolve
+ return filteredRouteStore.entrySet().stream()
+ .map(entry -> new RouteSet(id, entry.getKey(), entry.getValue()))
+ .collect(Collectors.toSet());
+ }
+
public RouteSet getRoutes(IpPrefix prefix) {
Route route = routes.get(prefix);
if (route != null) {