Changed NetconfDeviceDatastoreAdapter and NetconfDeviceTopologyAdapter to use Transac... 88/16188/4
authorTomas Cere <tcere@cisco.com>
Mon, 9 Mar 2015 12:26:40 +0000 (13:26 +0100)
committerTomas Cere <tcere@cisco.com>
Mon, 9 Mar 2015 15:29:06 +0000 (16:29 +0100)
instead of Transactions to prevent race condition between init and update when a device is created.

Change-Id: I8b7f507dd66d3bf95e15858c456f8905c9bbf4b9
Signed-off-by: Tomas Cere <tcere@cisco.com>
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapter.java
opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapterTest.java

index 8590c491e470de643c156c5c5f20db6c5c96352e..48b41da3fa83d617211f1b7850a8380708377a4d 100644 (file)
@@ -16,10 +16,14 @@ import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Set;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
@@ -46,11 +50,22 @@ final class NetconfDeviceDatastoreAdapter implements AutoCloseable {
     private static final Logger logger  = LoggerFactory.getLogger(NetconfDeviceDatastoreAdapter.class);
 
     private final RemoteDeviceId id;
-    private final DataBroker dataService;
+    private final BindingTransactionChain txChain;
 
     NetconfDeviceDatastoreAdapter(final RemoteDeviceId deviceId, final DataBroker dataService) {
         this.id = Preconditions.checkNotNull(deviceId);
-        this.dataService = Preconditions.checkNotNull(dataService);
+        this.txChain = Preconditions.checkNotNull(dataService).createTransactionChain(new TransactionChainListener() {
+            @Override
+            public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction, Throwable cause) {
+                logger.error("{}: TransactionChain({}) {} FAILED!", id, chain, transaction.getIdentifier(), cause);
+                throw new IllegalStateException(id + "  TransactionChain(" + chain + ") not committed correctly", cause);
+            }
+
+            @Override
+            public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
+                logger.trace("{}: TransactionChain({}) {} SUCCESSFUL", id, chain);
+            }
+        });
 
         initDeviceData();
     }
