Class Transaction
java.lang.Object
net.neoforged.neoforge.transfer.transaction.Transaction
- All Implemented Interfaces:
AutoCloseable,TransactionContext
A global operation that guarantees either the whole operation succeeds,
or it is completely aborted and rolls back.
Generally when passed to a method, a
Transaction should be passed as a TransactionContext to prevent misuse such as calling commit() or close()
One can imagine that transactions are like video game checkpoints.
- Opening a transaction with a try-with-resources block creates a checkpoint.
- Modifications to game state can then happen.
- Calling
commit()validates the modifications that happened during the transaction, essentially discarding the checkpoint. - Calling
close()or doing nothing and letting the transaction be closed at the end of the try-with-resources block cancels any modification that happened during the transaction, reverting to the checkpoint. - Calling
openwith a non-nullparent creates a new inner transaction, i.e. a new checkpoint with the current state. Committing an inner transaction will validate the changes that happened, but they may still be cancelled later if a parent transaction is cancelled. Aborting an inner transaction immediately reverts the changes within that inner transaction - cancelling any modification made after the call toopen.
This is illustrated in the following example.
try (Transaction rootTransaction = Transaction.openRoot()) {
// (A) some transaction operations
try (Transaction innerTransaction = Transaction.open(rootTransaction)) {
// (B) more operations
innerTransaction.commit();
// Commit the changes that happened in this transaction.
// This is an inner transaction, so changes will only be applied if the root
// transaction is committed too.
}
// (C) even more operations
rootTransaction.commit();
// This is a root transaction: changes (A), (B) and (C) are applied.
}
// If we hadn't committed the rootTransaction, all changes (A), (B) and (C) would have been reverted.
Transaction-aware objects are responsible for upholding this contract themselves,
by subclassing SnapshotJournal and using it to manage their state.
See the documentation of SnapshotJournal for detailed instructions.
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.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enumThe different possible states of the transaction stack. -
Field Summary
FieldsModifier and TypeFieldDescription(package private) Class<?> private final int(package private) final List<SnapshotJournal<?>> (package private) final TransactionManager(package private) booleantruewhen the transaction is open,falsewhen it is closing or closed.private static final StackWalkerStack walker to provide a name for the opener of the transaction. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidclose()Abort the current transaction if it was not closed already.private voidclose(boolean wasAborted) voidcommit()Close the current transaction, committing all the changes that happened during this transaction and its committed child transactions.intdepth()Gets the current depth of the transaction.static @Nullable TransactionContextDeprecated.Only intended to be used in the case you don't have the transaction context in the method you are in, while expecting a transaction to be open already.(package private) StringGets what should be printed during exceptions to represent the caller class.static Transaction.LifecycleReturns The current lifecycle of the transaction stack on this thread..static Transactionopen(@Nullable TransactionContext parent) Opens a new transaction with a specified parent.static TransactionopenRoot()Opens a new transaction without a parent: a root transaction.toString()(package private) void
-
Field Details
-
STACK_WALKER
Stack walker to provide a name for the opener of the transaction. This is used for debugging purposes such asTransactionManager.validateCurrentTransaction(net.neoforged.neoforge.transfer.transaction.Transaction). -
manager
-
depth
private final int depth -
open
boolean opentruewhen the transaction is open,falsewhen it is closing or closed. -
journalsToClose
-
callerClass
Class<?> callerClass
-
-
Constructor Details
-
Transaction
Transaction(TransactionManager manager, int depth, Class<?> callerClass)
-
-
Method Details
-
openRoot
Opens a new transaction without a parent: a root transaction.For opening a transaction within an already running transaction, see
open(TransactionContext).- Throws:
IllegalStateException- If a transaction is already open or closing on the current thread.
-
open
Opens a new transaction with a specified parent. The example below, we open the outermost layer or the `root`.try (var transaction = TransactionManager.open(null)) { // do exchanges }- Parameters:
parent- the parent transaction, or null if this is the root transaction. Passingnullis equivalent to callingopenRoot().- Throws:
IllegalStateException- If no parent is passed, but a transaction is already open or closing on the current thread.IllegalStateException- If a parent is passed, but it's not the current transaction.IllegalStateException- If a parent is passed, but it was already closed.
-
getLifecycle
Returns The current lifecycle of the transaction stack on this thread..- Returns:
- The current lifecycle of the transaction stack on this thread.
-
getCurrentOpenedTransaction
Deprecated.Only intended to be used in the case you don't have the transaction context in the method you are in, while expecting a transaction to be open already. If you have access to a transaction context already, be sure to use that rather than using this method.Intended to be used when a method will be part of a transaction chain, but the current transaction is not passed in with no way to change the method signature.- Returns:
- Current
Transactionon the current thread - Throws:
IllegalStateException- when called while a transaction is closing.
-
commit
public void commit()Close the current transaction, committing all the changes that happened during this transaction and its committed child transactions. If this transaction was opened with anullparent, all changes are applied. If this transaction was opened with a non-nullparent, 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, this transaction is not the current transaction, or this transaction was closed.
-
close
public void close()Abort the current transaction if it was not closed already.- Specified by:
closein interfaceAutoCloseable
-
depth
public int depth()Description copied from interface:TransactionContextGets the current depth of the transaction.- Specified by:
depthin interfaceTransactionContext- Returns:
- The depth of this transaction: 0 if it is the root and has no parent; 1 or more otherwise indicating how far away from the root the transaction is.
-
toString
-
validateOpen
void validateOpen() -
getDebugName
String getDebugName()Gets what should be printed during exceptions to represent the caller class. This should include the package name as well. -
close
private void close(boolean wasAborted) - Parameters:
wasAborted-trueif the transaction was aborted,falseif it was committed
-