2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.bgp.rib.spi;
10 import com.google.common.base.Preconditions;
11 import java.util.HashMap;
13 import javax.annotation.concurrent.GuardedBy;
14 import org.opendaylight.protocol.bgp.rib.spi.AbstractAdjRIBs.RIBEntryData;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
16 import org.opendaylight.yangtools.yang.binding.Identifiable;
17 import org.opendaylight.yangtools.yang.binding.Identifier;
18 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
23 * A single RIB table entry, which holds multiple versions of the entry's state and elects the authoritative based
24 * on ordering specified by the supplied comparator.
28 final class RIBEntry<I, D extends Identifiable<K> & Route, K extends Identifier<D>> {
29 private static final Logger LOG = LoggerFactory.getLogger(RIBEntry.class);
30 private static final int DEFAULT_MAP_SIZE = 2;
33 * TODO: we could dramatically optimize performance by using the comparator
34 * to retain the candidate states ordered -- thus selection would occur
35 * automatically through insertion, without the need of a second walk.
37 private final Map<Peer, RIBEntryData<I, D, K>> candidates = new HashMap<>(DEFAULT_MAP_SIZE);
42 private final AbstractAdjRIBs<I, D, K> parent;
46 KeyedInstanceIdentifier<D, K> name;
48 AbstractAdjRIBs.RIBEntryData<I, D, K> currentState;
50 RIBEntry(final AbstractAdjRIBs<I, D, K> parent, final I key) {
51 this.parent = Preconditions.checkNotNull(parent);
52 this.key = Preconditions.checkNotNull(key);
59 private KeyedInstanceIdentifier<D, K> getName() {
60 if (this.name == null) {
61 this.name = parent.identifierForKey(this.key);
62 LOG.trace("Entry {} grew key {}", this, this.name);
68 * Based on given comparator, finds a new best candidate for initial route.
72 * @return candidate for founded initial route
74 private RIBEntryData<I, D, K> findCandidate(final BGPObjectComparator comparator, final RIBEntryData<I, D, K> initial) {
75 RIBEntryData<I, D, K> newState = initial;
76 for (final AbstractAdjRIBs.RIBEntryData<I, D, K> s : this.candidates.values()) {
77 if (newState == null || comparator.compare(newState, s) > 0) {
86 * Advertize newly elected best candidate to datastore.
91 private void electCandidate(final AdjRIBsTransaction transaction, final RIBEntryData<I, D, K> candidate) {
92 LOG.trace("Electing state {} to supersede {}", candidate, this.currentState);
94 if (this.currentState == null || !this.currentState.equals(candidate)) {
95 LOG.trace("Elected new state for {}: {}", getName(), candidate);
96 transaction.advertise(parent, this.key, getName(), candidate.getPeer(), candidate.getDataObject(this.key, getName().getKey()));
97 this.currentState = candidate;
102 * Removes RIBEntry from database. If we are removing best path, elect another candidate (using BPS).
103 * If there are no other candidates, remove the path completely.
106 * @return true if the list of the candidates for this path is empty
108 synchronized boolean removeState(final AdjRIBsTransaction transaction, final Peer peer) {
109 final RIBEntryData<I, D, K> data = this.candidates.remove(peer);
110 LOG.trace("Removed data {}", data);
112 final AbstractAdjRIBs.RIBEntryData<I, D, K> candidate = findCandidate(transaction.comparator(), null);
113 if (candidate != null) {
114 electCandidate(transaction, candidate);
116 LOG.trace("Final candidate disappeared, removing entry {}", getName());
117 transaction.withdraw(parent, this.key, getName());
120 return this.candidates.isEmpty();
123 synchronized void setState(final AdjRIBsTransaction transaction, final Peer peer, final RIBEntryData<I, D, K> state) {
124 this.candidates.put(Preconditions.checkNotNull(peer), Preconditions.checkNotNull(state));
125 electCandidate(transaction, findCandidate(transaction.comparator(), state));