Interface Transaction

All Superinterfaces:
AutoCloseable, TransactionContext

@Experimental @NonExtendable public interface Transaction extends AutoCloseable, TransactionContext
A global operation where participants guarantee atomicity: either the whole operation succeeds, or it is completely aborted and rolled back.

One can imagine that transactions are like video game checkpoints.

This is illustrated in the following example.


 try (Transaction outerTransaction = Transaction.openOuter()) {
     // (A) some transaction operations
     try (Transaction nestedTransaction = outerTransaction.openNested()) {
         // (B) more operations
         nestedTransaction.commit(); // Validate the changes that happened in this transaction.
                                     // This is a nested transaction, so changes will only be applied if the outer
                                     // transaction is committed too.
     }
     // (C) even more operations
     outerTransaction.commit(); // This is an outer transaction: changes (A), (B) and (C) are applied.
 }
 // If we hadn't committed the outerTransaction, all changes (A), (B) and (C) would have been reverted.
 

Participants are responsible for upholding this contract themselves, by using TransactionContext.addCloseCallback(net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext.CloseCallback) to react to transaction close events and properly validate or revert changes. Any action that modifies state outside of the transaction, such as calls to markDirty() or neighbor updates, should be deferred until after the outer transaction is closed to give every participant a chance to react to transaction close events.

This is very low-level for most applications, and most participants should subclass SnapshotParticipant that will take care of properly maintaining their state.

Participants should generally be passed a TransactionContext parameter instead of the full Transaction, to make sure they don't call abort(), commit() or close() mistakenly.

Every transaction is only valid on the thread it was opened on, and attempts to use it on another thread will throw an exception. Consequently, transactions can be concurrent across multiple threads, as long as they don't share any state.

Experimental feature, we reserve the right to remove or change it without further notice. The transfer API is a complex addition, and we want to be able to correct possible design mistakes.

  • Method Details

    • openOuter

      static Transaction openOuter()
      Open a new outer transaction.
      Throws:
      IllegalStateException - If a transaction is already active on the current thread.
    • isOpen

      static boolean isOpen()
      Returns:
      True if a transaction is open or closing on the current thread, and false otherwise.
    • getLifecycle

      static Transaction.Lifecycle getLifecycle()
      Returns:
      The current lifecycle of the transaction stack on this thread.
    • openNested

      static Transaction openNested(@Nullable @Nullable TransactionContext maybeParent)
      Open a nested transaction if maybeParent is non-null, or an outer transaction if maybeParent is null.
    • getCurrentUnsafe

      @Deprecated @Nullable static @Nullable TransactionContext getCurrentUnsafe()
      Deprecated.
      Only use if you absolutely need it, there is almost always a better way.
      Retrieve the currently open transaction, or null if there is none.

      Usage of this function is strongly discouraged, this is why it is deprecated and contains unsafe in its name. The transaction may be aborted unbeknownst to you and anything you think that you have committed might be undone. Only use it if you have no way to pass the transaction down the stack, for example if you are implementing compat with a simulation-based API, and you know what you are doing, for example because you opened the outer transaction.

      Throws:
      IllegalStateException - If called from a close or outer close callback.
    • abort

      void abort()
      Close the current transaction, rolling back all the changes that happened during this transaction and the transactions opened with openNested(net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext) from this transaction.
      Throws:
      IllegalStateException - If this function is not called on the thread this transaction was opened in.
      IllegalStateException - If this transaction is not the current transaction.
      IllegalStateException - If this transaction was closed.
    • commit

      void commit()
      Close the current transaction, committing all the changes that happened during this transaction and the committed transactions opened with openNested(net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext) from this transaction. If this transaction was opened with openOuter(), all changes are applied. If this transaction was opened with openNested(net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext), all changes will be applied when and if the changes of the parent transactions are applied.
      Throws:
      IllegalStateException - If this function is not called on the thread this transaction was opened in.
      IllegalStateException - If this transaction is not the current transaction.
      IllegalStateException - If this transaction was closed.
    • close

      void close()
      Abort the current transaction if it was not closed already.
      Specified by:
      close in interface AutoCloseable