Added device transaction log cli
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / HwvtepDeviceInfo.java
1 /*
2  * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. 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
9 package org.opendaylight.ovsdb.hwvtepsouthbound;
10
11 import com.google.common.collect.Sets;
12 import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependencyQueue;
13 import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependentJob;
14 import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactCommand;
15 import org.opendaylight.ovsdb.lib.notation.UUID;
16 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
17 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocator;
18 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
19 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionHistory;
20 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
24 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
25 import org.opendaylight.yangtools.yang.binding.Identifiable;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.concurrent.ConcurrentHashMap;
35
36 /*
37  * HwvtepDeviceInfo is used to store some of the table entries received
38  * in updates from a Hwvtep device. There will be one instance of this per
39  * Hwvtep device connected. Table entries are stored in a map keyed by
40  * uuids of respective rows.
41  *
42  * Purpose of this class is to provide data present in tables which
43  * were updated in a previous transaction and are not available in
44  * current updatedRows. This allows us to handle updates for Tables
45  * which reference other tables and need information in those tables
46  * to add data to Operational data store.
47  *
48  * e.g. Mac-entries in data store use logical-switch-ref as one of the
49  * keys. Mac-entry updates from switch rarely contain Logical_Switch
50  * table entries. To add mac-entries we need table entries from
51  * Logical_Switch table which were created in an earlier update.
52  *
53  */
54 public class HwvtepDeviceInfo {
55
56     private static final Logger LOG = LoggerFactory.getLogger(HwvtepDeviceInfo.class);
57
58     public enum DeviceDataStatus {
59         IN_TRANSIT,
60         UNAVAILABLE,
61         AVAILABLE
62     }
63
64     public static class DeviceData {
65         private final InstanceIdentifier key;
66         private final UUID uuid;
67         private final Object data;
68         private final DeviceDataStatus status;
69         private long intransitTimeStamp;
70
71         DeviceData(InstanceIdentifier key, UUID uuid, Object data, DeviceDataStatus status) {
72             this.data = data;
73             this.key = key;
74             this.status = status;
75             this.uuid = uuid;
76             if (status == DeviceDataStatus.IN_TRANSIT) {
77                 intransitTimeStamp = System.currentTimeMillis();
78             }
79         }
80
81         public Object getData() {
82             return data;
83         }
84
85         public DeviceDataStatus getStatus() {
86             return status;
87         }
88
89         public UUID getUuid() {
90             return uuid;
91         }
92
93         public InstanceIdentifier getKey() {
94             return key;
95         }
96
97         public boolean isIntransitTimeExpired() {
98             return System.currentTimeMillis()
99                     > intransitTimeStamp + HwvtepSouthboundConstants.IN_TRANSIT_STATE_EXPIRY_TIME_MILLIS;
100         }
101
102         public boolean isInTransitState() {
103             return status == DeviceDataStatus.IN_TRANSIT;
104         }
105     }
106
107     private Map<InstanceIdentifier, Set<InstanceIdentifier>> tepIdReferences;
108     private Map<InstanceIdentifier<LogicalSwitches>, Map<InstanceIdentifier<RemoteUcastMacs>, RemoteUcastMacs>> logicalSwitchVsUcasts;
109     private Map<InstanceIdentifier<LogicalSwitches>, Map<InstanceIdentifier<RemoteMcastMacs>, RemoteMcastMacs>> logicalSwitchVsMcasts;
110     private Map<UUID, LogicalSwitch> logicalSwitches = null;
111     private Map<UUID, PhysicalSwitch> physicalSwitches = null;
112     private Map<UUID, PhysicalLocator> physicalLocators = null;
113     private Map<UUID, UUID> mapTunnelToPhysicalSwitch = null;
114
115     private HwvtepConnectionInstance connectionInstance;
116
117     private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> configKeyVsData = new ConcurrentHashMap<>();
118     private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> opKeyVsData = new ConcurrentHashMap<>();
119     private Map<Class<? extends Identifiable>, Map<UUID, Object>> uuidVsData = new ConcurrentHashMap<>();
120     private DependencyQueue dependencyQueue;
121     private TransactionHistory controllerTxHistory;
122     private TransactionHistory deviceUpdateHistory;
123
124
125     public HwvtepDeviceInfo(HwvtepConnectionInstance hwvtepConnectionInstance) {
126         this.connectionInstance = hwvtepConnectionInstance;
127         this.logicalSwitches = new ConcurrentHashMap<>();
128         this.physicalSwitches = new ConcurrentHashMap<>();
129         this.physicalLocators = new ConcurrentHashMap<>();
130         this.mapTunnelToPhysicalSwitch = new ConcurrentHashMap<>();
131         this.tepIdReferences = new ConcurrentHashMap<>();
132         this.logicalSwitchVsUcasts = new ConcurrentHashMap<>();
133         this.logicalSwitchVsMcasts = new ConcurrentHashMap<>();
134         this.dependencyQueue = new DependencyQueue(this);
135     }
136
137     public LogicalSwitch getLogicalSwitch(UUID uuid) {
138         return (LogicalSwitch) getDeviceOperData(LogicalSwitches.class, uuid);
139     }
140
141     public Map<UUID, LogicalSwitch> getLogicalSwitches() {
142         Map<UUID, Object> switches = uuidVsData.get(LogicalSwitches.class);
143         Map<UUID, LogicalSwitch> result = new HashMap<>();
144         if (switches != null) {
145             for (Map.Entry<UUID, Object> entry : switches.entrySet()) {
146                 result.put(entry.getKey(), (LogicalSwitch) entry.getValue());
147             }
148         }
149         return result;
150     }
151
152     public void putPhysicalSwitch(UUID uuid, PhysicalSwitch pSwitch) {
153         physicalSwitches.put(uuid, pSwitch);
154     }
155
156     public PhysicalSwitch getPhysicalSwitch(UUID uuid) {
157         return physicalSwitches.get(uuid);
158     }
159
160     public PhysicalSwitch removePhysicalSwitch(UUID uuid) {
161         return physicalSwitches.remove(uuid);
162     }
163
164     public Map<UUID, PhysicalSwitch> getPhysicalSwitches() {
165         return physicalSwitches;
166     }
167
168     public PhysicalLocator getPhysicalLocator(UUID uuid) {
169         return (PhysicalLocator) getDeviceOperData(TerminationPoint.class, uuid);
170     }
171
172     public Map<UUID, PhysicalLocator> getPhysicalLocators() {
173         Map<UUID, Object> locators = uuidVsData.get(TerminationPoint.class);
174         Map<UUID, PhysicalLocator> result = new HashMap<>();
175         if (locators != null) {
176             for (Map.Entry<UUID, Object> entry : locators.entrySet()) {
177                 result.put(entry.getKey(), (PhysicalLocator) entry.getValue());
178             }
179         }
180         return result;
181     }
182
183     public void putPhysicalSwitchForTunnel(UUID uuid, UUID psUUID) {
184         mapTunnelToPhysicalSwitch.put(uuid, psUUID);
185     }
186
187     public PhysicalSwitch getPhysicalSwitchForTunnel(UUID uuid) {
188         return physicalSwitches.get(mapTunnelToPhysicalSwitch.get(uuid));
189     }
190
191     public void removePhysicalSwitchForTunnel(UUID uuid) {
192         mapTunnelToPhysicalSwitch.remove(uuid);
193     }
194
195     public Map<UUID, UUID> getPhysicalSwitchesForTunnels() {
196         return mapTunnelToPhysicalSwitch;
197     }
198
199     public boolean isKeyInTransit(Class<? extends Identifiable> cls, InstanceIdentifier key) {
200         DeviceData deviceData = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
201         return deviceData != null && DeviceDataStatus.IN_TRANSIT == deviceData.status;
202     }
203
204     public boolean isConfigDataAvailable(Class<? extends Identifiable> cls, InstanceIdentifier key) {
205         return HwvtepSouthboundUtil.getData(configKeyVsData, cls, key) != null;
206     }
207
208     public void updateConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key, Object data) {
209         HwvtepSouthboundUtil.updateData(configKeyVsData, cls, key,
210                 new DeviceData(key, null, data, DeviceDataStatus.AVAILABLE));
211     }
212
213     public Object getConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
214         DeviceData deviceData = HwvtepSouthboundUtil.getData(configKeyVsData, cls, key);
215         if (deviceData != null) {
216             return deviceData.getData();
217         }
218         return null;
219     }
220
221     public void clearConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
222         HwvtepSouthboundUtil.clearData(configKeyVsData, cls, key);
223     }
224
225     public void markKeyAsInTransit(Class<? extends Identifiable> cls, InstanceIdentifier key) {
226         LOG.debug("Marking device data as intransit {}", key);
227         DeviceData deviceData = getDeviceOperData(cls, key);
228         UUID uuid = null;
229         Object data = null;
230         if (deviceData != null) {
231             uuid = deviceData.getUuid();
232             data = deviceData.getData();
233         }
234         HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key,
235                 new DeviceData(key, uuid, data, DeviceDataStatus.IN_TRANSIT));
236     }
237
238     public void updateDeviceOperData(Class<? extends Identifiable> cls, InstanceIdentifier key, UUID uuid, Object data) {
239         LOG.debug("Updating device data {}", key);
240         HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key,
241                 new DeviceData(key, uuid, data, DeviceDataStatus.AVAILABLE));
242         HwvtepSouthboundUtil.updateData(uuidVsData, cls, uuid, data);
243     }
244
245     public void clearDeviceOperData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
246         DeviceData deviceData = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
247         if (deviceData != null && deviceData.uuid != null) {
248             HwvtepSouthboundUtil.clearData(uuidVsData, cls, deviceData.uuid);
249         }
250         HwvtepSouthboundUtil.clearData(opKeyVsData, cls, key);
251     }
252
253     public Object getDeviceOperData(Class<? extends Identifiable> cls, UUID uuid) {
254         return HwvtepSouthboundUtil.getData(uuidVsData, cls, uuid);
255     }
256
257     public DeviceData getDeviceOperData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
258         return HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
259     }
260
261     public UUID getUUID(Class<? extends Identifiable> cls, InstanceIdentifier key) {
262         DeviceData data = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
263         if (data != null) {
264             return data.uuid;
265         }
266         return null;
267     }
268
269     public <T extends Identifiable> void addJobToQueue(DependentJob<T> job) {
270         dependencyQueue.addToQueue(job);
271     }
272
273     public void onConfigDataAvailable() {
274         dependencyQueue.processReadyJobsFromConfigQueue(connectionInstance);
275     }
276
277     public synchronized void onOperDataAvailable() {
278         dependencyQueue.processReadyJobsFromOpQueue(connectionInstance);
279     }
280
281     public void scheduleTransaction(final TransactCommand transactCommand) {
282         dependencyQueue.submit(() -> connectionInstance.transact(transactCommand));
283     }
284
285     public void clearDeviceOperData(Class<? extends Identifiable> cls) {
286         Map<InstanceIdentifier, DeviceData> iids = opKeyVsData.get(cls);
287         if (iids != null && !iids.isEmpty()) {
288             Iterator<Map.Entry<InstanceIdentifier, DeviceData>> it = iids.entrySet().iterator();
289             while (it.hasNext()) {
290                 Map.Entry<InstanceIdentifier, DeviceData> entry = it.next();
291                 DeviceData deviceData = entry.getValue();
292                 if (deviceData != null && deviceData.getStatus() != DeviceDataStatus.IN_TRANSIT) {
293                     it.remove();
294                 }
295             }
296         }
297     }
298
299     public void clearInTransit(Class<? extends Identifiable> cls, InstanceIdentifier key) {
300         DeviceData deviceData = getDeviceOperData(cls, key);
301         if (deviceData != null && deviceData.isInTransitState()) {
302             if (deviceData.getData() != null) {
303                 HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key,
304                         new DeviceData(key, deviceData.getUuid(), deviceData.getData(), DeviceDataStatus.AVAILABLE));
305             } else {
306                 clearDeviceOperData(cls, key);
307             }
308         }
309     }
310
311     public Map<InstanceIdentifier, DeviceData> getDeviceOperData(Class<? extends Identifiable> cls) {
312         return opKeyVsData.get(cls);
313     }
314
315     public void incRefCount(InstanceIdentifier reference, InstanceIdentifier tep) {
316         if (reference == null || tep == null) {
317             return;
318         }
319         tepIdReferences.computeIfAbsent(tep, (tepId) -> Sets.newConcurrentHashSet());
320         tepIdReferences.get(tep).add(reference);
321     }
322
323     public int getRefCount(InstanceIdentifier tep) {
324         return tepIdReferences.containsKey(tep) ? tepIdReferences.get(tep).size() : 0;
325     }
326
327     public Set<InstanceIdentifier> getRefCounts(InstanceIdentifier tep) {
328         return tepIdReferences.get(tep);
329     }
330
331     public void decRefCount(InstanceIdentifier reference, InstanceIdentifier tep) {
332         if (reference == null || tep == null || !tepIdReferences.containsKey(tep)) {
333             return;
334         }
335         //synchronize to make sure that no two parallel deletes puts the key in transit state twice
336         synchronized (this) {
337             boolean removed = tepIdReferences.get(tep).remove(reference);
338             if (removed && tepIdReferences.get(tep).isEmpty()) {
339                 LOG.debug("Marking the termination point as in transit ref count zero {} ", tep);
340                 markKeyAsInTransit(TerminationPoint.class, tep);
341             }
342         }
343     }
344
345     public void clearLogicalSwitchRefs(InstanceIdentifier<LogicalSwitches> logicalSwitchKey) {
346         Map<InstanceIdentifier<RemoteMcastMacs>, RemoteMcastMacs> mcasts = logicalSwitchVsMcasts.get(logicalSwitchKey);
347         if (mcasts != null ) {
348             mcasts.entrySet().forEach( (entry) -> removeRemoteMcast(logicalSwitchKey, entry.getKey()));
349         }
350         Map<InstanceIdentifier<RemoteUcastMacs>, RemoteUcastMacs> ucasts = logicalSwitchVsUcasts.get(logicalSwitchKey);
351         if (ucasts != null ) {
352             ucasts.entrySet().forEach( (entry) -> removeRemoteUcast(logicalSwitchKey, entry.getKey()));
353         }
354         markKeyAsInTransit(LogicalSwitches.class, logicalSwitchKey);
355     }
356
357     public  void updateRemoteMcast(InstanceIdentifier<LogicalSwitches> lsIid,
358                                    InstanceIdentifier<RemoteMcastMacs> mcastIid,
359                                    RemoteMcastMacs mac) {
360         logicalSwitchVsMcasts.computeIfAbsent(lsIid, (lsKey) -> new ConcurrentHashMap<>());
361         logicalSwitchVsMcasts.get(lsIid).put(mcastIid, mac);
362         if (mac.getLocatorSet() != null) {
363             mac.getLocatorSet().forEach( (iid) -> incRefCount(mcastIid, iid.getLocatorRef().getValue()));
364         }
365     }
366
367     public  void updateRemoteUcast(InstanceIdentifier<LogicalSwitches> lsIid,
368                                    InstanceIdentifier<RemoteUcastMacs> ucastIid,
369                                    RemoteUcastMacs mac) {
370         logicalSwitchVsUcasts.computeIfAbsent(lsIid, (lsKey) -> new ConcurrentHashMap<>());
371         logicalSwitchVsUcasts.get(lsIid).put(ucastIid, mac);
372         incRefCount(ucastIid, mac.getLocatorRef().getValue());
373     }
374
375     public  void removeRemoteMcast(InstanceIdentifier<LogicalSwitches> lsIid, InstanceIdentifier<RemoteMcastMacs> mcastIid) {
376         if (!logicalSwitchVsMcasts.containsKey(lsIid)) {
377             return;
378         }
379         RemoteMcastMacs mac = logicalSwitchVsMcasts.get(lsIid).remove(mcastIid);
380         if (mac != null && mac.getLocatorSet() != null) {
381             mac.getLocatorSet().forEach((iid) -> decRefCount(mcastIid, iid.getLocatorRef().getValue()));
382         }
383         markKeyAsInTransit(RemoteMcastMacs.class, mcastIid);
384     }
385
386     public void removeRemoteUcast(InstanceIdentifier<LogicalSwitches> lsIid,
387                                    InstanceIdentifier<RemoteUcastMacs> ucastIid) {
388         if (!logicalSwitchVsUcasts.containsKey(lsIid)) {
389             return;
390         }
391         RemoteUcastMacs mac = logicalSwitchVsUcasts.get(lsIid).remove(ucastIid);
392         if (mac != null) {
393             decRefCount(ucastIid, mac.getLocatorRef().getValue());
394         }
395         markKeyAsInTransit(RemoteUcastMacs.class, ucastIid);
396     }
397
398     public HwvtepConnectionInstance getConnectionInstance() {
399         return connectionInstance;
400     }
401
402     public void setConfigKeyVsData(Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> configKeyVsData) {
403         this.configKeyVsData = configKeyVsData;
404     }
405
406     public void setControllerTxHistory(TransactionHistory controllerTxHistory) {
407         this.controllerTxHistory = controllerTxHistory;
408     }
409
410     public void setDeviceUpdateHistory(TransactionHistory deviceUpdateHistory) {
411         this.deviceUpdateHistory = deviceUpdateHistory;
412     }
413
414     public void addToControllerTx(TransactionType transactionType, Object object) {
415         controllerTxHistory.addToHistory(transactionType, object);
416     }
417
418     public void addToDeviceUpdate(TransactionType transactionType, Object object) {
419         deviceUpdateHistory.addToHistory(transactionType, object);
420     }
421 }