BUG-2383 : make LocalRIB count on complexity of the routes 54/18254/2
authorDana Kutenicsova <dkutenic@cisco.com>
Tue, 14 Apr 2015 11:29:30 +0000 (13:29 +0200)
committerDana Kutenicsova <dkutenic@cisco.com>
Tue, 14 Apr 2015 11:35:50 +0000 (13:35 +0200)
- by creating complex route we can ensure that no data
goes missing in LocalRIB

Change-Id: Ide263d4c277b8a2ab598f1a3ae2306b9ee031590
Signed-off-by: Robert Varga <rovarga@cisco.com>
Signed-off-by: Dana Kutenicsova <dkutenic@cisco.com>
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractRouteEntry.java [moved from bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouteEntry.java with 66% similarity]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ComplexRouteEntry.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/LocRibWriter.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/OffsetMap.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/SimpleRouteEntry.java [new file with mode: 0644]

similarity index 66%
rename from bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouteEntry.java
rename to bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractRouteEntry.java
index 9830b6af0c5ebcea1fb759cc9d4f2c14d168f57f..c92a78f220f65a2b37688003e3a1c71bdb6ba1c4 100644 (file)
@@ -10,7 +10,12 @@ package org.opendaylight.protocol.bgp.rib.impl;
 import com.google.common.primitives.UnsignedInteger;
 import java.util.Objects;
 import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -22,9 +27,9 @@ import org.slf4j.LoggerFactory;
  * where individual object overhead becomes the dominating factor.
  */
 @NotThreadSafe
