Rework OffsetMap.remove() and share empty arrays 02/70702/4
authorClaudio D. Gasparini <claudio.gasparini@pantheon.tech>
Tue, 10 Apr 2018 09:46:04 +0000 (11:46 +0200)
committerClaudio D. Gasparini <claudio.gasparini@pantheon.tech>
Tue, 10 Apr 2018 09:46:04 +0000 (11:46 +0200)
Empty arrays are immutable, hence we can share those instances,
reducing overheads. Also updates OffsetMap.remove() to take an
empty array argument, which will be used when the map would become
empty.

Change-Id: I58116eddce3d8b1a1f7d049c0c1f12fcd9f79966
Signed-off-by: Claudio D. Gasparini <claudio.gasparini@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/add/AddPathAbstractRouteEntry.java
bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/add/OffsetMap.java
bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/add/all/paths/ComplexRouteEntry.java
bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/add/n/paths/ComplexRouteEntry.java
bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/base/BaseAbstractRouteEntry.java
bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/base/ComplexRouteEntry.java
bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/base/OffsetMap.java
bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/spi/AbstractRouteEntry.java

index 6fe70b0554703d08bf0ac162dd3dc71d8f1f1188..c37e8db8c6611016f38f3cb3f75f692d3b8d5510 100644 (file)
@@ -48,11 +48,13 @@ import org.slf4j.LoggerFactory;
 public abstract class AddPathAbstractRouteEntry extends AbstractRouteEntry<AddPathBestPath> {
 
     private static final Logger LOG = LoggerFactory.getLogger(AddPathAbstractRouteEntry.class);
+    private static final Long[] EMPTY_PATHS_ID = new Long[0];
+
     private List<AddPathBestPath> bestPath;
     private List<AddPathBestPath> bestPathRemoved;
     protected OffsetMap offsets = OffsetMap.EMPTY;
-    protected Attributes[] values = new Attributes[0];
-    protected Long[] pathsId = new Long[0];
+    protected Attributes[] values = EMPTY_ATTRIBUTES;
+    protected Long[] pathsId =  EMPTY_PATHS_ID;
     private long pathIdCounter = 0L;
     private boolean oldNonAddPathBestPathTheSame;
     private List<AddPathBestPath> newBestPathToBeAdvertised;
@@ -106,8 +108,8 @@ public abstract class AddPathAbstractRouteEntry extends AbstractRouteEntry<AddPa
      */
     protected final boolean removeRoute(final RouteKey key, final int offset) {
         final long pathId = this.offsets.getValue(this.pathsId, offset);
-        this.values = this.offsets.removeValue(this.values, offset);
-        this.pathsId = this.offsets.removeValue(this.pathsId, offset);
+        this.values = this.offsets.removeValue(this.values, offset, EMPTY_ATTRIBUTES);
+        this.pathsId = this.offsets.removeValue(this.pathsId, offset, EMPTY_PATHS_ID);
         this.offsets = this.offsets.without(key);
         if (this.removedPaths == null) {
             this.removedPaths = new ArrayList<>();
index 9887dd3bd60ec5f8b9fa51e072fb2db7b2de4529..5f6de622dcba0434b0ddcf8204a979ac3aa28a61 100644 (file)
@@ -43,12 +43,13 @@ public final class OffsetMap {
                 }
             });
     private static final Comparator<RouteKey> COMPARATOR = RouteKey::compareTo;
+    private static final RouteKey[] EMPTY_KEYS = new RouteKey[0];
     static final OffsetMap EMPTY = new OffsetMap(Collections.emptySet());
 
     private final RouteKey[] routeKeys;
 
     private OffsetMap(final Set<RouteKey> routerIds) {
-        final RouteKey[] array = routerIds.toArray(new RouteKey[0]);
+        final RouteKey[] array = routerIds.toArray(EMPTY_KEYS);
         Arrays.sort(array, COMPARATOR);
         this.routeKeys = array;
     }
@@ -79,7 +80,7 @@ public final class OffsetMap {
         if (index < 0) {
             LOG.trace("Router key not found", key);
         } else {
-            builder.add(removeValue(this.routeKeys, index));
+            builder.add(removeValue(this.routeKeys, index, EMPTY_KEYS));
         }
         return OFFSETMAPS.getUnchecked(builder.build());
     }
@@ -116,15 +117,21 @@ public final class OffsetMap {
         return ret;
     }
 
-    public <T> T[] removeValue(final T[] oldArray, final int offset) {
+    public <T> T[] removeValue(final T[] oldArray, final int offset, final T[] emptyArray) {
         final int length = oldArray.length;
         Preconditions.checkArgument(offset >= 0, NEGATIVEOFFSET, offset);
         Preconditions.checkArgument(offset < this.routeKeys.length, INVALIDOFFSET, offset, length);
 
-        final T[] ret = (T[]) Array.newInstance(oldArray.getClass().getComponentType(), length - 1);
+        final int newLength = length - 1;
+        if (newLength == 0) {
+            Preconditions.checkArgument(emptyArray.length == 0);
+            return emptyArray;
+        }
+
+        final T[] ret = (T[]) Array.newInstance(oldArray.getClass().getComponentType(), newLength);
         System.arraycopy(oldArray, 0, ret, 0, offset);
-        if (offset < length - 1) {
-            System.arraycopy(oldArray, offset + 1, ret, offset, length - offset - 1);
+        if (offset < newLength) {
+            System.arraycopy(oldArray, offset + 1, ret, offset, newLength - offset);
         }
 
         return ret;
index 0cc7618005d013922fb104b4bb05c128a01f0ec0..2b9935dd433870e4087ed78aa6357756ed048302 100644 (file)
@@ -16,7 +16,6 @@ import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
 
 final class ComplexRouteEntry extends AbstractAllPathsRouteEntry {
-    private static final Route[] EMPTY_VALUES = new Route[0];
     private Route[] values = EMPTY_VALUES;
 
     ComplexRouteEntry(final BGPPeerTracker peerTracker) {
@@ -28,7 +27,7 @@ final class ComplexRouteEntry extends AbstractAllPathsRouteEntry {
         final RouteKey key = new RouteKey(routerId, remotePathId);
         final OffsetMap map = getOffsets();
         final int offset = map.offsetOf(key);
-        this.values = map.removeValue(this.values, offset);
+        this.values = map.removeValue(this.values, offset, EMPTY_VALUES);
         return removeRoute(key, offset);
     }
 
index 651b1e2ca259b71b40a392c1521d729bb20bf3bf..9bc4c38f744075759ffc220cd93732d039afc9a2 100644 (file)
@@ -16,7 +16,6 @@ import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
 
 final class ComplexRouteEntry extends AbstractNPathsRouteEntry {
-    private static final Route[] EMPTY_VALUES = new Route[0];
     private Route[] values = EMPTY_VALUES;
 
     ComplexRouteEntry(final long npaths, final BGPPeerTracker peerTracker) {
@@ -28,7 +27,7 @@ final class ComplexRouteEntry extends AbstractNPathsRouteEntry {
         final RouteKey key = new RouteKey(routerId, remotePathId);
         final OffsetMap map = getOffsets();
         final int offset = map.offsetOf(key);
-        this.values = map.removeValue(this.values, offset);
+        this.values = map.removeValue(this.values, offset, EMPTY_VALUES);
         return removeRoute(key, offset);
     }
 
index 4e8c178714fd6f2e7246ed9b53e0ad3506d6765f..501a7a90f93ec343f5af4df5d3d387d2a77506c5 100644 (file)
@@ -37,7 +37,6 @@ import org.slf4j.LoggerFactory;
 @NotThreadSafe
 abstract class BaseAbstractRouteEntry extends AbstractRouteEntry<BaseBestPath> {
     private static final Logger LOG = LoggerFactory.getLogger(BaseAbstractRouteEntry.class);
-    private static final Attributes[] EMPTY_ATTRIBUTES = new Attributes[0];
     private OffsetMap offsets = OffsetMap.EMPTY;
     private Attributes[] values = EMPTY_ATTRIBUTES;
     private BaseBestPath bestPath;
@@ -55,7 +54,7 @@ abstract class BaseAbstractRouteEntry extends AbstractRouteEntry<BaseBestPath> {
      * @return true if its the last route
      */
     protected final boolean removeRoute(final UnsignedInteger routerId, final int offset) {
-        this.values = this.offsets.removeValue(this.values, offset);
+        this.values = this.offsets.removeValue(this.values, offset, EMPTY_ATTRIBUTES);
         this.offsets = this.offsets.without(routerId);
         return this.offsets.isEmpty();
     }
index 60529c64cde18a9b2127a2e31c90ba90422041be..6cbbcb2b7a63f8a0edd58b3b0dc0390afca7919c 100644 (file)
@@ -13,7 +13,6 @@ import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
 
 final class ComplexRouteEntry extends BaseAbstractRouteEntry {
-    private static final Route[] EMPTY_VALUES = new Route[0];
     private Route[] values = EMPTY_VALUES;
 
     ComplexRouteEntry(final BGPPeerTracker peerTracker) {
@@ -38,7 +37,7 @@ final class ComplexRouteEntry extends BaseAbstractRouteEntry {
     public boolean removeRoute(final UnsignedInteger routerId, final long remotePathId) {
         final OffsetMap map = getOffsets();
         final int offset = map.offsetOf(routerId);
-        this.values = map.removeValue(this.values, offset);
+        this.values = map.removeValue(this.values, offset, EMPTY_VALUES);
         return removeRoute(routerId, offset);
     }
 
index 6ae03377b7e492087879cd1bac896b2d48883bf7..d07ccf3b51f05000ce02db4a79eea3528a02744a 100644 (file)
@@ -42,11 +42,12 @@ final class OffsetMap {
                 }
             });
     private static final Comparator<UnsignedInteger> COMPARATOR = UnsignedInteger::compareTo;
+    private static final UnsignedInteger[] EMPTY_KEYS = new UnsignedInteger[0];
     static final OffsetMap EMPTY = new OffsetMap(Collections.emptySet());
     private final UnsignedInteger[] routeKeys;
 
     private OffsetMap(final Set<UnsignedInteger> routerIds) {
-        final UnsignedInteger[] array = routerIds.toArray(new UnsignedInteger[0]);
+        final UnsignedInteger[] array = routerIds.toArray(EMPTY_KEYS);
         Arrays.sort(array, COMPARATOR);
         this.routeKeys = array;
     }
@@ -82,7 +83,7 @@ final class OffsetMap {
         if (index < 0) {
             LOG.trace("Router key not found", key);
         } else {
-            builder.add(removeValue(this.routeKeys, index));
+            builder.add(removeValue(this.routeKeys, index, EMPTY_KEYS));
         }
         return OFFSETMAPS.getUnchecked(builder.build());
     }
@@ -119,15 +120,21 @@ final class OffsetMap {
         return ret;
     }
 
-    public <T> T[] removeValue(final T[] oldArray, final int offset) {
+    public <T> T[] removeValue(final T[] oldArray, final int offset, final T[] emptyArray) {
         final int length = oldArray.length;
         Preconditions.checkArgument(offset >= 0, NEGATIVEOFFSET, offset);
         Preconditions.checkArgument(offset < this.routeKeys.length, INVALIDOFFSET, offset, length);
 
-        final T[] ret = (T[]) Array.newInstance(oldArray.getClass().getComponentType(), length - 1);
+        final int newLength = length - 1;
+        if (newLength == 0) {
+            Preconditions.checkArgument(emptyArray.length == 0);
+            return emptyArray;
+        }
+
+        final T[] ret = (T[]) Array.newInstance(oldArray.getClass().getComponentType(), newLength);
         System.arraycopy(oldArray, 0, ret, 0, offset);
-        if (offset < length - 1) {
-            System.arraycopy(oldArray, offset + 1, ret, offset, length - offset - 1);
+        if (offset < newLength) {
+            System.arraycopy(oldArray, offset + 1, ret, offset, newLength - offset);
         }
 
         return ret;
index ff1d164e266b67f513b0e14556c4e84bfcca3d9a..bfc1e76e2641ad50297b1acc026d74995b02a715 100644 (file)
@@ -16,12 +16,15 @@ import org.opendaylight.protocol.bgp.mode.api.RouteEntry;
 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
 import org.opendaylight.protocol.bgp.rib.spi.Peer;
 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.Attributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
 
 public abstract class AbstractRouteEntry<T extends BestPath> implements RouteEntry {
+    protected static final Attributes[] EMPTY_ATTRIBUTES = new Attributes[0];
+    protected static final Route[] EMPTY_VALUES = new Route[0];
     protected final BGPPeerTracker peerTracker;
 
     public AbstractRouteEntry(final BGPPeerTracker peerTracker) {