Interface TxnExecutor

All Superinterfaces:
MultiverseConstants
All Known Subinterfaces:
GammaTxnExecutor
All Known Implementing Classes:
AbstractGammaTxnExecutor, FatGammaTxnExecutor, LeanGammaTxnExecutor

public interface TxnExecutor extends MultiverseConstants
An TxnExecutor is responsible for executing an atomic callable. It is created by the TxnFactoryBuilder and this gives the Stm the opportunity to return different implementations based on the TxnFactory configuration. And it also gives the opportunity to provide Stm specific transaction handling mechanism. In the Multiverse 0.6 design and before, a single TransactionTemplate implementation was used that should be used by all Stm's, but that design is limiting.

Another useful features of this design is that for certain primitives it doesn't require any form of boxing. It also provides an execute for a transactional Callables which doesn't force a developer to return something when nothing needs to be returned.

Transactional Callables

The TxnCallable is the functionality that needs to be executed isolated, consistent and atomically. There are different tastes of TxnCallables but essentially the only difference is the return type. There are primitive closures that prevent unwanted autoboxing and there also is a TxnVoidCallable that prevents returning a value if none is needed. And last but not least there also is the general purpose TxnCallable that returns an Object reference.

Automatic retries

If a transaction encounters a ReadWriteConflict or a { @link org.multiverse.api.exceptions.SpeculativeConfigurationError} it will automatically retry the the TxnCallable until either the next execution completes or the maximum number of retries has been reached. To prevent contention, also a BackoffPolicy is used, to prevent transactions from causing more contention if there already is contention. For configuring the maximum number of retries, see the TxnFactoryBuilder.setMaxRetries(int) and for configuring the BackoffPolicy, see TxnFactoryBuilder.setBackoffPolicy(org.multiverse.api.BackoffPolicy).

It is very important to realize that automatically retrying a transaction on a conflict is something else than the Txn.retry(). The latter is really a blocking operation that only retries when there is a reason to retry.

Configuration

The TxnExecutor can be configured through the TxnFactoryBuilder. So see that for more details since there are tons of settings to choose from.

Thread-safety

TxnExecutors are threadsafe. The TxnExecutor is designed to be shared between threads.

Reuse

TxnExecutor can be expensive to create and should be reused. Creating an TxnExecutor can lead to a lot of objects being created and not reusing them leads to a lot of object waste (so put a lot of pressure on the garbage collector).

It is best to create the TxnExecutor in the beginning and store it in a (static) field and reuse it. It is very unlikely that an TxnExecutor is going to be a contention point itself since in almost all cases only volatile reads are required and for the rest it will be mostly immutable.

This is even more important when speculative transactions are used because speculative transactions learn on the TxnExecutor level. So if the TxnExecutor is not reused, the speculative mechanism will not have full effect.

execute vs executeChecked

The TxnExecutor provides two different types of execute methods:

  1. execute: it will automatically wrap the checked exception that can be thrown from an TxnCallable in a InvisibleCheckedException. Unchecked exceptions are let through as is.
  2. execute checked: it will not do anything with thrown checked of unchecked exceptions and lets them through
If an exception happens inside an TxnCallable, the Txn will be always aborted (unless it is caught by the logic inside the TxnCallable). Catching the exceptions inside the callable should be done with care since an exception could indicate that the system has entered an invalid state.

In the future also a rollback-for functionality will be added to let a transaction commit, even though certain types of exceptions have occurred. This is similar with the Spring framework where this can be configured through the 9.5.3: Rolling back

Atomic operation composition/nesting

Using traditional concurrency control, composing locking operations is extremely hard because it is very likely that it is impossible without knowing implementation details of the structure, or because of deadlocks. With Stm transactional operations can be composed and controlling how the system should react on existing or missing transactions can be controlled through the TxnFactoryBuilder.setPropagationLevel(org.multiverse.api.PropagationLevel) where the PropagationLevel.Requires is the default.

Normally the system uses a flat-nesting approach, so only the outermost commit is going to lead to a commit. But if a commit is done before the outer most TxnExecutor completes, that commit is leading.

If the transaction is committed (or aborted) manually, operations on the transaction will fail with a IllegalTxnStateException exception. So in most cases you want to let the TxnExecutor be in charge of committing/aborting. If also allows for a correct flattening of nested transactions. If a transaction should not commit, but you don't want to disrupt the code, the Txn.setAbortOnly() can be called, to make sure that the transaction is not going to commit (or prepare) successfully.

The configuration of the outer most TxnExecutor is leading. So if the outer TxnExecutor is not readonly and the inner is, the transaction will not be readonly. If this becomes an issue (e.g. for security) it can be implemented that some form of runtime verification is done to prevent this behavior.

  • Method Details

    • getTxnFactory

      TxnFactory getTxnFactory()
      Returns the TxnFactory that is used by this TxnExecutor to create transactions used to execute transactional closures.
      Returns:
      the TxnFactory used by this TxnExecutor.
    • execute

      <E> E execute(TxnCallable<E> callable)
      Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the getCause method.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      InvisibleCheckedException - if a checked exception is thrown by the callable.
    • executeChecked

      <E> E executeChecked(TxnCallable<E> callable) throws Exception
      Executes the callable.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      Exception - if the execute call fails.
    • execute

      int execute(TxnIntCallable callable)
      Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the getCause method.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      InvisibleCheckedException - if a checked exception is thrown by the callable.
    • executeChecked

      int executeChecked(TxnIntCallable callable) throws Exception
      Executes the callable.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      Exception - if the execute call fails.
    • execute

      long execute(TxnLongCallable callable)
      Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the getCause method.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      InvisibleCheckedException - if a checked exception is thrown by the callable.
    • executeChecked

      long executeChecked(TxnLongCallable callable) throws Exception
      Executes the callable.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      Exception - if the execute call fails.
    • execute

      double execute(TxnDoubleCallable callable)
      Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the getCause method.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      InvisibleCheckedException - if a checked exception is thrown by the callable.
    • executeChecked

      double executeChecked(TxnDoubleCallable callable) throws Exception
      Executes the callable.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      Exception - if the execute call fails.
    • execute

      boolean execute(TxnBooleanCallable callable)
      Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the getCause method.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      InvisibleCheckedException - if a checked exception is thrown by the callable.
    • executeChecked

      boolean executeChecked(TxnBooleanCallable callable) throws Exception
      Executes the callable.
      Parameters:
      callable - the callable to execute.
      Returns:
      the result of the execution.
      Throws:
      NullPointerException - if callable is null.
      Exception - if the execute call fails.
    • execute

      void execute(TxnVoidCallable callable)
      Executes the transactional callable. If in the execution of the callable a checked exception is thrown, the exception is wrapped in a InvisibleCheckedException. The original exception can be retrieved by calling the getCause method.
      Parameters:
      callable - the callable to execute.
      Throws:
      NullPointerException - if callable is null.
      InvisibleCheckedException - if a checked exception is thrown by the callable.
    • executeChecked

      void executeChecked(TxnVoidCallable callable) throws Exception
      Executes the callable.
      Parameters:
      callable - the callable to execute.
      Throws:
      NullPointerException - if callable is null.
      Exception - if the execute call fails.