Package org.multiverse.api

## Interface Txn

- All Known Implementing Classes:
    `FatFixedLengthGammaTxn`, `FatMonoGammaTxn`, `FatVariableLengthGammaTxn`, `GammaTxn`, `LeanFixedLengthGammaTxn`, `LeanMonoGammaTxn`

      public interface Txn

  The unit of work for `Stm`. The transaction make sure that changes on `TxnObject` instances are:
  1. Atomic: all or nothing gets committed (Failure atomicity)
  2. Consistent :
  3. 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. It depends on the `IsolationLevel` or `LockMode` used how strict the isolation is.

  ### Thread-safety

  A Txn is not thread-safe (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 the `TxnThreadLocal` or other thread specific state like the stackframe of a method (this is an issue when instrumentation is used since the stackframe is likely to be enhanced to include the Txn as a local variable.

  ### TxnListener

  It is possible to listen to a Txn when it aborts/prepares/commits/starts. There are 2 different flavors of listeners:

  1. normal listeners: are registered during the execution of a transaction using the `register(org.multiverse.api.lifecycle.TxnListener)` method. If the transactions aborts/commits these listeners are removed. So if the transaction is retried, the listeners need to be registered (this is easy since the logic inside the transactional closure that did the register, is executed again.
  2. permanent listeners: are registered once and will always remain. It can be done on the TxnExecutor level using the `TxnFactoryBuilder.addPermanentListener(org.multiverse.api.lifecycle.TxnListener)` or it can be done on the Stm level. Permanent listeners are suited for products that want to integrate with Multiverse and always execute some logic at important transaction events. Registration of permanent can also be done on the `Stm` level. See the implementations for more details. Permanent listeners are always executed after the normal listeners.

  ### Storing transaction references

  Txn instances should not be stored since they are likely to be pooled by the STM. So it could be that the same transaction instance is re-used to execute a completely unrelated piece of logic, and it can also be that different instances are used to execute the same logic.

- - ### Method Summary

    All Methods Instance Methods Abstract Methods
    Modifier and Type | Method | Description
    --- | --- | ---
    `void` | `abort()` | Aborts this Txn.
    `void` | `commit()` | Commits this Txn.
    `int` | `getAttempt()` | Gets the current attempt (so the number of tries this transaction already had).
    `TxnConfig` | `getConfig()` | Returns the TxnConfig used by this Txn.
    `long` | `getRemainingTimeoutNs()` | Gets the remaining timeout in nanoseconds.
    `TxnStatus` | `getStatus()` | Returns the status of this Txn.
    `boolean` | `isAbortOnly()` | Checks if this Txn is abort only (so will always fail when committing or preparing).
    `void` | `prepare()` | Prepares this transaction to be committed.
    `void` | `register​(TxnListener listener)` | Registers a TxnListener.
    `void` | `retry()` | Retries the transaction.
    `void` | `setAbortOnly()` | Signals that the only possible outcome of the Txn is one that aborts.

- - ### Method Detail

    - #### getConfig

          TxnConfig getConfig()

      Returns the TxnConfig used by this Txn.

      Because the Txn can be reused, the TxnConfig used by this Txn doesn't need to be constant.

      Returns:
        the TxnConfig.

    - #### getStatus

          TxnStatus getStatus()

      Returns the status of this Txn.
      Returns:
        the status of this Txn.

    - #### getAttempt

          int getAttempt()

      Gets the current attempt (so the number of tries this transaction already had). Value will always be equal or larger than 1 (the first attempt returns 1). The maximum number of attempts for retrying is determined based on the `TxnConfig.getMaxRetries()`
      Returns:
        the current attempt.

    - #### getRemainingTimeoutNs

          long getRemainingTimeoutNs()

      Gets the remaining timeout in nanoseconds. Long.MAX_VALUE indicates that no timeout is used.

      The remaining timeout only is decreased if a transaction blocks on a retry or when doing a backoff.

      Returns:
        the remaining timeout.

    - #### commit

          void commit()

      Commits this Txn. If the Txn is:
      1. active: it is prepared for commit and then committed
      2. prepared: it is committed. Once it is prepared, the commit is guaranteed to succeed.
      3. aborted: a DeadTxnException is thrown
      4. committed: the call is ignored

      Txn will always be aborted if the commit does not succeed.

      Commit will not throw a `ReadWriteConflict` after the transaction is prepared. So if prepared successfully, a commit will always succeed.

      If there are TxnListeners (either normal ones or permanent ones) and they thrown a `RuntimeException` or `Error`, this will be re-thrown. If a listener fails after the prepare/commit the transaction still is committed.

      Throws:
        `ReadWriteConflict` - if the commit failed. Check the class hierarchy of the ReadWriteConflict for more information.
        `IllegalTxnStateException` - if the Txn is not in the correct state for this operation.

    - #### prepare

          void prepare()

      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. Once a transaction is prepared, the commit will always succeed.

      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:
        `ReadWriteConflict` - if the transaction can't be prepared.
        `DeadTxnException` - if the transaction already is committed or aborted.

    - #### abort

          void abort()

      Aborts this Txn. 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 Txn already is aborted, the call is ignored.

      Throws:
        `IllegalTxnStateException` - if the Txn is not in the correct state for this operation.

    - #### retry

          void retry()

      Retries the transaction. This call doesn't block, but if all goes well a `RetryError` is thrown which is caught by the `TxnExecutor`.
      Throws:
        `TxnExecutionException` - if the transaction is not in a legal state for this operation.
        `ControlFlowError`

    - #### setAbortOnly

          void setAbortOnly()

      Signals that the only possible outcome of the Txn is one that aborts. When the transaction prepares or commits it checks if the transaction is marked as abort only. If so, it will automatically aborted and an `AbortOnlyException` is thrown.

      This method is not threadsafe, so can only be called by the thread that used the transaction.

      Throws:
        `IllegalTxnStateException` - if the transaction is not active.
        `ControlFlowError`

    - #### isAbortOnly

          boolean isAbortOnly()

      Checks if this Txn is abort only (so will always fail when committing or preparing).

      This method is not threadsafe, so can only be called by the thread that used the transaction.

      Returns:
        true if abort only, false otherwise.
      Throws:
        `DeadTxnException` - if the transaction is committed/aborted.

    - #### register

          void register​(TxnListener listener)

      Registers a TxnListener. Every time a transaction is retried, the listener needs to be registered again if you want the task to be executed again. If you want a permanent listener, have a look at the `TxnFactoryBuilder.addPermanentListener(org.multiverse.api.lifecycle.TxnListener)`.

      If a TxnListener is added more than once, it is executed more than once. No checks are made. The permanent listeners are executed in the order they are added.

      If a TxnListener throws an Error/RuntimeException and the transaction still is alive, it is aborted. For compensating and deferred actions this is not an issue, but for the PrePrepare state or the state it could since the transaction is aborted.

      Parameters:
        `listener` - the listener to add.
      Throws:
        `NullPointerException` - if listener is null. If the transaction is still alive, it is aborted.
        `IllegalTxnStateException` - if the transaction is not in the correct state (e.g. aborted or committed).
        `ControlFlowError`