Fix delete of Logical_Switch for the "referential integrity violation" failure. 68/88968/4
authorChandra Shekar S <chandra.shekar.s@ericsson.com>
Wed, 8 Apr 2020 08:50:31 +0000 (14:20 +0530)
committerChandra Shekar S <chandra.shekar.s@ericsson.com>
Mon, 13 Apr 2020 05:25:43 +0000 (10:55 +0530)
Currently the Logical_Switch delete is failing with "referential integrity violation" error as listed below
2020-04-13T05:27:36,854 | ERROR | hwvtep-waiting-job-0 | TransactInvokerImpl              | 403 - org.opendaylight.ovsdb.hwvtepsouthbound-impl - 1.11.0.SNAPSHOT | HWVTEP transaction operation failed referential integrity violation cannot delete Logical_Switch row 7392ce5a-1bf6-4951-a22e-740ac78aaa60 because of 9 remaining reference(s)
2020-04-13T05:27:36,855 | ERROR | hwvtep-waiting-job-0 | TransactInvokerImpl              | 403 - org.opendaylight.ovsdb.hwvtepsouthbound-impl - 1.11.0.SNAPSHOT | Failed transaction delete from Logical_Switchdelete from Ucast_Macs_Remotedelete from Ucast_Macs_Localdelete from Mcast_Macs_Remotedelete from Mcast_Macs_Local
2020-04-13T05:27:36,856 | ERROR | hwvtep-waiting-job-0 | TransactInvokerImpl              | 403 - org.opendaylight.ovsdb.hwvtepsouthbound-impl - 1.11.0.SNAPSHOT | Failed on second attempt too aborting the transaction org.opendaylight.ovsdb.hwvtepsouthbound.transact.LogicalSwitchRemoveCommand$1@575aaf7c
2020-04-13T05:27:36,857 | ERROR | hwvtep-waiting-job-0 | TransactInvokerImpl              | 403 - org.opendaylight.ovsdb.hwvtepsouthbound-impl - 1.11.0.SNAPSHOT | HWVTEP transaction operation failed referential integrity violation cannot delete Logical_Switch row 064cc69b-cce8-4f08-9478-9b82c6059cac because of 9 remaining reference(s)
2020-04-13T05:27:36,858 | ERROR | hwvtep-waiting-job-0 | TransactInvokerImpl              | 403 - org.opendaylight.ovsdb.hwvtepsouthbound-impl - 1.11.0.SNAPSHOT | Failed transaction delete from Logical_Switchdelete from Ucast_Macs_Remotedelete from Ucast_Macs_Localdelete from Mcast_Macs_Remotedelete from Mcast_Macs_Local
2020-04-13T05:27:36,858 | ERROR | hwvtep-waiting-job-0 | TransactInvokerImpl              | 403 - org.opendaylight.ovsdb.hwvtepsouthbound-impl - 1.11.0.SNAPSHOT | Failed on second attempt too aborting the transaction org.opendaylight.ovsdb.hwvtepsouthbound.transact.LogicalSwitchRemoveCommand$1@569e133b

The Logical_Switch reference will be present in other tables like Ucast_Macs_Remote, Pysical_Port and Ucast_Macs_Remote etc.
These should be deleted first when the Logical_Switch is going to be deleted.

Signed-off-by: Chandra Shekar S <chandra.shekar.s@ericsson.com>
Change-Id: Ic2b101368bd50f6494e357fa49ccf53e641a09a3

16 files changed:
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDeviceInfo.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundConstants.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/AbstractTransactCommand.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/DependencyQueue.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/DependentJob.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchRemoveCommand.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUcastsRemoveCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/McastMacsRemoteRemoveCommand.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/McastMacsRemoteUpdateCommand.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PhysicalPortUpdateCommand.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PlainLogicalSwitchRemoveCmd.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/UcastMacsRemoteRemoveCommand.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/UcastMacsRemoteUpdateCommand.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DependencyQueueTest.java

index 4e13e46dbc2d54d30bb288fd8c259dfa85b1ffe0..21c269bfc5976caaba2340fdb74e20bab554db6d 100644 (file)
@@ -407,4 +407,8 @@ public class HwvtepConnectionInstance {
         deviceInfo.setDeviceUpdateHistory(deviceUpdateLog);
         this.deviceUpdateHistory = deviceUpdateLog;
     }
+
+    public TransactionInvoker getTxInvoker() {
+        return txInvoker;
+    }
 }
index f31554248f1c342ad877ddf143ee57839a7e0a6a..430f8edf39b245deb76648767a9ae1c02ea7fdc3 100644 (file)
@@ -146,6 +146,7 @@ public class HwvtepDeviceInfo {
 
     private final HwvtepConnectionInstance connectionInstance;
 
+    private Map<InstanceIdentifier, AtomicInteger> iidInQueueCount = new ConcurrentHashMap<>();
     private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> configKeyVsData =
             new ConcurrentHashMap<>();
     private final Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> opKeyVsData =
@@ -482,4 +483,17 @@ public class HwvtepDeviceInfo {
         return Collections.unmodifiableMap(uuidVsData);
     }
 
+    public void putKeyInDependencyQueue(InstanceIdentifier iid) {
+        iidInQueueCount.putIfAbsent(iid, new AtomicInteger(0));
+        iidInQueueCount.get(iid).incrementAndGet();
+    }
+
+    public void clearKeyFromDependencyQueue(InstanceIdentifier iid) {
+        iidInQueueCount.remove(iid);
+    }
+
+    public boolean isKeyInDependencyQueue(InstanceIdentifier iid) {
+        return iidInQueueCount.containsKey(iid);
+    }
+
 }
index c0afe20b5845103c37de47975d81bcf57ccdf0a4..c42be5bc953b2d465417da4d6b42663d1b7b3f47 100644 (file)
@@ -55,5 +55,7 @@ public interface HwvtepSouthboundConstants {
             "config.node.update.max.delay.ms", 10000);
     int EOS_TIMEOUT = Integer.getInteger("hwvtep.eos.timeout.delay.secs", 240);
     int CHAIN_RETRY_COUNT = 10;
+    long LS_REMOVE_DELAY_SECS = 5;
+    int LS_REMOVE_RETRIES = 10;
 
 }
index 8437224791757ebd9ec7e1da08d8a9bd17f76bf4..712f2ef7cf155c816daf7f7437d5eea96fc7b77e 100644 (file)
@@ -8,30 +8,32 @@
 
 package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
 
+import com.google.common.collect.Lists;
+
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepTableReader;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
-import org.opendaylight.ovsdb.utils.mdsal.utils.ControllerMdsalUtils;
 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
@@ -50,7 +52,7 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
     protected volatile HwvtepOperationalState hwvtepOperationalState = null;
     protected volatile TransactionBuilder deviceTransaction = null;
     private Collection<DataTreeModification<Node>> changes;
