
org.multiverse.api.Transaction Maven / Gradle / Ivy
package org.multiverse.api;
/**
* All changes on transaction objects must be done through a Transaction. The transaction make sure that changes
* on java objects are:
*
* - Atomic: all or nothing gets committed (Failure atomicity)
* - Consistent :
* - Isolated: a
* transaction is executed isolated from other transactions. Meaning that a transaction won't see changed made by
* transactions executed concurrently, but it will see changes made by transaction completed before.
*
*
*
*
* - Thread-safety
* -
* A Transaction is not thread-safe to use (just like a Hibernate Session is not thread-safe to use). It can be
* handed over from thread to thread, but one needs to be really careful with threadlocals. Although the
* Stm/Transaction implementation don't care about threadlocals, the stuff in front (templates, instrumented code etc)
* could depend on threadlocals.
*
*
* - Listen to lifecycles
* -
* It is possible to listen to a Transaction when it aborts, or commits. This can be done with the
* {@link #registerLifecycleListener(TransactionLifecycleListener)}.
*
* When the Transaction is reset, the lifecycle tasks are dropped. So the lifecycle task need to be registered again.
*
*
* - Blocking
* -
* It is possible to let a transaction block until some state changes has happened; comparable with
* the waitset/{@link java.util.concurrent.locks.Condition} functionality already provided. For more information see the
* {@link #registerRetryLatch(Latch)}.
*
* Because a custom {@link Latch} implementation can be provided, you have a lot of control on the blocking behavior.
* But atm it is not possible to get fairness on when the Latch is opened. Policies to customize starvation,
* lifelocking, deadlocking will be added in the future.
*
*
*
*
* @author Peter Veentjer.
*/
public interface Transaction {
/**
* Gets the {@link TransactionConfig} that is used by this Transaction.
*
* @return the used TransactionConfig.
*/
TransactionConfig getConfig();
/**
* Returns the clock version of the stm when this Transaction started. This version is needed to provide a
* transaction level read consistent view (so a transaction will always see a stable view of the objects at some
* point in time).
*
* The value is unspecified once the Transaction is aborted or committed.
*
* Method depends on long as time, and is going to be removed or replaced in the future.
*
* @return the version of the stm when this Transaction started.
*/
long getReadVersion();
/**
* Returns the status of this Transaction.
*
* @return the status of this Transaction.
*/
TransactionStatus getStatus();
/**
* Commits this Transaction. If the Transaction is:
*
* - active: it is prepared for commit and then committed
* - prepared: it is committed (so changes persisted)
* - aborted: a DeadTransactionException is thrown
* - committed: a DeadTransactionException is thrown
*
So it is safe to call while active
* or prepared.
*
* Transaction will be aborted if the commit does not succeed.
*
* Commit will not throw any validation exceptions after the transaction is prepared.
*
* @throws org.multiverse.api.exceptions.CommitFailureException
* if the commit failed. Check the class hierarchy of the CommitFailureException for more information.
* @throws org.multiverse.api.exceptions.DeadTransactionException
* if this transaction already is aborted.
*/
void commit();
/**
* Prepares this transaction to be committed. It can lock resources to make sure that no conflicting changes are
* made after the transaction has been prepared. If the transaction already is prepared, the call is ignored. If
* the prepare fails, the transaction automatically is aborted.
*
* It is very important that the transaction eventually commits or aborts, if it doesn't no other transaction
* reading/writing the committed resources, can't commit.
*
* @throws org.multiverse.api.exceptions.CommitFailureException
* if the transaction can't be prepared.
* @throws org.multiverse.api.exceptions.DeadTransactionException
* if the transaction already is committed or aborted.
*/
void prepare();
/**
* Aborts this Transaction. This means that the changes made in this transaction are not committed. It depends on
* the implementation if this operation is simple (ditching objects for example), or if changes need to be rolled
* back. If an exception is thrown while executing the abort, the transaction is still aborted. And example of
* such a situation is a pre-abort task that fails. So the transaction always is aborted (unless it is committed).
*
* If the Transaction already is aborted, the call is ignored.
*
*
* @throws org.multiverse.api.exceptions.DeadTransactionException
* if this transaction already is committed
*/
void abort();
/**
* Restarts this Transaction. It doesn't matter what the transaction state of the transaction is. This is the
* preferred way to restart a transaction once a recoverable exception or retry occurred.
*
* If the Transaction is prepared or committed, it will be aborted before it is restarted. If there are
* TransactionLifecycleListeners that cause problems while executing the pre/post abort notification, the
* transaction will be aborted and the exception will be propagated.
*/
void restart();
/**
* Registers the retry Latch on this Transaction. This functionality is required for the retry mechanism
* (so blocking!) and is something different than 'just' restarting. The Latch contains all the 'waiting' logic,
* so you can do timed and non interruptible timeouts on that structure. A latch can be compared to a
* {@link java.util.concurrent.Future} because it also pops closed once some event occurs (an interesting write
* in the case of a Latch).
*
* @param latch the Latch to register.
* @throws NullPointerException if latch is null.
* @throws org.multiverse.api.exceptions.NoRetryPossibleException
* if the retry can't make progress, e.g. because the transaction has not
* loaded any object.
* @throws org.multiverse.api.exceptions.DeadTransactionException
* if this transaction already is committed or aborted.
* @throws UnsupportedOperationException if the Transaction doesn't support this operation (for example because it
* doesn't do readtracking).
*/
void registerRetryLatch(Latch latch);
/**
* Registers a TransactionLifecycleListener on this Transaction. It can be used to receive a callback from the
* transaction if the {@link TransactionStatus} of that transaction. Without this functionality it would not
* be possible to execute compensating or deferred action once a transaction aborts or commits.
*
* If the execution of one of the listeners fails, the others won't be executed. If one of the listeners fails
* before the commit/abort, the transaction is aborted (no matter what).
*
* The listeners are executed in the order they are registered.
*
* If the same listener is added multiple times, it will be notified multiple times.
*
* The listener will be executed on the thread that starts the commit/abort.
*
* If the listener is added after the Transaction is prepared, the preCommit event will not be called on the
* listener.
*
* If the listener accesses the stm after the transaction has been committed or aborted, it could see changes
* made after that transaction. So all assumptions about state are possibly wrong so one needs to take care of
* re-validating state if needed.
*
* A good use case of this feature is starting up threads. If you need to start threads, you don't want to start
* them immediately because eventually the transaction could be aborted.
*
* @param listener the TransactionLifecycleListener to registerLifecycleListener
* @throws NullPointerException if listener is null.
* @throws org.multiverse.api.exceptions.DeadTransactionException
* if transaction already is aborted or committed.
*/
void registerLifecycleListener(TransactionLifecycleListener listener);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy