BUG-2383: introduce OffsetMap 36/15936/6
authorRobert Varga <rovarga@cisco.com>
Mon, 2 Mar 2015 16:02:33 +0000 (17:02 +0100)
committerDana Kutenicsova <dkutenic@cisco.com>
Thu, 5 Mar 2015 08:49:51 +0000 (09:49 +0100)
For the sectionprocess we will need a compact way of tracing
peer/attribute mappings. Storing things in array is the most compact
form, but we need to manage a lookup table. This is the role of
OffsetMap, which maps an UnsignedInteger (e.g. a BGP Identifier) to an
offset. We then need to only allocate a single array for each entry to
hold the actual values.

Change-Id: I7c4c8b841cca0330f9646e5e629a824fd929f181
Signed-off-by: Robert Varga <rovarga@cisco.com>
bgp/rib-impl/pom.xml
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/OffsetMap.java [new file with mode: 0644]

index cca459b28a0a3550330bd6cadbbf339bf76a9684..1baf98207a631e50f6d38647493d58dd919bc969 100644 (file)
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-binding</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>concepts</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-common</artifactId>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
-            <artifactId>concepts</artifactId>
+            <artifactId>yang-data-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-impl</artifactId>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools.model</groupId>
             <artifactId>yang-parser-impl</artifactId>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.opendaylight.yangtools</groupId>
-            <artifactId>yang-data-impl</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/OffsetMap.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/OffsetMap.java
new file mode 100644 (file)
index 0000000..1dcb46d
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.bgp.rib.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.primitives.UnsignedInteger;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Set;
+
+/**
+ * A map of Router identifier to an offset. Used to maintain a simple
+ * offset-based lookup across multiple {@link RouteEntry} objects,
+ * which share either contributors or consumers.
+ *
+ * We also provide utility reformat methods, which provide access to
+ * array members and array management features.
+ */
+final class OffsetMap {
+    static final OffsetMap EMPTY = new OffsetMap(Collections.<UnsignedInteger>emptySet());
+    private static final LoadingCache<Set<UnsignedInteger>, OffsetMap> OFFSETMAPS = CacheBuilder.newBuilder().weakValues().build(new CacheLoader<Set<UnsignedInteger>, OffsetMap>() {
+        @Override
+        public OffsetMap load(final Set<UnsignedInteger> key) throws Exception {
+            return new OffsetMap(key);
+        }
+    });
+    private static final Comparator<UnsignedInteger> IPV4_COMPARATOR = new Comparator<UnsignedInteger>() {
+        @Override
+        public int compare(final UnsignedInteger o1, final UnsignedInteger o2) {
+            return o1.compareTo(o2);
+        }
+    };
+    private final UnsignedInteger[] routerIds;
+
+    private OffsetMap(final Set<UnsignedInteger> routerIds) {
+        final UnsignedInteger[] array = routerIds.toArray(new UnsignedInteger[0]);
+        Arrays.sort(array, IPV4_COMPARATOR);
+        this.routerIds = array;
+    }
+
+    UnsignedInteger getRouterId(final int offset) {
+        Preconditions.checkArgument(offset >= 0);
+        return this.routerIds[offset];
+    }
+
+    int offsetOf(final UnsignedInteger routerId) {
+        return Arrays.binarySearch(this.routerIds, routerId, IPV4_COMPARATOR);
+    }
+
+    int size() {
+        return this.routerIds.length;
+    }
+
+    OffsetMap with(final UnsignedInteger routerId) {
+        // TODO: we could make this faster if we had an array-backed Set and requiring
+        //       the caller to give us the result of offsetOf() -- as that indicates
+        //       where to insert the new routerId while maintaining the sorted nature
+        //       of the array
+        final Builder<UnsignedInteger> b = ImmutableSet.builder();
+        b.add(this.routerIds);
+        b.add(routerId);
+
+        return OFFSETMAPS.getUnchecked(b.build());
+    }
+
+    <T> T getValue(final T[] array, final int offset) {
+        Preconditions.checkArgument(offset >= 0, "Invalid negative offset {}", offset);
+        return array[offset];
+    }
+
+    <T> void setValue(final T[] array, final int offset, final T value) {
+        Preconditions.checkArgument(offset >= 0, "Invalid negative offset {}", offset);
+        array[offset] = value;
+    }
+
+    <T> T[] expand(final OffsetMap oldOffsets, final T[] oldArray, final int offset) {
+        @SuppressWarnings("unchecked")
+        final T[] ret = (T[]) new Object[this.routerIds.length];
+        final int oldSize = oldOffsets.routerIds.length;
+
+        System.arraycopy(oldArray, 0, ret, 0, offset);
+        System.arraycopy(oldArray, offset, ret, offset + 1, oldSize - offset);
+
+        return ret;
+    }
+}