Clover coverage report -
Coverage timestamp: Wed Jan 31 2007 15:38:53 EST
file stats: LOC: 289   Methods: 13
NCLOC: 228   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
ConcurrentBankTest.java 77.3% 86.4% 84.6% 84.8%
coverage coverage
 1    package org.jboss.cache.transaction;
 2   
 3    import junit.framework.Test;
 4    import junit.framework.TestCase;
 5    import junit.framework.TestSuite;
 6    import org.apache.commons.logging.Log;
 7    import org.apache.commons.logging.LogFactory;
 8    import org.jboss.cache.CacheException;
 9    import org.jboss.cache.CacheImpl;
 10    import org.jboss.cache.DefaultCacheFactory;
 11    import org.jboss.cache.factories.XmlConfigurationParser;
 12    import org.jboss.cache.lock.IsolationLevel;
 13    import org.jboss.cache.lock.TimeoutException;
 14    import org.jboss.cache.misc.TestingUtil;
 15   
 16    import javax.naming.Context;
 17    import javax.naming.InitialContext;
 18    import javax.transaction.UserTransaction;
 19    import java.util.HashMap;
 20    import java.util.Iterator;
 21    import java.util.Properties;
 22    import java.util.Set;
 23   
 24    /**
 25    * Unit test for local CacheImpl with concurrent transactions.
 26    * Uses locking and multiple threads to test concurrent r/w access to the tree.
 27    *
 28    * @author <a href="mailto:spohl@users.sourceforge.net">Stefan Pohl</a>
 29    * @author Ben Wang
 30    * @version $Revision: 1.9 $
 31    */
 32    public class ConcurrentBankTest extends TestCase
 33    {
 34    CacheImpl cache;
 35    private static Log logger_ = LogFactory.getLog(ConcurrentBankTest.class);
 36    static Properties p = null;
 37    String old_factory = null;
 38    final String FACTORY = "org.jboss.cache.transaction.DummyContextFactory";
 39    final String NODE = "/cachetest";
 40    final int ROLLBACK_CHANCE = 100;
 41   
 42    static String customer[] = {"cu1", "cu2", "cu3"};
 43    static final int BOOKINGS = 1000;
 44    static boolean _testFailedinThread = false;
 45   
 46  1 public ConcurrentBankTest(String name)
 47    {
 48  1 super(name);
 49    }
 50   
 51  0 public void failMain()
 52    {
 53  0 _testFailedinThread = true;
 54    }
 55   
 56  1 public void setUp() throws Exception
 57    {
 58  1 super.setUp();
 59  1 old_factory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
 60  1 System.setProperty(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
 61  1 DummyTransactionManager.getInstance();
 62  1 if (p == null)
 63    {
 64  1 p = new Properties();
 65  1 p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.cache.transaction.DummyContextFactory");
 66    }
 67   
 68  1 cache = (CacheImpl) DefaultCacheFactory.getInstance().createCache(false);
 69   
 70  1 cache.setConfiguration(new XmlConfigurationParser().parseFile("META-INF/local-lru-eviction-service.xml"));
 71   
 72    // XML file above only sets REPEATABLE-READ
 73  1 cache.getConfiguration().setIsolationLevel(IsolationLevel.SERIALIZABLE);
 74   
 75  1 cache.create();
 76  1 cache.start();
 77    }
 78   
 79  1 public void tearDown() throws Exception
 80    {
 81  1 super.tearDown();
 82  1 cache.stop();
 83    // BW. kind of a hack to destroy jndi binding and thread local tx before next run.
 84  1 DummyTransactionManager.destroy();
 85  1 if (old_factory != null)
 86    {
 87  0 System.setProperty(Context.INITIAL_CONTEXT_FACTORY, old_factory);
 88  0 old_factory = null;
 89    }
 90    }
 91   
 92  1 public void testConcurrentBooking()
 93    {
 94  1 Teller one, two;
 95  1 try
 96    {
 97  1 if (cache.get(NODE) == null)
 98    {
 99  1 cache.put(NODE, "cu1", 1000);
 100  1 cache.put(NODE, "cu2", 1000);
 101  1 cache.put(NODE, "cu3", 1000);
 102    }
 103   
 104  1 one = new Teller("one", cache);
 105  1 two = new Teller("two", cache);
 106   
 107  1 one.start();
 108  1 TestingUtil.sleepThread((long) 100);
 109  1 two.start();
 110  1 one.join();
 111  1 two.join();
 112   
 113  1 log("lock info:\n" + cache.printLockInfo() + _testFailedinThread);
 114  0 if (_testFailedinThread) fail();
 115    }
 116    catch (Exception e)
 117    {
 118  0 e.printStackTrace();
 119  0 fail(e.toString());
 120    }
 121    finally
 122    {
 123    /*
 124    try {
 125    cache.remove(NODE);
 126    } catch (Exception e) {
 127    e.printStackTrace();
 128    fail();
 129    }
 130    */
 131    }
 132    }
 133   
 134  10001 static void log(String msg)
 135    {
 136    // System.out.println("-- [" + Thread.currentThread() + "]: " + msg);
 137  10001 logger_.info("-- [" + Thread.currentThread() + "]: " + msg);
 138    }
 139   
 140  1 public static Test suite()
 141    {
 142  1 return new TestSuite(ConcurrentBankTest.class);
 143    }
 144   
 145  0 public static void main(String[] args)
 146    {
 147  0 junit.textui.TestRunner.run(suite());
 148    }
 149   
 150    class Teller extends Thread
 151    {
 152    CacheImpl cache;
 153   
 154  2 public Teller(String str, CacheImpl cache)
 155    {
 156  2 super(str);
 157  2 this.cache = cache;
 158    }
 159   
 160  2 public void run()
 161    {
 162  2 int count = customer.length;
 163  2 UserTransaction tx = null;
 164  2 try
 165    {
 166  2 tx = (UserTransaction) new InitialContext(p).lookup("UserTransaction");
 167   
 168  2 boolean again = false;
 169  2 int src = 0;
 170  2 int dst = 0;
 171  2 int amo = 0;
 172  2 int anz = 0;
 173  2 while (anz < BOOKINGS)
 174    {
 175  2000 if (!again)
 176    {
 177  1972 src = (int) (Math.random() * count);
 178  1972 dst = (int) (Math.random() * (count - 1));
 179  1972 amo = 1 + (int) (Math.random() * 20);
 180  1023 if (dst >= src) dst++;
 181    }
 182   
 183  2000 tx.begin();
 184  2000 HashMap accounts = getAccounts();// read lock on NODE
 185  2000 tx.commit();// releases read lock
 186   
 187  2000 int sum = sumAccounts(accounts);
 188  2000 log(anz + ": " + accounts + " Summe: " + sum);
 189    // the sum of all accounts always has to be 3000
 190  2000 if (sum != 3000)
 191    {
 192  0 failMain();
 193  0 return;// terminate thread
 194    }
 195  2000 assertEquals("the sum of all accounts always has to be 3000", 3000, sum);
 196   
 197  2000 try
 198    {
 199  2000 tx.begin();
 200  2000 deposit(customer[src], customer[dst], amo, tx);// gets write lock
 201  1972 tx.commit();// releases write lock
 202  1972 again = false;
 203    }
 204    catch (TimeoutException timeout_ex)
 205    {
 206  0 System.out.println("transaction is rolled back, will try again (ex=" + timeout_ex.getClass() + ")");
 207  0 tx.rollback();
 208  0 again = true;
 209    }
 210    catch (Throwable e)
 211    {
 212  28 System.out.println("transaction is rolled back, will try again (ex=" + e.getMessage() + ")");
 213  28 tx.rollback();
 214  28 again = true;
 215    }
 216  2000 anz++;
 217  2000 yield();
 218    }
 219    }
 220    catch (Throwable t)
 221    {
 222  0 t.printStackTrace();
 223  0 fail(t.toString());
 224    }
 225    }
 226   
 227    /**
 228    * Posting
 229    */
 230  2000 public void deposit(String from, String to, int amount, UserTransaction tx) throws Exception
 231    {
 232  2000 log("deposit(" + from + ", " + to + ", " + amount + ") called.");
 233  2000 int act;
 234    // debit
 235  2000 act = (Integer) cache.get(NODE, from);
 236  2000 cache.put(NODE, from, act - amount);
 237  2000 log("deposit(" + from + ", " + to + ", " + amount + ") debited.");
 238   
 239    // eventually rollback the transaction
 240  2000 if ((int) (Math.random() * ROLLBACK_CHANCE) == 0)
 241    {
 242  28 log("!!!manually set rollback (" + from + ", " + to + ", " + amount + ").");
 243  28 tx.setRollbackOnly();
 244  28 throw new Exception("Manually set rollback!");
 245    }
 246   
 247    // credit
 248  1972 act = (Integer) cache.get(NODE, to);
 249  1972 cache.put(NODE, to, act + amount);
 250   
 251  1972 log("deposit(" + from + ", " + to + ", " + amount + ") finished.");
 252    }
 253   
 254    /**
 255    * retrieving amounts of accounts
 256    */
 257  2000 public HashMap getAccounts() throws CacheException
 258    {
 259  2000 log("getAccounts() called.");
 260  2000 HashMap result = new HashMap();
 261  2000 try
 262    {
 263  2000 Set set = cache.getKeys(NODE);// gets read lock
 264  2000 Iterator iter = set.iterator();
 265  2000 while (iter.hasNext())
 266    {
 267  6000 String name = (String) iter.next();
 268  6000 result.put(name, cache.get(NODE, name));
 269    }
 270  2000 return result;
 271    }
 272    catch (CacheException ce)
 273    {
 274  0 throw ce;
 275    }
 276    }
 277   
 278  2000 protected int sumAccounts(HashMap map)
 279    {
 280  2000 Iterator iter = map.values().iterator();
 281  2000 int result = 0;
 282  2000 while (iter.hasNext())
 283    {
 284  6000 result += (Integer) iter.next();
 285    }
 286  2000 return result;
 287    }
 288    }
 289    }