bug 8029 handle expired in transit entries
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transact / DependentJob.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.transact;
10
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Optional;
14 import java.util.function.BiPredicate;
15 import java.util.function.Predicate;
16
17 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
18 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
19 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
20 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
21 import org.opendaylight.yangtools.yang.binding.DataObject;
22 import org.opendaylight.yangtools.yang.binding.Identifiable;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 public abstract class DependentJob<T extends Identifiable> {
28
29     private static final Logger LOG = LoggerFactory.getLogger(DependentJob.class);
30
31     private static final Predicate<HwvtepDeviceInfo.DeviceData> DATA_INTRANSIT
32             = (controllerData) -> controllerData != null && controllerData.isInTransitState();
33
34     private static final Predicate<HwvtepDeviceInfo.DeviceData> DATA_INTRANSIT_EXPIRED
35             = (controllerData) -> controllerData != null && controllerData.isInTransitState()
36             && controllerData.isIntransitTimeExpired();
37
38     //expecting the device to create the data
39     private static final BiPredicate<HwvtepDeviceInfo.DeviceData, Optional<TypedBaseTable>> INTRANSIT_DATA_CREATED
40             = (controllerData, deviceData) -> controllerData.getUuid() == null && deviceData.isPresent();
41
42     private static final BiPredicate<HwvtepDeviceInfo.DeviceData, Optional<TypedBaseTable>> INTRANSIT_DATA_NOT_CREATED
43             = (controllerData, deviceData) -> controllerData.getUuid() == null && !deviceData.isPresent();
44
45     //expecting the device to delete the data
46     private static final BiPredicate<HwvtepDeviceInfo.DeviceData, Optional<TypedBaseTable>> INTRANSIT_DATA_DELETED
47             = (controllerData, deviceData) -> controllerData.getUuid() != null && !deviceData.isPresent();
48
49     private static final BiPredicate<HwvtepDeviceInfo.DeviceData, Optional<TypedBaseTable>> INTRANSIT_DATA_NOT_DELETED
50             = (controllerData, deviceData) -> controllerData.getUuid() != null && deviceData.isPresent();
51
52     private final long expiryTime;
53     private final InstanceIdentifier key;
54     private final T data;
55     private final Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies;
56
57     DependentJob(InstanceIdentifier key,
58                            T data, Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies) {
59         this.expiryTime = System.currentTimeMillis() + HwvtepSouthboundConstants.WAITING_JOB_EXPIRY_TIME_MILLIS;
60         this.key = key;
61         this.data = data;
62         this.dependencies = dependencies;
63     }
64
65     /**
66      * This call back method gets called when all its dependencies are resolved
67      * @param operationalState   new current operational state
68      * @param transactionBuilder transaction builder to create device transaction
69      */
70     protected abstract void onDependencyResolved(HwvtepOperationalState operationalState,
71                                                  TransactionBuilder transactionBuilder);
72
73     /**
74      * This method is to check if all the given dependency of this job or not
75      * @param deviceInfo   The device info of tis job
76      * @param cls          dependency type to be checked for
77      * @param iid          instance identifier to be checked for
78      * @return true if the dependency is met
79      */
80     protected abstract boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class<? extends DataObject> cls,
81                                                InstanceIdentifier iid);
82
83     boolean isExpired(long currentTime) {
84         return currentTime > expiryTime;
85     }
86
87     /**
88      * This method checks if all the dependencies of this job or met or not
89      * @param deviceInfo The device info of this job
90      * @return true if all the dependencies are met
91      */
92     boolean areDependenciesMet(HwvtepDeviceInfo deviceInfo) {
93         for (Class<? extends DataObject> cls : dependencies.keySet()) {
94             for (InstanceIdentifier iid : dependencies.get(cls)) {
95                 if (!isDependencyMet(deviceInfo, cls, iid)) {
96                     return false;
97                 }
98             }
99         }
100         return true;
101     }
102
103     public InstanceIdentifier getKey() {
104         return key;
105     }
106
107     public T getData() {
108         return data;
109     }
110
111     public boolean isConfigWaitingJob() {
112         return true;
113     }
114
115     public void onFailure(TransactionBuilder deviceTransaction) {
116     }
117
118     public void onSuccess(TransactionBuilder deviceTransaction) {
119     }
120
121     public abstract static class ConfigWaitingJob<T extends Identifiable> extends DependentJob {
122
123         public ConfigWaitingJob(InstanceIdentifier key, T data, Map dependencies) {
124             super(key, data, dependencies);
125         }
126
127         @Override
128         protected boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, InstanceIdentifier iid) {
129             return deviceInfo.isConfigDataAvailable(cls, iid);
130         }
131     }
132
133     public abstract static class OpWaitingJob<T extends Identifiable> extends DependentJob {
134
135         public OpWaitingJob(InstanceIdentifier key, T data, Map dependencies) {
136             super(key, data, dependencies);
137         }
138
139         @Override
140         protected boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, InstanceIdentifier iid) {
141             boolean depenencyMet = true;
142             HwvtepDeviceInfo.DeviceData controllerData = deviceInfo.getDeviceOperData(cls, iid);
143
144             if (DATA_INTRANSIT_EXPIRED.test(controllerData)) {
145                 LOG.info("Intransit state expired for key: {} --- dependency {}", iid, getKey());
146                 String clsName = cls.getSimpleName();
147
148                 //either the device acted on the selected iid/uuid and sent the updated event or it did not
149                 //here we are querying the device directly to get the latest status on the iid
150                 Optional<TypedBaseTable> latestDeviceStatus = deviceInfo.getConnectionInstance().
151                         getHwvtepTableReader().getHwvtepTableEntryUUID(cls, iid, controllerData.getUuid());
152
153                 TypedBaseTable latestDeviceData = latestDeviceStatus.isPresent() ? latestDeviceStatus.get() : null;
154
155                 if (INTRANSIT_DATA_CREATED.test(controllerData, latestDeviceStatus)) {
156                     LOG.info("Intransit expired key is actually created but update is missed/delayed {}", iid);
157                     deviceInfo.updateDeviceOperData(cls, iid, latestDeviceStatus.get().getUuid(), latestDeviceData);
158
159                 } else if (INTRANSIT_DATA_NOT_CREATED.test(controllerData, latestDeviceStatus)) {
160                     LOG.info("Intransit expired key is actually not created but update is missed/delayed {}", iid);
161                     deviceInfo.clearDeviceOperData(cls, iid);
162
163                 } else if (INTRANSIT_DATA_DELETED.test(controllerData, latestDeviceStatus)) {
164                     //also deleted from device
165                     LOG.info("Intransit expired key is actually deleted but update is missed/delayed {}", iid);
166                     deviceInfo.clearDeviceOperData(cls, iid);
167
168                 } else if (INTRANSIT_DATA_NOT_DELETED.test(controllerData, latestDeviceStatus)) {
169                     //not deleted from device we will reuse existing uuid
170                     LOG.info("Intransit expired key is actually not deleted but update is missed/delayed {}", iid);
171                     deviceInfo.updateDeviceOperData(cls, iid, latestDeviceStatus.get().getUuid(), latestDeviceData);
172                 }
173             } else if (DATA_INTRANSIT.test(controllerData)) {
174                 //device status is still in transit
175                 depenencyMet = false;
176             }
177             return depenencyMet;
178         }
179
180         public boolean isConfigWaitingJob() {
181             return false;
182         }
183     }
184 }