From: tpantelis Date: Fri, 11 Jul 2014 06:21:25 +0000 (-0400) Subject: Bug 1362: New AsyncWriteTransaction#submit method X-Git-Tag: release/helium~466^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=0219d667fd81b48cd3f05faee7d39aa1acce73a4 Bug 1362: New AsyncWriteTransaction#submit method - Added new AsyncWriteTransaction#submit and deprecated AsyncWriteTransaction#commit. - Modified unit tests and current code (in the toaster) in the controller using commit. Change-Id: I92317d01427bf442def8e7217ccb13313a0fd229 Signed-off-by: tpantelis --- diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java index 9eceeb1e43..a8eef5a3ca 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java @@ -10,13 +10,12 @@ package org.opendaylight.controller.md.sal.binding.impl; import java.util.Collections; import java.util.Map.Entry; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.Identifiable; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.slf4j.Logger; @@ -24,7 +23,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.collect.Iterables; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; /** * @@ -122,8 +121,8 @@ public class AbstractWriteTransaction extends getDelegate().delete(store, normalized); } - protected final ListenableFuture> doCommit() { - return getDelegate().commit(); + protected final CheckedFuture doSubmit() { + return getDelegate().submit(); } protected final boolean doCancel() { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java index a62319be22..7e622baac3 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java @@ -10,11 +10,13 @@ package org.opendaylight.controller.md.sal.binding.impl; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; - +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.ListenableFuture; class BindingDataWriteTransactionImpl extends @@ -24,8 +26,6 @@ class BindingDataWriteTransactionImpl extends super(delegateTx, codec); } - - @Override public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { doPut(store, path, data); @@ -43,7 +43,12 @@ class BindingDataWriteTransactionImpl extends @Override public ListenableFuture> commit() { - return doCommit(); + return AbstractDataTransaction.convertToLegacyCommitFuture(submit()); + } + + @Override + public CheckedFuture submit() { + return doSubmit(); } @Override diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java index b45450ae3a..12f26b09bb 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java @@ -28,6 +28,7 @@ import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.Data import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; @@ -160,7 +161,7 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat @Override public ListenableFuture> apply(final Boolean requestCommitSuccess) throws Exception { if(requestCommitSuccess) { - return tx.getDelegate().commit(); + return AbstractDataTransaction.convertToLegacyCommitFuture(tx.getDelegate().submit()); } return Futures.immediateFuture(RpcResultBuilder.failed().withResult(TransactionStatus.FAILED).build()); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1125RegressionTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1125RegressionTest.java index 9f1ae38457..fb11535061 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1125RegressionTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1125RegressionTest.java @@ -49,13 +49,13 @@ public class Bug1125RegressionTest extends AbstractDataChangeListenerTest { "foo").build()).build(); initialTx.put(LogicalDatastoreType.OPERATIONAL, path(TOP_FOO_KEY), topLevelList(TOP_FOO_KEY, fooAugment)); - assertCommit(initialTx.commit()); + assertCommit(initialTx.submit()); } private void delete(final InstanceIdentifier path) { WriteTransaction tx = getDataBroker().newWriteOnlyTransaction(); tx.delete(LogicalDatastoreType.OPERATIONAL, path); - assertCommit(tx.commit()); + assertCommit(tx.submit()); } private void verifyRemoved( diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java index 05bc857969..54493300e3 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java @@ -48,7 +48,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe protected void setupWithDataBroker(final DataBroker dataBroker) { WriteTransaction initialTx = dataBroker.newWriteOnlyTransaction(); initialTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_FOO_KEY))); - assertCommit(initialTx.commit()); + assertCommit(initialTx.submit()); } @Test @@ -60,7 +60,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction(); writeTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY))); - assertCommit(writeTx.commit()); + assertCommit(writeTx.submit()); AsyncDataChangeEvent, DataObject> top = topListener.event(); AsyncDataChangeEvent, DataObject> all = allListener.event(); AsyncDataChangeEvent, DataObject> foo = fooListener.event(); @@ -115,7 +115,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction(); writeTx.merge(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY))); - assertCommit(writeTx.commit()); + assertCommit(writeTx.submit()); verifyBarOnlyAdded(topListener,allListener,fooListener,barListener); } @@ -129,7 +129,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction(); writeTx.put(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY)); - assertCommit(writeTx.commit()); + assertCommit(writeTx.submit()); verifyBarOnlyAdded(topListener,allListener,fooListener,barListener); } @@ -143,7 +143,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction(); writeTx.merge(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY)); - assertCommit(writeTx.commit()); + assertCommit(writeTx.submit()); verifyBarOnlyAdded(topListener,allListener,fooListener,barListener); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java index 43e951423c..b577e2af1f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java @@ -7,14 +7,11 @@ */ package org.opendaylight.controller.md.sal.binding.impl.test; -import static org.junit.Assert.assertEquals; - import java.util.concurrent.ExecutionException; import org.junit.Test; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder; @@ -35,7 +32,7 @@ public class WriteTransactionTest extends AbstractDataBrokerTest { WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); writeTx.put(LogicalDatastoreType.OPERATIONAL, TOP_PATH, new TopBuilder().build()); writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, new TopLevelListBuilder().setKey(TOP_LIST_KEY).build()); - assertEquals(TransactionStatus.COMMITED, writeTx.commit().get().getResult()); + writeTx.submit().get(); } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java index 7f23ac26b6..5789270dee 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java @@ -7,16 +7,12 @@ */ package org.opendaylight.controller.md.sal.binding.test; -import static org.junit.Assert.assertEquals; - import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import com.google.common.util.concurrent.ListenableFuture; @@ -53,9 +49,9 @@ public class AbstractDataBrokerTest extends AbstractSchemaAwareTest { return domBroker; } - protected static final void assertCommit(final ListenableFuture> commit) { + protected static final void assertCommit(final ListenableFuture commit) { try { - assertEquals(TransactionStatus.COMMITED,commit.get(500, TimeUnit.MILLISECONDS).getResult()); + commit.get(500, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { throw new IllegalStateException(e); } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java index f7eae27320..9aaa77ca61 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java @@ -11,6 +11,7 @@ import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.yangtools.concepts.Path; import org.opendaylight.yangtools.yang.common.RpcResult; +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.ListenableFuture; /** @@ -65,7 +66,7 @@ public interface AsyncWriteTransaction

