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>
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;
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();
}
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());
}
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());
}
private void initDeviceData() {
- final WriteTransaction transaction = dataService.newWriteOnlyTransaction();
+ final WriteTransaction transaction = txChain.newWriteOnlyTransaction();
createNodesListIfNotPresent(transaction);
@Override
public void close() throws Exception {
removeDeviceConfigAndState();
+ txChain.close();
}
public static org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node buildDataForDeviceState(
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;
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;
};
private final RemoteDeviceId id;
- private final DataBroker dataService;
+ private final BindingTransactionChain txChain;
private final InstanceIdentifier<NetworkTopology> networkTopologyPath;
private final KeyedInstanceIdentifier<Topology, TopologyKey> topologyListPath;
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())));
}
private void initDeviceData() {
- final WriteTransaction writeTx = dataService.newWriteOnlyTransaction();
+ final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
createNetworkTopologyIfNotPresent(writeTx);
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());
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());
}
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());
@Override
public void close() throws Exception {
removeDeviceConfiguration();
+ txChain.close();
}
}
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;
@Mock
private WriteTransaction writeTx;
@Mock
+ private BindingTransactionChain txChain;
+ @Mock
private Node data;
private String txIdent = "test transaction";
@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));
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));
}
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));
}