@@ -59,7 +74,7 @@ final class NetconfDeviceDatastoreAdapter implements AutoCloseable {
         final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node data = buildDataForDeviceState(
                 up, capabilities, id);
 
-        final ReadWriteTransaction transaction = dataService.newReadWriteTransaction();
+        final ReadWriteTransaction transaction = txChain.newReadWriteTransaction();
         logger.trace("{}: Update device state transaction {} merging operational data started.", id, transaction.getIdentifier());
         transaction.put(LogicalDatastoreType.OPERATIONAL, id.getBindingPath(), data);
         logger.trace("{}: Update device state transaction {} merging operational data ended.", id, transaction.getIdentifier());
@@ -68,7 +83,7 @@ final class NetconfDeviceDatastoreAdapter implements AutoCloseable {
     }
 
     private void removeDeviceConfigAndState() {
-        final WriteTransaction transaction = dataService.newWriteOnlyTransaction();
+        final WriteTransaction transaction = txChain.newWriteOnlyTransaction();
         logger.trace("{}: Close device state transaction {} removing all data started.", id, transaction.getIdentifier());
         transaction.delete(LogicalDatastoreType.CONFIGURATION, id.getBindingPath());
         transaction.delete(LogicalDatastoreType.OPERATIONAL, id.getBindingPath());
@@ -78,7 +93,7 @@ final class NetconfDeviceDatastoreAdapter implements AutoCloseable {
     }
 
     private void initDeviceData() {
-        final WriteTransaction transaction = dataService.newWriteOnlyTransaction();
+        final WriteTransaction transaction = txChain.newWriteOnlyTransaction();
 
         createNodesListIfNotPresent(transaction);
 
@@ -126,6 +141,7 @@ final class NetconfDeviceDatastoreAdapter implements AutoCloseable {
     @Override
     public void close() throws Exception {
         removeDeviceConfigAndState();
+        txChain.close();
     }
 
     public static org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node buildDataForDeviceState(
index 24b6205cdc18a8e3fd68ea2065cd72e211ca052d..055beda18493fca129c92e5f256ce9ca344e8e92 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.controller.sal.connect.netconf.sal;
 
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
@@ -16,9 +17,13 @@ import com.google.common.util.concurrent.Futures;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map.Entry;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCapabilities;
 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
@@ -68,7 +73,7 @@ final class NetconfDeviceTopologyAdapter implements AutoCloseable {
     };
 
     private final RemoteDeviceId id;
-    private final DataBroker dataService;
+    private final BindingTransactionChain txChain;
 
     private final InstanceIdentifier<NetworkTopology> networkTopologyPath;
     private final KeyedInstanceIdentifier<Topology, TopologyKey> topologyListPath;
@@ -76,7 +81,18 @@ final class NetconfDeviceTopologyAdapter implements AutoCloseable {
 
     NetconfDeviceTopologyAdapter(final RemoteDeviceId id, final DataBroker dataService) {
         this.id = id;
-        this.dataService = dataService;
+        this.txChain = Preconditions.checkNotNull(dataService).createTransactionChain(new TransactionChainListener() {
+            @Override
+            public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction, Throwable cause) {
+                logger.error("{}: TransactionChain({}) {} FAILED!", id, chain, transaction.getIdentifier(), cause);
+                throw new IllegalStateException(id + "  TransactionChain(" + chain + ") not committed correctly", cause);
+            }
+
+            @Override
+            public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
+                logger.trace("{}: TransactionChain({}) {} SUCCESSFUL", id, chain);
+            }
+        });
 
         this.networkTopologyPath = InstanceIdentifier.builder(NetworkTopology.class).build();
         this.topologyListPath = networkTopologyPath.child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
@@ -85,7 +101,7 @@ final class NetconfDeviceTopologyAdapter implements AutoCloseable {
     }
 
      private void initDeviceData() {
-        final WriteTransaction writeTx = dataService.newWriteOnlyTransaction();
+        final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
 
         createNetworkTopologyIfNotPresent(writeTx);
 
@@ -112,7 +128,7 @@ final class NetconfDeviceTopologyAdapter implements AutoCloseable {
     public void updateDeviceData(boolean up, NetconfDeviceCapabilities capabilities) {
         final Node data = buildDataForNetconfNode(up, capabilities);
 
-        final WriteTransaction writeTx = dataService.newWriteOnlyTransaction();
+        final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
         logger.trace("{}: Update device state transaction {} merging operational data started.", id, writeTx.getIdentifier());
         writeTx.put(LogicalDatastoreType.OPERATIONAL, id.getTopologyBindingPath(), data);
         logger.trace("{}: Update device state transaction {} merging operational data ended.", id, writeTx.getIdentifier());
@@ -126,7 +142,7 @@ final class NetconfDeviceTopologyAdapter implements AutoCloseable {
         final NetconfNode netconfNode = new NetconfNodeBuilder().setConnectionStatus(ConnectionStatus.UnableToConnect).setConnectedMessage(reason).build();
         final Node data = getNodeIdBuilder(id).addAugmentation(NetconfNode.class, netconfNode).build();
 
-        final WriteTransaction writeTx = dataService.newWriteOnlyTransaction();
+        final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
         logger.trace("{}: Setting device state as failed {} putting operational data started.", id, writeTx.getIdentifier());
         writeTx.put(LogicalDatastoreType.OPERATIONAL, id.getTopologyBindingPath(), data);
         logger.trace("{}: Setting device state as failed {} putting operational data ended.", id, writeTx.getIdentifier());
@@ -158,7 +174,7 @@ final class NetconfDeviceTopologyAdapter implements AutoCloseable {
     }
 
     public void removeDeviceConfiguration() {
-        final WriteTransaction writeTx = dataService.newWriteOnlyTransaction();
+        final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
 
         logger.trace("{}: Close device state transaction {} removing all data started.", id, writeTx.getIdentifier());
         writeTx.delete(LogicalDatastoreType.CONFIGURATION, id.getTopologyBindingPath());
@@ -214,5 +230,6 @@ final class NetconfDeviceTopologyAdapter implements AutoCloseable {
     @Override
     public void close() throws Exception {
         removeDeviceConfiguration();
+        txChain.close();
     }
 }
index a1551b23b61d978d3a895bc4ddf8bb8794a85228..158c4c43f098d0843cf24ec97b3f9fabc6a69831 100644 (file)
@@ -20,9 +20,11 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCapabilities;
 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
@@ -37,6 +39,8 @@ public class NetconfDeviceTopologyAdapterTest {
     @Mock
     private WriteTransaction writeTx;
     @Mock
+    private BindingTransactionChain txChain;
+    @Mock
     private Node data;
 
     private String txIdent = "test transaction";
@@ -44,7 +48,8 @@ public class NetconfDeviceTopologyAdapterTest {
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        doReturn(writeTx).when(broker).newWriteOnlyTransaction();
+        doReturn(txChain).when(broker).createTransactionChain(any(TransactionChainListener.class));
+        doReturn(writeTx).when(txChain).newWriteOnlyTransaction();
         doNothing().when(writeTx).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));
         doNothing().when(writeTx).merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));
 
@@ -58,7 +63,7 @@ public class NetconfDeviceTopologyAdapterTest {
         NetconfDeviceTopologyAdapter adapter = new NetconfDeviceTopologyAdapter(id, broker);
         adapter.setDeviceAsFailed(null);
 
-        verify(broker, times(2)).newWriteOnlyTransaction();
+        verify(txChain, times(2)).newWriteOnlyTransaction();
         verify(writeTx, times(3)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));
     }
 
@@ -69,7 +74,7 @@ public class NetconfDeviceTopologyAdapterTest {
         NetconfDeviceTopologyAdapter adapter = new NetconfDeviceTopologyAdapter(id, broker);
         adapter.updateDeviceData(true, new NetconfDeviceCapabilities());
 
-        verify(broker, times(2)).newWriteOnlyTransaction();
+        verify(txChain, times(2)).newWriteOnlyTransaction();
         verify(writeTx, times(3)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));
     }