From: K.V Suneelu Verma Date: Thu, 1 Dec 2016 07:11:23 +0000 (+0530) Subject: bug 6579 added dependency queue X-Git-Tag: release/carbon~55 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=ff2d1d2e83a0d221f3f354f47747449cd868f448;p=ovsdb.git bug 6579 added dependency queue Added Dependency Queue which gets processed upon config and op events. Any object ( mac / port ) whose dependencies are not met gets pushed the queue with an expiry timeout. Added the following apis in UnMetDependencyGetter getInTransitDependencies returns list of keys in json rpc transaction which are needed by this object to be processed. getUnMetConfigDependencies returns list of missing config keys Added the following apis in HwvtepDeviceInfo onConfigDataAvailable processes config dependency queue onOpDataAvailable processes in transit dependency queue , gets called after every json rpc transaction is done Change-Id: I012958a40e0ab0aa0e0db14dc670f9c4dacbdd09 Signed-off-by: K.V Suneelu Verma --- diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/pom.xml b/hwvtepsouthbound/hwvtepsouthbound-impl/pom.xml index d8d647c34..bbb24bde9 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/pom.xml +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/pom.xml @@ -101,6 +101,14 @@ and is available at http://www.eclipse.org/legal/epl-v10.html true + + org.apache.maven.plugins + maven-surefire-plugin + + 1 + false + + diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java index b40a7367c..835d435d9 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java @@ -8,22 +8,11 @@ package org.opendaylight.ovsdb.hwvtepsouthbound; -import static org.opendaylight.ovsdb.lib.operations.Operations.op; - -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; @@ -41,6 +30,7 @@ import org.opendaylight.ovsdb.hwvtepsouthbound.reconciliation.ReconciliationMana import org.opendaylight.ovsdb.hwvtepsouthbound.reconciliation.ReconciliationTask; import org.opendaylight.ovsdb.hwvtepsouthbound.reconciliation.configuration.HwvtepReconciliationTask; import org.opendaylight.ovsdb.hwvtepsouthbound.reconciliation.connection.ConnectionReconciliationTask; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependencyQueue; import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.HwvtepGlobalRemoveCommand; import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionCommand; import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker; @@ -54,7 +44,6 @@ import org.opendaylight.ovsdb.lib.schema.DatabaseSchema; import org.opendaylight.ovsdb.lib.schema.GenericTableSchema; import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils; import org.opendaylight.ovsdb.schema.hardwarevtep.Global; -import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils; 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.HwvtepPhysicalSwitchAttributes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation; @@ -65,11 +54,20 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.net.ConnectException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.opendaylight.ovsdb.lib.operations.Operations.op; public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoCloseable{ private Map clients = new ConcurrentHashMap<>(); @@ -103,6 +101,7 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo for (HwvtepConnectionInstance client: clients.values()) { client.disconnect(); } + DependencyQueue.close(); } @Override diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDataChangeListener.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDataChangeListener.java index 5cca754d4..f5d96e386 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDataChangeListener.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDataChangeListener.java @@ -184,7 +184,8 @@ public class HwvtepDataChangeListener implements ClusteredDataTreeChangeListener changesByConnectionInstance(changes).entrySet()) { HwvtepConnectionInstance connectionInstance = changesEntry.getKey(); connectionInstance.transact(new TransactCommandAggregator( - new HwvtepOperationalState(db, changesEntry.getValue()),changesEntry.getValue())); + new HwvtepOperationalState(db, connectionInstance, changesEntry.getValue()),changesEntry.getValue())); + connectionInstance.getDeviceInfo().onConfigDataAvailable(); } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDeviceInfo.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDeviceInfo.java index d4dba02b0..77725d7e9 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDeviceInfo.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDeviceInfo.java @@ -8,6 +8,8 @@ package org.opendaylight.ovsdb.hwvtepsouthbound; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependencyQueue; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependentJob; import org.opendaylight.ovsdb.lib.notation.UUID; import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch; import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocator; @@ -55,7 +57,7 @@ public class HwvtepDeviceInfo { private final Object data; private final DeviceDataStatus status; - public DeviceData(InstanceIdentifier key, UUID uuid, Object data, DeviceDataStatus status) { + DeviceData(InstanceIdentifier key, UUID uuid, Object data, DeviceDataStatus status) { this.data = data; this.key = key; this.status = status; @@ -86,6 +88,7 @@ public class HwvtepDeviceInfo { private Map, Map> configKeyVsData = new ConcurrentHashMap<>(); private Map, Map> opKeyVsData = new ConcurrentHashMap<>(); private Map, Map> uuidVsData = new ConcurrentHashMap<>(); + private DependencyQueue dependencyQueue; public HwvtepDeviceInfo(HwvtepConnectionInstance hwvtepConnectionInstance) { this.connectionInstance = hwvtepConnectionInstance; @@ -93,6 +96,7 @@ public class HwvtepDeviceInfo { this.physicalSwitches = new HashMap<>(); this.physicalLocators = new HashMap<>(); this.mapTunnelToPhysicalSwitch = new HashMap<>(); + this.dependencyQueue = new DependencyQueue(this); } public void putLogicalSwitch(UUID uuid, LogicalSwitch lSwitch) { @@ -211,4 +215,16 @@ public class HwvtepDeviceInfo { } return null; } + + public void addJobToQueue(DependentJob job) { + dependencyQueue.addToQueue(job); + } + + public void onConfigDataAvailable() { + dependencyQueue.processReadyJobsFromConfigQueue(connectionInstance); + } + + public void onOpDataAvailable() { + dependencyQueue.processReadyJobsFromOpQueue(connectionInstance); + } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundConstants.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundConstants.java index d594115e8..547b70a32 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundConstants.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundConstants.java @@ -44,4 +44,6 @@ public class HwvtepSouthboundConstants { = new ImmutableMap.Builder>() .put("Manager", Arrays.asList(new String[]{"_version", "status"})) .build(); + public static final int WAITING_QUEUE_CAPACITY = 1000; + public static final long WAITING_JOB_EXPIRY_TIME_MILLIS = 90000; } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java index f6300ec9c..eb29948f9 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java @@ -28,6 +28,7 @@ import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -181,4 +182,8 @@ public class HwvtepSouthboundUtil { map.get(cls).remove(key); } } + + public static boolean isEmpty(List list) { + return list == null || list.isEmpty(); + } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/reconciliation/configuration/HwvtepReconciliationTask.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/reconciliation/configuration/HwvtepReconciliationTask.java index cd9a8172d..a8adf4cf4 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/reconciliation/configuration/HwvtepReconciliationTask.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/reconciliation/configuration/HwvtepReconciliationTask.java @@ -57,7 +57,7 @@ public class HwvtepReconciliationTask extends ReconciliationTask { } private void transactChangesToDevice(Collection> changes) { - HwvtepOperationalState hwvtepOperationalState = new HwvtepOperationalState(db, changes); + HwvtepOperationalState hwvtepOperationalState = new HwvtepOperationalState(db, connectionInstance, changes); connectionInstance.transact(new TransactCommandAggregator(hwvtepOperationalState,changes)); } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/AbstractTransactCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/AbstractTransactCommand.java index d766f199f..f7fa3b40b 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/AbstractTransactCommand.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/AbstractTransactCommand.java @@ -8,12 +8,19 @@ package org.opendaylight.ovsdb.hwvtepsouthbound.transact; -import java.util.Collection; - import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo; +import org.opendaylight.ovsdb.lib.notation.UUID; +import org.opendaylight.ovsdb.lib.operations.TransactionBuilder; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.Collection; +import java.util.Map; -public abstract class AbstractTransactCommand implements TransactCommand { +public abstract class AbstractTransactCommand implements TransactCommand { private HwvtepOperationalState operationalState; private Collection> changes; @@ -34,4 +41,61 @@ public abstract class AbstractTransactCommand implements TransactCommand { public Collection> getChanges() { return changes; } + + void updateCurrentTxData(Class cls, InstanceIdentifier key, UUID uuid, Object data) { + operationalState.updateCurrentTxData(cls, key, uuid); + operationalState.getDeviceInfo().markKeyAsInTransit(cls, key); + operationalState.getDeviceInfo().updateConfigData(cls, key, data); + } + + void processDependencies(UnMetDependencyGetter unMetDependencyGetter, + TransactionBuilder transaction, + final InstanceIdentifier nodeIid, + final InstanceIdentifier key, + final T data) { + + HwvtepDeviceInfo deviceInfo = operationalState.getDeviceInfo(); + Map inTransitDependencies = unMetDependencyGetter.getInTransitDependencies(operationalState, data); + Map confingDependencies = unMetDependencyGetter.getUnMetConfigDependencies(operationalState, 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 (confingDependencies.isEmpty() && inTransitDependencies.isEmpty()) { + doDeviceTransaction(transaction, nodeIid, data); + } + if (!confingDependencies.isEmpty()) { + DependentJob configWaitingJob = new DependentJob.ConfigWaitingJob( + key, data, confingDependencies) { + + @Override + public void onDependencyResolved(HwvtepOperationalState operationalState, + TransactionBuilder transactionBuilder) { + AbstractTransactCommand.this.operationalState = operationalState; + onConfigUpdate(transactionBuilder, nodeIid, data); + } + }; + deviceInfo.addJobToQueue(configWaitingJob); + } + if (inTransitDependencies.size() > 0) { + DependentJob opWaitingJob = new DependentJob.OpWaitingJob( + key, data, inTransitDependencies) { + + @Override + public void onDependencyResolved(HwvtepOperationalState operationalState, + TransactionBuilder transactionBuilder) { + AbstractTransactCommand.this.operationalState = operationalState; + onConfigUpdate(transactionBuilder, nodeIid, data); + } + }; + deviceInfo.addJobToQueue(opWaitingJob); + } + } + + public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier nodeIid, T data) { + //tobe removed as part of refactoring patch + } + + public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier nodeIid, T data) { + //tobe removed as part of refactoring patch + } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/DependencyQueue.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/DependencyQueue.java new file mode 100644 index 000000000..314ab56d3 --- /dev/null +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/DependencyQueue.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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 com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance; +import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo; +import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants; +import org.opendaylight.ovsdb.lib.operations.TransactionBuilder; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; + +public class DependencyQueue { + + private static final Logger LOG = LoggerFactory.getLogger(DependencyQueue.class); + private static final ThreadFactory threadFact = new ThreadFactoryBuilder().setNameFormat("hwvtep-waiting-job-%d"). + build(); + private static final ExecutorService executorService = Executors.newSingleThreadScheduledExecutor(threadFact); + + private final LinkedBlockingQueue configWaitQueue = new LinkedBlockingQueue<>( + HwvtepSouthboundConstants.WAITING_QUEUE_CAPACITY); + private final LinkedBlockingQueue opWaitQueue = new LinkedBlockingQueue<>( + HwvtepSouthboundConstants.WAITING_QUEUE_CAPACITY); + private final HwvtepDeviceInfo deviceInfo; + + public DependencyQueue(HwvtepDeviceInfo hwvtepDeviceInfo) { + this.deviceInfo = hwvtepDeviceInfo; + } + + /** + * Tries to add the job to the waiting queue + * @param waitingJob The job to be enqueued + * @return true if it is successfully added to the queue + */ + public boolean addToQueue(DependentJob waitingJob) { + boolean addedToQueue; + if (waitingJob instanceof DependentJob.ConfigWaitingJob) { + addedToQueue = configWaitQueue.offer(waitingJob); + } else { + addedToQueue = opWaitQueue.offer(waitingJob); + } + if (addedToQueue) { + LOG.debug("Added the waiting job {} to queue", waitingJob.getKey()); + } else { + LOG.error("Failed to add the waiting job to queue {}", waitingJob.getKey()); + } + return addedToQueue; + } + + /** + * Checks if any config data dependent jobs are ready to be processed and process them + * @param connectionInstance The connection instance + */ + public void processReadyJobsFromConfigQueue(HwvtepConnectionInstance connectionInstance) { + processReadyJobs(connectionInstance, configWaitQueue); + } + + /** + * Checks if any operational data dependent jobs are ready to be processed and process them + * @param connectionInstance The connection instance + */ + public void processReadyJobsFromOpQueue(HwvtepConnectionInstance connectionInstance) { + processReadyJobs(connectionInstance, opWaitQueue); + } + + private void processReadyJobs(final HwvtepConnectionInstance hwvtepConnectionInstance, + LinkedBlockingQueue queue) { + final List readyJobs = getReadyJobs(queue); + if (readyJobs.size() > 0) { + executorService.submit(new Runnable() { + @Override + public void run() { + hwvtepConnectionInstance.transact(new TransactCommand() { + @Override + public void execute(TransactionBuilder transactionBuilder) { + HwvtepOperationalState operationalState = new HwvtepOperationalState(hwvtepConnectionInstance); + for (DependentJob job : readyJobs) { + job.onDependencyResolved(operationalState, transactionBuilder); + } + } + + @Override + public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier nodeIid, + Identifiable data) { + } + + @Override + public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier nodeIid, + Identifiable data) { + } + }); + } + }); + } + } + + private List getReadyJobs(LinkedBlockingQueue queue) { + List readyJobs = new ArrayList<>(); + Iterator jobIterator = queue.iterator(); + while(jobIterator.hasNext()) { + DependentJob job = jobIterator.next(); + long currentTime = System.currentTimeMillis(); + if (job.isExpired(currentTime)) { + jobIterator.remove(); + continue; + } + if (job.areDependenciesMet(deviceInfo)) { + jobIterator.remove(); + readyJobs.add(job); + } + } + return readyJobs; + } + + public static void close() { + executorService.shutdown(); + } +} \ No newline at end of file diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/DependentJob.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/DependentJob.java new file mode 100644 index 000000000..68dc79501 --- /dev/null +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/DependentJob.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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 org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo; +import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants; +import org.opendaylight.ovsdb.lib.operations.TransactionBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.List; +import java.util.Map; + +public abstract class DependentJob { + + private final long expiryTime; + private final InstanceIdentifier key; + private final T data; + private final Map, List> dependencies; + + DependentJob(InstanceIdentifier key, + T data, Map, List> dependencies) { + this.expiryTime = System.currentTimeMillis() + HwvtepSouthboundConstants.WAITING_JOB_EXPIRY_TIME_MILLIS; + this.key = key; + this.data = data; + this.dependencies = dependencies; + } + + /** + * This call back method gets called when all its dependencies are resolved + * @param operationalState new current operational state + * @param transactionBuilder transaction builder to create device transaction + */ + protected abstract void onDependencyResolved(HwvtepOperationalState operationalState, + TransactionBuilder transactionBuilder); + + /** + * This method is to check if all the given dependency of this job or not + * @param deviceInfo The device info of tis job + * @param cls dependency type to be checked for + * @param iid instance identifier to be checked for + * @return true if the dependency is met + */ + protected abstract boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, + InstanceIdentifier iid); + + boolean isExpired(long currentTime) { + return currentTime > expiryTime; + } + + /** + * This method checks if all the dependencies of this job or met or not + * @param deviceInfo The device info of this job + * @return true if all the dependencies are met + */ + boolean areDependenciesMet(HwvtepDeviceInfo deviceInfo) { + for (Class cls : dependencies.keySet()) { + for (InstanceIdentifier iid : dependencies.get(cls)) { + if (!isDependencyMet(deviceInfo, cls, iid)) { + return false; + } + } + } + return true; + } + + public InstanceIdentifier getKey() { + return key; + } + + public T getData() { + return data; + } + + public abstract static class ConfigWaitingJob extends DependentJob { + + public ConfigWaitingJob(InstanceIdentifier key, T data, Map dependencies) { + super(key, data, dependencies); + } + + @Override + protected boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, InstanceIdentifier iid) { + return deviceInfo.isConfigDataAvailable(cls, iid); + } + } + + public abstract static class OpWaitingJob extends DependentJob { + + public OpWaitingJob(InstanceIdentifier key, T data, Map dependencies) { + super(key, data, dependencies); + } + + @Override + protected boolean isDependencyMet(HwvtepDeviceInfo deviceInfo, Class cls, InstanceIdentifier iid) { + HwvtepDeviceInfo.DeviceData deviceData = deviceInfo.getDeviceOpData(cls, iid); + return deviceData == null || deviceData.getStatus() != HwvtepDeviceInfo.DeviceDataStatus.IN_TRANSIT; + } + } +} diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java index efecef985..2c15a506a 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java @@ -67,7 +67,10 @@ public class HwvtepOperationalState { private Map, Map> currentTxUUIDs = new ConcurrentHashMap<>(); private Map, Map> currentTxDeletedKeys = new ConcurrentHashMap<>(); - public HwvtepOperationalState(DataBroker db, Collection> changes) { + public HwvtepOperationalState(DataBroker db, HwvtepConnectionInstance connectionInstance, + Collection> changes) { + this.connectionInstance = connectionInstance; + this.deviceInfo = connectionInstance.getDeviceInfo(); Map, Node> nodeCreateOrUpdate = TransactUtils.extractCreatedOrUpdatedOrRemoved(changes, Node.class); if (nodeCreateOrUpdate != null) { @@ -340,7 +343,6 @@ public class HwvtepOperationalState { public void updateCurrentTxData(Class cls, InstanceIdentifier key, UUID uuid) { HwvtepSouthboundUtil.updateData(currentTxUUIDs, cls, key, uuid); - deviceInfo.markKeyAsInTransit(cls, key); } public void updateCurrentTxDeleteData(Class cls, InstanceIdentifier key) { diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUpdateCommand.java index bbde50e67..a0068d40e 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUpdateCommand.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/LogicalSwitchUpdateCommand.java @@ -20,6 +20,8 @@ import java.util.Set; import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil; +import org.opendaylight.ovsdb.lib.notation.UUID; import org.opendaylight.ovsdb.lib.operations.TransactionBuilder; import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils; import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch; @@ -63,6 +65,8 @@ public class LogicalSwitchUpdateCommand extends AbstractTransactCommand { private void updateLogicalSwitch(TransactionBuilder transaction, InstanceIdentifier instanceIdentifier, List lswitchList) { for (LogicalSwitches lswitch: lswitchList) { + InstanceIdentifier lsKey = instanceIdentifier. + augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class, lswitch.getKey()); LOG.debug("Creating logcial switch named: {}", lswitch.getHwvtepNodeName()); Optional operationalSwitchOptional = getOperationalState().getLogicalSwitches(instanceIdentifier, lswitch.getKey()); @@ -86,6 +90,8 @@ public class LogicalSwitchUpdateCommand extends AbstractTransactCommand { .build()); transaction.add(op.comment("Logical Switch: Updating " + existingLogicalSwitchName)); } + UUID lsUuid = new UUID(TransactUtils.getLogicalSwitchId(lswitch)); + updateCurrentTxData(LogicalSwitches.class, lsKey, lsUuid, lswitch); } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/McastMacsRemoteUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/McastMacsRemoteUpdateCommand.java index d53171df2..f29ccfb84 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/McastMacsRemoteUpdateCommand.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/McastMacsRemoteUpdateCommand.java @@ -8,17 +8,12 @@ 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.List; -import java.util.Map; -import java.util.Map.Entry; - +import com.google.common.base.Optional; +import com.google.common.collect.Lists; import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants; +import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil; import org.opendaylight.ovsdb.lib.notation.UUID; import org.opendaylight.ovsdb.lib.operations.TransactionBuilder; import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils; @@ -27,15 +22,25 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types. 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.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet; 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; -import com.google.common.base.Optional; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import static org.opendaylight.ovsdb.lib.operations.Operations.op; public class McastMacsRemoteUpdateCommand extends AbstractTransactCommand { private static final Logger LOG = LoggerFactory.getLogger(McastMacsRemoteUpdateCommand.class); + private static final McastMacUnMetDependencyGetter MCAST_MAC_DATA_VALIDATOR = new McastMacUnMetDependencyGetter(); public McastMacsRemoteUpdateCommand(HwvtepOperationalState state, Collection> changes) { @@ -192,4 +197,25 @@ public class McastMacsRemoteUpdateCommand extends AbstractTransactCommand { } return result; } + + static class McastMacUnMetDependencyGetter extends UnMetDependencyGetter { + + public List> getLogicalSwitchDependencies(RemoteMcastMacs data) { + if (data == null) { + return Collections.EMPTY_LIST; + } + return Lists.newArrayList(data.getLogicalSwitchRef().getValue()); + } + + public List> getTerminationPointDependencies(RemoteMcastMacs data) { + if (data == null || HwvtepSouthboundUtil.isEmpty(data.getLocatorSet())) { + return Collections.EMPTY_LIST; + } + List> locators = new ArrayList<>(); + for (LocatorSet locator: data.getLocatorSet()) { + locators.add(locator.getLocatorRef().getValue()); + } + return locators; + } + } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommand.java index ac9eeea8f..8a7771606 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommand.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommand.java @@ -9,9 +9,15 @@ package org.opendaylight.ovsdb.hwvtepsouthbound.transact; import org.opendaylight.ovsdb.lib.operations.TransactionBuilder; +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.Identifiable; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -public interface TransactCommand { +public interface TransactCommand { void execute(TransactionBuilder transaction); + void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier nodeIid, T data); + + void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier nodeIid, T data); } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommandAggregator.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommandAggregator.java index cd1c79c86..5d894fa8b 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommandAggregator.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommandAggregator.java @@ -8,13 +8,15 @@ package org.opendaylight.ovsdb.hwvtepsouthbound.transact; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.ovsdb.lib.operations.TransactionBuilder; 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.Identifiable; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; public class TransactCommandAggregator implements TransactCommand { @@ -45,4 +47,12 @@ public class TransactCommandAggregator implements TransactCommand { command.execute(transaction); } } + + @Override + public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data) { + } + + @Override + public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data) { + } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/UcastMacsRemoteUpdateCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/UcastMacsRemoteUpdateCommand.java index 3a2758d22..e26ec486b 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/UcastMacsRemoteUpdateCommand.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/UcastMacsRemoteUpdateCommand.java @@ -8,14 +8,8 @@ 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.List; -import java.util.Map; -import java.util.Map.Entry; - +import com.google.common.base.Optional; +import com.google.common.collect.Lists; import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.ovsdb.lib.notation.UUID; @@ -27,16 +21,24 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation; 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.TerminationPoint; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import static org.opendaylight.ovsdb.lib.operations.Operations.op; -public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand { +public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand { private static final Logger LOG = LoggerFactory.getLogger(UcastMacsRemoteUpdateCommand.class); + private static final UcastMacUnMetDependencyGetter UCAST_MAC_DATA_VALIDATOR = new UcastMacUnMetDependencyGetter(); public UcastMacsRemoteUpdateCommand(HwvtepOperationalState state, Collection> changes) { @@ -64,8 +66,30 @@ public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand { } private void updateUcastMacsRemote(TransactionBuilder transaction, - InstanceIdentifier instanceIdentifier, List remoteUcastMacs) { - for (RemoteUcastMacs remoteUcastMac: remoteUcastMacs) { + InstanceIdentifier instanceIdentifier, + List remoteUcastMacs) { + if (remoteUcastMacs == null) { + return; + } + for (RemoteUcastMacs remoteUcastMac : remoteUcastMacs) { + onConfigUpdate(transaction, instanceIdentifier, remoteUcastMac); + } + } + + @Override + public void onConfigUpdate(TransactionBuilder transaction, + InstanceIdentifier nodeIid, + RemoteUcastMacs remoteUcastMacs) { + InstanceIdentifier macIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class). + child(RemoteUcastMacs.class, remoteUcastMacs.getKey()); + //TODO uncommet in next commit + //processDependencies(UCAST_MAC_DATA_VALIDATOR, transaction, nodeIid, macIid, remoteUcastMacs); + doDeviceTransaction(transaction, nodeIid, remoteUcastMacs); + } + + @Override + public void doDeviceTransaction(TransactionBuilder transaction, + InstanceIdentifier instanceIdentifier, RemoteUcastMacs remoteUcastMac) { LOG.debug("Creating remoteUcastMacs, mac address: {}", remoteUcastMac.getMacEntryKey().getValue()); Optional operationalMacOptional = getOperationalState().getRemoteUcastMacs(instanceIdentifier, remoteUcastMac.getKey()); @@ -75,7 +99,7 @@ public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand { setLogicalSwitch(ucastMacsRemote, remoteUcastMac); if (!operationalMacOptional.isPresent()) { setMac(ucastMacsRemote, remoteUcastMac, operationalMacOptional); - LOG.trace("execute: creating RemotUcastMac entry: {}", ucastMacsRemote); + LOG.trace("doDeviceTransaction: creating RemotUcastMac entry: {}", ucastMacsRemote); transaction.add(op.insert(ucastMacsRemote)); transaction.add(op.comment("UcastMacRemote: Creating " + remoteUcastMac.getMacEntryKey().getValue())); } else if (operationalMacOptional.get().getMacEntryUuid() != null) { @@ -83,7 +107,7 @@ public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand { UcastMacsRemote extraMac = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), UcastMacsRemote.class, null); extraMac.getUuidColumn().setData(macEntryUUID); - LOG.trace("execute: updating RemotUcastMac entry: {}", ucastMacsRemote); + LOG.trace("doDeviceTransaction: updating RemotUcastMac entry: {}", ucastMacsRemote); transaction.add(op.update(ucastMacsRemote) .where(extraMac.getUuidColumn().getSchema().opEqual(macEntryUUID)) .build()); @@ -92,7 +116,6 @@ public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand { LOG.warn("Unable to update remoteMcastMacs {} because uuid not found in the operational store", remoteUcastMac.getMacEntryKey().getValue()); } - } } private void setLogicalSwitch(UcastMacsRemote ucastMacsRemote, RemoteUcastMacs inputMac) { @@ -219,4 +242,21 @@ public class UcastMacsRemoteUpdateCommand extends AbstractTransactCommand { } return result; } + + static class UcastMacUnMetDependencyGetter extends UnMetDependencyGetter { + + public List> getLogicalSwitchDependencies(RemoteUcastMacs data) { + if (data == null) { + return Collections.EMPTY_LIST; + } + return Lists.newArrayList(data.getLogicalSwitchRef().getValue()); + } + + public List> getTerminationPointDependencies(RemoteUcastMacs data) { + if (data == null) { + return Collections.EMPTY_LIST; + } + return Lists.newArrayList(data.getLocatorRef().getValue()); + } + } } \ No newline at end of file diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/UnMetDependencyGetter.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/UnMetDependencyGetter.java new file mode 100644 index 000000000..2141925e2 --- /dev/null +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/UnMetDependencyGetter.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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 org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo; +import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils; +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.TerminationPoint; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Utility class to retrieve the unmet dependencies (config/operational) of the given object + * @param + */ +public abstract class UnMetDependencyGetter { + + private final ConfigDependencyGetter configDependencyGetter = new ConfigDependencyGetter(); + private final InTransitDependencyGetter inTransitDependencyGetter = new InTransitDependencyGetter(); + + /** + * Returns the iids this data depends upon + * which are already intransit in the previous transaction if any + * @param opState The operatonal state + * @param data The data object + * @return The depenencies + */ + public Map, List> getInTransitDependencies( + HwvtepOperationalState opState, T data) { + return inTransitDependencyGetter.retrieveUnMetDependencies(opState, opState.getDeviceInfo(), data); + } + + /** + * Returns the iids this data depends upon + * which are not yet present in the config data store if any + * @param opState The operatonal state + * @param data The data object + * @return the depenencies + */ + public Map, List> getUnMetConfigDependencies( + HwvtepOperationalState opState, T data) { + return configDependencyGetter.retrieveUnMetDependencies(opState, opState.getDeviceInfo(), data); + } + + abstract class DependencyGetter { + + Map, List> retrieveUnMetDependencies( + HwvtepOperationalState opState, HwvtepDeviceInfo deviceInfo, T data) { + + Map, List> result = new HashMap<>(); + Map, List>> allKeys = new HashMap<>(); + allKeys.put(LogicalSwitches.class, getLogicalSwitchDependencies(data)); + allKeys.put(TerminationPoint.class, getTerminationPointDependencies(data)); + + for (Class cls : allKeys.keySet()) { + List> keysToCheck = allKeys.get(cls); + for (InstanceIdentifier key : keysToCheck) { + if (!isDependencyMet(opState, deviceInfo, cls, key)) { + result = addToResultMap(result, cls, key); + } + } + } + return result; + } + + Map, List> addToResultMap( + Map, List> result, + Class cls, InstanceIdentifier key) { + if (null == result) { + result = new HashMap<>(); + } + if (!result.containsKey(cls)) { + result.put(cls, new ArrayList<>()); + } + result.get(cls).add(key); + return result; + } + + abstract boolean isDependencyMet(HwvtepOperationalState opState, HwvtepDeviceInfo deviceInfo, + Class cls, InstanceIdentifier key); + } + + class ConfigDependencyGetter extends DependencyGetter { + boolean isDependencyMet(HwvtepOperationalState opState, HwvtepDeviceInfo deviceInfo, + Class cls, InstanceIdentifier key) { + return deviceInfo.isConfigDataAvailable(cls, key) || isConfigDataAvailable(opState, key); + } + + boolean isConfigDataAvailable(HwvtepOperationalState opState, InstanceIdentifier key) { + DataBroker db = opState.getConnectionInstance().getDataBroker(); + MdsalUtils mdsalUtils = new MdsalUtils(db); + return mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, key) != null; + } + } + + class InTransitDependencyGetter extends DependencyGetter { + boolean isDependencyMet(HwvtepOperationalState opState, HwvtepDeviceInfo deviceInfo, + Class cls, InstanceIdentifier key) { + return opState.isKeyPartOfCurrentTx(cls, key) || !deviceInfo.isKeyInTransit(cls, key); + } + } + + public abstract List> getLogicalSwitchDependencies(T data); + + public abstract List> getTerminationPointDependencies(T data); +} \ No newline at end of file diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepOperationalCommandAggregator.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepOperationalCommandAggregator.java index 2089a1af4..4eba084d7 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepOperationalCommandAggregator.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepOperationalCommandAggregator.java @@ -19,9 +19,11 @@ import org.opendaylight.ovsdb.lib.schema.DatabaseSchema; public class HwvtepOperationalCommandAggregator implements TransactionCommand { private List commands = new ArrayList<>(); + private final HwvtepConnectionInstance connectionInstance; public HwvtepOperationalCommandAggregator(HwvtepConnectionInstance key,TableUpdates updates, DatabaseSchema dbSchema) { + this.connectionInstance = key; commands.add(new GlobalUpdateCommand(key, updates, dbSchema)); commands.add(new HwvtepPhysicalSwitchUpdateCommand(key, updates, dbSchema)); commands.add(new HwvtepPhysicalSwitchRemoveCommand(key, updates, dbSchema)); @@ -47,5 +49,6 @@ public class HwvtepOperationalCommandAggregator implements TransactionCommand { for (TransactionCommand command: commands) { command.execute(transaction); } + connectionInstance.getDeviceInfo().onOpDataAvailable(); } } diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DataChangeListenerTestBase.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DataChangeListenerTestBase.java index 576f70023..5996bcb24 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DataChangeListenerTestBase.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DataChangeListenerTestBase.java @@ -49,6 +49,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology. import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.powermock.api.mockito.PowerMockito; +import org.powermock.api.support.membermodification.MemberMatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -148,6 +149,7 @@ public class DataChangeListenerTestBase extends AbstractDataBrokerTest { connectionInfo = mock(OvsdbConnectionInfo.class); ovsdbClient = mock(OvsdbClient.class); transactionInvoker = new TransactionInvokerImpl(dataBroker); + connectionInstance = PowerMockito.mock(HwvtepConnectionInstance.class, Mockito.CALLS_REAL_METHODS); field(HwvtepConnectionInstance.class, "instanceIdentifier").set(connectionInstance, nodeIid); field(HwvtepConnectionInstance.class, "txInvoker").set(connectionInstance, transactionInvoker); diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DependencyQueueTest.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DependencyQueueTest.java new file mode 100644 index 000000000..df1e7f9ad --- /dev/null +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DependencyQueueTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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; + +import com.google.common.util.concurrent.MoreExecutors; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependencyQueue; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependentJob; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.HwvtepOperationalState; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.McastMacsRemoteUpdateCommand; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.UnMetDependencyGetter; +import org.opendaylight.ovsdb.lib.notation.UUID; +import org.opendaylight.ovsdb.lib.operations.Operations; +import org.opendaylight.ovsdb.lib.operations.TransactionBuilder; +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.HwvtepNodeName; +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.LogicalSwitchesKey; +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.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +import static org.junit.Assert.assertEquals; +import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({HwvtepConnectionInstance.class, HwvtepConnectionManager.class, Operations.class, DependencyQueue.class}) +public class DependencyQueueTest extends DataChangeListenerTestBase { + + String[][] terminationPoints = new String[][]{ + {"192.168.122.20"}, + {"192.168.122.30"} + }; + + UnMetDependencyGetter MCAST_MAC_DATA_VALIDATOR; + HwvtepOperationalState opState; + RemoteMcastMacs mac; + InstanceIdentifier macIid; + InstanceIdentifier lsIid; + Map, List> unMetDependencies; + + void setupForTest() { + MCAST_MAC_DATA_VALIDATOR = Whitebox.getInternalState(McastMacsRemoteUpdateCommand.class, UnMetDependencyGetter.class); + opState = new HwvtepOperationalState(connectionInstance); + mac = TestBuilders.buildRemoteMcastMacs(nodeIid,"FF:FF:FF:FF:FF:FF", "ls0", + new String[]{"192.168.122.20", "192.168.122.30"}); + lsIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class). + child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName("ls0"))); + macIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class). + child(RemoteMcastMacs.class, new RemoteMcastMacsKey(mac.getKey())); + Whitebox.setInternalState(DependencyQueue.class, "executorService", MoreExecutors.sameThreadExecutor()); + } + + @Test + public void testLogicalSwitchConfigDependency() throws Exception { + setupForTest(); + unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getUnMetConfigDependencies(opState, mac); + unMetDependencies.remove(TerminationPoint.class); + + final CountDownLatch latch = new CountDownLatch(1); + opState.getDeviceInfo().addJobToQueue(new DependentJob.ConfigWaitingJob(macIid, mac, unMetDependencies) { + @Override + protected void onDependencyResolved(HwvtepOperationalState operationalState, TransactionBuilder transactionBuilder) { + latch.countDown(); + } + }); + assertEquals(1, latch.getCount()); + addData(CONFIGURATION, LogicalSwitches.class, new String[]{"ls0", "100"}); + addData(CONFIGURATION, TerminationPoint.class, terminationPoints); + assertEquals(0, latch.getCount()); + } + + @Test + public void testLogicalSwitchInTransitDependency() throws Exception { + setupForTest(); + opState.getDeviceInfo().markKeyAsInTransit(LogicalSwitches.class, lsIid); + unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac); + + final CountDownLatch latch = new CountDownLatch(1); + opState.getDeviceInfo().addJobToQueue(new DependentJob.OpWaitingJob(macIid, mac, unMetDependencies) { + @Override + protected void onDependencyResolved(HwvtepOperationalState operationalState, TransactionBuilder transactionBuilder) { + latch.countDown(); + } + }); + opState.getDeviceInfo().onOpDataAvailable(); + assertEquals(1, latch.getCount()); + + opState.getDeviceInfo().updateDeviceOpData(LogicalSwitches.class, lsIid, new UUID("ls0"), "ls0"); + opState.getDeviceInfo().onOpDataAvailable(); + assertEquals(0, latch.getCount()); + + } +} diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperationalStateTest.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperationalStateTest.java index 77ad5c4d2..45c010176 100644 --- a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperationalStateTest.java +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperationalStateTest.java @@ -20,6 +20,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitchesKey; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @@ -52,6 +53,10 @@ public class HwvtepOperationalStateTest extends DataChangeListenerTestBase { assertEquals(uuid, resultUuid); boolean result = opState.getDeviceInfo().isKeyInTransit(LogicalSwitches.class, lsIid); + assertFalse(result); + + opState.getDeviceInfo().markKeyAsInTransit(LogicalSwitches.class, lsIid); + result = opState.getDeviceInfo().isKeyInTransit(LogicalSwitches.class, lsIid); assertTrue(result); opState.getDeviceInfo().updateDeviceOpData(LogicalSwitches.class, lsIid, uuid, lsIid); diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/UnMetDependencyGetterTest.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/UnMetDependencyGetterTest.java new file mode 100644 index 000000000..50bf72006 --- /dev/null +++ b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/UnMetDependencyGetterTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.HwvtepOperationalState; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.McastMacsRemoteUpdateCommand; +import org.opendaylight.ovsdb.hwvtepsouthbound.transact.UnMetDependencyGetter; +import org.opendaylight.ovsdb.lib.notation.UUID; +import org.opendaylight.ovsdb.lib.operations.Operations; +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.HwvtepNodeName; +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.LogicalSwitchesKey; +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.TerminationPoint; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({HwvtepConnectionInstance.class, HwvtepConnectionManager.class, Operations.class}) +public class UnMetDependencyGetterTest extends DataChangeListenerTestBase { + + UnMetDependencyGetter MCAST_MAC_DATA_VALIDATOR; + HwvtepOperationalState opState; + RemoteMcastMacs mac; + InstanceIdentifier lsIid; + Map, List> unMetDependencies; + + void setupForTest() { + MCAST_MAC_DATA_VALIDATOR = Whitebox.getInternalState(McastMacsRemoteUpdateCommand.class, UnMetDependencyGetter.class); + opState = new HwvtepOperationalState(connectionInstance); + mac = TestBuilders.buildRemoteMcastMacs(nodeIid,"FF:FF:FF:FF:FF:FF", "ls0", + new String[]{"192.168.122.20", "192.168.122.30"}); + lsIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class). + child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName("ls0"))); + } + + @Test + public void testLogicalSwitchConfigDependency() throws Exception { + setupForTest(); + unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac); + assertEquals(0, unMetDependencies.size()); + + unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getUnMetConfigDependencies(opState, mac); + assertEquals(1, unMetDependencies.get(LogicalSwitches.class).size()); + assertEquals(2, unMetDependencies.get(TerminationPoint.class).size()); + + opState.getDeviceInfo().updateConfigData(LogicalSwitches.class, lsIid, "ls0"); + unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getUnMetConfigDependencies(opState, mac); + assertNull(unMetDependencies.get(LogicalSwitches.class)); + } + + @Test + public void testLogicalSwitchInTransitDependency() throws Exception { + setupForTest(); + unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac); + assertEquals(0, unMetDependencies.size()); + + opState.getDeviceInfo().markKeyAsInTransit(LogicalSwitches.class, lsIid); + unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac); + assertEquals(1, unMetDependencies.size()); + + opState.getDeviceInfo().updateDeviceOpData(LogicalSwitches.class, lsIid, new UUID("ls0"), "ls0"); + unMetDependencies = MCAST_MAC_DATA_VALIDATOR.getInTransitDependencies(opState, mac); + assertEquals(0, unMetDependencies.size()); + } +}