/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.optimistic;

import junit.framework.Assert;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.TreeCache;

import javax.transaction.TransactionManager;

/**
 * Tests multiple thread access on opt locked cache
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 */
public class ThreadedCacheAccessTest extends AbstractOptimisticTestCase
{
    private static final Log log = LogFactory.getLog(ThreadedCacheAccessTest.class);
    // 5 concurrent threads.
    private final int numThreads = 5;
    // how many times each thread loops
    private final int numLoopsPerThread = 25;
    // write frequency.  1 in writeFrequency loops will do a put().
    private final int writeFrequency = 5;
    // random sleep params (ms)
    private final int minSleep = 0, maxSleep = 100;

    private final Fqn fqn = Fqn.fromString("/a/b");
    private final String key = "key", value = "value";

    private TreeCache cache;

    public ThreadedCacheAccessTest(String name)
    {
        super(name);
    }

    public void testThreadedMostlyReads() throws Exception
    {
        cache = createCache();
        // write some stuff into the cache.

        cache.put(fqn, key, value);

        WorkerThread[] threads = new WorkerThread[ numThreads ];

        for (int i = 0; i < numThreads; i++)
        {
            threads[i] = new WorkerThread();
            threads[i].start();
        }

        for (int i = 0; i < numThreads; i++)
        {
            threads[i].join();
        }

        // test results.
        for (int i = 0; i < numThreads; i++)
        {
            Assert.assertTrue("Thread threw an exception!", threads[i].success);
        }
    }

    public class WorkerThread extends Thread
    {
        public boolean success = true;

        public void run()
        {
            log.debug(getName() + " starting up ... ");
            for (int j = 0; j < numLoopsPerThread; j++)
            {
                TransactionManager tm = cache.getTransactionManager();
                try
                {
                    tm.begin();
                    // read something from the cache - it should be in it's own thread.
                    cache.get(fqn, key);
                    if (j % writeFrequency == 0)
                    {
                        cache.put(fqn, key, value + j);
                    }
                    tm.commit();
                }
                catch (Exception e)
                {
                    log.error("Caught Exception!", e);
                    Assert.assertTrue("Caught Exception!", false);
                    success = false;
                    try
                    {
                        tm.rollback();
                    }
                    catch (Exception e2)
                    {
                        log.error("Rollback failed!", e2);
                    }
                    break;
                }
                randomSleep(minSleep, maxSleep);
            }
        }
    }
}
