package org.multiverse.api; import org.multiverse.*; import org.multiverse.api.callables.*; import java.util.concurrent.Callable; /** * An TxnExecutor is responsible for executing an atomic callable. It is created by the {@link TxnFactoryBuilder} * and this gives the {@link Stm} the opportunity to return different implementations based on the * {@link 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. * * <p>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. * * <h3>Transactional Callables</h3> * * <p>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 {@link org.multiverse.api.callables.TxnVoidCallable} that prevents * returning a value if none is needed. And last but not least there also is the general purpose * {@link org.multiverse.api.callables.TxnCallable} that returns an Object reference. * * <h3>Automatic retries</h3> * * <p>If a transaction encounters a {@link org.multiverse.api.exceptions.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 {@link BackoffPolicy} is used, to prevent transactions from causing more contention * if there already is contention. For configuring the maximum number of retries, see the {@link TxnFactoryBuilder#setMaxRetries} * and for configuring the BackoffPolicy, see {@link TxnFactoryBuilder#setBackoffPolicy}. * * <p>It is very important to realize that automatically retrying a transaction on a conflict is something else than the * {@link Txn#retry}. The latter is really a blocking operation that only retries when there is a reason to retry. * * <h3>Configuration</h3> * * <p>The {@link TxnExecutor} can be configured through the {@link TxnFactoryBuilder}. So see that for more details since * there are tons of settings to choose from. * * <h3>Thread-safety</h3> * * <p>TxnExecutors are threadsafe. The TxnExecutor is designed to be shared between threads. * * <h3>Reuse</h3> * * <p>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). * * <p>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. * * <p>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. * * <h3>execute vs executeChecked</h3> * * <p>The TxnExecutor provides two different types of execute methods: * <ol> * <li>execute: it will automatically wrap the checked exception that can be thrown from an TxnCallable in a * {@link org.multiverse.api.exceptions.InvisibleCheckedException}. Unchecked exceptions are let through as is. * </li> * <li>execute checked: it will not do anything with thrown checked of unchecked exceptions and lets them through * </li> * </ol> * 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. * * <p>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 * <a href="http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html#transaction-declarative-rolling-back}">9.5.3: Rolling back</a> * * <h3>Atomic operation composition/nesting</h3> * * <p>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 {@link TxnFactoryBuilder#setPropagationLevel} where the {@link PropagationLevel#Requires} is the default. * * <p>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. * * <p>If the transaction is committed (or aborted) manually, operations on the transaction will fail with a * {@link org.multiverse.api.exceptions.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 {@link Txn#setAbortOnly} can be called, to make sure that the * transaction is not going to commit (or prepare) successfully. * * <p>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. * * @author Peter Veentjer. */ public interface TxnExecutor extends MultiverseConstants{ /** * Returns the {@link TxnFactory} that is used by this TxnExecutor to create transactions used to execute * transactional closures. * * @return the TxnFactory used by this TxnExecutor. */ TxnFactory getTxnFactory(); /** * 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. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ <E> E execute(TxnCallable<E> callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ <E> E executeChecked(TxnCallable<E> callable)throws Exception; /** * 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. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ int execute(TxnIntCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ int executeChecked(TxnIntCallable callable)throws Exception; /** * 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. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ long execute(TxnLongCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ long executeChecked(TxnLongCallable callable)throws Exception; /** * 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. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ double execute(TxnDoubleCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ double executeChecked(TxnDoubleCallable callable)throws Exception; /** * 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. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ boolean execute(TxnBooleanCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @return the result of the execution. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ boolean executeChecked(TxnBooleanCallable callable)throws Exception; /** * 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. * * @param callable the callable to execute. * @throws NullPointerException if callable is null. * @throws org.multiverse.api.exceptions.InvisibleCheckedException if a checked exception is thrown by the callable. */ void execute(TxnVoidCallable callable); /** * Executes the callable. * * @param callable the callable to execute. * @throws NullPointerException if callable is null. * @throws Exception if the execute call fails. */ void executeChecked(TxnVoidCallable callable)throws Exception; }