Bug 4774: Wait for prior RO tx creates on tx chain
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / AbstractTransactionContextFactory.java
index 1e085523fdc0599e21a320e4d721abdba9bd13a1..4fda059f3182ee898f7f4bc076ae7800159b3a77 100644 (file)
@@ -55,7 +55,12 @@ abstract class AbstractTransactionContextFactory<F extends LocalTransactionFacto
                 LOG.debug("Tx {} - Creating local component for shard {} using factory {}",
                         parent.getIdentifier(), shardName, local);
             }
-            return createLocalTransactionContext(local, parent);
+
+            try {
+                return createLocalTransactionContext(local, parent);
+            } catch(Exception e) {
+                return new NoOpTransactionContext(e, parent.getIdentifier());
+            }
         }
 
         return null;
@@ -70,13 +75,17 @@ abstract class AbstractTransactionContextFactory<F extends LocalTransactionFacto
 
         updateShardInfo(shardName, primaryShardInfo);
 
-        TransactionContext localContext = maybeCreateLocalTransactionContext(parent, shardName);
-        if(localContext != null) {
-            transactionContextWrapper.executePriorTransactionOperations(localContext);
-        } else {
-            RemoteTransactionContextSupport remote = new RemoteTransactionContextSupport(transactionContextWrapper,
-                    parent, shardName);
-            remote.setPrimaryShard(primaryShardInfo.getPrimaryShardActor(), primaryShardInfo.getPrimaryShardVersion());
+        try {
+            TransactionContext localContext = maybeCreateLocalTransactionContext(parent, shardName);
+            if(localContext != null) {
+                transactionContextWrapper.executePriorTransactionOperations(localContext);
+            } else {
+                RemoteTransactionContextSupport remote = new RemoteTransactionContextSupport(transactionContextWrapper,
+                        parent, shardName);
+                remote.setPrimaryShard(primaryShardInfo.getPrimaryShardActor(), primaryShardInfo.getPrimaryShardVersion());
+            }
+        } finally {
+            onTransactionContextCreated(parent.getIdentifier());
         }
     }
 
@@ -84,15 +93,19 @@ abstract class AbstractTransactionContextFactory<F extends LocalTransactionFacto
             String shardName, TransactionContextWrapper transactionContextWrapper) {
         LOG.debug("Tx {}: Find primary for shard {} failed", parent.getIdentifier(), shardName, failure);
 
-        transactionContextWrapper.executePriorTransactionOperations(new NoOpTransactionContext(failure,
-                parent.getIdentifier()));
+        try {
+            transactionContextWrapper.executePriorTransactionOperations(new NoOpTransactionContext(failure,
+                    parent.getIdentifier()));
+        } finally {
+            onTransactionContextCreated(parent.getIdentifier());
+        }
     }
 
     final TransactionContextWrapper newTransactionContextWrapper(final TransactionProxy parent, final String shardName) {
         final TransactionContextWrapper transactionContextWrapper =
                 new TransactionContextWrapper(parent.getIdentifier(), actorContext);
 
-        Future<PrimaryShardInfo> findPrimaryFuture = findPrimaryShard(shardName);
+        Future<PrimaryShardInfo> findPrimaryFuture = findPrimaryShard(shardName, parent.getIdentifier());
         if(findPrimaryFuture.isCompleted()) {
             Try<PrimaryShardInfo> maybe = findPrimaryFuture.value().get();
             if(maybe.isSuccess()) {
@@ -154,7 +167,8 @@ abstract class AbstractTransactionContextFactory<F extends LocalTransactionFacto
      * @param shardName Shard name
      * @return Future containing shard information.
      */
-    protected abstract Future<PrimaryShardInfo> findPrimaryShard(String shardName);
+    protected abstract Future<PrimaryShardInfo> findPrimaryShard(@Nonnull String shardName,
+            @Nonnull TransactionIdentifier txId);
 
     /**
      * Create local transaction factory for specified shard, backed by specified shard leader
@@ -175,13 +189,20 @@ abstract class AbstractTransactionContextFactory<F extends LocalTransactionFacto
      */
     protected abstract <T> void onTransactionReady(@Nonnull TransactionIdentifier transaction, @Nonnull Collection<Future<T>> cohortFutures);
 
+    /**
+     * Callback invoked when the internal TransactionContext has been created for a transaction.
+     *
+     * @param transactionId the ID of the transaction.
+     */
+    protected abstract void onTransactionContextCreated(@Nonnull TransactionIdentifier transactionId);
+
     private static TransactionContext createLocalTransactionContext(final LocalTransactionFactory factory,
                                                                     final TransactionProxy parent) {
 
         switch(parent.getType()) {
             case READ_ONLY:
                 final DOMStoreReadTransaction readOnly = factory.newReadOnlyTransaction(parent.getIdentifier());
-                return new LocalTransactionContext(readOnly, parent.getIdentifier()) {
+                return new LocalTransactionContext(readOnly, parent.getIdentifier(), factory) {
                     @Override
                     protected DOMStoreWriteTransaction getWriteDelegate() {
                         throw new UnsupportedOperationException();
@@ -194,7 +215,7 @@ abstract class AbstractTransactionContextFactory<F extends LocalTransactionFacto
                 };
             case READ_WRITE:
                 final DOMStoreReadWriteTransaction readWrite = factory.newReadWriteTransaction(parent.getIdentifier());
-                return new LocalTransactionContext(readWrite, parent.getIdentifier()) {
+                return new LocalTransactionContext(readWrite, parent.getIdentifier(), factory) {
                     @Override
                     protected DOMStoreWriteTransaction getWriteDelegate() {
                         return readWrite;
@@ -207,7 +228,7 @@ abstract class AbstractTransactionContextFactory<F extends LocalTransactionFacto
                 };
             case WRITE_ONLY:
                 final DOMStoreWriteTransaction writeOnly = factory.newWriteOnlyTransaction(parent.getIdentifier());
-                return new LocalTransactionContext(writeOnly, parent.getIdentifier()) {
+                return new LocalTransactionContext(writeOnly, parent.getIdentifier(), factory) {
                     @Override
                     protected DOMStoreWriteTransaction getWriteDelegate() {
                         return writeOnly;