com.cloudtran.coherence.llapi
Class CTx

java.lang.Object
  extended by com.cloudtran.coherence.llapi.CTx

public class CTx
extends Object

Manages the lifecycle of CloudTran LLAPI transactions - start/enrol/commit/rollback. Instances of this class are created by CTxFactory.get(). This class are also the transactional cache factory for the low-level API; it manages the lifecycle of transactional caches, implemented by CTNamedCache.

A transactional cache is only valid for the lifetime of the transaction. You should not use it on transactional methods (put, remove, invoke) after the transaction has completed (committed/rolled back). If you are using Spring transactions, this is easy: use a method local variable, and it is guaranteed to go away as the transaction completes. If you are not using Spring transactions, the same approach works, except you have to do the commit/roll back yourself: store the transactional cache in a local variable of a method and do the commit/rollback as the last thing in the method.

This class also provides add/removeMapListener methods to make MapListeners participate in transactions. You only need to do this if the MapListener is a MapTriggerListener - these can make changes before an entry is committed and so can be incorporated into a transaction. Non-MapTrigger MapListeners are call after the cache update is completed so cannot be made transactional; CloudTran does not change the action of non-MapTrigger MapListeners.

What happens when the MapTrigger is transactional is that the cache operation - put, remove and invoke - can make transactional changes to an entry and the MapTrigger is then called before the changes are committed. The map listener is passed an Entry wrapper that has the values representing the transactional change that has occurred. The previous value passed is the previous transactional value if there is one, or the committed value is not. The new value passed is the new value as set by the cache operation. As usual, the MapTrigger can change the values to quietly affect the operation, or it can throw an exception, which will be propagated back to the user with out any changes being made.

The MapListener methods are available as static methods, and also on transactional caches created by the getCache() methods. The reasons for providing static methods are

Note that you must create transactional MapTriggerListeners programmatically. It is not possible to create make them transactional via cache-config.xml.

In the current version, CloudTran transactions work on Distributed scheme caches only.


Method Summary
 void addMapListener(NamedCache cache, MapListener listener)
           
 void addMapListener(NamedCache cache, MapListener listener, Filter filter, boolean fLite)
           
 void addMapListener(NamedCache cache, MapListener listener, Object oKey, boolean fLite)
           
 void commit()
          Commits the current CloudTran transaction.
 void enrol(CTxDefinition ctxDefinition)
          This method enrols in an existing transaction, which has previously been started.
 CTNamedCache getCache(NamedCache cohCache)
          Gets a CloudTran transactional cache, delegating normal operations to the Coherence NamedCache passed in.
 CTNamedCache getCache(String sName)
          Gets a transactional implementation of NamedCache.
 CTNamedCache getCache(String cacheName, ClassLoader loader)
          Gets a transactional cache based on getCache.
 CTxDefinition getCurrentContext()
          Gets the CloudTran transaction context for the current thread.
 Object getCurrentSpringTransaction()
           
 void removeMapListener(NamedCache cache, MapListener listener)
           
 void removeMapListener(NamedCache cache, MapListener listener, Filter filter)
           
 void removeMapListener(NamedCache cache, MapListener listener, Object oKey)
           
 void rollback()
          Rolls back the current CloudTran transaction.
 void start()
          start() starts a new transaction with the default transactional properties.
 void start(CTxDefinition ctxDefinition)
          start() starts a new transaction with the specified transactional properties.
 void startMvcc()
          start() starts a new transaction.
 void startPL()
          start() starts a new transaction.
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Method Detail

getCurrentContext

public CTxDefinition getCurrentContext()
Gets the CloudTran transaction context for the current thread. If there is no CloudTran transaction for the current thread, this returns null. The {link CTxDefinition} returned by this method can be sent to another thread, possibly in another virtual machine, which can use it to 'enrol' in the transaction.

Returns:
the current CloudTran transaction, or null if there is no on-going CloudTran transaction for the current thread.

getCurrentSpringTransaction

public Object getCurrentSpringTransaction()

start

public void start()
start() starts a new transaction with the default transactional properties.

The default transaction type is Pessimistic Locking.

If the start() is successful, a new transaction is added to the current thread. Caches can then be acquired from the CTCacheFactory to do transactional operations.

Throws:
TransactionExceptionParameterOrUsageError - if there is an existing CloudTran transaction for this thread.

startMvcc

public void startMvcc()
start() starts a new transaction. The transaction type is MVCC; other transaction properties use the default values.

If the start() is successful, a new transaction is added to the current thread. Caches can then be acquired from the CTCacheFactory to do transactional operations.

Throws:
TransactionExceptionParameterOrUsageError - if there is an existing CloudTran transaction for this thread.

startPL

public void startPL()
start() starts a new transaction. The transaction type is Pessimistic Locking; other transaction properties use the default values.

If the start() is successful, a new transaction is added to the current thread. Caches can then be acquired from the CTCacheFactory to do transactional operations.

Throws:
TransactionExceptionParameterOrUsageError - if there is an existing CloudTran transaction for this thread.

start

public void start(CTxDefinition ctxDefinition)
start() starts a new transaction with the specified transactional properties.

When you get a new CTxDefinition, it will contain the default transactional properties. You can then change the properties before starting the transaction.

If the start() is successful, a new transaction is added to the current thread. Caches can then be acquired from getCache(String) or getCache(NamedCache) to do transactional cache operations. The transaction stays active on the thread until you call commit() or rollback().

The ctxDefinition object is not changed by this call. This means you can have a single template/default ctxDefinition for an application with the required transaction properties preset and use it in this call.

