Class RetryingManagedNewTransactionRunner

  • All Implemented Interfaces:
    ManagedNewTransactionRunner, ManagedTransactionFactory

    @Beta
    public class RetryingManagedNewTransactionRunner
    extends java.lang.Object
    Implementation of ManagedNewTransactionRunner with automatic transparent retries on transaction failure (OptimisticLockFailedException on write transactions and ReadFailedException on read transactions will cause the operation constructing the transaction to be re-run).

    Details about the threading model used by this class

    This class runs the first attempt to call the delegated ManagedNewTransactionRunner, which typically is a ManagedNewTransactionRunnerImpl which safely invokes AsyncWriteTransaction.submit(), in the using application's thread (like a MoreExecutors.directExecutor() would, if this were an Executor, which it's not).

    Any retry attempts required, if that submit() (eventually) fails with an OptimisticLockFailedException, are run in the calling thread of that eventual future completion by a MoreExecutors.directExecutor() implicit in the constructor which does not require you to specify an explicit Executor argument. Normally that will be an internal thread from the respective DataBroker implementation, not your application's thread anymore, because that meanwhile could well be off doing something else! Normally, that is not a problem, because retries "should" be relatively uncommon, and (re)issuing some DataBroker put() or delete() and re-submit() should be fast.

    If this default is not suitable (e.g. for particularly slow try/retry code), then you can specify another Executor to be used for the retries by using the alternative constructor.

    Author:
    Michael Vorburger.ch & Stephen Kitt
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      <D extends Datastore,​E extends java.lang.Exception,​R>
      R
      applyWithNewReadOnlyTransactionAndClose​(java.lang.Class<D> datastoreType, org.opendaylight.infrautils.utils.function.InterruptibleCheckedFunction<TypedReadTransaction<D>,​R,​E> txFunction)
      Invokes a function with a NEW TypedReadTransaction, and ensures that that transaction is closed.
      <D extends Datastore,​E extends java.lang.Exception,​R>
      com.google.common.util.concurrent.FluentFuture<R>
      applyWithNewReadWriteTransactionAndSubmit​(java.lang.Class<D> datastoreType, org.opendaylight.infrautils.utils.function.InterruptibleCheckedFunction<TypedReadWriteTransaction<D>,​R,​E> txFunction)
      Invokes a function with a NEW ReadWriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception.
      <R> R applyWithNewTransactionChainAndClose​(java.util.function.Function<ManagedTransactionChain,​R> chainConsumer)
      Invokes a function with a new ManagedTransactionChain, which is a wrapper around standard transaction chains providing managed semantics.
      <D extends Datastore,​E extends java.lang.Exception>
      void
      callWithNewReadOnlyTransactionAndClose​(java.lang.Class<D> datastoreType, org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<TypedReadTransaction<D>,​E> txConsumer)
      Invokes a function with a NEW ReadTransaction, and ensures that that transaction is closed.
      <D extends Datastore,​E extends java.lang.Exception>
      com.google.common.util.concurrent.FluentFuture<java.lang.Void>
      callWithNewReadWriteTransactionAndSubmit​(java.lang.Class<D> datastoreType, org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<TypedReadWriteTransaction<D>,​E> txConsumer)
      Invokes a consumer with a NEW ReadWriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception.
      <E extends java.lang.Exception>
      com.google.common.util.concurrent.ListenableFuture<java.lang.Void>
      callWithNewReadWriteTransactionAndSubmit​(org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction,​E> txConsumer)
      Invokes a consumer with a NEW ReadWriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception.
      <D extends Datastore,​E extends java.lang.Exception>
      com.google.common.util.concurrent.FluentFuture<java.lang.Void>
      callWithNewWriteOnlyTransactionAndSubmit​(java.lang.Class<D> datastoreType, org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<TypedWriteTransaction<D>,​E> txConsumer)
      Invokes a consumer with a NEW WriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception.
      <E extends java.lang.Exception>
      com.google.common.util.concurrent.ListenableFuture<java.lang.Void>
      callWithNewWriteOnlyTransactionAndSubmit​(org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<org.opendaylight.controller.md.sal.binding.api.WriteTransaction,​E> txConsumer)
      Invokes a consumer with a NEW WriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Constructor Detail

      • RetryingManagedNewTransactionRunner

        @Inject
        public RetryingManagedNewTransactionRunner​(org.opendaylight.controller.md.sal.binding.api.DataBroker dataBroker)
        Constructor. Please see the class level documentation above for more details about the threading model used. This uses the default of 3 retries, which is typically suitable.
        Parameters:
        dataBroker - the DataBroker from which transactions are obtained
      • RetryingManagedNewTransactionRunner

        public RetryingManagedNewTransactionRunner​(org.opendaylight.controller.md.sal.binding.api.DataBroker dataBroker,
                                                   int maxRetries)
        Constructor. Please see the class level documentation above for more details about the threading model used.
        Parameters:
        dataBroker - the DataBroker from which transactions are obtained
        maxRetries - the maximum number of retry attempts
      • RetryingManagedNewTransactionRunner

        public RetryingManagedNewTransactionRunner​(org.opendaylight.controller.md.sal.binding.api.DataBroker dataBroker,
                                                   java.util.concurrent.Executor executor,
                                                   int maxRetries)
        Constructor. Please see the class level documentation above for more details about the threading model used.
        Parameters:
        dataBroker - the DataBroker from which transactions are obtained
        executor - the Executor to asynchronously run any retry attempts in
        maxRetries - the maximum number of retry attempts
    • Method Detail

      • applyWithNewReadOnlyTransactionAndClose

        public <D extends Datastore,​E extends java.lang.Exception,​R> R applyWithNewReadOnlyTransactionAndClose​(java.lang.Class<D> datastoreType,
                                                                                                                           org.opendaylight.infrautils.utils.function.InterruptibleCheckedFunction<TypedReadTransaction<D>,​R,​E> txFunction)
                                                                                                                    throws E extends java.lang.Exception,
                                                                                                                           java.lang.InterruptedException
        Description copied from interface: ManagedTransactionFactory
        Invokes a function with a NEW TypedReadTransaction, and ensures that that transaction is closed. Thus when this method returns, that transaction is guaranteed to have been closed, and will never "leak" and waste memory.

        The function must not itself attempt to close the transaction. (It can't directly, since TypedReadTransaction doesn't expose a close() method.)

        The provided transaction is specific to the given logical datastore type and cannot be used for any other.

        Specified by:
        applyWithNewReadOnlyTransactionAndClose in interface ManagedTransactionFactory
        Parameters:
        datastoreType - the Datastore type that will be accessed
        txFunction - the InterruptibleCheckedFunction that needs a new read transaction
        Returns:
        the result of the function.
        Throws:
        E - if an error occurs.
        java.lang.InterruptedException - if the transaction is interrupted.
        E extends java.lang.Exception
      • applyWithNewReadWriteTransactionAndSubmit

        public <D extends Datastore,​E extends java.lang.Exception,​R> com.google.common.util.concurrent.FluentFuture<R> applyWithNewReadWriteTransactionAndSubmit​(java.lang.Class<D> datastoreType,
                                                                                                                                                                             org.opendaylight.infrautils.utils.function.InterruptibleCheckedFunction<TypedReadWriteTransaction<D>,​R,​E> txFunction)
        Description copied from interface: ManagedTransactionFactory
        Invokes a function with a NEW ReadWriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception. Thus when this method returns, that transaction is guaranteed to have been either submitted or cancelled, and will never "leak" and waste memory.

        The function must not itself use AsyncWriteTransaction.cancel(), or AsyncWriteTransaction.submit() (it will throw an UnsupportedOperationException).

        The provided transaction is specific to the given logical datastore type and cannot be used for any other.

        This is an asynchronous API, like DataBroker's own; when returning from this method, the operation of the Transaction may well still be ongoing in the background, or pending; calling code therefore must handle the returned future, e.g. by passing it onwards (return), or by itself adding callback listeners to it using Futures' methods, or by transforming it into a CompletionStage using ListenableFutures.toCompletionStage(ListenableFuture) and chaining on that, or at the very least simply by using ListenableFutures.addErrorLogging(ListenableFuture, org.slf4j.Logger, String) (but better NOT by using the blocking Future.get() on it).

        Specified by:
        applyWithNewReadWriteTransactionAndSubmit in interface ManagedTransactionFactory
        Parameters:
        datastoreType - the Datastore type that will be accessed
        txFunction - the InterruptibleCheckedFunction that needs a new read-write transaction
        Returns:
        the ListenableFuture returned by AsyncWriteTransaction.submit(), or a failed future with an application specific exception (not from submit())
      • applyWithNewTransactionChainAndClose

        public <R> R applyWithNewTransactionChainAndClose​(java.util.function.Function<ManagedTransactionChain,​R> chainConsumer)
        Description copied from interface: ManagedNewTransactionRunner
        Invokes a function with a new ManagedTransactionChain, which is a wrapper around standard transaction chains providing managed semantics. The transaction chain will be closed when the function returns.

        This is an asynchronous API, like DataBroker's own; when this method returns, the transactions in the chain may well still be ongoing in the background, or pending. It is up to the consumer and caller to agree on how failure will be handled; for example, the return type can include the futures corresponding to the transactions in the chain. The implementation uses a default transaction chain listener which logs an error if any of the transactions fail.

        The MD-SAL transaction chain semantics are preserved: each transaction in the chain will see the results of the previous transactions in the chain, even if they haven't been fully committed yet; and any error will result in subsequent transactions in the chain not being submitted.

        Specified by:
        applyWithNewTransactionChainAndClose in interface ManagedNewTransactionRunner
        Type Parameters:
        R - The type of result returned by the function.
        Parameters:
        chainConsumer - The InterruptibleCheckedFunction that will build transactions in the transaction chain.
        Returns:
        The result of the function call.
      • callWithNewReadOnlyTransactionAndClose

        public <D extends Datastore,​E extends java.lang.Exception> void callWithNewReadOnlyTransactionAndClose​(java.lang.Class<D> datastoreType,
                                                                                                                     org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<TypedReadTransaction<D>,​E> txConsumer)
                                                                                                              throws E extends java.lang.Exception,
                                                                                                                     java.lang.InterruptedException
        Description copied from interface: ManagedTransactionFactory
        Invokes a function with a NEW ReadTransaction, and ensures that that transaction is closed. Thus when this method returns, that transaction is guaranteed to have been closed, and will never "leak" and waste memory.

        The function must not itself attempt to close the transaction. (It can't directly, since ReadTransaction doesn't expose a close() method.)

        The provided transaction is specific to the given logical datastore type and cannot be used for any other.

        Specified by:
        callWithNewReadOnlyTransactionAndClose in interface ManagedTransactionFactory
        Parameters:
        datastoreType - the Datastore type that will be accessed
        txConsumer - the InterruptibleCheckedFunction that needs a new read transaction
        Throws:
        E - if an error occurs.
        java.lang.InterruptedException - if the transaction is interrupted.
        E extends java.lang.Exception
      • callWithNewReadWriteTransactionAndSubmit

        public <E extends java.lang.Exception> com.google.common.util.concurrent.ListenableFuture<java.lang.Void> callWithNewReadWriteTransactionAndSubmit​(org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction,​E> txConsumer)
        Description copied from interface: ManagedNewTransactionRunner
        Invokes a consumer with a NEW ReadWriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception. Thus when this method returns, that transaction is guaranteed to have been either submitted or cancelled, and will never "leak" and waste memory.

        The consumer should not (cannot) itself use AsyncWriteTransaction.cancel(), or AsyncWriteTransaction.submit() (it will throw an UnsupportedOperationException).

        This is an asynchronous API, like DataBroker's own; when returning from this method, the operation of the Transaction may well still be ongoing in the background, or pending; calling code therefore must handle the returned future, e.g. by passing it onwards (return), or by itself adding callback listeners to it using Futures' methods, or by transforming it into a CompletionStage using ListenableFutures.toCompletionStage(ListenableFuture) and chaining on that, or at the very least simply by using ListenableFutures.addErrorLogging(ListenableFuture, org.slf4j.Logger, String) (but better NOT by using the blocking Future.get() on it).

        Specified by:
        callWithNewReadWriteTransactionAndSubmit in interface ManagedNewTransactionRunner
        Parameters:
        txConsumer - the CheckedConsumer that needs a new read-write transaction
        Returns:
        the ListenableFuture returned by AsyncWriteTransaction.submit(), or a failed future with an application specific exception (not from submit())
      • callWithNewReadWriteTransactionAndSubmit

        public <D extends Datastore,​E extends java.lang.Exception> com.google.common.util.concurrent.FluentFuture<java.lang.Void> callWithNewReadWriteTransactionAndSubmit​(java.lang.Class<D> datastoreType,
                                                                                                                                                                                 org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<TypedReadWriteTransaction<D>,​E> txConsumer)
        Description copied from interface: ManagedTransactionFactory
        Invokes a consumer with a NEW ReadWriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception. Thus when this method returns, that transaction is guaranteed to have been either submitted or cancelled, and will never "leak" and waste memory.

        The consumer should not (cannot) itself use AsyncWriteTransaction.cancel(), or AsyncWriteTransaction.submit() (it will throw an UnsupportedOperationException).

        The provided transaction is specific to the given logical datastore type and cannot be used for any other.

        This is an asynchronous API, like DataBroker's own; when returning from this method, the operation of the Transaction may well still be ongoing in the background, or pending; calling code therefore must handle the returned future, e.g. by passing it onwards (return), or by itself adding callback listeners to it using Futures' methods, or by transforming it into a CompletionStage using ListenableFutures.toCompletionStage(ListenableFuture) and chaining on that, or at the very least simply by using ListenableFutures.addErrorLogging(ListenableFuture, org.slf4j.Logger, String) (but better NOT by using the blocking Future.get() on it).

        Specified by:
        callWithNewReadWriteTransactionAndSubmit in interface ManagedTransactionFactory
        Parameters:
        datastoreType - the Datastore type that will be accessed
        txConsumer - the InterruptibleCheckedConsumer that needs a new read-write transaction
        Returns:
        the ListenableFuture returned by AsyncWriteTransaction.submit(), or a failed future with an application specific exception (not from submit())
      • callWithNewWriteOnlyTransactionAndSubmit

        public <E extends java.lang.Exception> com.google.common.util.concurrent.ListenableFuture<java.lang.Void> callWithNewWriteOnlyTransactionAndSubmit​(org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<org.opendaylight.controller.md.sal.binding.api.WriteTransaction,​E> txConsumer)
        Description copied from interface: ManagedNewTransactionRunner
        Invokes a consumer with a NEW WriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception. Thus when this method returns, that transaction is guaranteed to have been either submitted or cancelled, and will never "leak" and waste memory.

        The consumer should not (cannot) itself use AsyncWriteTransaction.cancel(), or AsyncWriteTransaction.submit() (it will throw an UnsupportedOperationException).

        This is an asynchronous API, like DataBroker's own; when returning from this method, the operation of the Transaction may well still be ongoing in the background, or pending; calling code therefore must handle the returned future, e.g. by passing it onwards (return), or by itself adding callback listeners to it using Futures' methods, or by transforming it into a CompletionStage using ListenableFutures.toCompletionStage(ListenableFuture) and chaining on that, or at the very least simply by using ListenableFutures.addErrorLogging(ListenableFuture, org.slf4j.Logger, String) (but better NOT by using the blocking Future.get() on it).

        Specified by:
        callWithNewWriteOnlyTransactionAndSubmit in interface ManagedNewTransactionRunner
        Parameters:
        txConsumer - the CheckedConsumer that needs a new write only transaction
        Returns:
        the ListenableFuture returned by AsyncWriteTransaction.submit(), or a failed future with an application specific exception (not from submit())
      • callWithNewWriteOnlyTransactionAndSubmit

        public <D extends Datastore,​E extends java.lang.Exception> com.google.common.util.concurrent.FluentFuture<java.lang.Void> callWithNewWriteOnlyTransactionAndSubmit​(java.lang.Class<D> datastoreType,
                                                                                                                                                                                 org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer<TypedWriteTransaction<D>,​E> txConsumer)
        Description copied from interface: ManagedTransactionFactory
        Invokes a consumer with a NEW WriteTransaction, and then submits that transaction and returns the Future from that submission, or cancels it if an exception was thrown and returns a failed future with that exception. Thus when this method returns, that transaction is guaranteed to have been either submitted or cancelled, and will never "leak" and waste memory.

        The consumer should not (cannot) itself use AsyncWriteTransaction.cancel(), or AsyncWriteTransaction.submit() (it will throw an UnsupportedOperationException).

        The provided transaction is specific to the given logical datastore type and cannot be used for any other.

        This is an asynchronous API, like DataBroker's own; when returning from this method, the operation of the Transaction may well still be ongoing in the background, or pending; calling code therefore must handle the returned future, e.g. by passing it onwards (return), or by itself adding callback listeners to it using Futures' methods, or by transforming it into a CompletionStage using ListenableFutures.toCompletionStage(ListenableFuture) and chaining on that, or at the very least simply by using ListenableFutures.addErrorLogging(ListenableFuture, org.slf4j.Logger, String) (but better NOT by using the blocking Future.get() on it).

        Specified by:
        callWithNewWriteOnlyTransactionAndSubmit in interface ManagedTransactionFactory
        Parameters:
        datastoreType - the Datastore type that will be accessed
        txConsumer - the InterruptibleCheckedConsumer that needs a new write only transaction
        Returns:
        the ListenableFuture returned by AsyncWriteTransaction.submit(), or a failed future with an application specific exception (not from submit())