Interface Transaction

All Superinterfaces:
AutoCloseable, TransactionContext

@Experimental @Deprecated @NonExtendable public interface Transaction extends AutoCloseable, TransactionContext
Deprecated.
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.
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.