Bug 3044 - Conversion from Flowspec BI -> BA
[bgpcep.git] / bgp / rib-spi / src / main / java / org / opendaylight / protocol / bgp / rib / spi / RIBEntry.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.bgp.rib.spi;
9
10 import com.google.common.base.Preconditions;
11 import java.util.HashMap;
12 import java.util.Map;
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;
21
22 /**
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.
25  *
26  */
27 @Deprecated
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;
31
32     /*
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.
36      */
37     private final Map<Peer, RIBEntryData<I, D, K>> candidates = new HashMap<>(DEFAULT_MAP_SIZE);
38
39     /**
40      *
41      */
42     private final AbstractAdjRIBs<I, D, K> parent;
43     private final I key;
44
45     @GuardedBy("this")
46     KeyedInstanceIdentifier<D, K> name;
47     @GuardedBy("this")
48     AbstractAdjRIBs.RIBEntryData<I, D, K> currentState;
49
50     RIBEntry(final AbstractAdjRIBs<I, D, K> parent, final I key) {
51         this.parent = Preconditions.checkNotNull(parent);
52         this.key = Preconditions.checkNotNull(key);
53     }
54
55     I getKey() {
56         return key;
57     }
58
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);
63         }
64         return this.name;
65     }
66
67     /**
68      * Based on given comparator, finds a new best candidate for initial route.
69      *
70      * @param comparator
71      * @param initial
72      * @return candidate for founded initial route
73      */
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) {
78                 newState = s;
79             }
80         }
81
82         return newState;
83     }
84
85     /**
86      * Advertize newly elected best candidate to datastore.
87      *
88      * @param transaction
89      * @param candidate
90      */
91     private void electCandidate(final AdjRIBsTransaction transaction, final RIBEntryData<I, D, K> candidate) {
92         LOG.trace("Electing state {} to supersede {}", candidate, this.currentState);
93
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;
98         }
99     }
100
101     /**
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.
104      * @param transaction
105      * @param peer
106      * @return true if the list of the candidates for this path is empty
107      */
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);
111
112         final AbstractAdjRIBs.RIBEntryData<I, D, K> candidate = findCandidate(transaction.comparator(), null);
113         if (candidate != null) {
114             electCandidate(transaction, candidate);
115         } else {
116             LOG.trace("Final candidate disappeared, removing entry {}", getName());
117             transaction.withdraw(parent, this.key, getName());
118         }
119
120         return this.candidates.isEmpty();
121     }
122
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));
126     }
127
128 }