-    protected Map<TransactionBuilder, List<MdsalUpdate<T>>> updates = new ConcurrentHashMap<>();
+    Set<MdsalUpdate<T>> updates = new HashSet<>();
 
     protected AbstractTransactCommand() {
         // NO OP
@@ -74,27 +76,25 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
     }
 
     void updateCurrentTxDeleteData(Class<? extends Identifiable> cls, InstanceIdentifier key, T data) {
-        getOperationalState().getDeviceInfo().markKeyAsInTransit(cls, key);
+        hwvtepOperationalState.updateCurrentTxDeleteData(cls, key);
+        markKeyAsInTransit(cls, key);
         addToUpdates(key, data);
-        getOperationalState().getDeviceInfo().clearConfigData(cls, key);
     }
 
     void updateCurrentTxData(Class<? extends Identifiable> cls, InstanceIdentifier key, UUID uuid, T data) {
-        getOperationalState().getDeviceInfo().markKeyAsInTransit(cls, key);
+        hwvtepOperationalState.updateCurrentTxData(cls, key, uuid);
+        markKeyAsInTransit(cls, key);
         addToUpdates(key, data);
-        getOperationalState().getDeviceInfo().updateConfigData(cls, key, data);
     }
 
     void addToUpdates(InstanceIdentifier key, T data) {
         T oldData = null;
         Type type = getClass().getGenericSuperclass();
         Type classType = ((ParameterizedType) type).getActualTypeArguments()[0];
-        if (getDeviceInfo().getConfigData((Class<? extends Identifiable>) classType, key) != null
-                && getDeviceInfo().getConfigData((Class<? extends Identifiable>) classType, key).getData() != null) {
-            oldData = (T) getDeviceInfo().getConfigData((Class<? extends Identifiable>) classType, key).getData();
+        if (getConfigData((Class<? extends Identifiable>) classType, key) != null) {
+            oldData = (T) getConfigData((Class<? extends Identifiable>) classType, key).getData();
         }
-        updates.putIfAbsent(getDeviceTransaction(), new ArrayList<MdsalUpdate<T>>());
-        updates.get(getDeviceTransaction()).add(new MdsalUpdate<>(key, data, oldData));
+        updates.add(new MdsalUpdate<T>(key, data, oldData));
     }
 
     void processDependencies(final UnMetDependencyGetter<T> unMetDependencyGetter,
@@ -103,28 +103,32 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
             final InstanceIdentifier key,
             final T data, final Object... extraData) {
 
-        this.deviceTransaction = transaction;
-        HwvtepDeviceInfo deviceInfo = getOperationalState().getDeviceInfo();
-        Map inTransitDependencies = new HashMap<>();
-        Map configDependencies = new HashMap<>();
-
-        if (!isDeleteCmd() && unMetDependencyGetter != null) {
-            inTransitDependencies = unMetDependencyGetter.getInTransitDependencies(getOperationalState(), data);
-            configDependencies = unMetDependencyGetter.getUnMetConfigDependencies(getOperationalState(), data);
-            //we can skip the config termination point dependency as we can create them in device as part of this tx
-            configDependencies.remove(TerminationPoint.class);
-        }
-
+        HwvtepDeviceInfo deviceInfo = hwvtepOperationalState.getDeviceInfo();
         Type type = getClass().getGenericSuperclass();
         Type classType = ((ParameterizedType) type).getActualTypeArguments()[0];
+        Map inTransitDependencies = Collections.emptyMap();
+        Map confingDependencies = Collections.emptyMap();
 
-        //If this key itself is in transit wait for the response of this key itself
-        if (deviceInfo.isKeyInTransit((Class<? extends Identifiable>) classType, key)) {
-            inTransitDependencies.put(classType, Collections.singletonList(key));
-        }
+        if (isDeleteCmd()) {
+            if (deviceInfo.isKeyInTransit((Class<? extends Identifiable>) classType, key)) {
+                inTransitDependencies = new HashMap<>();
+                inTransitDependencies.put((Class<? extends Identifiable>) classType, Lists.newArrayList(key));
+            }
+        } else {
+            inTransitDependencies = unMetDependencyGetter.getInTransitDependencies(hwvtepOperationalState, data);
+            confingDependencies = unMetDependencyGetter.getUnMetConfigDependencies(hwvtepOperationalState, data);
+            //we can skip the config termination point dependency as we can create them in device as part of this tx
+            confingDependencies.remove(TerminationPoint.class);
 
-        if (HwvtepSouthboundUtil.isEmptyMap(configDependencies) && HwvtepSouthboundUtil.isEmptyMap(
-                inTransitDependencies)) {
+            //If this key itself is in transit wait for the response of this key itself
+            if (deviceInfo.isKeyInTransit((Class<? extends Identifiable>) classType, key)
+                    || deviceInfo.isKeyInDependencyQueue(key)) {
+                inTransitDependencies.put((Class<? extends Identifiable>) classType, Lists.newArrayList(key));
+            }
+        }
+        LOG.info("Update received for key: {} txId: {}", key, getOperationalState().getTransactionId());
+        if (HwvtepSouthboundUtil.isEmptyMap(confingDependencies)
+                && HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
             doDeviceTransaction(transaction, nodeIid, data, key, extraData);
             if (isDeleteCmd()) {
                 getDeviceInfo().clearConfigData((Class<? extends Identifiable>) classType, key);
@@ -132,42 +136,77 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
                 getDeviceInfo().updateConfigData((Class<? extends Identifiable>) classType, key, data);
             }
         }
-        if (!HwvtepSouthboundUtil.isEmptyMap(configDependencies)) {
-            DependentJob<T> configWaitingJob = new DependentJob.ConfigWaitingJob<T>(
-                    key, data, configDependencies) {
+
+        if (!HwvtepSouthboundUtil.isEmptyMap(confingDependencies)) {
+            DependentJob<T> configWaitingJob = new DependentJob.ConfigWaitingJob(
+                    key, data, confingDependencies) {
+                AbstractTransactCommand clone = getClone();
 
                 @Override
                 public void onDependencyResolved(HwvtepOperationalState operationalState,
-                        TransactionBuilder transactionBuilder) {
-                    hwvtepOperationalState = operationalState;
-                    deviceTransaction = transactionBuilder;
-                    onConfigUpdate(transactionBuilder, nodeIid, data, key, extraData);
+                                                 TransactionBuilder transactionBuilder) {
+                    clone.hwvtepOperationalState = operationalState;
+                    HwvtepDeviceInfo.DeviceData deviceData =
+                            getDeviceInfo().getConfigData((Class<? extends Identifiable>)getClassType(), key);
+                    T latest = data;
+                    if (deviceData != null && deviceData.getData() != null) {
+                        latest = (T) deviceData.getData();
+                        clone.onConfigUpdate(transactionBuilder, nodeIid, latest, key, extraData);
+                    } else if (isDeleteCmd()) {
+                        clone.onConfigUpdate(transactionBuilder, nodeIid, latest, key, extraData);
+                    }
+                }
+
+                @Override
+                public void onFailure() {
+                    clone.onFailure(transaction);
+                }
+
+                @Override
+                public void onSuccess() {
+                    clone.onSuccess(transaction);
                 }
             };
-            deviceInfo.addJobToQueue(configWaitingJob);
+            LOG.info("Update Adding to config wait queue for key: {} txId: {}",
+                    key, getOperationalState().getTransactionId());
+            addJobToQueue(configWaitingJob);
+            return;
         }
-
+        final long transactionId = hwvtepOperationalState.getTransactionId();
         if (!HwvtepSouthboundUtil.isEmptyMap(inTransitDependencies)) {
 
-            DependentJob<T> opWaitingJob = new DependentJob.OpWaitingJob<T>(
-                    key, data, inTransitDependencies) {
+            DependentJob<T> opWaitingJob = new DependentJob.OpWaitingJob(
+                    key, data, inTransitDependencies, transactionId) {
+                AbstractTransactCommand clone = getClone();
 
                 @Override
                 public void onDependencyResolved(HwvtepOperationalState operationalState,
-                        TransactionBuilder transactionBuilder) {
-                    //data would have got deleted by , push the data only if it is still in configds
-                    hwvtepOperationalState = operationalState;
-                    deviceTransaction = transactionBuilder;
-                    T data = (T) new ControllerMdsalUtils(operationalState.getDataBroker()).read(
-                            LogicalDatastoreType.CONFIGURATION, key);
-                    if (data != null) {
-                        onConfigUpdate(transactionBuilder, nodeIid, data, key, extraData);
-                    } else {
-                        LOG.warn("Skipping add of key: {} as it is not present", key);
+                                                 TransactionBuilder transactionBuilder) {
+                    clone.hwvtepOperationalState = operationalState;
+                    HwvtepDeviceInfo.DeviceData deviceData = getDeviceInfo()
+                            .getConfigData((Class<? extends Identifiable>)getClassType(), key);
+                    T latest = data;
+                    if (deviceData != null && deviceData.getData() != null) {
+                        latest = (T) deviceData.getData();
+                        clone.onConfigUpdate(transactionBuilder, nodeIid, latest, key, extraData);
+                    } else if (isDeleteCmd()) {
+                        clone.onConfigUpdate(transactionBuilder, nodeIid, latest, key, extraData);
                     }
                 }
+
+                @Override
+                public void onFailure() {
+                    clone.onFailure(transaction);
+                }
+
+                @Override
+                public void onSuccess() {
+                    clone.onSuccess(transaction);
+                }
             };
-            deviceInfo.addJobToQueue(opWaitingJob);
+            LOG.info("Update Adding to op wait queue for key: {} txId: {}", key, transactionId);
+            addJobToQueue(opWaitingJob);
+            return;
         }
     }
 
@@ -216,6 +255,9 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
         if (modification != null && !modification.isEmpty()) {
             for (DataTreeModification<Node> change : modification) {
                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
+                if (!Objects.equals(hwvtepOperationalState.getConnectionInstance().getInstanceIdentifier(), key)) {
+                    continue;
+                }
                 Class<? extends Identifiable> classType = (Class<? extends Identifiable>) getClassType();
                 List<T> removed;
                 if (getOperationalState().isInReconciliation()) {
@@ -237,6 +279,9 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
         if (modification != null && !modification.isEmpty()) {
             for (DataTreeModification<Node> change : modification) {
                 InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
+                if (!Objects.equals(hwvtepOperationalState.getConnectionInstance().getInstanceIdentifier(), key)) {
+                    continue;
+                }
                 Class<? extends Identifiable> classType = (Class<? extends Identifiable>) getClassType();
                 List<T> updated = null;
                 if (getOperationalState().isInReconciliation()) {
@@ -292,7 +337,7 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
         List<T> data1 = getData(include);
         List<T> data2 = diffOf(node1, node2, compareKeyOnly);
         if (HwvtepSouthboundUtil.isEmpty(data1) && HwvtepSouthboundUtil.isEmpty(data2)) {
-            return Collections.emptyList();
+            return Collections.EMPTY_LIST;
         }
         List<T> result = new ArrayList<>(data1);
         result.addAll(data2);
@@ -306,30 +351,30 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
         List<T> list2 = getData(node2);
 
         if (HwvtepSouthboundUtil.isEmpty(list1)) {
-            return Collections.emptyList();
+            return Collections.EMPTY_LIST;
         }
         if (HwvtepSouthboundUtil.isEmpty(list2)) {
-            return HwvtepSouthboundUtil.isEmpty(list1) ? Collections.emptyList() : list1;
+            return HwvtepSouthboundUtil.isEmpty(list1) ? Collections.EMPTY_LIST : list1;
         }
 
-        Iterator<T> it1 = list1.iterator();
-
-        while (it1.hasNext()) {
-            T ele = it1.next();
-            Iterator<T> it2 = list2.iterator();
-            boolean found = false;
-            while (it2.hasNext()) {
-                T other = it2.next();
-                found = compareKeyOnly ? Objects.equals(ele.key(), other.key()) : areEqual(ele, other);
-                if (found) {
-                    it2.remove();
-                    break;
+        Map<Object, T> map1 = list1.stream().collect(Collectors.toMap(ele -> ele.key(), ele -> ele));
+        Map<Object, T> map2 = list2.stream().collect(Collectors.toMap(ele -> ele.key(), ele -> ele));
+        map1.entrySet().forEach(entry1 -> {
+            T val2 = map2.remove(entry1.getKey());
+            if (compareKeyOnly) {
+                if (val2 == null) {
+                    result.add(entry1.getValue());
+                }
+            } else {
+                if (val2 == null) {
+                    result.add(entry1.getValue());
+                    return;
+                }
+                if (!areEqual(entry1.getValue(), val2)) {
+                    result.add(entry1.getValue());
                 }
             }
-            if (!found) {
-                result.add(ele);
-            }
-        }
+        });
         return result;
     }
 
@@ -372,21 +417,11 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
 
     @Override
     public void onSuccess(TransactionBuilder deviceTx) {
-        if (deviceTx == null || !updates.containsKey(deviceTx)) {
-            return;
-        }
         onCommandSucceeded();
     }
 
     @Override
     public void onFailure(TransactionBuilder deviceTx) {
-        if (deviceTx == null || !updates.containsKey(deviceTx)) {
-            return;
-        }
-        for (MdsalUpdate mdsalUpdate : updates.get(deviceTx)) {
-            getDeviceInfo().clearInTransit((Class<? extends Identifiable>) mdsalUpdate.getClass(),
-                    mdsalUpdate.getKey());
-        }
         onCommandFailed();
     }
 
@@ -403,38 +438,69 @@ public abstract class AbstractTransactCommand<T extends Identifiable, A extends
     public <T> HwvtepDeviceInfo.DeviceData fetchDeviceData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
         HwvtepDeviceInfo.DeviceData deviceData  = getDeviceOpData(cls, key);
         if (deviceData == null) {
-            LOG.debug("Could not find data for key {}", getNodeKeyStr(key));
-            java.util.Optional<TypedBaseTable> optional = getTableReader().getHwvtepTableEntryUUID(cls, key, null);
+            LOG.debug("Could not find data for key {}", key);
+            java.util.Optional<TypedBaseTable> optional =
+                    getTableReader().getHwvtepTableEntryUUID(cls, key, null);
             if (optional.isPresent()) {
-                LOG.debug("Found the data for key from device {} ", getNodeKeyStr(key));
+                LOG.debug("Found the data for key from device {} ", key);
                 getDeviceInfo().updateDeviceOperData(cls, key, optional.get().getUuid(), (T)optional.get());
                 return getDeviceOpData(cls, key);
             } else {
-                LOG.info("Could not Find the data for key from device {} ", getNodeKeyStr(key));
+                LOG.info("Could not Find the data for key from device {} ", key);
             }
         }
         return deviceData;
     }
 
-    protected String getNodeKeyStr(InstanceIdentifier iid) {
-        try {
-            return getClassType().getTypeName() + "." + ((Node) iid.firstKeyOf(Node.class)).getNodeId().getValue() + "."
-                    + getKeyStr(iid);
-        } catch (ClassCastException  exp) {
-            LOG.error("Error in getting the Node id ", exp);
-        }
+    protected String getKeyStr(InstanceIdentifier iid) {
         return iid.toString();
     }
 
-    protected String getKeyStr(InstanceIdentifier iid) {
-        return iid.toString();
+    public <K extends Identifiable> void addJobToQueue(DependentJob<K> job) {
+        hwvtepOperationalState.getDeviceInfo().putKeyInDependencyQueue(job.getKey());
+        hwvtepOperationalState.getDeviceInfo().addJobToQueue(job);
+    }
+
+    public void markKeyAsInTransit(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        hwvtepOperationalState.getDeviceInfo().markKeyAsInTransit(cls, key);
     }
 
     public HwvtepDeviceInfo.DeviceData getDeviceOpData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
         return getOperationalState().getDeviceInfo().getDeviceOperData(cls, key);
     }
 
+    public void clearConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        hwvtepOperationalState.getDeviceInfo().clearConfigData(cls, key);
+    }
+
+    public HwvtepDeviceInfo.DeviceData getConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        return hwvtepOperationalState.getDeviceInfo().getConfigData(cls, key);
+    }
+
+    public void updateConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key, Object data) {
+        hwvtepOperationalState.getDeviceInfo().updateConfigData(cls, key, data);
+    }
+
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    public AbstractTransactCommand getClone() {
+        try {
+            return (AbstractTransactCommand) getClass().getConstructor(HwvtepOperationalState.class, Collection.class)
+                    .newInstance(hwvtepOperationalState, changes);
+        } catch (Throwable e) {
+            LOG.error("Failed to clone the cmd ", e);
+        }
+        return this;
+    }
+
     public HwvtepTableReader getTableReader() {
         return getOperationalState().getConnectionInstance().getHwvtepTableReader();
     }
+
+    public HwvtepConnectionInstance getConnectionInstance() {
+        return hwvtepOperationalState.getConnectionInstance();
+    }
+
+    public HwvtepOperationalState newOperState() {
+        return new HwvtepOperationalState(getConnectionInstance());
+    }
 }
index 5b5625f3bedb069dbdcdb73da5dce7889163b136..f6cd3aa7e624f336d4ac2e186b94c0c894af843a 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
 
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -17,7 +18,9 @@ import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
+
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
@@ -97,38 +100,45 @@ public class DependencyQueue {
         processReadyJobs(connectionInstance, opWaitQueue);
     }
 
+    @SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT")
     private void processReadyJobs(final HwvtepConnectionInstance hwvtepConnectionInstance,
                                   LinkedBlockingQueue<DependentJob> queue) {
-        final List<DependentJob> readyJobs =  getReadyJobs(queue);
-        if (readyJobs.size() > 0) {
-            EXECUTOR_SERVICE.execute(() -> hwvtepConnectionInstance.transact(new TransactCommand() {
-                private HwvtepOperationalState operationalState;
-
-                @Override
-                public void execute(TransactionBuilder transactionBuilder) {
-                    this.operationalState = new HwvtepOperationalState(hwvtepConnectionInstance);
-                    for (DependentJob job : readyJobs) {
-                        job.onDependencyResolved(operationalState, transactionBuilder);
+        final List<DependentJob> readyJobs = getReadyJobs(queue);
+        readyJobs.forEach((job) -> {
+            EXECUTOR_SERVICE.execute(() ->
+                hwvtepConnectionInstance.transact(new TransactCommand() {
+                    HwvtepOperationalState operationalState = new HwvtepOperationalState(hwvtepConnectionInstance);
+                    AtomicInteger retryCount = new AtomicInteger(5);
+
+                    @Override
+                    public boolean retry() {
+                        return retryCount.decrementAndGet() > 0;
                     }
-                }
 
-                @Override
-                public void onFailure(TransactionBuilder deviceTransaction) {
-                    readyJobs.forEach((job) -> job.onFailure(deviceTransaction));
-                    if (operationalState != null) {
+                    @Override
+                    public void execute(TransactionBuilder transactionBuilder) {
+                        deviceInfo.clearKeyFromDependencyQueue(job.getKey());
+                        if (operationalState.getConnectionInstance() != null
+                                && operationalState.getConnectionInstance().isActive()) {
+                            job.onDependencyResolved(operationalState, transactionBuilder);
+                        }
+                    }
+
+                    @Override
+                    @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR")
+                    public void onFailure(TransactionBuilder tx) {
+                        job.onFailure();
                         operationalState.clearIntransitKeys();
+
                     }
-                }
 
-                @Override
-                public void onSuccess(TransactionBuilder deviceTransaction) {
-                    readyJobs.forEach((job) -> job.onSuccess(deviceTransaction));
-                    if (operationalState != null) {
+                    @Override
+                    public void onSuccess(TransactionBuilder tx) {
+                        job.onSuccess();
                         operationalState.getDeviceInfo().onOperDataAvailable();
                     }
-                }
-            }));
-        }
+                }));
+        });
     }
 
     private List<DependentJob> getReadyJobs(LinkedBlockingQueue<DependentJob> queue) {
@@ -137,14 +147,13 @@ public class DependencyQueue {
         while (jobIterator.hasNext()) {
             DependentJob job = jobIterator.next();
             long currentTime = System.currentTimeMillis();
-
-            //first check if its dependencies are met later check for expired status
             if (job.areDependenciesMet(deviceInfo)) {
                 jobIterator.remove();
                 readyJobs.add(job);
                 continue;
             }
             if (job.isExpired(currentTime)) {
+                deviceInfo.clearKeyFromDependencyQueue(job.getKey());
                 jobIterator.remove();
                 continue;
             }
index d3e87802c637bc3ac2ee3269d2690e8ca4bc9617..e35bed005d81082bd2c5b33624d48754b1812c77 100644 (file)
@@ -53,13 +53,16 @@ public abstract class DependentJob<T extends Identifiable> {
     private final InstanceIdentifier key;
     private final T data;
     private final Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies;
+    private final long transactionId;
 
     DependentJob(InstanceIdentifier key,
-                           T data, Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies) {
+                           T data, Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies,
+                 long transactionId) {
         this.expiryTime = System.currentTimeMillis() + HwvtepSouthboundConstants.WAITING_JOB_EXPIRY_TIME_MILLIS;
         this.key = key;
         this.data = data;
         this.dependencies = dependencies;
+        this.transactionId = transactionId;
     }
 
     /**
@@ -108,6 +111,14 @@ public abstract class DependentJob<T extends Identifiable> {
         return key;
     }
 
+    public long getTransactionId() {
+        return transactionId;
+    }
+
+    public Map<Class<? extends DataObject>, List<InstanceIdentifier>> getDependencies() {
+        return dependencies;
+    }
+
     public T getData() {
         return data;
     }
@@ -116,30 +127,35 @@ public abstract class DependentJob<T extends Identifiable> {
         return true;
     }
 
-    public void onFailure(TransactionBuilder deviceTransaction) {
+    public void onFailure() {
     }
 
-    public void onSuccess(TransactionBuilder deviceTransaction) {
+    public void onSuccess() {
     }
 
     public abstract static class ConfigWaitingJob<T extends Identifiable> extends DependentJob<T> {
 
         public ConfigWaitingJob(InstanceIdentifier key, T data,
                 Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies) {
-            super(key, data, dependencies);
+            super(key, data, dependencies, 0);
         }
 
         @Override
         protected boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, InstanceIdentifier iid) {
             return deviceInfo.isConfigDataAvailable(cls, iid);
         }
+
+        public boolean isConfigWaitingJob() {
+            return true;
+        }
     }
 
     public abstract static class OpWaitingJob<T extends Identifiable> extends DependentJob<T> {
 
         public OpWaitingJob(InstanceIdentifier key, T data,
-                Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies) {
-            super(key, data, dependencies);
+                Map<Class<? extends DataObject>, List<InstanceIdentifier>> dependencies,
+                            long transactionId) {
+            super(key, data, dependencies, transactionId);
         }
 
         @Override
index 652f35e831c31f150ad92734ff2187d8dada1bf7..ef4804dc4c27bed22a255ebd0e99e1f2d4820da3 100644 (file)
@@ -84,6 +84,7 @@ public class HwvtepOperationalState {
     private boolean inReconciliation = false;
     private final DataBroker db;
     private final Collection<DataTreeModification<Node>> changes;
+    long transactionId = 0;
 
     public HwvtepOperationalState(DataBroker db, HwvtepConnectionInstance connectionInstance,
                                   Collection<DataTreeModification<Node>> changes) {
@@ -502,4 +503,8 @@ public class HwvtepOperationalState {
         currentTxDeletedKeys.clear();
         deviceInfo.onOperDataAvailable();
     }
+
+    public long getTransactionId() {
+        return transactionId;
+    }
 }
index 47b7e9366423f4cef615f6517915c1c316a8737b..e7c59f3d25d3560578d81f75b589210b6157b2e7 100644 (file)
@@ -7,27 +7,13 @@
  */
 package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
 
-import static org.opendaylight.ovsdb.lib.operations.Operations.op;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
-import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
-import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
-import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
-import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
-import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
-import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsLocal;
-import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote;
-import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsLocal;
-import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote;
-import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
@@ -37,6 +23,7 @@ import org.slf4j.LoggerFactory;
 
 public class LogicalSwitchRemoveCommand extends AbstractTransactCommand<LogicalSwitches, HwvtepGlobalAugmentation> {
     private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchRemoveCommand.class);
+    List<LogicalSwitches> deletedLs;
 
     public LogicalSwitchRemoveCommand(final HwvtepOperationalState state,
             final Collection<DataTreeModification<Node>> changes) {
@@ -46,54 +33,25 @@ public class LogicalSwitchRemoveCommand extends AbstractTransactCommand<LogicalS
     @Override
     public void execute(final TransactionBuilder transaction) {
         Map<InstanceIdentifier<Node>, List<LogicalSwitches>> removeds =
-                extractRemoved(getChanges(),LogicalSwitches.class);
-
-        for (Entry<InstanceIdentifier<Node>, List<LogicalSwitches>> created: removeds.entrySet()) {
-            if (!HwvtepSouthboundUtil.isEmpty(created.getValue())) {
-                HwvtepConnectionInstance connectionInstance = getDeviceInfo().getConnectionInstance();
-                getDeviceInfo().scheduleTransaction(new TransactCommand() {
-                    @Override
-                    public void execute(final TransactionBuilder transactionBuilder) {
-                        HwvtepOperationalState operState = new HwvtepOperationalState(
-                                connectionInstance.getDataBroker(), connectionInstance, Collections.EMPTY_LIST);
-                        hwvtepOperationalState = operState;
-                        deviceTransaction = deviceTransaction;
-                        LOG.debug("Running delete logical switch in seperate tx {}", created.getKey());
-                        removeLogicalSwitch(transactionBuilder, created.getKey(), created.getValue());
-                    }
-
-                    @Override
-                    public void onSuccess(final TransactionBuilder deviceTransaction) {
-                        LogicalSwitchRemoveCommand.this.onSuccess(deviceTransaction);
-                    }
-
-                    @Override
-                    public void onFailure(final TransactionBuilder deviceTransaction) {
-                        LogicalSwitchRemoveCommand.this.onFailure(deviceTransaction);
-                    }
-                });
+                extractRemoved(getChanges(), LogicalSwitches.class);
+        if (removeds != null) {
+            for (Entry<InstanceIdentifier<Node>, List<LogicalSwitches>> deleted: removeds.entrySet()) {
+                deletedLs = deleted.getValue();
+                for (LogicalSwitches lswitch : deleted.getValue()) {
+                    InstanceIdentifier<LogicalSwitches> lsKey =
+                            deleted.getKey().augmentation(HwvtepGlobalAugmentation.class)
+                                    .child(LogicalSwitches.class, lswitch.key());
+                    getDeviceInfo().clearConfigData(LogicalSwitches.class, lsKey);
+                    onConfigUpdate(transaction, deleted.getKey(), lswitch, lsKey);
+                }
             }
         }
     }
 
-    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
-            justification = "https://github.com/spotbugs/spotbugs/issues/811")
-    private void removeLogicalSwitch(final TransactionBuilder transaction,
-                                     final InstanceIdentifier<Node> nodeIid, final List<LogicalSwitches> lswitchList) {
-        for (LogicalSwitches lswitch: lswitchList) {
-            InstanceIdentifier<LogicalSwitches> lsKey = nodeIid.augmentation(HwvtepGlobalAugmentation.class)
-                    .child(LogicalSwitches.class, lswitch.key());
-            onConfigUpdate(transaction, nodeIid, lswitch, lsKey);
-        }
-    }
-
     @Override
-    public void onConfigUpdate(final TransactionBuilder transaction,
-                               final InstanceIdentifier<Node> nodeIid,
-                               final LogicalSwitches lswitch,
-                               final InstanceIdentifier lsKey,
-                               final Object... extraData) {
-        processDependencies(null, transaction, nodeIid, lsKey, lswitch);
+    public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier<Node> nodeIid,
+                               LogicalSwitches logicalSwitches, InstanceIdentifier lsKey, Object... extraData) {
+        processDependencies(EmptyDependencyGetter.INSTANCE, transaction, nodeIid, lsKey, logicalSwitches);
     }
 
     @Override
@@ -102,37 +60,11 @@ public class LogicalSwitchRemoveCommand extends AbstractTransactCommand<LogicalS
                                     final LogicalSwitches lswitch,
                                     final InstanceIdentifier lsKey,
                                     final Object... extraData) {
-        LOG.debug("Removing logical switch named: {}", lswitch.getHwvtepNodeName().getValue());
-        HwvtepDeviceInfo.DeviceData deviceData  = getOperationalState().getDeviceInfo().getDeviceOperData(
-                LogicalSwitches.class, lsKey);
-        LogicalSwitch logicalSwitch = transaction.getTypedRowSchema(LogicalSwitch.class);
-
-        if (deviceData != null && deviceData.getUuid() != null) {
-            UUID logicalSwitchUuid = deviceData.getUuid();
-            transaction.add(op.delete(logicalSwitch.getSchema())
-                    .where(logicalSwitch.getUuidColumn().getSchema().opEqual(logicalSwitchUuid)).build());
-
-            UcastMacsRemote ucastMacsRemote = transaction.getTypedRowSchema(UcastMacsRemote.class);
-            transaction.add(op.delete(ucastMacsRemote.getSchema())
-                    .where(ucastMacsRemote.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build());
-
-            UcastMacsLocal ucastMacsLocal = transaction.getTypedRowSchema(UcastMacsLocal.class);
-            transaction.add(op.delete(ucastMacsLocal.getSchema())
-                    .where(ucastMacsLocal.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build());
-
-            McastMacsRemote mcastMacsRemote = transaction.getTypedRowSchema(McastMacsRemote.class);
-            transaction.add(op.delete(mcastMacsRemote.getSchema())
-                    .where(mcastMacsRemote.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build());
-
-            McastMacsLocal mcastMacsLocal = transaction.getTypedRowSchema(McastMacsLocal.class);
-            transaction.add(op.delete(mcastMacsLocal.getSchema())
-                    .where(mcastMacsLocal.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build());
-            updateCurrentTxDeleteData(LogicalSwitches.class, lsKey, lswitch);
-            updateControllerTxHistory(TransactionType.DELETE, lswitch);
-        } else {
-            LOG.warn("Unable to delete logical switch {} because it was not found in the operational store",
-                    lswitch.getHwvtepNodeName().getValue());
-        }
+        LogicalSwitchUcastsRemoveCommand cmd = new LogicalSwitchUcastsRemoveCommand(
+                newOperState(), getChanges(), deletedLs, lswitch);
+        markKeyAsInTransit(LogicalSwitches.class, lsKey);
+        clearConfigData(LogicalSwitches.class, lsKey);
+        hwvtepOperationalState.getConnectionInstance().transact(cmd);
     }
 
     @Override
@@ -152,10 +84,7 @@ public class LogicalSwitchRemoveCommand extends AbstractTransactCommand<LogicalS
 
     @Override
     public void onCommandSucceeded() {
-        if (getDeviceTransaction() == null || !updates.containsKey(getDeviceTransaction())) {
-            return;
-        }
-        for (MdsalUpdate mdsalUpdate : updates.get(getDeviceTransaction())) {
+        for (MdsalUpdate mdsalUpdate : updates) {
             getDeviceInfo().clearLogicalSwitchRefs(mdsalUpdate.getKey());
         }
     }
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUcastsRemoveCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUcastsRemoveCommand.java
new file mode 100644 (file)
index 0000000..3433910
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
+import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsLocal;
+import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote;
+import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalPort;
+import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsLocal;
+import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote;
+import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LogicalSwitchUcastsRemoveCommand
+        extends AbstractTransactCommand<LogicalSwitches, HwvtepGlobalAugmentation> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchUcastsRemoveCommand.class);
+
+    volatile Map<String, Map<Long, UUID>> updatedPortBindings = new HashMap<>();
+    private AtomicInteger retryCount = new AtomicInteger(5);
+    private LogicalSwitches logicalSwitches;
+    private InstanceIdentifier<Node> nodeIid;
+    private List<LogicalSwitches> deletedLs;
+    private boolean firstAttempt = true;
+
+    public LogicalSwitchUcastsRemoveCommand(HwvtepOperationalState state,
+                                            Collection<DataTreeModification<Node>> changes,
+                                            List<LogicalSwitches> deletedLs,
+                                            LogicalSwitches logicalSwitches) {
+        super(state, changes);
+        this.deletedLs = deletedLs;
+        this.logicalSwitches = logicalSwitches;
+        this.nodeIid = getOperationalState().getConnectionInstance().getInstanceIdentifier();
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        InstanceIdentifier<LogicalSwitches> lsKey = nodeIid.augmentation(HwvtepGlobalAugmentation.class)
+                .child(LogicalSwitches.class, logicalSwitches.key());
+        HwvtepDeviceInfo.DeviceData deviceData  = super.<LogicalSwitch>fetchDeviceData(LogicalSwitches.class, lsKey);
+        if (deviceData != null && deviceData.getUuid() != null) {
+
+            UUID logicalSwitchUuid = deviceData.getUuid();
+
+            UcastMacsRemote ucastMacsRemote = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
+                    UcastMacsRemote.class, null);
+            transaction.add(op.delete(ucastMacsRemote.getSchema())
+                    .where(ucastMacsRemote.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build());
+
+            UcastMacsLocal ucastMacsLocal = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
+                    UcastMacsLocal.class, null);
+            transaction.add(op.delete(ucastMacsLocal.getSchema())
+                    .where(ucastMacsLocal.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build());
+
+            McastMacsRemote mcastMacsRemote = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
+                    McastMacsRemote.class, null);
+            transaction.add(op.delete(mcastMacsRemote.getSchema())
+                    .where(mcastMacsRemote.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build());
+
+            McastMacsLocal mcastMacsLocal = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
+                    McastMacsLocal.class, null);
+            transaction.add(op.delete(mcastMacsLocal.getSchema())
+                    .where(mcastMacsLocal.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build());
+
+            if (firstAttempt) {
+                LogicalSwitch logicalSwitch = TyperUtils.getTypedRowWrapper(
+                        transaction.getDatabaseSchema(), LogicalSwitch.class, null);
+                transaction.add(op.delete(logicalSwitch.getSchema()).where(logicalSwitch.getNameColumn().getSchema()
+                        .opEqual(logicalSwitches.getHwvtepNodeName().getValue())).build());
+                updateControllerTxHistory(TransactionType.DELETE, new StringBuilder(logicalSwitch.toString())
+                        .append(": ").append(logicalSwitches.getHwvtepNodeName()).append(" ")
+                        .append(logicalSwitches.getLogicalSwitchUuid()).append(" ")
+                        .append(logicalSwitches.getTunnelKey()));
+                LOG.info("CONTROLLER - {} {} {} {} {}", TransactionType.DELETE, logicalSwitch,
+                        logicalSwitches.getHwvtepNodeName(), logicalSwitches.getLogicalSwitchUuid(),
+                        logicalSwitches.getTunnelKey());
+            } else {
+                for (Entry<String, Map<Long, UUID>> entry : updatedPortBindings.entrySet()) {
+                    PhysicalPort physicalPort = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
+                            PhysicalPort.class);
+                    physicalPort.setName(entry.getKey());
+                    physicalPort.setVlanBindings(entry.getValue());
+                    transaction.add(op.update(physicalPort)
+                            .where(physicalPort.getNameColumn().getSchema().opEqual(physicalPort.getName())).build());
+                    updateControllerTxHistory(TransactionType.UPDATE, physicalPort);
+                    LOG.info("CONTROLLER - {} {}", TransactionType.UPDATE, physicalPort);
+                }
+            }
+        } else {
+            firstAttempt = false;
+            onSuccess(transaction);
+        }
+    }
+
+    @Override
+    protected List<LogicalSwitches> getData(HwvtepGlobalAugmentation augmentation) {
+        return augmentation.getLogicalSwitches();
+    }
+
+    @Override
+    protected boolean areEqual(LogicalSwitches logicalSwitches1 , LogicalSwitches logicalSwitches2) {
+        return logicalSwitches1.key().equals(logicalSwitches2.key())
+                && Objects.equals(logicalSwitches1.getTunnelKey(), logicalSwitches2.getTunnelKey());
+    }
+
+    @Override
+    public void onSuccess(TransactionBuilder tx) {
+        if (firstAttempt) {
+            //LOG.error("check succeeded in deletion of logical swtich at first attempt ");
+            //succeed in removing the logical switch upon first attempt
+            return;
+        }
+        //LOG.error("check succeeded in deletion of logical swtich after first attempt ");
+        PlainLogicalSwitchRemoveCmd cmd = new PlainLogicalSwitchRemoveCmd(
+                newOperState(), getChanges(), logicalSwitches, HwvtepSouthboundConstants.LS_REMOVE_RETRIES);
+        hwvtepOperationalState.getConnectionInstance().transact(cmd);
+    }
+
+    @Override
+    public void onFailure(TransactionBuilder tx) {
+        //Failed to remove logical swith upon first attempt,
+        //will attempt to remove the local ucasts and vlan bindings alone in the next attemtps
+        firstAttempt = false;
+        getFreshPortBindingsExcludingDeleted();
+        super.onFailure(tx);
+    }
+
+    private void getFreshPortBindingsExcludingDeleted() {
+        Set<UUID> deletedLsUuids = new HashSet<>();
+        for (LogicalSwitches ls : deletedLs) {
+            InstanceIdentifier<LogicalSwitches> lsKey = nodeIid
+                    .augmentation(HwvtepGlobalAugmentation.class)
+                    .child(LogicalSwitches.class, ls.key());
+            HwvtepDeviceInfo.DeviceData deviceData  =
+                    super.<LogicalSwitch>fetchDeviceData(LogicalSwitches.class, lsKey);
+            if (deviceData.getUuid() != null) {
+                deletedLsUuids.add(deviceData.getUuid());
+            }
+        }
+        updatedPortBindings = new HashMap<>();
+        List<TypedBaseTable> portsFromDevice = getOperationalState().getConnectionInstance()
+                .getHwvtepTableReader().getHwvtepTableEntries(VlanBindings.class);
+        if (portsFromDevice == null || portsFromDevice.isEmpty()) {
+            LOG.debug("Check did not get any bindings from tor while doing failure of logical switch delete");
+            return;
+        }
+        portsFromDevice.stream()
+                .map(row -> (PhysicalPort) row)
+                .filter(port -> port.getVlanBindingsColumn() != null && port.getVlanBindingsColumn().getData() != null)
+                .forEach(port -> {
+                    int originalBindingsSize = port.getVlanBindingsColumn().getData().size();
+                    Map<Long, UUID> bindingsAfterExclusion = excludeVlanBindings(deletedLsUuids, port);
+                    if (bindingsAfterExclusion.size() < originalBindingsSize) {
+                        updatedPortBindings.put(port.getName(), bindingsAfterExclusion);
+                    }
+                });
+    }
+
+    private Map<Long, UUID> excludeVlanBindings(Set<UUID> deletedLsUuids, PhysicalPort port) {
+        return port.getVlanBindingsColumn().getData()
+                .entrySet().stream()
+                .peek(entry -> {
+                    if (deletedLsUuids.contains(entry.getValue())) {
+                        LOG.trace("check Excluding the vlan binding {}", entry.getValue());
+                    }
+                })
+                .filter(entry -> !deletedLsUuids.contains(entry.getValue()))
+                .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));
+    }
+
+    public boolean retry() {
+        boolean ret = retryCount.decrementAndGet() > 0;
+        return ret;
+    }
+
+    protected boolean isDeleteCmd() {
+        return true;
+    }
+
+}
index 29558f2b1b908192222562e4cedb25c693f71e27..2c7024bff3f54d49f49f23f08ab89396eaa6717d 100644 (file)
@@ -23,7 +23,6 @@ import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
 import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote;
 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -93,6 +92,7 @@ public class McastMacsRemoteRemoveCommand extends AbstractTransactCommand<Remote
                                     final InstanceIdentifier macIid,
                                     final Object... extraData) {
         LOG.debug("Removing remoteMcastMacs, mac address: {}", mac.getMacEntryKey().getValue());
+        clearConfigData(RemoteMcastMacs.class, macIid);
         HwvtepDeviceInfo.DeviceData operationalMacOptional =
                 getDeviceInfo().getDeviceOperData(RemoteMcastMacs.class, macIid);
         McastMacsRemote mcastMacsRemote = transaction.getTypedRowSchema(McastMacsRemote.class);
@@ -127,15 +127,4 @@ public class McastMacsRemoteRemoveCommand extends AbstractTransactCommand<Remote
         return true;
     }
 
-
-    @Override
-    public void onCommandSucceeded() {
-        //remove the refcounts of the deleted macs
-        for (MdsalUpdate mdsalUpdate : updates.get(getDeviceTransaction())) {
-            RemoteMcastMacs deletedMac = (RemoteMcastMacs) mdsalUpdate.getNewData();
-            InstanceIdentifier<RemoteMcastMacs> macIid = mdsalUpdate.getKey();
-            getDeviceInfo().removeRemoteMcast(
-                    (InstanceIdentifier<LogicalSwitches>) deletedMac.getLogicalSwitchRef().getValue(), macIid);
-        }
-    }
 }
index e1edc7ed09b32d20efd648c57f4f9734d3915c44..78f00a43edfee1683b1fb105059a7ddafed75f5a 100644 (file)
@@ -59,6 +59,10 @@ public class McastMacsRemoteUpdateCommand extends AbstractTransactCommand<Remote
             final InstanceIdentifier<Node> instanceIdentifier, final List<RemoteMcastMacs> macList) {
         for (RemoteMcastMacs mac: macList) {
             //add / update only if locator set got changed
+            InstanceIdentifier<RemoteMcastMacs> macIid = instanceIdentifier
+                    .augmentation(HwvtepGlobalAugmentation.class)
+                    .child(RemoteMcastMacs.class, mac.key());
+            updateConfigData(RemoteMcastMacs.class, macIid, mac);
             if (!HwvtepSouthboundUtil.isEmpty(mac.getLocatorSet())) {
                 onConfigUpdate(transaction, instanceIdentifier, mac, null);
             }
@@ -112,6 +116,9 @@ public class McastMacsRemoteUpdateCommand extends AbstractTransactCommand<Remote
             LOG.warn("Unable to update remoteMcastMacs {} because uuid not found in the operational store",
                     mac.getMacEntryKey().getValue());
         }
+        InstanceIdentifier<RemoteMcastMacs> macIid = instanceIdentifier.augmentation(HwvtepGlobalAugmentation.class)
+                .child(RemoteMcastMacs.class, mac.key());
+        updateConfigData(RemoteMcastMacs.class, macIid, mac);
     }
 
     private void setLogicalSwitch(final TransactionBuilder transaction, final McastMacsRemote mcastMacsRemote,
@@ -203,8 +210,8 @@ public class McastMacsRemoteUpdateCommand extends AbstractTransactCommand<Remote
     }
 
     @Override
-    protected void onCommandSucceeded() {
-        for (MdsalUpdate mdsalUpdate : updates.get(getDeviceTransaction())) {
+    public void onSuccess(TransactionBuilder tx) {
+        for (MdsalUpdate mdsalUpdate : updates) {
             updateLocatorRefCounts(mdsalUpdate);
             RemoteMcastMacs mac = (RemoteMcastMacs) mdsalUpdate.getNewData();
             InstanceIdentifier<RemoteMcastMacs> macIid = mdsalUpdate.getKey();
@@ -212,4 +219,5 @@ public class McastMacsRemoteUpdateCommand extends AbstractTransactCommand<Remote
                     (InstanceIdentifier<LogicalSwitches>) mac.getLogicalSwitchRef().getValue(), macIid, mac);
         }
     }
+
 }
index c0874fddfc9e97e464421ad0871c40d075f09cd9..a23a26aa6d4887315abcd2bd7f6c7b182f527f01 100644 (file)
@@ -158,7 +158,7 @@ public class PhysicalPortUpdateCommand extends AbstractTransactCommand {
                                       final InstanceIdentifier<VlanBindings> vlanIid) {
 
         DependentJob<VlanBindings> opWaitingJob = new DependentJob.OpWaitingJob<VlanBindings>(
-                vlanIid, vlanBinding, inTransitDependencies) {
+                vlanIid, vlanBinding, inTransitDependencies, getOperationalState().getTransactionId()) {
             @Override
             public void onDependencyResolved(final HwvtepOperationalState operationalState,
                                              final TransactionBuilder transactionBuilder) {
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PlainLogicalSwitchRemoveCmd.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/PlainLogicalSwitchRemoveCmd.java
new file mode 100644 (file)
index 0000000..95b6333
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015 China Telecom Beijing Research Institute and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
+import org.opendaylight.ovsdb.utils.mdsal.utils.Scheduler;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PlainLogicalSwitchRemoveCmd extends AbstractTransactCommand<LogicalSwitches, HwvtepGlobalAugmentation> {
+    private static final Logger LOG = LoggerFactory.getLogger(PlainLogicalSwitchRemoveCmd.class);
+    private AtomicInteger retryCount = new AtomicInteger(5);
+    private LogicalSwitches logicalSwitches;
+    private InstanceIdentifier<Node> nodeIid;
+
+    public PlainLogicalSwitchRemoveCmd(HwvtepOperationalState state,
+                                       Collection<DataTreeModification<Node>> changes,
+                                       LogicalSwitches logicalSwitches,
+                                       int retryCount) {
+        super(state, changes);
+        this.logicalSwitches = logicalSwitches;
+        this.retryCount = new AtomicInteger(retryCount);
+        this.nodeIid = getOperationalState().getConnectionInstance().getInstanceIdentifier();
+    }
+
+    @Override
+    public void execute(TransactionBuilder transaction) {
+        LogicalSwitch logicalSwitch = TyperUtils.getTypedRowWrapper(
+                transaction.getDatabaseSchema(), LogicalSwitch.class, null);
+        transaction.add(op.delete(logicalSwitch.getSchema())
+                .where(logicalSwitch.getNameColumn().getSchema().opEqual(
+                        logicalSwitches.getHwvtepNodeName().getValue())).build());
+    }
+
+    @Override
+    protected List<LogicalSwitches> getData(HwvtepGlobalAugmentation augmentation) {
+        return augmentation.getLogicalSwitches();
+    }
+
+    @Override
+    protected boolean areEqual(LogicalSwitches logicalSwitches1 , LogicalSwitches logicalSwitches2) {
+        return logicalSwitches1.key().equals(logicalSwitches2.key())
+                && Objects.equals(logicalSwitches1.getTunnelKey(), logicalSwitches2.getTunnelKey());
+    }
+
+    public boolean retry() {
+        boolean ret = retryCount.decrementAndGet() > 0;
+        if (ret) {
+            Scheduler.getScheduledExecutorService().schedule(() -> {
+                getOperationalState().getConnectionInstance().transact(this);
+            }, HwvtepSouthboundConstants.LS_REMOVE_DELAY_SECS, TimeUnit.SECONDS);
+        } else {
+            LOG.error("Failed in deletion of logical switch {}", logicalSwitches);
+        }
+        return ret;
+    }
+
+    protected boolean isDeleteCmd() {
+        return true;
+    }
+}
index b794030c9a478c2b372a42fb470cdaf46f5a3420..7007b1e432dd6ed60bc69c84c1ab368fa3c2f2c0 100644 (file)
@@ -19,7 +19,6 @@ import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
 import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -103,13 +102,4 @@ public class UcastMacsRemoteRemoveCommand extends AbstractTransactCommand<Remote
         return true;
     }
 
-    @Override
-    public void onCommandSucceeded() {
-        for (MdsalUpdate mdsalUpdate : updates.get(getDeviceTransaction())) {
-            RemoteUcastMacs deletedMac = (RemoteUcastMacs) mdsalUpdate.getNewData();
-            InstanceIdentifier<RemoteUcastMacs> macIid = mdsalUpdate.getKey();
-            getDeviceInfo().removeRemoteUcast(
-                    (InstanceIdentifier<LogicalSwitches>) deletedMac.getLogicalSwitchRef().getValue(), macIid);
-        }
-    }
 }
index e845cfd600c579ebe2d3dca88714e42493054a75..3769806ccd339dda536a0a1bf9ed55a792a9cecd 100644 (file)
@@ -78,6 +78,7 @@ public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand<Remote
                                     final InstanceIdentifier macKey,
                                     final Object... extraData) {
         LOG.debug("Creating remoteUcastMacs, mac address: {}", remoteUcastMac.getMacEntryKey().getValue());
+        updateConfigData(RemoteUcastMacs.class, macKey, remoteUcastMac);
         final HwvtepDeviceInfo.DeviceData deviceData =
                 getOperationalState().getDeviceInfo().getDeviceOperData(RemoteUcastMacs.class, macKey);
 
@@ -167,16 +168,12 @@ public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand<Remote
     }
 
     @Override
-    public void onCommandSucceeded() {
-        for (MdsalUpdate mdsalUpdate : updates.get(getDeviceTransaction())) {
-            RemoteUcastMacs newMac = (RemoteUcastMacs) mdsalUpdate.getNewData();
+    public void onSuccess(TransactionBuilder tx) {
+        for (MdsalUpdate mdsalUpdate : updates) {
+            RemoteUcastMacs mac = (RemoteUcastMacs) mdsalUpdate.getNewData();
             InstanceIdentifier<RemoteUcastMacs> macIid = mdsalUpdate.getKey();
-            RemoteUcastMacs oldMac = (RemoteUcastMacs) mdsalUpdate.getOldData();
-            if (oldMac != null && !oldMac.equals(newMac)) {
-                getDeviceInfo().decRefCount(macIid, oldMac.getLocatorRef().getValue());
-            }
             getDeviceInfo().updateRemoteUcast(
-                    (InstanceIdentifier<LogicalSwitches>) newMac.getLogicalSwitchRef().getValue(), macIid, newMac);
+                    (InstanceIdentifier<LogicalSwitches>) mac.getLogicalSwitchRef().getValue(), macIid, mac);
         }
     }
 }
index 7fd4960f3a4b583b88c5ceb2b020111cab6c2990..d124032f3ab21492262197960a31bc2f1c112ad1 100644 (file)
@@ -93,7 +93,7 @@ public class DependencyQueueTest extends DataChangeListenerTestBase {
 
         final CountDownLatch latch = new CountDownLatch(1);
         opState.getDeviceInfo().addJobToQueue(new DependentJob.OpWaitingJob<RemoteMcastMacs>(
-                macIid, mac, (Map)unMetDependencies) {
+                macIid, mac, (Map)unMetDependencies, 0) {
             @Override
             protected void onDependencyResolved(HwvtepOperationalState operationalState,
                     TransactionBuilder transactionBuilder) {
@@ -105,6 +105,8 @@ public class DependencyQueueTest extends DataChangeListenerTestBase {
 
         opState.getDeviceInfo().updateDeviceOperData(LogicalSwitches.class, lsIid, new UUID("ls0"), "ls0");
         opState.getDeviceInfo().onOperDataAvailable();
+        //wait for sometime so that the onDependencyResolved is triggered
+        Thread.sleep(500);
         assertEquals(0, latch.getCount());
 
     }