, D> extends AsyncTransa * true otherwise * */ - public boolean cancel(); + boolean cancel(); /** * Store a piece of data at specified path. This acts as an add / replace @@ -97,7 +98,7 @@ public interface AsyncWriteTransaction

, D> extends AsyncTransa * @throws IllegalStateException * if the transaction is no longer {@link TransactionStatus#NEW} */ - public void put(LogicalDatastoreType store, P path, D data); + void put(LogicalDatastoreType store, P path, D data); /** * Store a piece of data at the specified path. This acts as a merge operation, @@ -132,7 +133,7 @@ public interface AsyncWriteTransaction

, D> extends AsyncTransa * @throws IllegalStateException * if the transaction is no longer {@link TransactionStatus#NEW} */ - public void merge(LogicalDatastoreType store, P path, D data); + void merge(LogicalDatastoreType store, P path, D data); /** * Remove a piece of data from specified path. This operation does not fail @@ -145,10 +146,14 @@ public interface AsyncWriteTransaction

, D> extends AsyncTransa * @throws IllegalStateException * if the transaction is no longer {@link TransactionStatus#NEW} */ - public void delete(LogicalDatastoreType store, P path); + void delete(LogicalDatastoreType store, P path); /** - * Submits transaction to be applied to update logical data tree. + * Submits this transaction to be asynchronously applied to update the logical data tree. + * The returned CheckedFuture conveys the result of applying the data changes. + *

+ * Note: It is strongly recommended to process the CheckedFuture result in an asynchronous + * manner rather than using the blocking get() method. See example usage below. *

* This call logically seals the transaction, which prevents the client from * further changing data tree using this transaction. Any subsequent calls to @@ -158,31 +163,65 @@ public interface AsyncWriteTransaction

, D> extends AsyncTransa * {@link IllegalStateException}. * * The transaction is marked as {@link TransactionStatus#SUBMITED} and - * enqueued into the data store backed for processing. + * enqueued into the data store back-end for processing. * *

* Whether or not the commit is successful is determined by versioning - * of data tree and validation of registered commit participants - * {@link AsyncConfigurationCommitHandler} - * if transaction changes {@link LogicalDatastoreType#CONFIGURATION} data tree. - *

- * The effects of successful commit of data depends on - * other data change listeners {@link AsyncDataChangeListener} and - * {@link AsyncConfigurationCommitHandler}, which was registered to the - * same {@link AsyncDataBroker}, to which this transaction belongs. - * + * of the data tree and validation of registered commit participants + * ({@link AsyncConfigurationCommitHandler}) + * if the transaction changes the data tree. + *

+ * The effects of a successful commit of data depends on data change listeners + * ({@link AsyncDataChangeListener}) and commit participants + * ({@link AsyncConfigurationCommitHandler}) that are registered with the data broker. + *

+ *

Example usage:

+ *
+     *  private void doWrite( final int tries ) {
+     *      WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+     *
+     *      MyDataObject data = ...;
+     *      InstanceIdentifier path = ...;
+     *      writeTx.put( LogicalDatastoreType.OPERATIONAL, path, data );
+     *
+     *      Futures.addCallback( writeTx.commit(), new FutureCallback() {
+     *          public void onSuccess( Void result ) {
+     *              // succeeded
+     *          }
+     *
+     *          public void onFailure( Throwable t ) {
+     *              if( t instanceof OptimisticLockFailedException ) {
+     *                  if( ( tries - 1 ) > 0 ) {
+     *                      // do retry
+     *                      doWrite( tries - 1 );
+     *                  } else {
+     *                      // out of retries
+     *                  }
+     *              } else {
+     *                  // failed due to another type of TransactionCommitFailedException.
+     *              }
+     *          } );
+     * }
+     * ...
+     * doWrite( 2 );
+     * 
*

Failure scenarios

*

* Transaction may fail because of multiple reasons, such as *

    - *
  • Another transaction finished earlier and modified the same node in - * non-compatible way (see below). In this case the returned future will fail with + *
  • Another transaction finished earlier and modified the same node in a + * non-compatible way (see below). In this case the returned future will fail with an * {@link OptimisticLockFailedException}. It is the responsibility of the * caller to create a new transaction and submit the same modification again in - * order to update data tree.
  • + * order to update data tree. Warning: In most cases, retrying after an + * OptimisticLockFailedException will result in a high probability of success. + * However, there are scenarios, albeit unusual, where any number of retries will + * not succeed. Therefore it is strongly recommended to limit the number of retries (2 or 3) + * to avoid an endless loop. + * *
  • Data change introduced by this transaction did not pass validation by * commit handlers or data was incorrectly structured. Returned future will - * fail with {@link DataValidationFailedException}. User should not retry to + * fail with a {@link DataValidationFailedException}. User should not retry to * create new transaction with same data, since it probably will fail again. *
  • *
@@ -288,19 +327,21 @@ public interface AsyncWriteTransaction

, D> extends AsyncTransa * with {@link OptimisticLockFailedException} exception, which indicates to * client that concurrent transaction prevented the submitted transaction from being * applied. - * - * @return Result of the Commit, containing success information or list of - * encountered errors, if commit was not successful. The Future - * blocks until {@link TransactionStatus#COMMITED} is reached. - * Future will fail with {@link TransactionCommitFailedException} if - * Commit of this transaction failed. TODO: Usability: Consider - * change from ListenableFuture to - * {@link com.google.common.util.concurrent.CheckedFuture} which - * will throw {@link TransactionCommitFailedException}. + *
+ * @return a CheckFuture containing the result of the commit. The Future blocks until the + * commit operation is complete. A successful commit returns nothing. On failure, + * the Future will fail with a {@link TransactionCommitFailedException} or an exception + * derived from TransactionCommitFailedException. * * @throws IllegalStateException * if the transaction is not {@link TransactionStatus#NEW} */ - public ListenableFuture> commit(); + CheckedFuture submit(); + + /** + * @deprecated Use {@link #submit()} instead. + */ + @Deprecated + ListenableFuture> commit(); } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataValidationFailedException.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataValidationFailedException.java index c59c12ec5c..d48bfc79fe 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataValidationFailedException.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataValidationFailedException.java @@ -8,6 +8,8 @@ package org.opendaylight.controller.md.sal.common.api.data; import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import com.google.common.base.Preconditions; @@ -31,14 +33,17 @@ public class DataValidationFailedException extends TransactionCommitFailedExcept private Class> pathType; - public

