Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 384   Methods: 25
NCLOC: 209   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
TransactionEntry.java 63.6% 88.9% 92% 84.5%
coverage coverage
 1    /*
 2    * JBoss, the OpenSource J2EE webOS
 3    *
 4    * Distributable under LGPL license.
 5    * See terms of license at gnu.org.
 6    */
 7    package org.jboss.cache.transaction;
 8   
 9   
 10    import net.jcip.annotations.ThreadSafe;
 11    import org.apache.commons.logging.Log;
 12    import org.apache.commons.logging.LogFactory;
 13    import org.jboss.cache.CacheSPI;
 14    import org.jboss.cache.Fqn;
 15    import org.jboss.cache.Modification;
 16    import org.jboss.cache.config.Option;
 17    import org.jboss.cache.lock.IdentityLock;
 18    import org.jboss.cache.lock.NodeLock;
 19    import org.jboss.cache.marshall.MethodCall;
 20   
 21    import javax.transaction.Transaction;
 22    import java.util.ArrayList;
 23    import java.util.Collection;
 24    import java.util.Collections;
 25    import java.util.LinkedHashSet;
 26    import java.util.LinkedList;
 27    import java.util.List;
 28    import java.util.ListIterator;
 29    import java.util.concurrent.CopyOnWriteArrayList;
 30   
 31    /**
 32    * Information associated with a {@link GlobalTransaction} about the transaction state.
 33    * <p/>
 34    * A TransactionEntry maintains:
 35    * <ul>
 36    * <li>Handle to local Transactions: there can be more than 1 local TX associated with a GlobalTransaction
 37    * <li>List of modifications ({@link Modification})
 38    * <li>List of nodes that were created as part of lock acquisition. These nodes can be
 39    * safely deleted when a transaction is rolled back
 40    * <li>List of locks ({@link IdentityLock}) that have been acquired by
 41    * this transaction so far
 42    * </ul>
 43    *
 44    * @author <a href="mailto:bela@jboss.org">Bela Ban</a> Apr 14, 2003
 45    * @version $Revision: 1.10 $
 46    */
 47    @ThreadSafe
 48    public class TransactionEntry
 49    {
 50   
 51    private static Log log = LogFactory.getLog(TransactionEntry.class);
 52   
 53    /**
 54    * Local transaction
 55    */
 56    private Transaction ltx = null;
 57    private Option option;
 58   
 59    private boolean forceAsyncReplication = false;
 60   
 61    /**
 62    * List<MethodCall> of modifications ({@link MethodCall}). They will be replicated on TX commit
 63    */
 64    private List<MethodCall> modification_list = new LinkedList<MethodCall>();
 65   
 66    // For some reason we see multiple threads accessing this list - even within the same tx. Could be due to reuse of
 67    // tx identifiers in the DummyTM, which is where we see this problem.
 68    private List<MethodCall> cl_mod_list = new CopyOnWriteArrayList<MethodCall>();
 69   
 70    /**
 71    * List<MethodCall>. List of compensating {@link org.jboss.cache.marshall.MethodCall} objects
 72    * which revert the ones in <tt>modification_list</tt>. For each entry in the modification list,
 73    * we have a corresponding entry in this list. A rollback will simply iterate over this list in
 74    * reverse to undo the modifications. Note that these undo-ops will never be replicated.
 75    */
 76    private final List<MethodCall> undo_list = new LinkedList<MethodCall>();
 77   
 78    /**
 79    * LinkedHashSet<IdentityLock> of locks acquired by the transaction. We use
 80    * a LinkedHashSet because we need efficient Set semantics (same lock can
 81    * be added multiple times) but also need guaranteed ordering for use
 82    * by lock release code (see JBCCACHE-874).
 83    */
 84    private LinkedHashSet<NodeLock> locks = new LinkedHashSet<NodeLock>();
 85   
 86    /**
 87    * A list of dummy uninitialised nodes created by the cache loader interceptor to load data for a
 88    * given node in this tx.
 89    */
 90    private List<Fqn> dummyNodesCreatedByCacheLoader;
 91   
 92    /**
 93    * List<Fqn> of nodes that have been removed by the transaction
 94    */
 95    private List<Fqn> removedNodes = new LinkedList<Fqn>();
 96   
 97    /**
 98    * Constructs a new TransactionEntry.
 99    */
 100  1121973 public TransactionEntry()
 101    {
 102    }
 103   
 104    /**
 105    * Adds a modification to the modification list.
 106    */
 107  168022 public void addModification(MethodCall m)
 108    {
 109  0 if (m == null) return;
 110  168022 modification_list.add(m);
 111    }
 112   
 113  41080 public void addCacheLoaderModification(MethodCall m)
 114    {
 115  41080 if (m != null) cl_mod_list.add(m);
 116    }
 117   
 118    /**
 119    * Returns all modifications.
 120    */
 121  2243444 public List<MethodCall> getModifications()
 122    {
 123  2243444 return modification_list;
 124    }
 125   
 126  40703 public List<MethodCall> getCacheLoaderModifications()
 127    {
 128    // make sure this isn't modified externally
 129  40703 return Collections.unmodifiableList(cl_mod_list);
 130    }
 131   
 132    /**
 133    * Adds an undo operation to the undo list.
 134    *
 135    * @see #undoOperations
 136    */
 137  183190 public void addUndoOperation(MethodCall m)
 138    {
 139  183190 undo_list.add(m);
 140    }
 141   
 142    /**
 143    * Adds the node that has been removed.
 144    *
 145    * @param fqn
 146    */
 147  10853 public void addRemovedNode(Fqn fqn)
 148    {
 149  10853 removedNodes.add(fqn);
 150    }
 151   
 152    /**
 153    * Gets the list of removed nodes.
 154    */
 155  69787 public List<Fqn> getRemovedNodes()
 156    {
 157  69787 return new ArrayList<Fqn>(removedNodes);
 158    }
 159   
 160    /**
 161    * Returns the undo operations in use.
 162    * Note: This list may be concurrently modified.
 163    */
 164  0 public List<MethodCall> getUndoOperations()
 165    {
 166  0 return undo_list;
 167    }
 168   
 169    /**
 170    * Sets the local transaction for this entry.
 171    */
 172  1121973 public void setTransaction(Transaction tx)
 173    {
 174  1121973 ltx = tx;
 175    }
 176   
 177    /**
 178    * Returns a local transaction associated with this TransactionEntry
 179    */
 180  0 public Transaction getTransaction()
 181    {
 182  0 return ltx;
 183    }
 184   
 185    /**
 186    * Adds a lock to the end of the lock list, if it isn't already present.
 187    */
 188  294779 public void addLock(NodeLock l)
 189    {
 190  294779 if (l != null)
 191    {
 192  294779 synchronized (locks)
 193    {
 194  294779 locks.add(l);
 195    }
 196    }
 197    }
 198   
 199    /**
 200    * Add multiple locks to the lock list.
 201    *
 202    * @param newLocks Collection<NodeLock>
 203    */
 204  51 public void addLocks(Collection<NodeLock> newLocks)
 205    {
 206  51 if (newLocks != null)
 207    {
 208  51 synchronized (locks)
 209    {
 210  51 locks.addAll(newLocks);
 211    }
 212    }
 213    }
 214   
 215    /**
 216    * Returns the locks in use.
 217    *
 218    * @return a defensive copy of the internal data structure.
 219    */
 220  62 public List<NodeLock> getLocks()
 221    {
 222  62 synchronized (locks)
 223    {
 224  62 return new ArrayList<NodeLock>(locks);
 225    }
 226    }
 227   
 228    /**
 229    * Releases all locks held by the owner, in reverse order of creation.
 230    * Clears the list of locks held.
 231    */
 232  69310 public void releaseAllLocksLIFO(Object owner)
 233    {
 234   
 235  69310 boolean trace = log.isTraceEnabled();
 236  69310 synchronized (locks)
 237    {
 238    // Copying out to an array is faster than creating an ArrayList and iterating,
 239    // since list creation will just copy out to an array internally
 240  69310 IdentityLock[] lockArray = locks.toArray(new IdentityLock[locks.size()]);
 241  69310 for (int i = lockArray.length - 1; i >= 0; i--)
 242    {
 243  277815 if (trace)
 244    {
 245  0 log.trace("releasing lock for " + lockArray[i].getFqn() + " (" + lockArray[i] + ")");
 246    }
 247  277815 lockArray[i].release(owner);
 248    }
 249  69310 locks.clear();
 250    }
 251    }
 252   
 253    /**
 254    * Releases all locks held by the owner, in order of creation.
 255    * Does not clear the list of locks held.
 256    */
 257  1052431 public void releaseAllLocksFIFO(Object owner)
 258    {
 259    // I guess a copy would work as well
 260    // This seems fairly safe though
 261  1052431 synchronized (locks)
 262    {
 263  1052431 for (NodeLock lock : locks)
 264    {
 265  2860 lock.release(owner);
 266  2860 if (log.isTraceEnabled())
 267    {
 268  0 log.trace("releasing lock for " + ((IdentityLock) lock).getFqn() + " (" + lock + ")");
 269    }
 270    }
 271    }
 272    }
 273   
 274    /**
 275    * Gets the value of the forceAsyncReplication flag. Used by ReplicationInterceptor and OptimisticReplicationInterceptor
 276    * when dealing with {@link org.jboss.cache.Cache#putForExternalRead(org.jboss.cache.Fqn,Object,Object)} within
 277    * a transactional context.
 278    *
 279    * @return true if the forceAsyncReplication flag is set to true.
 280    */
 281  21640 public boolean isForceAsyncReplication()
 282    {
 283  21640 return forceAsyncReplication;
 284    }
 285   
 286    /**
 287    * Sets the value of the forceAsyncReplication flag. Used by ReplicationInterceptor and OptimisticReplicationInterceptor
 288    * when dealing with {@link org.jboss.cache.Cache#putForExternalRead(org.jboss.cache.Fqn,Object,Object)} within
 289    * a transactional context.
 290    *
 291    * @param forceAsyncReplication value of forceAsyncReplication
 292    */
 293  16 public void setForceAsyncReplication(boolean forceAsyncReplication)
 294    {
 295  16 this.forceAsyncReplication = forceAsyncReplication;
 296    }
 297   
 298   
 299    /**
 300    * Posts all undo operations to the CacheImpl.
 301    */
 302  269 public void undoOperations(CacheSPI cache)
 303    {
 304  269 if (log.isTraceEnabled())
 305    {
 306  0 log.trace("undoOperations " + undo_list);
 307    }
 308  269 ArrayList<MethodCall> l;
 309  269 synchronized (undo_list)
 310    {
 311  269 l = new ArrayList<MethodCall>(undo_list);
 312    }
 313  269 for (ListIterator<MethodCall> i = l.listIterator(l.size()); i.hasPrevious();)
 314    {
 315  1273 MethodCall undo_op = i.previous();
 316  1273 undo(undo_op, cache);
 317    }
 318    }
 319   
 320  1273 private void undo(MethodCall undo_op, CacheSPI cache)
 321    {
 322  1273 try
 323    {
 324  1273 Object retval = undo_op.invoke(cache);
 325  1272 if (retval instanceof Throwable)
 326    {
 327  0 throw (Throwable) retval;
 328    }
 329    }
 330    catch (Throwable t)
 331    {
 332  1 log.error("undo operation failed, error=" + t);
 333  1 log.trace(t, t);
 334    }
 335    }
 336   
 337    /**
 338    * Returns debug information about this transaction.
 339    */
 340  12 public String toString()
 341    {
 342  12 StringBuffer sb = new StringBuffer();
 343  12 sb.append("TransactionEntry\nmodification_list: ").append(modification_list);
 344  12 synchronized (undo_list)
 345    {
 346  12 sb.append("\nundo_list: ").append(undo_list);
 347    }
 348  12 synchronized (locks)
 349    {
 350  12 sb.append("\nlocks: ").append(locks);
 351    }
 352  12 return sb.toString();
 353    }
 354   
 355  110 public void loadUninitialisedNode(Fqn fqn)
 356    {
 357  110 if (dummyNodesCreatedByCacheLoader == null)
 358  82 dummyNodesCreatedByCacheLoader = new LinkedList<Fqn>();
 359  110 dummyNodesCreatedByCacheLoader.add(fqn);
 360    }
 361   
 362  49 public List<Fqn> getDummyNodesCreatedByCacheLoader()
 363    {
 364  49 return dummyNodesCreatedByCacheLoader;
 365    }
 366   
 367    /**
 368    * Sets a transaction-scope option override
 369    *
 370    * @param o
 371    */
 372  1401756 public void setOption(Option o)
 373    {
 374  1401756 this.option = o;
 375    }
 376   
 377    /**
 378    * Retrieves a transaction scope option override
 379    */
 380  1189211 public Option getOption()
 381    {
 382  1189211 return this.option;
 383    }
 384    }