JBoss Cache can be configured to use transactions to bundle units of work, which can then be replicated as one unit. Alternatively, if transaction support is disabled, it is equivalent to setting AutoCommit to on where modifications are potentially[5] replicated after every change (if replication is enabled).
What JBoss Cache does on every incoming call (e.g. put()) is:
get the transaction associated with the thread
register (if not already done) with the transaction manager to be notified when a transaction commits or is rolled back.
In order to do this, the cache has to be configured with an instance of a TransactionManagerLookup which returns a javax.transaction.TransactionManager.
JBoss Cache ships with JBossTransactionManagerLookup and GenericTransactionManagerLookup. The JBossTransactionManagerLookup is able to bind to a running JBoss Application Server and retrieve a TransactionManager while the GenericTransactionManagerLookup is able to bind to most popular Java EE application servers and provide the same functionality. A dummy implementation - DummyTransactionManagerLookup - is also provided, which may be used for standalone JBoss Cache applications and unit tests running outside a Java EE Application Server. Being a dummy, however, this is just for demo and testing purposes and is not recommended for production use.
The implementation of the JBossTransactionManagerLookup is as follows:
public class JBossTransactionManagerLookup implements TransactionManagerLookup {
public JBossTransactionManagerLookup() {}
public TransactionManager getTransactionManager() throws Exception {
Object tmp=new InitialContext().lookup("java:/TransactionManager");
return (TransactionManager)tmp;
}
}
The implementation looks up the JBoss Transaction Manager from JNDI and returns it.
When a call comes in, the TreeCache gets the current transaction and records the modification under the transaction as key. (If there is no transaction, the modification is applied immediately and possibly replicated). So over the lifetime of the transaction all modifications will be recorded and associated with the transaction. Also, the TreeCache registers with the transaction to be notified of transaction committed or aborted when it first encounters the transaction.
When a transaction rolls back, we undo the changes in the cache and release all locks.
When the transaction commits, we initiate a two-phase commit protocol[6] : in the first phase, a PREPARE containing all modifications for the current transaction is sent to all nodes in the cluster. Each node acquires all necessary locks and applies the changes, and then sends back a success message. If a node in a cluster cannot acquire all locks, or fails otherwise, it sends back a failure message.
The coordinator of the two-phase commit protocol waits for all responses (or a timeout, whichever occurs first). If one of the nodes in the cluster responds with FAIL (or we hit the timeout), then a rollback phase is initiated: a ROLLBACK message is sent to all nodes in the cluster. On reception of the ROLLBACK message, every node undoes the changes for the given transaction, and releases all locks held for the transaction.
If all responses are OK, a COMMIT message is sent to all nodes in the cluster. On reception of a COMMIT message, each node applies the changes for the given transaction and releases all locks associated with the transaction.
When we referred to 'transaction', we actually mean a global representation of a local transaction, which uniquely identifies a transaction across a cluster.