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;
* 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];
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);
}
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 {
}
// 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.
*/
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);
}
--- /dev/null
+/*
+ * 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;
+ }
+}
*/
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;
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;
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;
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();
* 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);
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;
}
// 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) {
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;
/**
* 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
--- /dev/null
+/*
+ * 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();
+ }
+}