*/
package org.opendaylight.protocol.bgp.mode.impl.add;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.annotation.concurrent.NotThreadSafe;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
import org.opendaylight.protocol.bgp.mode.api.BestPath;
-import org.opendaylight.protocol.bgp.mode.impl.OffsetMap;
import org.opendaylight.protocol.bgp.mode.spi.AbstractRouteEntry;
import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
public abstract class AddPathAbstractRouteEntry extends AbstractRouteEntry {
private static final Logger LOG = LoggerFactory.getLogger(AddPathAbstractRouteEntry.class);
- protected List<AddPathBestPath> bestPath = new ArrayList<>();
- protected List<AddPathBestPath> bestPathRemoved = new ArrayList<>();
- protected OffsetMap<RouteKey> offsets = new OffsetMap<>(RouteKey.class);
+ protected List<AddPathBestPath> bestPath;
+ protected List<AddPathBestPath> bestPathRemoved;
+ protected OffsetMap offsets = OffsetMap.EMPTY;
protected ContainerNode[] values = new ContainerNode[0];
protected Long[] pathsId = new Long[0];
private long pathIdCounter = 0L;
private int addRoute(final RouteKey key, final ContainerNode attributes) {
int offset = this.offsets.offsetOf(key);
if (offset < 0) {
- final OffsetMap<RouteKey> newOffsets = this.offsets.with(key);
+ final OffsetMap newOffsets = this.offsets.with(key);
offset = newOffsets.offsetOf(key);
final ContainerNode[] newAttributes = newOffsets.expand(this.offsets, this.values, offset);
final Long[] newPathsId = newOffsets.expand(this.offsets, this.pathsId, offset);
@Override
public void updateRoute(final TablesKey localTK, final ExportPolicyPeerTracker peerPT, final YangInstanceIdentifier locRibTarget, final RIBSupport ribSup,
final CacheDisconnectedPeers discPeers, final DOMDataWriteTransaction tx, final PathArgument routeIdPA) {
- this.bestPathRemoved.forEach(path -> removePathFromDataStore(path, isFirstBestPath(bestPathRemoved.indexOf(path)), routeIdPA, locRibTarget, ribSup,
- peerPT, localTK, discPeers,tx));
- this.bestPathRemoved = Collections.emptyList();
+ if(this.bestPathRemoved != null) {
+ this.bestPathRemoved.forEach(path -> removePathFromDataStore(path, isFirstBestPath(bestPathRemoved.indexOf(path)), routeIdPA, locRibTarget, ribSup,
+ peerPT, localTK, discPeers, tx));
+ this.bestPathRemoved = null;
+ }
- this.bestPath.forEach(path -> addPathToDataStore(path, isFirstBestPath(this.bestPath.indexOf(path)), routeIdPA, locRibTarget, ribSup,
- peerPT, localTK, discPeers,tx));
+ if(this.bestPath != null) {
+ this.bestPath.forEach(path -> addPathToDataStore(path, isFirstBestPath(this.bestPath.indexOf(path)), routeIdPA, locRibTarget, ribSup,
+ peerPT, localTK, discPeers, tx));
+ }
}
@Override
final TablesKey localTK, final ExportPolicyPeerTracker peerPT, final RIBSupport ribSup, final CacheDisconnectedPeers discPeers,
final DOMDataWriteTransaction tx) {
final boolean destPeerSupAddPath = peerPT.isAddPathSupportedByPeer(destPeer);
- this.bestPath.stream().filter(path -> filterRoutes(path.getPeerId(), destPeer, peerPT, localTK, discPeers) &&
- peersSupportsAddPathOrIsFirstBestPath(destPeerSupAddPath, isFirstBestPath(this.bestPath.indexOf(path))))
- .forEach(path -> writeRoutePath(destPeer, routeId, peerGroup, destPeerSupAddPath, path, rootPath, localTK, ribSup, tx));
+ if(this.bestPath != null) {
+ this.bestPath.stream().filter(path -> filterRoutes(path.getPeerId(), destPeer, peerPT, localTK, discPeers) &&
+ peersSupportsAddPathOrIsFirstBestPath(destPeerSupAddPath, isFirstBestPath(this.bestPath.indexOf(path))))
+ .forEach(path -> writeRoutePath(destPeer, routeId, peerGroup, destPeerSupAddPath, path, rootPath, localTK, ribSup, tx));
+ }
}
private void writeRoutePath(final PeerId destPeer, final PathArgument routeId, final PeerExportGroup peerGroup, final boolean destPeerSupAddPath,
}
}
- protected final OffsetMap<RouteKey> getOffsets() {
+ protected final OffsetMap getOffsets() {
return this.offsets;
}
public final boolean isEmpty() {
- return this.offsets.isEmty();
+ return this.offsets.isEmpty();
}
protected void selectBest(final RouteKey key, final AddPathSelector selector) {
super(ourAs);
}
- public void processPath(final ContainerNode attrs, final RouteKey key, final int offsetPosition, final Long pathId) {
+ void processPath(final ContainerNode attrs, final RouteKey key, final int offsetPosition, final Long pathId) {
Preconditions.checkNotNull(key.getRouteId(), "Router ID may not be null");
// Consider only non-null attributes
* 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.mode.impl;
+package org.opendaylight.protocol.bgp.mode.impl.add;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableSet.Builder;
import java.lang.reflect.Array;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
* We also provide utility reformat methods, which provide access to
* array members and array management features.
*/
-public final class OffsetMap<E extends Comparable<E>> {
+public final class OffsetMap {
+ static final OffsetMap EMPTY = new OffsetMap(Collections.emptySet());
private static final Logger LOG = LoggerFactory.getLogger(OffsetMap.class);
private static final String NEGATIVEOFFSET = "Invalid negative offset %s";
private static final String INVALIDOFFSET = "Invalid offset %s for %s router IDs";
- private final Comparator<E> ipv4Comparator = E::compareTo;
- private final E[] routeKeys;
- private final Class<E> clazz;
- private final LoadingCache<Set<E>, OffsetMap<E>> keyCache = CacheBuilder.newBuilder().weakValues().build(new CacheLoader<Set<E>, OffsetMap<E>>() {
- @Override
- public OffsetMap<E> load(@Nonnull final Set<E> key) throws Exception {
- return new OffsetMap<>(key, clazz);
- }
- });
-
- public OffsetMap(final Class<E> clazz) {
- this.clazz = clazz;
- this.routeKeys = (E[]) Array.newInstance(clazz, 0);
- }
+ private static final LoadingCache<Set<RouteKey>, OffsetMap> OFFSETMAPS = CacheBuilder.newBuilder().weakValues().build(
+ new CacheLoader<Set<RouteKey>, OffsetMap>() {
+ @Override
+ public OffsetMap load(@Nonnull final Set<RouteKey> key) throws Exception {
+ return new OffsetMap(key);
+ }
+ });
+ private static final Comparator<RouteKey> COMPARATOR = RouteKey::compareTo;
+ private final RouteKey[] routeKeys;
- private OffsetMap(final Set<E> keysSet, final Class<E> clazz) {
- this.clazz = clazz;
- final E[] array = keysSet.toArray((E[]) Array.newInstance(this.clazz, keysSet.size()));
- Arrays.sort(array, ipv4Comparator);
+ private OffsetMap(final Set<RouteKey> routerIds) {
+ final RouteKey[] array = routerIds.toArray(new RouteKey[0]);
+ Arrays.sort(array, COMPARATOR);
this.routeKeys = array;
}
- public List<E> getRouteKeysList() {
- return Arrays.stream(this.routeKeys).collect(Collectors.toList());
- }
-
- public E getRouterKey(final int offset) {
- Preconditions.checkArgument(offset >= 0);
- return this.routeKeys[offset];
- }
-
- public int offsetOf(final E key) {
- return Arrays.binarySearch(this.routeKeys, key, ipv4Comparator);
+ public int offsetOf(final RouteKey key) {
+ return Arrays.binarySearch(this.routeKeys, key, COMPARATOR);
}
public int size() {
return this.routeKeys.length;
}
- public OffsetMap<E> with(final E key) {
+ public OffsetMap with(final RouteKey key) {
// 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<E> b = ImmutableSet.builder();
- b.add(this.routeKeys);
- b.add(key);
+ final Builder<RouteKey> builder = ImmutableSet.builder();
+ builder.add(this.routeKeys);
+ builder.add(key);
- return keyCache.getUnchecked(b.build());
+ return OFFSETMAPS.getUnchecked(builder.build());
}
- public OffsetMap<E> without(final E key) {
- final Builder<E> b = ImmutableSet.builder();
- int index = indexOfRouterId(key);
+ public OffsetMap without(final RouteKey key) {
+ final Builder<RouteKey> builder = ImmutableSet.builder();
+ final int index = indexOfRouterId(key);
if (index < 0) {
LOG.trace("Router key not found", key);
} else {
- b.add(removeValue(this.routeKeys, index));
+ builder.add(removeValue(this.routeKeys, index));
}
- return keyCache.getUnchecked(b.build());
+ return OFFSETMAPS.getUnchecked(builder.build());
}
- private int indexOfRouterId(final E key) {
+ private int indexOfRouterId(final RouteKey key) {
for (int i = 0; i < this.routeKeys.length; i++) {
if (key.equals(this.routeKeys[i])) {
return i;
return ret;
}
- public boolean isEmty() {
+ boolean isEmpty() {
return this.size() == 0;
}
-}
+
+ public List<RouteKey> getRouteKeysList() {
+ return Arrays.stream(this.routeKeys).collect(Collectors.toList());
+ }
+}
\ No newline at end of file
newBestPathList.add(newBest);
keyList.remove(newBest.getRouteKey());
/*we add the rest of path, regardless in what order they are, since this is all path case */
- for (RouteKey key : keyList) {
+ for (final RouteKey key : keyList) {
final int offset = this.offsets.offsetOf(key);
final ContainerNode attributes = this.offsets.getValue(this.values, offset);
Preconditions.checkNotNull(key.getRouteId(), "Router ID may not be null");
}
}
- this.bestPathRemoved = new ArrayList<>(this.bestPath);
- if (this.bestPathRemoved.removeAll(newBestPathList) && !this.bestPathRemoved.isEmpty() || !this.bestPath.equals(newBestPathList)) {
+ if(this.bestPath != null) {
+ this.bestPathRemoved = new ArrayList<>(this.bestPath);
+ }
+
+ if (!newBestPathList.equals(this.bestPath) || this.bestPathRemoved != null && this.bestPathRemoved.removeAll(newBestPathList)) {
this.bestPath = newBestPathList;
LOG.trace("Actual Best {}, removed best {}", this.bestPath, this.bestPathRemoved);
return true;
}
return false;
}
-
-
}
import com.google.common.primitives.UnsignedInteger;
import org.opendaylight.protocol.bgp.mode.api.BestPath;
-import org.opendaylight.protocol.bgp.mode.impl.OffsetMap;
import org.opendaylight.protocol.bgp.mode.impl.add.AddPathBestPath;
+import org.opendaylight.protocol.bgp.mode.impl.add.OffsetMap;
import org.opendaylight.protocol.bgp.mode.impl.add.RouteKey;
import org.opendaylight.protocol.bgp.mode.spi.RouteEntryUtil;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@Override
public boolean removeRoute(final UnsignedInteger routerId, final Long remotePathId) {
final RouteKey key = new RouteKey(routerId, remotePathId);
- final OffsetMap<RouteKey> map = getOffsets();
+ final OffsetMap map = getOffsets();
final int offset = map.offsetOf(key);
this.values = map.removeValue(this.values, offset);
return removeRoute(key, offset);
@Override
public MapEntryNode createValue(final YangInstanceIdentifier.PathArgument routeId, final BestPath path) {
- final OffsetMap<RouteKey> map = getOffsets();
+ final OffsetMap map = getOffsets();
final MapEntryNode mapValues = map.getValue(this.values, map.offsetOf(((AddPathBestPath) path).getRouteKey()));
return RouteEntryUtil.createComplexRouteValue(routeId, path, mapValues);
}
@Override
public int addRoute(final UnsignedInteger routerId, final Long remotePathId, final YangInstanceIdentifier.NodeIdentifier attII, final NormalizedNode<?, ?> data) {
- final OffsetMap<RouteKey> oldMap = getOffsets();
+ final OffsetMap oldMap = getOffsets();
final int offset = addRoute(new RouteKey(routerId, remotePathId), attII, data);
- final OffsetMap<RouteKey> newMap = getOffsets();
+ final OffsetMap newMap = getOffsets();
if (!newMap.equals(oldMap)) {
this.values = newMap.expand(oldMap, this.values, offset);
keyList.remove(newBest.getRouteKey());
}
- this.bestPathRemoved = new ArrayList<>(this.bestPath);
- if (this.bestPathRemoved.removeAll(newBestPathList) && !this.bestPathRemoved.isEmpty() || !this.bestPath.equals(newBestPathList)) {
+ if(this.bestPath != null) {
+ this.bestPathRemoved = new ArrayList<>(this.bestPath);
+ }
+ if (!newBestPathList.equals(this.bestPath) ||
+ this.bestPathRemoved != null && this.bestPathRemoved.removeAll(newBestPathList) && !this.bestPathRemoved.isEmpty()) {
this.bestPath = newBestPathList;
LOG.trace("Actual Best {}, removed best {}", this.bestPath, this.bestPathRemoved);
return true;
import com.google.common.primitives.UnsignedInteger;
import org.opendaylight.protocol.bgp.mode.api.BestPath;
-import org.opendaylight.protocol.bgp.mode.impl.OffsetMap;
import org.opendaylight.protocol.bgp.mode.impl.add.AddPathBestPath;
+import org.opendaylight.protocol.bgp.mode.impl.add.OffsetMap;
import org.opendaylight.protocol.bgp.mode.impl.add.RouteKey;
import org.opendaylight.protocol.bgp.mode.spi.RouteEntryUtil;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
@Override
public boolean removeRoute(final UnsignedInteger routerId, final Long remotePathId) {
final RouteKey key = new RouteKey(routerId, remotePathId);
- final OffsetMap<RouteKey> map = getOffsets();
+ final OffsetMap map = getOffsets();
final int offset = map.offsetOf(key);
this.values = map.removeValue(this.values, offset);
return removeRoute(key, offset);
@Override
public MapEntryNode createValue(final PathArgument routeId, final BestPath path) {
- final OffsetMap<RouteKey> map = getOffsets();
+ final OffsetMap map = getOffsets();
final MapEntryNode mapValues = map.getValue(this.values, map.offsetOf(((AddPathBestPath) path).getRouteKey()));
return RouteEntryUtil.createComplexRouteValue(routeId, path, mapValues);
}
@Override
public int addRoute(final UnsignedInteger routerId, final Long remotePathId, final NodeIdentifier attributesIdentifier, final NormalizedNode<?, ?> data) {
- final OffsetMap<RouteKey> oldMap = getOffsets();
+ final OffsetMap oldMap = getOffsets();
final int offset = addRoute(new RouteKey(routerId, remotePathId), attributesIdentifier, data);
- final OffsetMap<RouteKey> newMap = getOffsets();
+ final OffsetMap newMap = getOffsets();
if (!newMap.equals(oldMap)) {
this.values = newMap.expand(oldMap, this.values, offset);
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
import org.opendaylight.protocol.bgp.mode.api.BestPath;
-import org.opendaylight.protocol.bgp.mode.impl.OffsetMap;
import org.opendaylight.protocol.bgp.mode.spi.AbstractRouteEntry;
import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
@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<UnsignedInteger> offsets = new OffsetMap<>(UnsignedInteger.class);
+ private OffsetMap offsets = OffsetMap.EMPTY;
private ContainerNode[] values = EMPTY_ATTRIBUTES;
- private Optional<BaseBestPath> bestPath = Optional.empty();
- private Optional<BaseBestPath> removedBestPath = Optional.empty();
+ private BaseBestPath bestPath;
+ private BaseBestPath removedBestPath;
private int addRoute(final UnsignedInteger routerId, final ContainerNode attributes) {
int offset = this.offsets.offsetOf(routerId);
if (offset < 0) {
- final OffsetMap<UnsignedInteger> newOffsets = this.offsets.with(routerId);
+ final OffsetMap newOffsets = this.offsets.with(routerId);
offset = newOffsets.offsetOf(routerId);
this.values = newOffsets.expand(this.offsets, this.values, offset);
protected final boolean removeRoute(final UnsignedInteger routerId, final int offset) {
this.values = this.offsets.removeValue(this.values, offset);
this.offsets = this.offsets.without(routerId);
- return this.offsets.isEmty();
+ return this.offsets.isEmpty();
}
@Override
}
// Get the newly-selected best path.
- final Optional<BaseBestPath> newBestPath = Optional.ofNullable(selector.result());
- final boolean modified = !newBestPath.equals(this.bestPath);
+ final BaseBestPath newBestPath = selector.result();
+ final boolean modified = newBestPath == null || !newBestPath.equals(this.bestPath);
if (modified) {
this.removedBestPath = this.bestPath;
LOG.trace("Previous best {}, current best {}", this.bestPath, newBestPath);
@Override
public void updateRoute(final TablesKey localTK, final ExportPolicyPeerTracker peerPT, final YangInstanceIdentifier locRibTarget, final RIBSupport ribSup,
final CacheDisconnectedPeers discPeers, final DOMDataWriteTransaction tx, final PathArgument routeIdPA) {
- if (this.removedBestPath.isPresent()) {
- removePathFromDataStore(this.removedBestPath.get(), routeIdPA, locRibTarget, peerPT, localTK, ribSup, discPeers, tx);
- this.removedBestPath = Optional.empty();
+ if (this.removedBestPath != null) {
+ removePathFromDataStore(this.removedBestPath, routeIdPA, locRibTarget, peerPT, localTK, ribSup, discPeers, tx);
+ this.removedBestPath = null;
}
- if (this.bestPath.isPresent()) {
- addPathToDataStore(this.bestPath.get(), routeIdPA, locRibTarget, ribSup, peerPT, localTK, discPeers, tx);
+ if (this.bestPath != null) {
+ addPathToDataStore(this.bestPath, routeIdPA, locRibTarget, ribSup, peerPT, localTK, discPeers, tx);
}
}
public void writeRoute(final PeerId destPeer, final PathArgument routeId, final YangInstanceIdentifier rootPath, final PeerExportGroup peerGroup,
final TablesKey localTK, final ExportPolicyPeerTracker peerPT, final RIBSupport ribSup, final CacheDisconnectedPeers discPeers,
final DOMDataWriteTransaction tx) {
- if (this.bestPath.isPresent()) {
- final BaseBestPath path = this.bestPath.get();
+ if (this.bestPath != null) {
+ final BaseBestPath path = this.bestPath;
if (filterRoutes(path.getPeerId(), destPeer, peerPT, localTK, discPeers)) {
final ContainerNode effAttrib = peerGroup.effectiveAttributes(path.getPeerId(), path.getAttributes());
writeRoute(destPeer, getAdjRibOutYII(ribSup, rootPath, routeId, localTK), effAttrib, createValue(routeId, path), ribSup, tx);
fillAdjRibsOut(path.getAttributes(), value, routeIdPA, path.getPeerId(), peerPT, localTK, ribSup, discPeers, tx);
}
- protected final OffsetMap<UnsignedInteger> getOffsets() {
+ final OffsetMap getOffsets() {
return this.offsets;
}
import com.google.common.primitives.UnsignedInteger;
import org.opendaylight.protocol.bgp.mode.api.BestPath;
-import org.opendaylight.protocol.bgp.mode.impl.OffsetMap;
import org.opendaylight.protocol.bgp.mode.spi.RouteEntryUtil;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
@Override
public int addRoute(final UnsignedInteger routerId, final Long remotePathId, final NodeIdentifier attrII, final NormalizedNode<?, ?> data) {
- final OffsetMap<UnsignedInteger> oldMap = getOffsets();
+ final OffsetMap oldMap = getOffsets();
final int offset = super.addRoute(routerId, remotePathId, attrII, data);
- final OffsetMap<UnsignedInteger> newMap = getOffsets();
+ final OffsetMap newMap = getOffsets();
if (!newMap.equals(oldMap)) {
this.values = newMap.expand(oldMap, this.values, offset);
@Override
public boolean removeRoute(final UnsignedInteger routerId, final Long remotePathId) {
- final OffsetMap<UnsignedInteger> map = getOffsets();
+ final OffsetMap map = getOffsets();
final int offset = map.offsetOf(routerId);
this.values = map.removeValue(this.values, offset);
return removeRoute(routerId, offset);
@Override
public MapEntryNode createValue(final PathArgument routeId, final BestPath path) {
- final OffsetMap<UnsignedInteger> map = getOffsets();
+ final OffsetMap map = getOffsets();
final MapEntryNode mapValues = map.getValue(this.values, map.offsetOf(path.getRouterId()));
return RouteEntryUtil.createComplexRouteValue(routeId, path, mapValues);
}
--- /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.mode.impl.base;
+
+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.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A map of Router identifier to an offset. Used to maintain a simple
+ * offset-based lookup across multiple 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.emptySet());
+ private static final Logger LOG = LoggerFactory.getLogger(OffsetMap.class);
+ private static final String NEGATIVEOFFSET = "Invalid negative offset %s";
+ private static final String INVALIDOFFSET = "Invalid offset %s for %s router IDs";
+ private static final LoadingCache<Set<UnsignedInteger>, OffsetMap> OFFSETMAPS = CacheBuilder.newBuilder().weakValues().build(
+ new CacheLoader<Set<UnsignedInteger>, OffsetMap>() {
+ @Override
+ public OffsetMap load(@Nonnull final Set<UnsignedInteger> key) throws Exception {
+ return new OffsetMap(key);
+ }
+ });
+ private static final Comparator<UnsignedInteger> COMPARATOR = UnsignedInteger::compareTo;
+ private final UnsignedInteger[] routeKeys;
+
+ private OffsetMap(final Set<UnsignedInteger> routerIds) {
+ final UnsignedInteger[] array = routerIds.toArray(new UnsignedInteger[0]);
+ Arrays.sort(array, COMPARATOR);
+ this.routeKeys = array;
+ }
+
+ UnsignedInteger getRouterKey(final int offset) {
+ Preconditions.checkArgument(offset >= 0);
+ return this.routeKeys[offset];
+ }
+
+ public int offsetOf(final UnsignedInteger key) {
+ return Arrays.binarySearch(this.routeKeys, key, COMPARATOR);
+ }
+
+ public int size() {
+ return this.routeKeys.length;
+ }
+
+ public OffsetMap with(final UnsignedInteger key) {
+ // 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> builder = ImmutableSet.builder();
+ builder.add(this.routeKeys);
+ builder.add(key);
+
+ return OFFSETMAPS.getUnchecked(builder.build());
+ }
+
+ public OffsetMap without(final UnsignedInteger key) {
+ final Builder<UnsignedInteger> builder = ImmutableSet.builder();
+ final int index = indexOfRouterId(key);
+ if (index < 0) {
+ LOG.trace("Router key not found", key);
+ } else {
+ builder.add(removeValue(this.routeKeys, index));
+ }
+ return OFFSETMAPS.getUnchecked(builder.build());
+ }
+
+ private int indexOfRouterId(final UnsignedInteger key) {
+ for (int i = 0; i < this.routeKeys.length; i++) {
+ if (key.equals(this.routeKeys[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public <T> T getValue(final T[] array, final int offset) {
+ Preconditions.checkArgument(offset >= 0, NEGATIVEOFFSET, offset);
+ Preconditions.checkArgument(offset < routeKeys.length, INVALIDOFFSET, offset, routeKeys.length);
+ return array[offset];
+ }
+
+ public <T> void setValue(final T[] array, final int offset, final T value) {
+ Preconditions.checkArgument(offset >= 0, NEGATIVEOFFSET, offset);
+ Preconditions.checkArgument(offset < routeKeys.length, INVALIDOFFSET, offset, routeKeys.length);
+ array[offset] = value;
+ }
+
+ <T> T[] expand(final OffsetMap oldOffsets, final T[] oldArray, final int offset) {
+ @SuppressWarnings("unchecked")
+ final T[] ret = (T[]) Array.newInstance(oldArray.getClass().getComponentType(), this.routeKeys.length);
+ final int oldSize = oldOffsets.routeKeys.length;
+
+ System.arraycopy(oldArray, 0, ret, 0, offset);
+ System.arraycopy(oldArray, offset, ret, offset + 1, oldSize - offset);
+
+ return ret;
+ }
+
+ public <T> T[] removeValue(final T[] oldArray, final int offset) {
+ final int length = oldArray.length;
+ Preconditions.checkArgument(offset >= 0, NEGATIVEOFFSET, offset);
+ Preconditions.checkArgument(offset < routeKeys.length, INVALIDOFFSET, offset, length);
+
+ final T[] ret = (T[]) Array.newInstance(oldArray.getClass().getComponentType(), length - 1);
+ System.arraycopy(oldArray, 0, ret, 0, offset);
+ if (offset < length - 1) {
+ System.arraycopy(oldArray, offset + 1, ret, offset, length - offset - 1);
+ }
+
+ return ret;
+ }
+
+ boolean isEmpty() {
+ return this.size() == 0;
+ }
+}
\ No newline at end of file
private void testAddRouteSelectBestAndWriteOnDS() {
this.testBARE.addRoute(ROUTER_ID, REMOTE_PATH_ID, this.ribSupport.routeAttributesIdentifier(), this.attributes);
- assertFalse(this.testBARE.getOffsets().isEmty());
+ assertFalse(this.testBARE.getOffsets().isEmpty());
this.testBARE.selectBest(AS);
this.testBARE.updateRoute(TABLES_KEY, this.peerPT, LOC_RIB_TARGET, this.ribSupport, this.discCache, this.tx, ROUTE_ID_PA);
Map<YangInstanceIdentifier, Long> yiiCount = this.yIIChanges.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));