e1aeec27c7289383f9ba2aa57df23f7e52269935
[l2switch.git] / hosttracker / implementation / src / main / java / org / opendaylight / l2switch / hosttracker / plugin / internal / ConcurrentClusterAwareHostHashMap.java
1 /**
2  * Copyright (c) 2014 AndrĂ© Martins 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.l2switch.hosttracker.plugin.internal;
9
10 import java.util.Collection;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.concurrent.ConcurrentHashMap;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.l2switch.hosttracker.plugin.inventory.Host;
18 import org.opendaylight.l2switch.hosttracker.plugin.util.Utilities;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.host.tracker.rev140624.HostId;
20 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
21 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * This will (try to) submit all writes and deletes in to the MD-SAL database.
27  * The removeLocally and putLocally methods should be used when dataChanges are dealt locally and not update to MD-SAL.
28  */
29 public class ConcurrentClusterAwareHostHashMap {
30     private static final Logger LOG = LoggerFactory.getLogger(ConcurrentClusterAwareHostHashMap.class);
31
32     private final OperationProcessor opProcessor;
33     private final String topologyId;
34
35     /**
36      * The instance identifiers for each host submitted to MD-SAL.
37      */
38     private final ConcurrentHashMap<InstanceIdentifier<Node>, HostId> instanceIDs = new ConcurrentHashMap<>();
39
40     /**
41      * The local Hosts' HashMap.
42      */
43     private final ConcurrentHashMap<HostId, Host> hostHashMap = new ConcurrentHashMap<>();
44
45     public ConcurrentClusterAwareHostHashMap(OperationProcessor opProcessor, String topologyId) {
46         this.opProcessor = opProcessor;
47         this.topologyId = topologyId;
48     }
49
50     /**
51      * Removes, if exists, the Host with the given
52      * InstanceIdentifier&lt;Node&gt; from this local HashMap. Ideally used for
53      * host data listener events.
54      *
55      * @param iiN
56      *            the InstanceIdentifier&lt;Node&gt; of the Host to remove.
57      * @return the removed Host if exits, null if it doesn't exist.
58      */
59     public synchronized Host removeLocally(InstanceIdentifier<Node> iiN) {
60         HostId hostId = this.instanceIDs.remove(iiN);
61         if (hostId != null) {
62             return this.hostHashMap.remove(hostId);
63         }
64         return null;
65     }
66
67     /**
68      * Removes, if exists, the Host with the given Key (HostId) from this local
69      * HashMap. Ideally used for host data listener events.
70      *
71      * @param key
72      *            the key (HostId) of the Host to remove.
73      * @return the removed Host if exits, null if it doesn't exist.
74      */
75     public synchronized Host removeLocally(HostId key) {
76         Iterator<Entry<InstanceIdentifier<Node>, HostId>> iterator = this.instanceIDs.entrySet().iterator();
77         while (iterator.hasNext()) {
78             if (iterator.next().getValue().equals(key)) {
79                 iterator.remove();
80                 break;
81             }
82         }
83         return hostHashMap.remove(key);
84     }
85
86     /**
87      * Puts the given value (Host) only in this local HashMap. Ideally used for
88      * host data listener events.
89      *
90      * @param ii
91      *            the value's (Host's) InstanceIdentifier&lt;Node&gt;
92      * @param value
93      *            the Host to store locally.
94      * @return the previous value associated with <tt>key</tt>, or <tt>null</tt>
95      *         if there was no mapping for <tt>key</tt>
96      */
97     public synchronized Host putLocally(InstanceIdentifier<Node> ii, Host value) {
98         Host host = value;
99         LOG.trace("Putting locally {}", host.getId());
100         this.instanceIDs.put(ii, host.getId());
101         return this.hostHashMap.put(host.getId(), value);
102     }
103
104     /**
105      * Removes the given hosts both locally and on MD-SAL database.
106      *
107      * @param hosts
108      *            the hosts to remove.
109      */
110     public synchronized void removeAll(List<Host> hosts) {
111         for (final Map.Entry<InstanceIdentifier<Node>, HostId> e : this.instanceIDs.entrySet()) {
112             for (Host h : hosts) {
113                 if (e.getValue().equals(h.getId())) {
114                     this.opProcessor.enqueueOperation(tx -> tx.delete(LogicalDatastoreType.OPERATIONAL, e.getKey()));
115                     this.hostHashMap.remove(e.getValue());
116                     break;
117                 }
118             }
119         }
120     }
121
122     /**
123      * Forces the local Host with the given HostId to be merged into MD-SAL
124      * database.
125      *
126      * @param hostid
127      *            the Host's hostId that will be merged into MD-SAL database.
128      */
129     public synchronized void submit(HostId hostid) {
130         Host host = this.hostHashMap.get(hostid);
131         final Node hostNode = host.getHostNode();
132         final InstanceIdentifier<Node> buildNodeIID = Utilities.buildNodeIID(hostNode.getKey(), topologyId);
133         this.opProcessor.enqueueOperation(tx -> tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID,
134                 hostNode, true));
135         putLocally(buildNodeIID, host);
136         this.instanceIDs.put(buildNodeIID, host.getId());
137         LOG.trace("Enqueued for MD-SAL transaction {}", hostNode.getNodeId());
138     }
139
140     /**
141      * Puts all the given hosts into this local HashMap and into MD-SAL
142      * database.
143      *
144      * @param hosts
145      *            the hosts to be sent into MD-SAL database.
146      */
147     public synchronized void putAll(List<Host> hosts) {
148         for (Host h : hosts) {
149             final Node hostNode = h.getHostNode();
150             final InstanceIdentifier<Node> buildNodeIID = Utilities.buildNodeIID(hostNode.getKey(), topologyId);
151             this.opProcessor.enqueueOperation(tx -> tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID,
152                     hostNode, true));
153             putLocally(buildNodeIID, h);
154             this.instanceIDs.put(buildNodeIID, h.getId());
155             LOG.trace("Putting MD-SAL {}", hostNode.getNodeId());
156         }
157     }
158
159     /**
160      * Puts the given host in the this local HashMap and into MD-SAL database.
161      *
162      * @param hostId
163      *            the key for the map
164      * @param host
165      *            the value for the map
166      * @return the old value from the local cache if present, null otherwise.
167      */
168     public synchronized Host put(HostId hostId, Host host) {
169         final Node hostNode = host.getHostNode();
170         final InstanceIdentifier<Node> buildNodeIID = Utilities.buildNodeIID(hostNode.getKey(), topologyId);
171         this.opProcessor.enqueueOperation(tx -> tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID,
172                 hostNode, true));
173         LOG.trace("Putting MD-SAL {}", hostNode.getNodeId());
174         return putLocally(buildNodeIID, host);
175     }
176
177     /**
178      * Removes the value (Host) with the given hostId from this local HashMap
179      * and MD-SAL database.
180      *
181      * @param hostId
182      *            the Host's hostId to remove
183      * @return the old value from the local cache if present, null otherwise.
184      */
185     public synchronized Host remove(HostId hostId) {
186         Host removedValue = this.hostHashMap.remove(hostId);
187         if (removedValue != null) {
188             Node hostNode = removedValue.getHostNode();
189             final InstanceIdentifier<Node> hnIID = Utilities.buildNodeIID(hostNode.getKey(), topologyId);
190             this.opProcessor.enqueueOperation(tx -> tx.delete(LogicalDatastoreType.OPERATIONAL, hnIID));
191             this.instanceIDs.remove(hnIID);
192         }
193         return removedValue;
194     }
195
196     public boolean containsKey(Object key) {
197         return this.hostHashMap.containsKey(key);
198     }
199
200     public Host get(HostId key) {
201         return this.hostHashMap.get(key);
202     }
203
204     /**
205      * Removes all of the mappings from this local HashMap and from MD-SAL. The
206      * local HashMap will be empty after this call returns.
207      */
208     public synchronized void clear() {
209         for (final Map.Entry<? extends InstanceIdentifier<Node>, HostId> e : this.instanceIDs.entrySet()) {
210             this.opProcessor.enqueueOperation(tx -> tx.delete(LogicalDatastoreType.OPERATIONAL, e.getKey()));
211         }
212         this.hostHashMap.clear();
213     }
214
215     /**
216      * Returns the Values from this local HashMap.
217      *
218      * @return the Values from this local HashMap.
219      */
220     public Collection<Host> values() {
221         return this.hostHashMap.values();
222     }
223 }