> DataValidationFailedException(final Class

pathType,final P path, final String message, final Throwable cause) { - super(message, cause); + public

> DataValidationFailedException(final Class

pathType,final P path, + final String message, final Throwable cause) { + super(message, cause, RpcResultBuilder.newError(ErrorType.APPLICATION, "invalid-value", message, null, + path != null ? path.toString() : null, cause)); this.pathType = Preconditions.checkNotNull(pathType, "path type must not be null"); this.path = Preconditions.checkNotNull(path,"path must not be null."); } - public

> DataValidationFailedException(final Class

pathType,final P path,final String message) { - this(pathType,path,message,null); + public

> DataValidationFailedException(final Class

pathType,final P path, + final String message) { + this(pathType, path, message, null); } public final Path getPath() { diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/OptimisticLockFailedException.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/OptimisticLockFailedException.java index 222289ab6c..5ddec6b1ed 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/OptimisticLockFailedException.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/OptimisticLockFailedException.java @@ -1,5 +1,8 @@ package org.opendaylight.controller.md.sal.common.api.data; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; + /** * * Failure of asynchronous transaction commit caused by failure @@ -18,17 +21,13 @@ public class OptimisticLockFailedException extends TransactionCommitFailedExcept private static final long serialVersionUID = 1L; - protected OptimisticLockFailedException(final String message, final Throwable cause, final boolean enableSuppression, - final boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - public OptimisticLockFailedException(final String message, final Throwable cause) { - super(message, cause); + super(message, cause, RpcResultBuilder.newError(ErrorType.APPLICATION, "resource-denied", + message, null, null, cause)); } public OptimisticLockFailedException(final String message) { - super(message); + this(message, null); } } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java index f3c2e1093c..18a857e1d5 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java @@ -7,6 +7,15 @@ */ package org.opendaylight.controller.md.sal.common.api.data; +import java.util.Arrays; +import java.util.List; + +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; + +import com.google.common.collect.ImmutableList; + /** * * Failed commit of asynchronous transaction @@ -17,18 +26,39 @@ package org.opendaylight.controller.md.sal.common.api.data; */ public class TransactionCommitFailedException extends Exception { - private static final long serialVersionUID = -6138306275373237068L; + private static final long serialVersionUID = 1L; - protected TransactionCommitFailedException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); + private final List errorList; + + public TransactionCommitFailedException(final String message, final RpcError... errors) { + this(message, null, errors); } - public TransactionCommitFailedException(final String message, final Throwable cause) { + public TransactionCommitFailedException(final String message, final Throwable cause, + final RpcError... errors) { super(message, cause); + + if( errors != null && errors.length > 0 ) { + errorList = ImmutableList.builder().addAll( Arrays.asList( errors ) ).build(); + } + else { + // Add a default RpcError. + errorList = ImmutableList.of(RpcResultBuilder.newError(ErrorType.APPLICATION, null, + getMessage(), null, null, getCause())); + } } - public TransactionCommitFailedException(final String message) { - super(message); + /** + * Returns additional error information about this exception. + * + * @return a List of RpcErrors. There is always at least one RpcError. + */ + public List getErrorList() { + return errorList; } + @Override + public String getMessage() { + return new StringBuilder( super.getMessage() ).append(", errors: ").append( errorList ).toString(); + } } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java index b030e6cb5f..d544c4b371 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java @@ -11,13 +11,19 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification; import org.opendaylight.yangtools.concepts.Path; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.AsyncFunction; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; public abstract class AbstractDataTransaction

, D extends Object> extends AbstractDataModification { @@ -83,18 +89,23 @@ public abstract class AbstractDataTransaction

, D extends Objec @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } AbstractDataTransaction other = (AbstractDataTransaction) obj; if (identifier == null) { - if (other.identifier != null) + if (other.identifier != null) { return false; - } else if (!identifier.equals(other.identifier)) + } + } else if (!identifier.equals(other.identifier)) { return false; + } return true; } @@ -122,4 +133,15 @@ public abstract class AbstractDataTransaction

, D extends Objec this.status = status; this.onStatusChange(status); } + + public static ListenableFuture> convertToLegacyCommitFuture( + CheckedFuture from ) { + return Futures.transform(from, new AsyncFunction>() { + @Override + public ListenableFuture> apply(Void input) throws Exception { + return Futures.immediateFuture(RpcResultBuilder. + success(TransactionStatus.COMMITED).build()); + } + } ); + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedTransactionFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedTransactionFactory.java index 5694d0bca9..d354cca005 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedTransactionFactory.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedTransactionFactory.java @@ -114,7 +114,7 @@ public abstract class AbstractDOMForwardedTransactionFactory {@link DOMDataWriteTransaction#commit()} - results in invoking * {@link DOMStoreWriteTransaction#ready()}, gathering all resulting cohorts * and then invoking finalized implementation callback - * {@link #commit(DOMDataWriteTransaction, Iterable)} with transaction which + * {@link #submit(DOMDataWriteTransaction, Iterable)} with transaction which * was commited and gathered results. * * @@ -167,7 +167,7 @@ public abstract class AbstractDOMForwardedTransactionFactory {@link DOMDataWriteTransaction#commit()} - results in invoking * {@link DOMStoreWriteTransaction#ready()}, gathering all resulting cohorts * and then invoking finalized implementation callback - * {@link #commit(DOMDataWriteTransaction, Iterable)} with transaction which + * {@link #submit(DOMDataWriteTransaction, Iterable)} with transaction which * was commited and gathered results. *

  • * diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java index 7e37a1e3a3..7731646a57 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java @@ -12,9 +12,9 @@ import static com.google.common.base.Preconditions.checkState; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicLong; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; @@ -23,14 +23,13 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStore; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.ListeningExecutorService; public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory implements DOMDataBroker, @@ -78,7 +77,7 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory> commit(final DOMDataWriteTransaction transaction, + public CheckedFuture submit(final DOMDataWriteTransaction transaction, final Iterable cohorts) { LOG.debug("Transaction: {} submitted with cohorts {}.", transaction.getIdentifier(), cohorts); return coordinator.submit(transaction, cohorts, Optional. absent()); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java index b9f096aafc..227693ca4d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java @@ -10,21 +10,20 @@ import java.util.concurrent.atomic.AtomicLong; import javax.annotation.concurrent.GuardedBy; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; /** * NormalizedNode implementation of {@link org.opendaylight.controller.md.sal.common.api.data.TransactionChain} which is backed @@ -73,7 +72,7 @@ public class DOMDataBrokerTransactionChainImpl extends AbstractDOMForwardedTrans } @Override - public synchronized ListenableFuture> commit( + public synchronized CheckedFuture submit( final DOMDataWriteTransaction transaction, final Iterable cohorts) { return coordinator.submit(transaction, cohorts, Optional. of(this)); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java index 13a0093d34..8b9eb445fd 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java @@ -12,12 +12,9 @@ import java.util.concurrent.ExecutionException; import javax.annotation.concurrent.GuardedBy; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,18 +79,19 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { } @Override - public ListenableFuture> submit(final DOMDataWriteTransaction transaction, + public CheckedFuture submit(final DOMDataWriteTransaction transaction, final Iterable cohorts, final Optional listener) { Preconditions.checkArgument(transaction != null, "Transaction must not be null."); Preconditions.checkArgument(cohorts != null, "Cohorts must not be null."); Preconditions.checkArgument(listener != null, "Listener must not be null"); LOG.debug("Tx: {} is submitted for execution.", transaction.getIdentifier()); - ListenableFuture> commitFuture = executor.submit(new CommitCoordinationTask( + ListenableFuture commitFuture = executor.submit(new CommitCoordinationTask( transaction, cohorts, listener)); if (listener.isPresent()) { Futures.addCallback(commitFuture, new DOMDataCommitErrorInvoker(transaction, listener.get())); } - return commitFuture; + + return Futures.makeChecked(commitFuture, TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER); } /** @@ -139,7 +137,7 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { * support of cancelation. * */ - private static class CommitCoordinationTask implements Callable> { + private static class CommitCoordinationTask implements Callable { private final DOMDataWriteTransaction tx; private final Iterable cohorts; @@ -156,12 +154,13 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { } @Override - public RpcResult call() throws TransactionCommitFailedException { + public Void call() throws TransactionCommitFailedException { try { canCommitBlocking(); preCommitBlocking(); - return commitBlocking(); + commitBlocking(); + return null; } catch (TransactionCommitFailedException e) { LOG.warn("Tx: {} Error during phase {}, starting Abort", tx.getIdentifier(), currentPhase, e); abortBlocking(e); @@ -217,9 +216,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { * If one of cohorts failed preCommit * */ - private RpcResult commitBlocking() throws TransactionCommitFailedException { + private void commitBlocking() throws TransactionCommitFailedException { commitAll().checkedGet(); - return RpcResultBuilder.success(TransactionStatus.COMMITED).build(); } /** diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java index 811d4d8839..5ce9241dd2 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java @@ -6,10 +6,7 @@ */ package org.opendaylight.controller.md.sal.dom.broker.impl; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.common.RpcResult; - import com.google.common.base.Preconditions; import com.google.common.util.concurrent.FutureCallback; @@ -22,7 +19,7 @@ import com.google.common.util.concurrent.FutureCallback; * callback is invoked with associated transaction and throwable is invoked on listener. * */ -class DOMDataCommitErrorInvoker implements FutureCallback> { +class DOMDataCommitErrorInvoker implements FutureCallback { private final DOMDataWriteTransaction tx; private final DOMDataCommitErrorListener listener; @@ -46,7 +43,7 @@ class DOMDataCommitErrorInvoker implements FutureCallback result) { + public void onSuccess(Void result) { // NOOP } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java index 2050d148a8..234758ca75 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java @@ -7,13 +7,11 @@ */ package org.opendaylight.controller.md.sal.dom.broker.impl; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; -import org.opendaylight.yangtools.yang.common.RpcResult; - import com.google.common.base.Optional; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; /** * Executor of Three Phase Commit coordination for @@ -40,12 +38,12 @@ interface DOMDataCommitExecutor { * subtransactoins. * @param listener * Error listener which should be notified if transaction failed. - * @return ListenableFuture which contains RpcResult with - * {@link TransactionStatus#COMMITED} if commit coordination on - * cohorts finished successfully. + * @return a CheckedFuture. if commit coordination on cohorts finished successfully, + * nothing is returned from the Future, On failure, + * the Future fails with a {@link TransactionCommitFailedException}. * */ - ListenableFuture> submit(DOMDataWriteTransaction tx, + CheckedFuture submit(DOMDataWriteTransaction tx, Iterable cohort, Optional listener); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitImplementation.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitImplementation.java index 4906b6e84d..2f2b6e508a 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitImplementation.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitImplementation.java @@ -7,12 +7,10 @@ */ package org.opendaylight.controller.md.sal.dom.broker.impl; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; -import org.opendaylight.yangtools.yang.common.RpcResult; - -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; /** * @@ -23,10 +21,10 @@ import com.google.common.util.concurrent.ListenableFuture; public interface DOMDataCommitImplementation { /** - * User-supplied implementation of {@link DOMDataWriteTransaction#commit()} + * User-supplied implementation of {@link DOMDataWriteTransaction#submit()} * for transaction. * - * Callback invoked when {@link DOMDataWriteTransaction#commit()} is invoked + * Callback invoked when {@link DOMDataWriteTransaction#submit()} is invoked * on transaction created by this factory. * * @param transaction @@ -37,7 +35,7 @@ public interface DOMDataCommitImplementation { * commited transaction. * */ - ListenableFuture> commit(final DOMDataWriteTransaction transaction, + CheckedFuture submit(final DOMDataWriteTransaction transaction, final Iterable cohorts); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java index f5b96e27f5..e1d27e453b 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java @@ -29,7 +29,7 @@ import com.google.common.util.concurrent.ListenableFuture; *
  • {@link #merge(LogicalDatastoreType, InstanceIdentifier, NormalizedNode)} * * {@link #commit()} will result in invocation of - * {@link DOMDataCommitImplementation#commit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)} + * {@link DOMDataCommitImplementation#submit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)} * invocation with all {@link org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort} for underlying * transactions. * diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedWriteTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedWriteTransaction.java index f791522a2a..5bddd763fb 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedWriteTransaction.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedWriteTransaction.java @@ -13,6 +13,8 @@ import javax.annotation.concurrent.GuardedBy; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; @@ -23,6 +25,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.ListenableFuture; /** @@ -39,7 +42,7 @@ import com.google.common.util.concurrent.ListenableFuture; * *

    * {@link #commit()} will result in invocation of - * {@link DOMDataCommitImplementation#commit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)} + * {@link DOMDataCommitImplementation#submit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)} * invocation with all {@link org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort} for underlying * transactions. * @@ -74,7 +77,7 @@ class DOMForwardedWriteTransaction extends * */ @GuardedBy("this") - private volatile ListenableFuture> commitFuture; + private volatile CheckedFuture commitFuture; protected DOMForwardedWriteTransaction(final Object identifier, final ImmutableMap backingTxs, final DOMDataCommitImplementation commitImpl) { @@ -119,6 +122,11 @@ class DOMForwardedWriteTransaction extends @Override public synchronized ListenableFuture> commit() { + return AbstractDataTransaction.convertToLegacyCommitFuture(submit()); + } + + @Override + public CheckedFuture submit() { checkNotReady(); ImmutableList.Builder cohortsBuilder = ImmutableList.builder(); @@ -126,7 +134,7 @@ class DOMForwardedWriteTransaction extends cohortsBuilder.add(subTx.ready()); } ImmutableList cohorts = cohortsBuilder.build(); - commitFuture = commitImpl.commit(this, cohorts); + commitFuture = commitImpl.submit(this, cohorts); /* *We remove reference to Commit Implementation in order @@ -148,5 +156,4 @@ class DOMForwardedWriteTransaction extends private void checkNotCommited() { checkState(commitFuture == null, "Transaction was already submited."); } - } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleTransaction.java index 27e322f23b..f57579858c 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleTransaction.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleTransaction.java @@ -21,6 +21,7 @@ import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; @@ -204,7 +205,7 @@ DataModificationTransaction, Delegator { public Future> commit() { Preconditions.checkState(status == TransactionStatus.NEW); status = TransactionStatus.SUBMITED; - return getDelegate().commit(); + return AbstractDataTransaction.convertToLegacyCommitFuture(getDelegate().submit()); } @Override diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerPerformanceTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerPerformanceTest.java index 29e078918e..2dec6f2e4d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerPerformanceTest.java +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerPerformanceTest.java @@ -169,7 +169,7 @@ public class DOMBrokerPerformanceTest { public List> call() throws Exception { List> builder = new ArrayList<>(txNum); for (DOMDataReadWriteTransaction tx :transactions) { - builder.add(tx.commit()); + builder.add(tx.submit()); } return builder; } @@ -267,7 +267,7 @@ public class DOMBrokerPerformanceTest { measure("Txs:1 Submit", new Callable>() { @Override public ListenableFuture call() throws Exception { - return writeTx.commit(); + return writeTx.submit(); } }).get(); return null; diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java index fec73d665b..b006ca94e5 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java @@ -107,7 +107,7 @@ public class DOMBrokerTest { TestModel.TEST_PATH); assertTrue(writeTxContainer.get().isPresent()); - writeTx.commit().get(); + writeTx.submit().get(); Optional> afterCommitRead = domBroker.newReadOnlyTransaction() .read(OPERATIONAL, TestModel.TEST_PATH).get(); diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMTransactionChainTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMTransactionChainTest.java index 38f08b30f9..3ea0bcefa5 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMTransactionChainTest.java +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMTransactionChainTest.java @@ -7,7 +7,6 @@ */ package org.opendaylight.controller.md.sal.dom.broker.impl; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -21,7 +20,6 @@ import java.util.concurrent.TimeoutException; import org.junit.Before; import org.junit.Test; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; @@ -29,7 +27,6 @@ import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; import org.opendaylight.controller.md.sal.dom.store.impl.TestModel; import org.opendaylight.controller.sal.core.spi.data.DOMStore; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -80,7 +77,7 @@ public class DOMTransactionChainTest { * First transaction is marked as ready, we are able to allocate chained * transactions */ - ListenableFuture> firstWriteTxFuture = firstTx.commit(); + ListenableFuture firstWriteTxFuture = firstTx.submit(); /** * We alocate chained transaction - read transaction. @@ -126,7 +123,7 @@ public class DOMTransactionChainTest { /** * third transaction is sealed and commited */ - ListenableFuture> thirdDeleteTxFuture = thirdDeleteTx.commit(); + ListenableFuture thirdDeleteTxFuture = thirdDeleteTx.submit(); assertCommitSuccessful(thirdDeleteTxFuture); /** @@ -188,11 +185,9 @@ public class DOMTransactionChainTest { return tx; } - private static void assertCommitSuccessful(final ListenableFuture> future) + private static void assertCommitSuccessful(final ListenableFuture future) throws InterruptedException, ExecutionException { - RpcResult rpcResult = future.get(); - assertTrue(rpcResult.isSuccessful()); - assertEquals(TransactionStatus.COMMITED, rpcResult.getResult()); + future.get(); } private static void assertTestContainerExists(final DOMDataReadTransaction readTx) throws InterruptedException, diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java index ea2ddc9b65..b7518e094d 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java @@ -20,10 +20,10 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; 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.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; 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.TransactionCommitFailedException; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.DisplayString; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInput; @@ -100,12 +100,11 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti executor.shutdown(); if (dataProvider != null) { - WriteTransaction t = dataProvider.newWriteOnlyTransaction(); - t.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID); - ListenableFuture> future = t.commit(); - Futures.addCallback( future, new FutureCallback>() { + WriteTransaction tx = dataProvider.newWriteOnlyTransaction(); + tx.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID); + Futures.addCallback( tx.submit(), new FutureCallback() { @Override - public void onSuccess( final RpcResult result ) { + public void onSuccess( final Void result ) { LOG.debug( "Delete Toaster commit result: " + result ); } @@ -170,7 +169,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti final SettableFuture> futureResult = SettableFuture.create(); - checkStatusAndMakeToast( input, futureResult ); + checkStatusAndMakeToast( input, futureResult, 2 ); return futureResult; } @@ -186,7 +185,8 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti } private void checkStatusAndMakeToast( final MakeToastInput input, - final SettableFuture> futureResult ) { + final SettableFuture> futureResult, + final int tries ) { // Read the ToasterStatus and, if currently Up, try to write the status to Down. // If that succeeds, then we essentially have an exclusive lock and can proceed @@ -196,12 +196,11 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti ListenableFuture> readFuture = tx.read( LogicalDatastoreType.OPERATIONAL, TOASTER_IID ); - final ListenableFuture> commitFuture = - Futures.transform( readFuture, new AsyncFunction, - RpcResult>() { + final ListenableFuture commitFuture = + Futures.transform( readFuture, new AsyncFunction,Void>() { @Override - public ListenableFuture> apply( + public ListenableFuture apply( final Optional toasterData ) throws Exception { ToasterStatus toasterStatus = ToasterStatus.Up; @@ -216,8 +215,8 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti if( outOfBread() ) { LOG.debug( "Toaster is out of bread" ); - return Futures.immediateFuture( RpcResultBuilder.failed() - .withRpcError( makeToasterOutOfBreadError() ).build() ); + return Futures.immediateFailedCheckedFuture( + new TransactionCommitFailedException( "", makeToasterOutOfBreadError() ) ); } LOG.debug( "Setting Toaster status to Down" ); @@ -227,7 +226,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti // concurrent toasting. tx.put( LogicalDatastoreType.OPERATIONAL, TOASTER_IID, buildToaster( ToasterStatus.Down ) ); - return tx.commit(); + return tx.submit(); } LOG.debug( "Oops - already making toast!" ); @@ -235,30 +234,16 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti // Return an error since we are already making toast. This will get // propagated to the commitFuture below which will interpret the null // TransactionStatus in the RpcResult as an error condition. - return Futures.immediateFuture( RpcResultBuilder.failed() - .withRpcError( makeToasterInUseError() ).build() ); + return Futures.immediateFailedCheckedFuture( + new TransactionCommitFailedException( "", makeToasterInUseError() ) ); } } ); - Futures.addCallback( commitFuture, new FutureCallback>() { + Futures.addCallback( commitFuture, new FutureCallback() { @Override - public void onSuccess( final RpcResult result ) { - if( result.getResult() == TransactionStatus.COMMITED ) { - - // OK to make toast - currentMakeToastTask.set( executor.submit( - new MakeToastTask( input, futureResult ) ) ); - } else { - - LOG.debug( "Setting error result" ); - - // Either the transaction failed to commit for some reason or, more likely, - // the read above returned ToasterStatus.Down. Either way, fail the - // futureResult and copy the errors. - - futureResult.set( RpcResultBuilder.failed().withRpcErrors( - result.getErrors() ).build() ); - } + public void onSuccess( final Void result ) { + // OK to make toast + currentMakeToastTask.set( executor.submit( new MakeToastTask( input, futureResult ) ) ); } @Override @@ -269,17 +254,24 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti // status before us. Try reading the status again - if another make toast is // now in progress, we should get ToasterStatus.Down and fail. - LOG.debug( "Got OptimisticLockFailedException - trying again" ); + if( ( tries - 1 ) > 0 ) { + LOG.debug( "Got OptimisticLockFailedException - trying again" ); - checkStatusAndMakeToast( input, futureResult ); + checkStatusAndMakeToast( input, futureResult, tries - 1 ); + } + else { + futureResult.set( RpcResultBuilder. failed() + .withError( ErrorType.APPLICATION, ex.getMessage() ).build() ); + } } else { - LOG.error( "Failed to commit Toaster status", ex ); + LOG.debug( "Failed to commit Toaster status", ex ); - // Got some unexpected error so fail. + // Probably already making toast. futureResult.set( RpcResultBuilder. failed() - .withError( ErrorType.APPLICATION, ex.getMessage() ).build() ); + .withRpcErrors( ((TransactionCommitFailedException)ex).getErrorList() ) + .build() ); } } } ); @@ -327,16 +319,10 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti WriteTransaction tx = dataProvider.newWriteOnlyTransaction(); tx.put( LogicalDatastoreType.OPERATIONAL,TOASTER_IID, buildToaster( ToasterStatus.Up ) ); - ListenableFuture> commitFuture = tx.commit(); - - Futures.addCallback( commitFuture, new FutureCallback>() { + Futures.addCallback( tx.submit(), new FutureCallback() { @Override - public void onSuccess( final RpcResult result ) { - if( result.getResult() != TransactionStatus.COMMITED ) { - LOG.error( "Failed to update toaster status: " + result.getErrors() ); - } - - notifyCallback( result.getResult() == TransactionStatus.COMMITED ); + public void onSuccess( final Void result ) { + notifyCallback( true ); } @Override