From: Tony Tkacik Date: Wed, 11 Mar 2015 19:27:46 +0000 (+0000) Subject: Merge "Changed NetconfDeviceDatastoreAdapter and NetconfDeviceTopologyAdapter to... X-Git-Tag: release/lithium~416 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=874a18a9ce5dc09bc49922754bf8fb3e981fffb9;hp=262f25762a55f26db800c8881819a200803b729c Merge "Changed NetconfDeviceDatastoreAdapter and NetconfDeviceTopologyAdapter to use TransactionChains instead of Transactions to prevent race condition between init and update when a device is created." --- diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java index 8590c491e4..48b41da3fa 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java @@ -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( diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapter.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapter.java index 24b6205cdc..055beda184 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapter.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapter.java @@ -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 networkTopologyPath; private final KeyedInstanceIdentifier 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(); } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapterTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapterTest.java index a1551b23b6..158c4c43f0 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapterTest.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTopologyAdapterTest.java @@ -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)); }