Rework OffsetMap.remove() and share empty arrays 23/70623/6
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 7 Apr 2018 12:20:39 +0000 (14:20 +0200)
committerClaudio David Gasparini <claudio.gasparini@pantheon.tech>
Thu, 26 Apr 2018 09:15:08 +0000 (09:15 +0000)
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: I9e44ec0eb984f8614d307dd679bed8db0739478a
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/BaseComplexRouteEntry.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 d6854b0b20e9c244ddd4d502d798aef568bf381c..f448359e4a253bb4556e000ba32fc165afcbc841 100644 (file)
@@ -46,11 +46,13 @@ import org.slf4j.LoggerFactory;
 public abstract class AddPathAbstractRouteEntry extends AbstractRouteEntry {
 
     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 ContainerNode[] values = new ContainerNode[0];
-    protected Long[] pathsId = new Long[0];
+    protected ContainerNode[] values = EMPTY_ATTRIBUTES;
+    protected Long[] pathsId = EMPTY_PATHS_ID;
     private long pathIdCounter = 0L;
     private boolean oldNonAddPathBestPathTheSame;
     private List<AddPathBestPath> newBestPathToBeAdvertised;
@@ -108,8 +110,8 @@ public abstract class AddPathAbstractRouteEntry extends AbstractRouteEntry {
      */
     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 2c829c4ad95349a5d246d5654336bb54400d77a0..b4944aa3ce9cd7af8c47baa87376538c346a8d1d 100644 (file)
@@ -28,7 +28,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 747496abd30e3d8a89bfe100064d127d757dd65e..8c7a791a666359b269c9478e9d23030a1e1551e8 100644 (file)
@@ -31,7 +31,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 4cae936af56f007ce20a079998ebefb2d5857fc5..37b1421f0d5865d6aa3716f0d1a82ab92e04aeea 100644 (file)
@@ -32,7 +32,6 @@ import org.slf4j.LoggerFactory;
 @NotThreadSafe
 abstract class BaseAbstractRouteEntry extends AbstractRouteEntry {
     private static final Logger LOG = LoggerFactory.getLogger(BaseAbstractRouteEntry.class);
-    private static final ContainerNode[] EMPTY_ATTRIBUTES = new ContainerNode[0];
     private OffsetMap offsets = OffsetMap.EMPTY;
     private ContainerNode[] values = EMPTY_ATTRIBUTES;
     private BaseBestPath bestPath;
@@ -46,7 +45,7 @@ abstract class BaseAbstractRouteEntry extends AbstractRouteEntry {
      * @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 4195a5c6e12f4d295dbf9baa99ed15a7446e7467..4a40bdd24e028160b599827e6f62bc023648b9d5 100644 (file)
@@ -38,7 +38,7 @@ final class BaseComplexRouteEntry 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..890e5ff28f057f7f823c663e189a21ea2c404abd 100644 (file)
@@ -42,11 +42,13 @@ 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 +84,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 +121,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 ec2a4a0256edb2bf81c0a750cbab896e49183f7a..9d1864f683edfd8857652e9f4605451ebb927306 100644 (file)
@@ -31,6 +31,8 @@ import org.slf4j.LoggerFactory;
 
 public abstract class AbstractRouteEntry implements RouteEntry {
     protected static final NodeIdentifier ROUTES_IDENTIFIER = new NodeIdentifier(Routes.QNAME);
+    protected static final ContainerNode[] EMPTY_ATTRIBUTES = new ContainerNode[0];
+
     private static final Logger LOG = LoggerFactory.getLogger(AbstractRouteEntry.class);
 
     protected static void fillLocRib(final YangInstanceIdentifier routeTarget, final NormalizedNode<?, ?> value,