BUG 7801: prevent OptimisticLockFailedExceptions in write-transactions. 84/53784/7
authorTomas Cere <tcere@cisco.com>
Fri, 24 Mar 2017 10:29:16 +0000 (11:29 +0100)
committerTom Pantelis <tompantelis@gmail.com>
Sat, 1 Apr 2017 08:40:14 +0000 (08:40 +0000)
When multiple instances of this rpc are running concurrently in paralel
we would run into an optimistic lock since every instance tries to write
the topmost parent list first.
When these happen handle these failures as expected and resume with the
next stage of the rpc.

Change-Id: I43efaea3315b04272113eb86733e68609e434984
Signed-off-by: Tomas Cere <tcere@cisco.com>
opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/WriteTransactionsHandler.java

index fd47b71..664e7fd 100644 (file)
@@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit;
 import javax.annotation.Nullable;
 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.OptimisticLockFailedException;
 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;
@@ -127,17 +128,31 @@ public class WriteTransactionsHandler implements Runnable {
 
     private boolean ensureListExists(final SettableFuture<RpcResult<WriteTransactionsOutput>> settableFuture) {
 
+        final MapNode mapNode = ImmutableNodes.mapNodeBuilder(ID_INTS).build();
+
+        DOMDataWriteTransaction tx = txProvider.createTransaction();
+        // write only the top list
+        tx.merge(LogicalDatastoreType.CONFIGURATION, ID_INTS_YID, mapNode);
+        try {
+            tx.submit().checkedGet();
+        } catch (final OptimisticLockFailedException e) {
+            // when multiple write-transactions are executed concurrently we need to ignore this.
+            // If we get optimistic lock here it means id-ints already exists and we can continue.
+            LOG.debug("Got an optimistic lock when writing initial top level list element.", e);
+        } catch (final TransactionCommitFailedException e) {
+            LOG.warn("Unable to ensure IdInts list for id: {} exists.", id, e);
+            settableFuture.set(RpcResultBuilder.<WriteTransactionsOutput>failed()
+                    .withError(RpcError.ErrorType.APPLICATION, "Unexpected-exception", e).build());
+            return false;
+        }
+
         final MapEntryNode entry = ImmutableNodes.mapEntryBuilder(ID_INTS, ID, id)
                 .withChild(ImmutableNodes.mapNodeBuilder(ITEM).build())
                 .build();
-        final MapNode mapNode =
-                ImmutableNodes.mapNodeBuilder(ID_INTS)
-                        .withChild(entry)
-                        .build();
 
-        final DOMDataWriteTransaction tx = txProvider.createTransaction();
         idListWithKey = ID_INTS_YID.node(entry.getIdentifier());
-        tx.merge(LogicalDatastoreType.CONFIGURATION, ID_INTS_YID, mapNode);
+        tx = txProvider.createTransaction();
+        tx.merge(LogicalDatastoreType.CONFIGURATION, idListWithKey, entry);
 
         try {
             tx.submit().checkedGet();