public interface TxnExecutor extends MultiverseConstants
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.
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.
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.
The TxnExecutor
can be configured through the TxnFactoryBuilder
. So see that for more details since
there are tons of settings to choose from.
TxnExecutors are threadsafe. The TxnExecutor is designed to be shared between threads.
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.
The TxnExecutor provides two different types of execute methods:
InvisibleCheckedException
. Unchecked exceptions are let through as is.
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
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.
LOCKMODE_EXCLUSIVE, LOCKMODE_NONE, LOCKMODE_READ, LOCKMODE_WRITE, SHAKE_BUGS, SPIN_YIELD, TRACING_ENABLED
Modifier and Type | Method and Description |
---|---|
boolean |
execute(TxnBooleanCallable callable)
Executes the transactional callable.
|
<E> E |
execute(TxnCallable<E> callable)
Executes the transactional callable.
|
double |
execute(TxnDoubleCallable callable)
Executes the transactional callable.
|
int |
execute(TxnIntCallable callable)
Executes the transactional callable.
|
long |
execute(TxnLongCallable callable)
Executes the transactional callable.
|
void |
execute(TxnVoidCallable callable)
Executes the transactional callable.
|
boolean |
executeChecked(TxnBooleanCallable callable)
Executes the callable.
|
<E> E |
executeChecked(TxnCallable<E> callable)
Executes the callable.
|
double |
executeChecked(TxnDoubleCallable callable)
Executes the callable.
|
int |
executeChecked(TxnIntCallable callable)
Executes the callable.
|
long |
executeChecked(TxnLongCallable callable)
Executes the callable.
|
void |
executeChecked(TxnVoidCallable callable)
Executes the callable.
|
TxnFactory |
getTxnFactory()
Returns the
TxnFactory that is used by this TxnExecutor to create transactions used to execute
transactional closures. |
TxnFactory getTxnFactory()
TxnFactory
that is used by this TxnExecutor to create transactions used to execute
transactional closures.<E> E execute(TxnCallable<E> callable)
callable
- the callable to execute.NullPointerException
- if callable is null.InvisibleCheckedException
- if a checked exception is thrown by the callable.<E> E executeChecked(TxnCallable<E> callable) throws Exception
callable
- the callable to execute.NullPointerException
- if callable is null.Exception
- if the execute call fails.int execute(TxnIntCallable callable)
callable
- the callable to execute.NullPointerException
- if callable is null.InvisibleCheckedException
- if a checked exception is thrown by the callable.int executeChecked(TxnIntCallable callable) throws Exception
callable
- the callable to execute.NullPointerException
- if callable is null.Exception
- if the execute call fails.long execute(TxnLongCallable callable)
callable
- the callable to execute.NullPointerException
- if callable is null.InvisibleCheckedException
- if a checked exception is thrown by the callable.long executeChecked(TxnLongCallable callable) throws Exception
callable
- the callable to execute.NullPointerException
- if callable is null.Exception
- if the execute call fails.double execute(TxnDoubleCallable callable)
callable
- the callable to execute.NullPointerException
- if callable is null.InvisibleCheckedException
- if a checked exception is thrown by the callable.double executeChecked(TxnDoubleCallable callable) throws Exception
callable
- the callable to execute.NullPointerException
- if callable is null.Exception
- if the execute call fails.boolean execute(TxnBooleanCallable callable)
callable
- the callable to execute.NullPointerException
- if callable is null.InvisibleCheckedException
- if a checked exception is thrown by the callable.boolean executeChecked(TxnBooleanCallable callable) throws Exception
callable
- the callable to execute.NullPointerException
- if callable is null.Exception
- if the execute call fails.void execute(TxnVoidCallable callable)
callable
- the callable to execute.NullPointerException
- if callable is null.InvisibleCheckedException
- if a checked exception is thrown by the callable.void executeChecked(TxnVoidCallable callable) throws Exception
callable
- the callable to execute.NullPointerException
- if callable is null.Exception
- if the execute call fails.Copyright © 2020. All rights reserved.