Author: ozeigermann Date: Fri Aug 17 18:37:46 2007 New Revision: 567198 URL: http://svn.apache.org/viewvc?view=rev&rev=567198 Log: Completed initial tests (not all complete successfully, yet)
Added: commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/locking/ commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/locking/LockTest.java Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/BasicTxMapTest.java Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java?view=diff&rev=567198&r1=567197&r2=567198 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java Fri Aug 17 18:37:46 2007 @@ -22,7 +22,7 @@ */ public class MemoryUndoManager implements FileResourceUndoManager { - private Log logger = LogFactory.getLog(getClass()); + private Log log = LogFactory.getLog(getClass()); protected ThreadLocal<List<UndoRecord>> localRecords = new ThreadLocal<List<UndoRecord>>(); @@ -68,7 +68,7 @@ moveAllowed)); } catch (IOException e) { // FIXME: This really is fatal: How to signal? - logger.fatal("Can not record content update", e); + log.fatal("Can not record content update", e); } } @@ -124,7 +124,7 @@ FileHelper.move(updatedFile, file); } catch (IOException e) { // FIXME: This really is fatal: How to signal? - logger.fatal("Can not undo content update", e); + log.fatal("Can not undo content update", e); } break; } Modified: commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java?view=diff&rev=567198&r1=567197&r2=567198 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java Fri Aug 17 18:37:46 2007 @@ -18,23 +18,56 @@ import static junit.framework.Assert.fail; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.util.concurrent.TimeUnit; import junit.framework.JUnit4TestAdapter; +import static junit.framework.Assert.*; +import org.junit.Test; import org.apache.commons.transaction.file.FileResourceManager.FileResource; -import org.junit.Test; +import org.apache.commons.transaction.util.FileHelper; +import org.apache.commons.transaction.util.RendezvousBarrier; public class TxFileResourceManagerTest { - + private static final String ENCODING = "ISO-8859-15"; + // XXX INCREASE THIS WHEN DEBUGGING OTHERWISE THE BARRIER WILL TIME OUT + // AFTER TWO SECONDS + // MOST LIKELY CONFUSING YOU COMPLETELY + private static final long BARRIER_TIMEOUT = 200000; + + private static final String rootPath = "d:/tmp/content"; + + private static final String tmpDir = "d:/tmp/txlogs"; + + private static String msg; + + private static void reset() { + removeRec(rootPath); + removeRec(tmpDir); + } + + private static final String[] INITIAL_FILES = new String[] { rootPath + "/olli/Hubert6", + rootPath + "/olli/Hubert" }; + + private static void removeRec(String dirPath) { + FileHelper.removeRecursive(new File(dirPath)); + } + + private static void createInitialFiles() { + createFiles(INITIAL_FILES); + } + public static junit.framework.Test suite() { return new JUnit4TestAdapter(TxFileResourceManagerTest.class); } @@ -43,6 +76,13 @@ junit.textui.TestRunner.run(suite()); } + // XXX need this, as JUnit seems to print only part of these strings + private static void report(String should, String is) { + if (!is.equals(should)) { + fail("\nWrong output:\n'" + is + "'\nShould be:\n'" + should + "'\n"); + } + } + private static final void createFiles(String[] filePaths) { createFiles(filePaths, null, null); } @@ -85,6 +125,7 @@ private static final void checkIsEmpty(String dirPath) { checkExactlyContains(dirPath, null); } + private static final void checkExactlyContains(String dirPath, String[] fileNames) { checkExactlyContains(dirPath, fileNames, null); } @@ -173,13 +214,13 @@ @Test public void basic() { - TxFileResourceManager manager = new TxFileResourceManager("TxFileManager", "d:/tmp/content"); + TxFileResourceManager manager = new TxFileResourceManager("TxFileManager", rootPath); FileResourceUndoManager um; try { - um = new MemoryUndoManager("d:/tmp/txlogs"); + um = new MemoryUndoManager(tmpDir); manager.setUndoManager(um); manager.startTransaction(60, TimeUnit.SECONDS); - FileResource file = manager.getResource("d:/tmp/content/aha"); + FileResource file = manager.getResource(rootPath + "/aha"); if (!file.exists()) { file.createAsFile(); } @@ -193,5 +234,123 @@ } } - + + @Test + public void global() throws Throwable { + reset(); + createInitialFiles(); + + final TxFileResourceManager rm = new TxFileResourceManager("TxFileManager", rootPath); + FileResourceUndoManager um; + um = new MemoryUndoManager(tmpDir); + rm.setUndoManager(um); + + final RendezvousBarrier shutdownBarrier = new RendezvousBarrier("Shutdown", 3, + BARRIER_TIMEOUT); + final RendezvousBarrier start2Barrier = new RendezvousBarrier("Start2", BARRIER_TIMEOUT); + final RendezvousBarrier commit1Barrier = new RendezvousBarrier("Commit1", BARRIER_TIMEOUT); + + Thread create = new Thread(new Runnable() { + public void run() { + try { + rm.startTransaction(60, TimeUnit.SECONDS); + + shutdownBarrier.call(); + start2Barrier.call(); + + rm.getResource(rootPath + "/olli/Hubert4").createAsFile(); + rm.getResource(rootPath + "/olli/Hubert5").createAsFile(); + msg = "Greetings from " + Thread.currentThread().getName() + "\n"; + OutputStream out = rm.getResource(rootPath + "/olli/Hubert6") + .writeStream(false); + out.write(msg.getBytes(ENCODING)); + + commit1Barrier.meet(); + + rm.commitTransaction(); + + checkExactlyContains(rootPath + "/olli", new String[] { "Hubert", "Hubert4", + "Hubert5", "Hubert6" }, new String[] { "", "", "", msg }); + + } catch (Throwable e) { + System.err.println("Error: " + e); + e.printStackTrace(); + } + } + }, "Create Thread"); + + Thread modify = new Thread(new Runnable() { + public void run() { + Object txId = null; + try { + + { + InputStream in = rm.getResource(rootPath + "/olli/Hubert6").readStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in, + ENCODING)); + String line = reader.readLine(); + assertEquals(line, null); + in.close(); + } + + txId = "Modify"; + rm.startTransaction(60, TimeUnit.SECONDS); + + { + InputStream in = rm.getResource(rootPath + "/olli/Hubert6").readStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in, + ENCODING)); + String line = reader.readLine(); + assertEquals(line, null); + in.close(); + } + + shutdownBarrier.call(); + + rm.getResource(rootPath + "/olli/Hubert1").createAsFile(); + rm.getResource(rootPath + "/olli/Hubert2").createAsFile(); + rm.getResource(rootPath + "/olli/Hubert3").createAsFile(); + + // wait until tx commits, so there already are Hubert4 and + // Hubert5 and + // Hubert6 changes + commit1Barrier.meet(); + + rm.getResource(rootPath + "/olli/Hubert4").createAsFile(); + rm.getResource(rootPath + "/olli/Hubert5").createAsFile(); + rm.getResource(rootPath + "/olli/Hubert6").createAsFile(); + InputStream in = rm.getResource(rootPath + "/olli/Hubert6").readStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in, ENCODING)); + String line = reader.readLine(); + // allow for update while in tx as this is READ_COMMITED + report(msg, line); + in.close(); + + + rm.getResource(rootPath + "/olli/Hubert").delete(); + rm.getResource(rootPath + "/olli/Hubert2").delete(); + rm.getResource(rootPath + "/olli/Hubert3").delete(); + rm.getResource(rootPath + "/olli/Hubert4").delete(); + rm.getResource(rootPath + "/olli/Hubert5").delete(); + + rm.commitTransaction(); + } catch (Throwable e) { + System.err.println("Error: " + e); + e.printStackTrace(); + } + } + }, "Modify Thread"); + + create.start(); + // be sure first thread is started before trying next + start2Barrier.meet(); + modify.start(); + + // let both transaction start before trying to shut down + shutdownBarrier.meet(); + + checkExactlyContains(rootPath + "/olli", new String[] { "Hubert1", "Hubert6" }, + new String[] { "", msg }); + } + } Added: commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/locking/LockTest.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/locking/LockTest.java?view=auto&rev=567198 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/locking/LockTest.java (added) +++ commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/locking/LockTest.java Fri Aug 17 18:37:46 2007 @@ -0,0 +1,719 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.transaction.locking; + +import java.io.PrintWriter; +import java.util.concurrent.TimeUnit; + +import junit.framework.JUnit4TestAdapter; +import static junit.framework.Assert.*; +import org.junit.Test; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.transaction.file.TxFileResourceManagerTest; +import org.apache.commons.transaction.util.RendezvousBarrier; +import org.apache.commons.transaction.util.TurnBarrier; + +/** + * Tests for locking. + * + */ +public class LockTest { + + private Log log = LogFactory.getLog(getClass()); + + private static final int CONCURRENT_TESTS = 25; + + protected static final long TIMEOUT = 1000000; + + private static int deadlockCnt = 0; + + private static String first = null; + + private static String defaultResource = "resource"; + + public static junit.framework.Test suite() { + return new JUnit4TestAdapter(TxFileResourceManagerTest.class); + } + + public static void main(java.lang.String[] args) { + junit.textui.TestRunner.run(suite()); + } + + @Test + public void deadlock() throws Throwable { + + log.info("\n\nChecking deadlock detection\n\n"); + + final String res1 = "res1"; + final String res2 = "res2"; + + final RWLockManager<Object, Object> manager = new RWLockManager<Object, Object>(); + + final RendezvousBarrier restart = new RendezvousBarrier("restart", TIMEOUT); + + for (int i = 0; i < CONCURRENT_TESTS; i++) { + + System.out.print("."); + + final RendezvousBarrier deadlockBarrier1 = new RendezvousBarrier("deadlock1" + i, + TIMEOUT); + + Thread deadlock = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10, TimeUnit.SECONDS); + // first both threads get a lock, this one on res2 + manager.lock(defaultResource, res2, true); + synchronized (deadlockBarrier1) { + deadlockBarrier1.meet(); + deadlockBarrier1.reset(); + } + // if I am first, the other thread will be dead, i.e. + // exactly one + manager.lock(defaultResource, res1, true); + } catch (LockException le) { + assertEquals(le.getCode(), LockException.Code.WOULD_DEADLOCK); + deadlockCnt++; + } catch (InterruptedException ie) { + } finally { + manager.endWork(); + try { + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } catch (InterruptedException ie) { + } + } + } + }, "Deadlock Thread"); + + deadlock.start(); + + try { + manager.startWork(10, TimeUnit.SECONDS); + // first both threads get a lock, this one on res2 + manager.lock(defaultResource, res1, false); + synchronized (deadlockBarrier1) { + deadlockBarrier1.meet(); + deadlockBarrier1.reset(); + } + // if I am first, the other thread will be dead, i.e. exactly + // one + manager.lock(defaultResource, res2, true); + } catch (LockException le) { + assertEquals(le.getCode(), LockException.Code.WOULD_DEADLOCK); + deadlockCnt++; + } finally { + manager.endWork(); + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } + + // XXX in special scenarios the current implementation might cause + // both + // owners to be deadlock victims + if (deadlockCnt != 1) { + log.warn("More than one thread was deadlock victim!"); + } + assertTrue(deadlockCnt >= 1); + deadlockCnt = 0; + } + } + + /* + * + * Test detection of an indirect deadlock: + * + * Owner Owner Owner Step #1 #2 #3 1 read res1 (ok) 2 read res2 (ok) 3 read + * res3 (ok) 4 write res2 (blocked because of #2) 5 write res1 (blocked + * because of #1) 6 write res3 (blocked because #3) - Thread#1 waits for + * Thread#3 on res3 - Thread#2 waits for Thread#1 on res1 - Thread#3 waits + * for Thread#2 on res2 + * + * This needs recursion of the deadlock detection algorithm + * + */ + @Test + public void indirectDeadlock() throws Throwable { + + log.info("\n\nChecking detection of indirect deadlock \n\n"); + + final String res1 = "res1"; + final String res2 = "res2"; + final String res3 = "res3"; + + final RWLockManager<Object, Object> manager = new RWLockManager<Object, Object>(); + + final RendezvousBarrier restart = new RendezvousBarrier("restart", 5, TIMEOUT); + + final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, 1); + + for (int i = 0; i < CONCURRENT_TESTS; i++) { + + System.out.print("."); + + // thread that accesses lock of res1 just to cause interference and + // possibly detect concurrency problems + Thread jamThread1 = new Thread(new Runnable() { + public void run() { + try { + for (int i = 0; i < 10; i++) { + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + Thread.sleep(10); + manager.endWork(); + Thread.sleep(10); + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, true); + Thread.sleep(10); + manager.endWork(); + Thread.sleep(10); + } + } catch (LockException le) { + fail("Jam Thread should not fail"); + } catch (InterruptedException ie) { + } finally { + manager.endWork(); + synchronized (restart) { + try { + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } catch (InterruptedException ie) { + } + } + } + } + }, "Jam Thread #1"); + + jamThread1.start(); + + // thread that accesses lock of res1 just to cause interference and + // possibly detect concurrency problems + Thread jamThread2 = new Thread(new Runnable() { + public void run() { + try { + for (int i = 0; i < 10; i++) { + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, true); + Thread.sleep(10); + manager.endWork(); + manager.startWork(10, TimeUnit.SECONDS); + Thread.sleep(10); + manager.lock(defaultResource, res1, false); + Thread.sleep(10); + manager.endWork(); + Thread.sleep(10); + } + } catch (LockException le) { + fail("Jam Thread should not fail"); + } catch (InterruptedException ie) { + } finally { + manager.endWork(); + synchronized (restart) { + try { + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } catch (InterruptedException ie) { + } + } + } + } + }, "Jam Thread #2"); + + jamThread2.start(); + + Thread t1 = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10, TimeUnit.SECONDS); + cb.waitForTurn(2); + manager.lock(defaultResource, res2, false); + cb.signalTurn(3); + cb.waitForTurn(5); + synchronized (cb) { + cb.signalTurn(6); + manager.lock(defaultResource, res1, true); + } + } catch (LockException le) { + assertEquals(le.getCode(), LockException.Code.WOULD_DEADLOCK); + deadlockCnt++; + } catch (InterruptedException ie) { + } finally { + manager.endWork(); + synchronized (restart) { + try { + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } catch (InterruptedException ie) { + } + } + } + } + }, "Thread #1"); + + t1.start(); + + Thread t2 = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10, TimeUnit.SECONDS); + cb.waitForTurn(3); + manager.lock(defaultResource, res3, false); + synchronized (cb) { + cb.signalTurn(5); + manager.lock(defaultResource, res2, true); + } + } catch (LockException le) { + assertEquals(le.getCode(), LockException.Code.WOULD_DEADLOCK); + deadlockCnt++; + } catch (InterruptedException ie) { + } finally { + manager.endWork(); + synchronized (restart) { + try { + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } catch (InterruptedException ie) { + } + } + } + } + }, "Thread #2"); + + t2.start(); + + try { + manager.startWork(10, TimeUnit.SECONDS); + cb.waitForTurn(1); + manager.lock(defaultResource, res1, false); + cb.signalTurn(2); + cb.waitForTurn(6); + manager.lock(defaultResource, res3, true); + } catch (LockException le) { + assertEquals(le.getCode(), LockException.Code.WOULD_DEADLOCK); + deadlockCnt++; + } catch (InterruptedException ie) { + } finally { + manager.endWork(); + synchronized (restart) { + try { + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } catch (InterruptedException ie) { + } + } + } + + // XXX in special scenarios the current implementation might cause + // more than one + // owner to be a deadlock victim + if (deadlockCnt != 1) { + log.warn("\nMore than one thread was deadlock victim!\n"); + } + assertTrue(deadlockCnt >= 1); + deadlockCnt = 0; + cb.reset(); + } + } + + @Test + public void globalTimeout() throws Throwable { + + log.info("\n\nChecking global timeouts\n\n"); + + final String owner1 = "owner1"; + final String owner2 = "owner2"; + + final String res1 = "res1"; + + final RWLockManager<Object, Object> manager = new RWLockManager<Object, Object>(); + + final RendezvousBarrier restart = new RendezvousBarrier("restart", 2, TIMEOUT); + + final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, 1); + + for (int i = 0; i < CONCURRENT_TESTS; i++) { + + System.out.print("."); + + Thread t1 = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10, TimeUnit.SECONDS); + cb.waitForTurn(2); + manager.lock(defaultResource, res1, false); + cb.signalTurn(3); + manager.endWork(); + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } catch (InterruptedException ie) { + } + } + }, "Thread #1"); + + t1.start(); + + cb.waitForTurn(1); + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + cb.signalTurn(2); + cb.waitForTurn(3); + boolean failed = false; + try { + manager.tryLock(defaultResource, res1, false); + } catch (LockException le) { + failed = true; + } + assertTrue(failed); + manager.endWork(); + failed = false; + manager.startWork(10, TimeUnit.SECONDS); + try { + manager.tryLock(defaultResource, res1, false); + } catch (LockException le) { + failed = true; + } + assertFalse(failed); + manager.endWork(); + synchronized (restart) { + restart.meet(); + restart.reset(); + } + + cb.reset(); + } + + } + + @Test + public void stress() throws Throwable { + + log.info("\n\nStress checking locks\n\n"); + + final String res1 = "res1"; + final String res2 = "res2"; + final String res3 = "res3"; + + final RWLockManager<Object, Object> manager = new RWLockManager<Object, Object>(); + + final RendezvousBarrier restart = new RendezvousBarrier("restart", 5, TIMEOUT); + final RendezvousBarrier start = new RendezvousBarrier("start", 5, TIMEOUT); + + for (int i = 0; i < CONCURRENT_TESTS; i++) { + + System.out.print("."); + + Thread t1 = new Thread(new Runnable() { + public void run() { + try { + try { + synchronized (start) { + start.meet(); + start.reset(); + } + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, true); + } catch (LockException ie) { + } finally { + manager.endWork(); + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } + } catch (InterruptedException ie) { + } + } + }, "Thread #1"); + t1.start(); + + Thread t2 = new Thread(new Runnable() { + public void run() { + try { + try { + synchronized (start) { + start.meet(); + start.reset(); + } + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, true); + } catch (LockException ie) { + } finally { + manager.endWork(); + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } + } catch (InterruptedException ie) { + } + } + }, "Thread #2"); + t2.start(); + + Thread t3 = new Thread(new Runnable() { + public void run() { + try { + try { + synchronized (start) { + start.meet(); + start.reset(); + } + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, true); + } catch (LockException ie) { + } finally { + manager.endWork(); + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } + } catch (InterruptedException ie) { + } + } + }, "Thread #3"); + t3.start(); + + Thread t4 = new Thread(new Runnable() { + public void run() { + try { + try { + synchronized (start) { + start.meet(); + start.reset(); + } + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, true); + } catch (LockException ie) { + } finally { + manager.endWork(); + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } + } catch (InterruptedException ie) { + } + } + }, "Thread #4"); + t4.start(); + + try { + try { + synchronized (start) { + start.meet(); + start.reset(); + } + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, false); + } catch (LockException ie) { + } finally { + manager.endWork(); + try { + synchronized (restart) { + restart.meet(); + restart.reset(); + } + } catch (InterruptedException ie) { + } + } + } catch (InterruptedException ie) { + } + } + + } + + @Test + public void choas() throws Throwable { + + log.info("\n\nChaos testing locks for internal deadlocks resp. concurrent mods\n\n"); + + final String res1 = "res1"; + final String res2 = "res2"; + final String res3 = "res3"; + + final RWLockManager<Object, Object> manager = new RWLockManager<Object, Object>(); + + int concurrentThreads = 7; + int threads = CONCURRENT_TESTS * concurrentThreads; + + final RendezvousBarrier end = new RendezvousBarrier("end", threads + 1, TIMEOUT); + + log.info("\n\nStarting " + threads + " threads\n\n"); + + for (int i = 0; i < CONCURRENT_TESTS; i++) { + + final int cnt = i; + + System.out.print("."); + + Thread t1 = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, true); + } catch (LockException ie) { + System.out.print("-"); + } finally { + manager.endWork(); + end.call(); + } + } + }, "Thread #1"); + + Thread t2 = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, true); + } catch (LockException ie) { + System.out.print("-"); + } finally { + manager.endWork(); + end.call(); + } + } + }, "Thread #2"); + + Thread t3 = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10 + cnt, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, true); + } catch (LockException le) { + if (le.getCode() == LockException.Code.TIMED_OUT) { + System.out.print("*"); + } else { + System.out.print("-"); + } + } finally { + manager.endWork(); + end.call(); + } + } + }, "Thread #3"); + + Thread t4 = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, true); + } catch (LockException le) { + System.out.print("-"); + } finally { + manager.endWork(); + end.call(); + } + } + }, "Thread #4"); + + Thread deadlock1 = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res2, true); + manager.lock(defaultResource, res1, true); + } catch (LockException le) { + assertEquals(le.getCode(), LockException.Code.WOULD_DEADLOCK); + System.out.print("-"); + } finally { + manager.endWork(); + end.call(); + } + } + }, "Deadlock1 Thread"); + + Thread deadlock2 = new Thread(new Runnable() { + public void run() { + try { + manager.startWork(10, TimeUnit.SECONDS); + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + } catch (LockException le) { + assertEquals(le.getCode(), LockException.Code.WOULD_DEADLOCK); + System.out.print("-"); + } finally { + manager.endWork(); + end.call(); + } + } + }, "Deadlock1 Thread"); + + Thread reader = new Thread(new Runnable() { + public void run() { + try { + manager.lock(defaultResource, res1, false); + manager.lock(defaultResource, res2, false); + manager.lock(defaultResource, res3, false); + } catch (LockException ie) { + System.out.print("-"); + } finally { + manager.endWork(); + end.call(); + } + } + }, "Reader Thread"); + + t4.start(); + t3.start(); + reader.start(); + t1.start(); + deadlock2.start(); + t2.start(); + deadlock1.start(); + } + // wait until all threads have really terminated + end.meet(); + + } +} Modified: commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/BasicTxMapTest.java URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/BasicTxMapTest.java?view=diff&rev=567198&r1=567197&r2=567198 ============================================================================== --- commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/BasicTxMapTest.java (original) +++ commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/BasicTxMapTest.java Fri Aug 17 18:37:46 2007 @@ -33,7 +33,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.commons.transaction.locking.LockManager; import org.apache.commons.transaction.util.RendezvousBarrier; /**