Parameters:
ctxDefinition - the transaction properties definition.
Throws:
TransactionExceptionParameterOrUsageError - if there is an existing CloudTran transaction for this thread.

enrol

public void enrol(CTxDefinition ctxDefinition)
           throws TransactionExceptionParameterOrUsageError
This method enrols in an existing transaction, which has previously been started.

When one or more threads enrols in a transaction - so more than just the original starter is contributing to the transaction - the semantics of commit() changes.

The transaction manager keeps track of the number of threads contributing to the transaction. Any thread can issue a commit() for the transaction at any time - there is no requirement to commit in any order. All the commit calls decrease the contributor count at the manager. Until this count reaches 0, this is all that happens at the manager; the transaction information from the committer is remembered in backed-up memory but the transactional entries in the grid are not committed. When one of the contributes commits and the contributor count goes to 0, the transaction manager commits the complete transaction, and makes the transactional entries permanent.

The threads contributing to the transaction are responsible for committing precisely once. Also, the commit must be done within the transaction timeout set by the original start call in the CTxDefinition.getTransactionTimeout().

Because the transaction does not finally commit or rollback until the last client commits, in a multi-client transaction only the last client to commit or rollback can definitely know the outcome of the transaction. This means that if there is to be any external effect (i.e outside the change in data) of the transaction, such as logging of the result, this should be done by a predetermined client. The normal way to ensure this is for the client that starts the transaction to also receive outcomes from the other clients.

There is another reason for having the client that starts the transaction be the committer. It avoids a race condition with the alternative - where the starting client sends work to be done to other clients and then immediately commits - because the first client can commit before the second client has enrolled. This will lead to premature termination of the transaction.

In this version of CloudTran, when a thread enrols in a transaction, it must programmatically issue the commit. In other words, unlike start() which can be issued via annotations, enrol() and its corresponding commit() must be called explicitly by the application.

Furthermore, in this version, the thread that calls enrol() must call one of commit() or rollback(). Of course, this is necessary to correctly complete the transaction: not doing so is a contract violation. But this is also necessary because, if it is not done, the thread will still have the previous transaction in a ThreadLocal variable and no further transactions will be possible on this thread.

TBD: enrol() and @Transactional annotation approaches to transaction don't interwork well within the same thread, e.g. in propagation. (But they do work when the @Transactional annotation starts a transaction and other threads use the enrol() approach.

Parameters:
ctxDefinition - The existing transaction's attributes, as returned by the 'start' transaction. The CTxDefinition can be accessed by getCurrentContext().
Throws:
TransactionExceptionParameterOrUsageError - This is thrown if any of the following situations occurs:
  • the ctxDefinition parameter is null
  • the transaction is not active at the manager. ('Active' means it has been started by another thread and has not been committed, rolled-back or timed out.)
  • There is an outstanding transaction on this thread.

commit

public void commit()
            throws CTxException
Commits the current CloudTran transaction. The 'current transaction' is attached to the calling thread and must be started, and not committed or rolled back. (The current context is returned by getCurrentContext().

Throws:
TransactionExceptionParameterOrUsageError - Thrown if there is no current transaction
CTxException

rollback

public void rollback()
              throws TransactionExceptionParameterOrUsageError
Rolls back the current CloudTran transaction. The 'current transaction' is attached to the calling thread and must be started, and not committed or rolled back. (The current context is returned by getCurrentContext().

All transactional data is discarded and all transactional entries in data caches created by the transaction are reverted to their pre-transaction values, without any transactional information.

In the case where there are multiple client threads involved in the transaction (i.e. one or more threads have enrolled in the transaction via enrol(CTxDefinition)) and this caller is not the last to commit or rollback, then the transaction manager will note that the transaction is to be rolled back and discard all transactional cache entries when the last client commits.

Throws:
TransactionExceptionParameterOrUsageError

getCache

public CTNamedCache getCache(String sName)
                      throws CannotCreateTransactionException
Gets a transactional implementation of NamedCache. This method throws an exception if there is no current transaction

Returns:
a transactional cache linked to the ongoing transaction.
Throws:
CannotCreateTransactionException

getCache

public CTNamedCache getCache(String cacheName,
                             ClassLoader loader)
Gets a transactional cache based on getCache.

Parameters:
cacheName - as for NamedCache.cacheName
loader - as for NamedCache.loader
Returns:
a cache linked to the ongoing transaction.
Throws:
CannotCreateTransactionException - if there is no CloudTran transaction for this thread
TransactionExceptionTxComplete - if the attached transaction is completed.

getCache

public CTNamedCache getCache(NamedCache cohCache)
Gets a CloudTran transactional cache, delegating normal operations to the Coherence NamedCache passed in.

Parameters:
cohCache - The Coherence NamedCache
Returns:
The CloudTran transactional cache. getName() will return the same name as the Coherence NamedCache.

addMapListener

public void addMapListener(NamedCache cache,
                           MapListener listener,
                           Filter filter,
                           boolean fLite)

addMapListener

public void addMapListener(NamedCache cache,
                           MapListener listener,
                           Object oKey,
                           boolean fLite)

addMapListener

public void addMapListener(NamedCache cache,
                           MapListener listener)

removeMapListener

public void removeMapListener(NamedCache cache,
                              MapListener listener,
                              Filter filter)

removeMapListener

public void removeMapListener(NamedCache cache,
                              MapListener listener,
                              Object oKey)

removeMapListener

public void removeMapListener(NamedCache cache,
                              MapListener listener)