Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 144   Methods: 4
NCLOC: 98   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
OptimisticLockingInterceptor.java 50% 74.4% 100% 73.6%
coverage coverage
 1    /*
 2    * JBoss, Home of Professional Open Source
 3    *
 4    * Distributable under LGPL license.
 5    * See terms of license at gnu.org.
 6    */
 7    package org.jboss.cache.interceptors;
 8   
 9    import org.jboss.cache.CacheException;
 10    import org.jboss.cache.CacheSPI;
 11    import org.jboss.cache.InvocationContext;
 12    import org.jboss.cache.NodeSPI;
 13    import org.jboss.cache.lock.NodeLock;
 14    import org.jboss.cache.marshall.MethodCall;
 15    import org.jboss.cache.marshall.MethodDeclarations;
 16    import org.jboss.cache.optimistic.TransactionWorkspace;
 17    import org.jboss.cache.optimistic.WorkspaceNode;
 18    import org.jboss.cache.transaction.GlobalTransaction;
 19    import org.jboss.cache.transaction.TransactionEntry;
 20   
 21    /**
 22    * Locks nodes during transaction boundaries. Only affects prepare/commit/rollback method calls; other method calls
 23    * are simply passed up the interceptor stack.
 24    *
 25    * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 26    * @author <a href="mailto:stevew@jofti.com">Steve Woodcock (stevew@jofti.com)</a>
 27    */
 28    public class OptimisticLockingInterceptor extends OptimisticInterceptor
 29    {
 30    private long lockAcquisitionTimeout;
 31   
 32  842 public void setCache(CacheSPI cache)
 33    {
 34  842 super.setCache(cache);
 35  842 lockAcquisitionTimeout = cache.getConfiguration().getLockAcquisitionTimeout();
 36    }
 37   
 38  2107988 public Object invoke(InvocationContext ctx) throws Throwable
 39    {
 40  2107988 MethodCall m = ctx.getMethodCall();
 41  2107988 Object retval = null;
 42   
 43    //we are interested in the prepare/commit/rollback
 44    //this is irrespective of whether we are local or remote
 45  2107988 switch (m.getMethodId())
 46    {
 47  1127 case MethodDeclarations.optimisticPrepareMethod_id:
 48    //try and acquire the locks - before passing on
 49  1127 GlobalTransaction gtx = getGlobalTransaction(ctx);
 50  1127 try
 51    {
 52  1127 lockNodes(gtx);
 53    }
 54    catch (Throwable e)
 55    {
 56  0 log.debug("Caught exception attempting to lock nodes ", e);
 57    //we have failed - set to rollback and throw exception
 58  0 try
 59    {
 60  0 unlock(gtx);
 61    }
 62    catch (Throwable t)
 63    {
 64    // we have failed to unlock - now what?
 65  0 log.error("Failed to unlock nodes, after failing to lock nodes during a prepare! Locks are possibly in a very inconsistent state now!", t);
 66    }
 67  0 throw e;
 68    }
 69   
 70    // locks have acquired so lets pass on up
 71  1127 retval = super.invoke(ctx);
 72  1098 break;
 73  1052380 case MethodDeclarations.commitMethod_id:
 74  51 case MethodDeclarations.rollbackMethod_id:
 75    // we need to let the stack run its commits or rollbacks first -
 76    // we unlock last - even if an exception occurs
 77  1052431 try
 78    {
 79  1052431 retval = super.invoke(ctx);
 80    }
 81    finally
 82    {
 83  1052431 try
 84    {
 85  1052431 unlock(getGlobalTransaction(ctx));
 86    }
 87    catch (Exception e)
 88    {
 89    // we have failed to unlock - now what?
 90  0 log.error("Failed to unlock nodes after a commit or rollback! Locks are possibly in a very inconsistent state now!", e);
 91    }
 92    }
 93  1052431 break;
 94  0 case MethodDeclarations.lockMethodLocal_id:
 95    // bail out if _lock() is being called on the tree cache... this should never be called with o/l enabled.
 96  0 throw new CacheException("_lock() passed up the interceptor stack when Optimistic Locking is used. This is NOT supported.");
 97  1054430 default:
 98    //we do not care, just pass up the chain.
 99  1054430 retval = super.invoke(ctx);
 100  1054430 break;
 101    }
 102   
 103  2107959 return retval;
 104    }
 105   
 106    /**
 107    * Locks all nodes held in the transaction workspace registered with the given global transaction.
 108    *
 109    * @param gtx global transaction which contains a workspace
 110    */
 111  1127 private void lockNodes(GlobalTransaction gtx) throws InterruptedException
 112    {
 113  1127 TransactionWorkspace<?, ?> workspace = getTransactionWorkspace(gtx);
 114  0 if (log.isDebugEnabled()) log.debug("Locking nodes in transaction workspace for GlobalTransaction " + gtx);
 115   
 116  1127 for (WorkspaceNode workspaceNode : workspace.getNodes().values())
 117    {
 118  2863 NodeSPI node = workspaceNode.getNode();
 119  2863 boolean acquired = node.getLock().acquire(gtx, lockAcquisitionTimeout, NodeLock.LockType.WRITE);
 120  2863 if (acquired)
 121    {
 122  0 if (trace) log.trace("Acquired lock on node " + node.getFqn());
 123  2863 cache.getTransactionTable().addLock(gtx, node.getLock());
 124    }
 125    else
 126    {
 127  0 throw new CacheException("Unable to acquire lock on node " + node.getFqn());
 128    }
 129   
 130    }
 131    }
 132   
 133    /**
 134    * Releases all locks held by the specified global transaction.
 135    *
 136    * @param gtx which holds locks
 137    */
 138  1052431 private void unlock(GlobalTransaction gtx)
 139    {
 140  1052431 TransactionEntry entry = txTable.get(gtx);
 141  1052431 entry.releaseAllLocksFIFO(gtx);
 142    }
 143   
 144    }