-final class RouteEntry {
+abstract class AbstractRouteEntry {
 
-    private static final Logger LOG = LoggerFactory.getLogger(RouteEntry.class);
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractRouteEntry.class);
 
     private static final ContainerNode[] EMPTY_ATTRIBUTES = new ContainerNode[0];
 
@@ -32,7 +37,7 @@ final class RouteEntry {
     private ContainerNode[] values = EMPTY_ATTRIBUTES;
     private BestPath bestPath;
 
-    void addRoute(final UnsignedInteger routerId, final ContainerNode attributes) {
+    private int addRoute(final UnsignedInteger routerId, final ContainerNode attributes) {
         int offset = this.offsets.offsetOf(routerId);
         if (offset < 0) {
             final OffsetMap newOffsets = this.offsets.with(routerId);
@@ -44,13 +49,20 @@ final class RouteEntry {
         }
 
         this.offsets.setValue(this.values, offset, attributes);
+        LOG.trace("Added route from {} attributes {}", routerId, attributes);
+        return offset;
+    }
+
+    protected int addRoute(final UnsignedInteger routerId, final NodeIdentifier attributesIdentifier, final NormalizedNode<?, ?> data) {
+        LOG.trace("Find {} in {}", attributesIdentifier, data);
+        final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes.findNode(data, attributesIdentifier).orNull();
+        return addRoute(routerId, advertisedAttrs);
     }
 
     // Indicates whether this was the last route
-    boolean removeRoute(final UnsignedInteger routerId) {
+    protected final boolean removeRoute(final int offset) {
         if (this.offsets.size() != 1) {
             // FIXME: actually shrink the array
-            final int offset = this.offsets.offsetOf(routerId);
             this.offsets.setValue(this.values, offset, null);
             return false;
         } else {
@@ -59,7 +71,7 @@ final class RouteEntry {
     }
 
     // Indicates whether best has changed
-    boolean selectBest(final long localAs) {
+    final boolean selectBest(final long localAs) {
         /*
          * FIXME: optimize flaps by making sure we consider stability of currently-selected route.
          */
@@ -82,7 +94,18 @@ final class RouteEntry {
         return ret;
     }
 
-    public ContainerNode attributes() {
+    final ContainerNode attributes() {
         return this.bestPath.getState().getAttributes();
     }
+
+    protected final OffsetMap getOffsets() {
+        return this.offsets;
+    }
+
+    protected final UnsignedInteger getBestRouterId() {
+        return this.bestPath.getRouterId();
+    }
+
+    abstract boolean removeRoute(final UnsignedInteger routerId);
+    abstract MapEntryNode createValue(PathArgument routeId);
 }
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ComplexRouteEntry.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ComplexRouteEntry.java
new file mode 100644 (file)
index 0000000..071c64e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.primitives.UnsignedInteger;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+final class ComplexRouteEntry extends AbstractRouteEntry {
+    private static final MapEntryNode[] EMPTY_VALUES = new MapEntryNode[0];
+    private MapEntryNode[] values = EMPTY_VALUES;
+
+    @Override
+    protected int addRoute(final UnsignedInteger routerId, final NodeIdentifier attributesIdentifier, final NormalizedNode<?, ?> data) {
+        final OffsetMap oldMap = getOffsets();
+        final int offset = super.addRoute(routerId, attributesIdentifier, data);
+        final OffsetMap newMap = getOffsets();
+
+        if (!newMap.equals(oldMap)) {
+            this.values = newMap.expand(oldMap, this.values, offset);
+        }
+
+        newMap.setValue(this.values, offset, data);
+        return offset;
+    }
+
+    @Override
+    protected MapEntryNode createValue(final PathArgument routeId) {
+        final OffsetMap map = getOffsets();
+        final int offset = map.offsetOf(getBestRouterId());
+        return map.getValue(this.values, offset);
+    }
+
+    @Override
+    boolean removeRoute(final UnsignedInteger routerId) {
+        final OffsetMap map = getOffsets();
+        final int offset = map.offsetOf(routerId);
+
+        final boolean ret = removeRoute(offset);
+        // FIXME: actually shrink the array
+        map.setValue(this.values, offset, null);
+        return ret;
+    }
+}
index 4401aaa461cae499d3cc84de35b8da6fec6dad09..38f5dcf9926de805ecd029662f0f85f52c4fb85b 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.protocol.bgp.rib.impl;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.primitives.UnsignedInteger;
 import java.util.Arrays;
@@ -41,13 +42,9 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,7 +53,7 @@ final class LocRibWriter implements AutoCloseable, DOMDataTreeChangeListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(LocRibWriter.class);
 
-    private final Map<PathArgument, RouteEntry> routeEntries = new HashMap<>();
+    private final Map<PathArgument, AbstractRouteEntry> routeEntries = new HashMap<>();
     private final YangInstanceIdentifier locRibTarget;
     private final DOMTransactionChain chain;
     private final ExportPolicyPeerTracker peerPolicyTracker;
@@ -99,6 +96,14 @@ final class LocRibWriter implements AutoCloseable, DOMDataTreeChangeListener {
         this.peerPolicyTracker.close();
     }
 
+    private AbstractRouteEntry createEntry(final PathArgument routeId) {
+        final AbstractRouteEntry ret = this.ribSupport.isComplexRoute() ? new ComplexRouteEntry() : new SimpleRouteEntry();
+
+        this.routeEntries.put(routeId, ret);
+        LOG.trace("Created new entry for {}", routeId);
+        return ret;
+    }
+
     @Override
     public void onDataTreeChanged(final Collection<DataTreeCandidate> changes) {
         final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
@@ -107,7 +112,7 @@ final class LocRibWriter implements AutoCloseable, DOMDataTreeChangeListener {
          * We use two-stage processing here in hopes that we avoid duplicate
          * calculations when multiple peers have changed a particular entry.
          */
-        final Map<RouteUpdateKey, RouteEntry> toUpdate = new HashMap<>();
+        final Map<RouteUpdateKey, AbstractRouteEntry> toUpdate = new HashMap<>();
         for (final DataTreeCandidate tc : changes) {
             final YangInstanceIdentifier path = tc.getRootPath();
             final NodeIdentifierWithPredicates peerKey = IdentifierUtils.peerKey(path);
@@ -116,17 +121,15 @@ final class LocRibWriter implements AutoCloseable, DOMDataTreeChangeListener {
             for (final DataTreeCandidateNode child : tc.getRootNode().getChildNodes()) {
                 for (final DataTreeCandidateNode route : this.ribSupport.changedRoutes(child)) {
                     final PathArgument routeId = route.getIdentifier();
-                    RouteEntry entry = this.routeEntries.get(routeId);
-                    if (route.getDataAfter().isPresent()) {
+                    AbstractRouteEntry entry = this.routeEntries.get(routeId);
+
+                    final Optional<NormalizedNode<?, ?>> maybeData = route.getDataAfter();
+                    if (maybeData.isPresent()) {
                         if (entry == null) {
-                            entry = new RouteEntry();
-                            this.routeEntries.put(routeId, entry);
-                            LOG.trace("Created new entry for {}", routeId);
+                            entry = createEntry(routeId);
                         }
-                        LOG.trace("Find {} in {}", this.attributesIdentifier, route.getDataAfter());
-                        final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes.findNode(route.getDataAfter(), this.attributesIdentifier).orNull();
-                        entry.addRoute(routerId, advertisedAttrs);
-                        LOG.trace("Added route from {} attributes {}", routerId, advertisedAttrs);
+
+                        entry.addRoute(routerId, this.attributesIdentifier, maybeData.get());
                     } else if (entry != null && entry.removeRoute(routerId)) {
                         this.routeEntries.remove(routeId);
                         entry = null;
@@ -139,9 +142,9 @@ final class LocRibWriter implements AutoCloseable, DOMDataTreeChangeListener {
         }
 
         // Now walk all updated entries
-        for (final Entry<RouteUpdateKey, RouteEntry> e : toUpdate.entrySet()) {
+        for (final Entry<RouteUpdateKey, AbstractRouteEntry> e : toUpdate.entrySet()) {
             LOG.trace("Walking through {}", e);
-            final RouteEntry entry = e.getValue();
+            final AbstractRouteEntry entry = e.getValue();
             final NormalizedNode<?, ?> value;
 
             if (entry != null) {
@@ -150,10 +153,7 @@ final class LocRibWriter implements AutoCloseable, DOMDataTreeChangeListener {
                     LOG.trace("Continuing");
                     continue;
                 }
-                final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> b = Builders.mapEntryBuilder();
-                b.withNodeIdentifier((NodeIdentifierWithPredicates) e.getKey().getRouteId());
-                b.addChild(entry.attributes());
-                value = b.build();
+                value = entry.createValue(e.getKey().getRouteId());
                 LOG.trace("Selected best value {}", value);
             } else {
                 value = null;
index 0641489fc405220853abff5b6af8bef151610789..ff59078178278ba4cd26e306fc3f599c97279c8c 100644 (file)
@@ -22,7 +22,7 @@ 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,
+ * offset-based lookup across multiple {@link AbstractRouteEntry} objects,
  * which share either contributors or consumers.
  *
  * We also provide utility reformat methods, which provide access to
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/SimpleRouteEntry.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/SimpleRouteEntry.java
new file mode 100644 (file)
index 0000000..13923b7
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.primitives.UnsignedInteger;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+
+final class SimpleRouteEntry extends AbstractRouteEntry {
+    @Override
+    boolean removeRoute(UnsignedInteger routerId) {
+        return removeRoute(getOffsets().offsetOf(routerId));
+    }
+
+    @Override
+    protected MapEntryNode createValue(final PathArgument routeId) {
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> b = Builders.mapEntryBuilder();
+        b.withNodeIdentifier((NodeIdentifierWithPredicates) routeId);
+        b.addChild(attributes());
+        return b.build();
+    }
+}