/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Created on Oct 1, 2007 */ package com.bigdata.concurrent; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.apache.log4j.Logger; import com.bigdata.util.DaemonThreadFactory; /** * basic unit tests. * * FIXME Verify interaction with the writeService. The runnable target should * not complete until after the commit (should be ok). * * @todo test to verify that we can cancel a running task using its * {@link Future}. * * @todo test cancellation of the task using get() w/ timeout (or get rid of the * lock timeout). * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class TestNonBlockingLockManager extends TestCase { protected static final Logger log = Logger.getLogger(TestNonBlockingLockManager.class); protected static final boolean INFO = log.isInfoEnabled(); protected static final boolean DEBUG = log.isDebugEnabled(); /** * */ public TestNonBlockingLockManager() { super(); } public TestNonBlockingLockManager(String name) { super(name); } /** * Waits 10ms once it acquires its locks. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public static class Wait10ResourceTask<T> implements Callable<T> { public T call() throws Exception { // if (INFO) // log.info("Executing: "+this); synchronized (this) { try { if (DEBUG) log.debug("Waiting: "+this); wait(10/* milliseconds */); // if (INFO) // log.info("Done waiting: "+this); } catch (InterruptedException e) { throw new RuntimeException(e); } } // if (INFO) // log.info("Done: "+this); return null; } } /** * Dies once it acquires its locks by throwing {@link HorridTaskDeath}. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ static class DeathResourceTask<T> implements Callable<T> { public T call() throws Exception { if(DEBUG) log.debug("Arrgh!"); throw new HorridTaskDeath(); } } /** * Mock executor used by a few unit tests optionally wraps a real * {@link Executor}. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ private class MockExecutor implements Executor { final Executor delegate; public MockExecutor(Executor delegate) { this.delegate = delegate; } public void execute(final Runnable arg0) { if (INFO) log.info("Executing: " + arg0); if (delegate == null) { throw new AssertionFailedError( "Not expecting task (no delegate): " + arg0); } delegate.execute(arg0); if (INFO) log.info("Executed: " + arg0); } } /** * Test startup and fast shutdown. * * @throws InterruptedException * @throws ExecutionException */ public void test_shutdownNow() throws InterruptedException, ExecutionException { final NonBlockingLockManager<String> service = new NonBlockingLockManager<String>( 10/* maxConcurrency */, true/* predeclareLocks */, new MockExecutor(null/*delegate*/)); try { assertTrue(service.isOpen()); } finally { assertFalse(service.isShutdown()); service.shutdownNow(); assertTrue(service.isShutdown()); } } /** * Test startup and normal shutdown. * * @throws InterruptedException * @throws ExecutionException */ public void test_shutdown() throws InterruptedException, ExecutionException { final NonBlockingLockManager<String> service = new NonBlockingLockManager<String>( 10/* maxConcurrency */, true/* predeclareLocks */, new MockExecutor(null/*delegate*/)); try { assertTrue(service.isOpen()); } finally { assertFalse(service.isShutdown()); service.shutdown(); assertTrue(service.isShutdown()); } } // /** // * Test startup that runs the service for a bit so you can verify that it is // * not sucking down the CPU. // * // * @throws InterruptedException // * @throws ExecutionException // * // * @todo this does not test anything and should be removed. // */ // public void test_running() throws InterruptedException, ExecutionException { // // final NonBlockingLockManager<String> service = new NonBlockingLockManager<String>( // 10/* maxConcurrency */, true/* predeclareLocks */, // new MockExecutor(null/*delegate*/)); // // try { // // assertTrue(service.isOpen()); // // Thread.sleep(5000/* ms */); // // } finally { // // assertFalse(service.isShutdown()); // // service.shutdown(); // // assertTrue(service.isShutdown()); // // } // // } /** * Test ability to run a {@link Callable} on the service, get() the result, * and then shutdown the service. * * @throws InterruptedException * @throws ExecutionException */ public void test_run1() throws InterruptedException, ExecutionException { final ExecutorService delegate = Executors .newCachedThreadPool(new DaemonThreadFactory(getClass() .getName())); final NonBlockingLockManager<String> service = new NonBlockingLockManager<String>( 10/* maxConcurrency */, true/* predeclareLocks */, new MockExecutor(delegate)); try { final String expected = "a"; final Future<String> f = service.submit(new String[0], new Callable<String>(){ public String call() throws Exception { return expected; } }); assertEquals(expected,f.get()); } finally { service.shutdownNow(); delegate.shutdownNow(); } } /** * Test ability to obtain a lock, run a {@link Callable} on the service, * get() the result, and then shutdown the service. * * @throws InterruptedException * @throws ExecutionException */ public void test_run1WithLock() throws InterruptedException, ExecutionException { final ExecutorService delegate = Executors .newCachedThreadPool(new DaemonThreadFactory(getClass() .getName())); final NonBlockingLockManager<String> service = new NonBlockingLockManager<String>( 10/* maxConcurrency */, true/* predeclareLocks */, new MockExecutor(delegate)); try { final String expected = "a"; final Future<String> f = service.submit(new String[] { "test" }, new Callable<String>() { public String call() throws Exception { return expected; } }); assertEquals(expected, f.get()); } finally { service.shutdownNow(); delegate.shutdownNow(); } } // /** // * Unit test verifies that {@link TxDag} can resolve a // * {@link LockFutureTask} in its internal "mapping" table. This is designed // * to detect problems with hashCode() and equals() as they relate to // * {@link TxDag}. // */ // public void test_txDagLookup() { // // final MockNonBlockingLockManager<String> service = new MockNonBlockingLockManager<String>( // 2/* maxConcurrency */, false/* predeclareLocks */, // new MockExecutor(null)); // // try { // // final TxDag txDag = service.getWaitsFor(); // // final NonBlockingLockManager<String>.LockFutureTask<Void> t1 = service.newFutureTask( // new String[] { "a" }, new Callable<Void>() { // public Void call() throws Exception { // return null; // } // }); // // final NonBlockingLockManager<String>.LockFutureTask<Void> t2 = service.newFutureTask( // new String[] { "a" }, new Callable<Void>() { // public Void call() throws Exception { // return null; // } // }); // // assertEquals(0,txDag.size()); // txDag.addEdge(t1, t2); // t1 WAITS_FOR t2 // assertEquals(2,txDag.size()); // txDag.removeEdges(t1, true/*waiting*/); //// txDag.removeEdge(t1, t2); //// txDag.releaseVertex(t1); //// txDag.releaseVertex(t2); // assertEquals(0,txDag.size()); // // } finally { // // service.shutdownNow(); // // } // // } // // /** // * Class exposes a factory for {@link LockFutureTask} objects. // * // * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> // * @version $Id$ // * @param <R> // */ // static class MockNonBlockingLockManager<R extends Comparable<R>> extends // NonBlockingLockManager<R> { // // public MockNonBlockingLockManager(int maxConcurrency, // boolean predeclareLocks, Executor delegate) { // // super(maxConcurrency, predeclareLocks, delegate); // // } // // TxDag getWaitsFor() { // // return waitsFor; // // } // // <T> LockFutureTask<T> newFutureTask(R[] resources, // final Callable<T> task) { // // return new LockFutureTask<T>(resources, task, // Long.MAX_VALUE/* timeout */, 3/* maxLockTries */); // // } // // } }