ozeigermann 2005/01/08 10:56:03
Modified: transaction/src/test/org/apache/commons/transaction/locking
GenericLockTest.java
Log:
Added tests for indirect deadlocks and mean chaos test with many threads
Revision Changes Path
1.11 +317 -6
jakarta-commons/transaction/src/test/org/apache/commons/transaction/locking/GenericLockTest.java
Index: GenericLockTest.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/transaction/src/test/org/apache/commons/transaction/locking/GenericLockTest.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- GenericLockTest.java 7 Jan 2005 12:41:58 -0000 1.10
+++ GenericLockTest.java 8 Jan 2005 18:56:03 -0000 1.11
@@ -224,13 +224,160 @@
}
}
- assertEquals(1, deadlockCnt);
+ // XXX in special scenarios the current implementation might
cause both
+ // owners to be deadlock victims
+ if (deadlockCnt != 1) {
+ sLogger.logWarning("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
+ *
+ */
+ public void testIndirectDeadlock() throws Throwable {
+
+ sLogger.logInfo("\n\nChecking detection of indirect deadlock \n\n");
+
+ final String owner1 = "owner1";
+ final String owner2 = "owner2";
+ final String owner3 = "owner3";
+
+ final String res1 = "res1";
+ final String res2 = "res2";
+ final String res3 = "res3";
+
+ // a read / write lock
+ final ReadWriteLockManager manager = new
ReadWriteLockManager(sLogger,
+ TIMEOUT);
+
+ final RendezvousBarrier restart = new RendezvousBarrier("restart",
3, TIMEOUT, sLogger);
+
+ final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger, 1);
+
+ for (int i = 0; i < CONCURRENT_TESTS; i++) {
+
+ System.out.print(".");
+
+ Thread t1 = new Thread(new Runnable() {
+ public void run() {
+ try {
+ cb.waitForTurn(2);
+ manager.readLock(owner2, res2);
+ cb.signalTurn(3);
+ cb.waitForTurn(5);
+ synchronized (manager.getLock(res1)) {
+ cb.signalTurn(6);
+ manager.writeLock(owner2, res1);
+ }
+ } catch (LockException le) {
+ assertEquals(le.getCode(),
LockException.CODE_DEADLOCK_VICTIM);
+ deadlockCnt++;
+ } catch (InterruptedException ie) {
+ } finally {
+ manager.releaseAll(owner2);
+ 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 {
+ cb.waitForTurn(3);
+ manager.readLock(owner3, res3);
+ synchronized (manager.getLock(res2)) {
+ cb.signalTurn(5);
+ manager.writeLock(owner3, res2);
+ }
+ } catch (LockException le) {
+ assertEquals(le.getCode(),
LockException.CODE_DEADLOCK_VICTIM);
+ deadlockCnt++;
+ } catch (InterruptedException ie) {
+ } finally {
+ manager.releaseAll(owner3);
+ synchronized (restart) {
+ try {
+ synchronized (restart) {
+ restart.meet();
+ restart.reset();
+ }
+ } catch (InterruptedException ie) {}
+ }
+ }
+ }
+ }, "Thread #2");
+
+ t2.start();
+
+ try {
+ cb.waitForTurn(1);
+ manager.readLock(owner1, res1);
+ cb.signalTurn(2);
+ cb.waitForTurn(6);
+ manager.writeLock(owner1, res3);
+ } catch (LockException le) {
+ assertEquals(le.getCode(),
LockException.CODE_DEADLOCK_VICTIM);
+ deadlockCnt++;
+ } catch (InterruptedException ie) {
+ } finally {
+ manager.releaseAll(owner1);
+ 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) {
+ sLogger.logWarning("More than one thread was deadlock
victim!");
+ }
+ assertTrue(deadlockCnt >= 1);
+ deadlockCnt = 0;
+ cb.reset();
+ }
+ }
+
+ /*
+ *
* Test shows the following
* - upgrade works with read locks no matter if they are acquired before
or later (1-4)
* - write is blocked by read (5)
@@ -500,8 +647,8 @@
t1.start();
cb.waitForTurn(1);
+ manager.startGlobalTimeout(owner1, 500);
manager.lock(owner1, res1, 1, true);
- manager.setGlobalTimeout(owner1, 500);
cb.signalTurn(2);
cb.waitForTurn(3);
boolean failed = false;
@@ -519,6 +666,7 @@
failed = true;
}
assertFalse(failed);
+ manager.releaseAll(owner1);
synchronized (restart) {
restart.meet();
restart.reset();
@@ -686,6 +834,169 @@
} catch (InterruptedException ie) {
}
}
+
+ }
+
+ public void testChaos() throws Throwable {
+
+ sLogger.logInfo("\n\nChaos testing locks for internal deadlocks
resp. concurrent mods\n\n");
+
+ final String owner1 = "owner1";
+ final String owner2 = "owner2";
+ final String owner3 = "owner3";
+ final String owner4 = "owner4";
+ final String owner5 = "owner5";
+ final String owner6 = "owner6";
+ final String owner7 = "owner7";
+ final String owner8 = "owner8";
+ final String owner9 = "owner9";
+ final String owner10 = "owner10";
+
+ final String res1 = "res1";
+ final String res2 = "res2";
+ final String res3 = "res3";
+
+ // choose low timeout so sometimes an owner times out
+ final ReadWriteUpgradeLockManager manager = new
ReadWriteUpgradeLockManager(sLogger, 100);
+
+ int concurrentThreads = 7;
+ int threads = CONCURRENT_TESTS * concurrentThreads;
+
+ final RendezvousBarrier end = new RendezvousBarrier("end", threads +
1, TIMEOUT, sLogger);
+
+ sLogger.logInfo("\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.readLock(owner1, res1);
+ manager.readLock(owner1, res2);
+ manager.upgradeLock(owner1, res3);
+ manager.writeLock(owner1, res3);
+ } catch (LockException ie) {
+ System.out.print("-");
+ } finally {
+ manager.releaseAll(owner1);
+ end.call();
+ }
+ }
+ }, "Thread #1");
+
+ Thread t2 = new Thread(new Runnable() {
+ public void run() {
+ try {
+ manager.readLock(owner2, res1);
+ manager.readLock(owner2, res2);
+ manager.upgradeLock(owner2, res3);
+ manager.writeLock(owner2, res3);
+ } catch (LockException ie) {
+ System.out.print("-");
+ } finally {
+ manager.releaseAll(owner2);
+ end.call();
+ }
+ }
+ }, "Thread #2");
+
+ Thread t3 = new Thread(new Runnable() {
+ public void run() {
+ try {
+ manager.startGlobalTimeout(owner3, 10 + cnt);
+ manager.readLock(owner3, res1);
+ manager.readLock(owner3, res2);
+ manager.upgradeLock(owner3, res3);
+ manager.writeLock(owner3, res3);
+ } catch (LockException le) {
+ if (le.getCode() == LockException.CODE_TIMED_OUT) {
+ System.out.print("*");
+ } else {
+ System.out.print("-");
+ }
+ } finally {
+ manager.releaseAll(owner3);
+ end.call();
+ }
+ }
+ }, "Thread #3");
+
+ Thread t4 = new Thread(new Runnable() {
+ public void run() {
+ try {
+ manager.readLock(owner4, res1);
+ manager.readLock(owner4, res2);
+ manager.upgradeLock(owner4, res3);
+ manager.writeLock(owner4, res3);
+ } catch (LockException le) {
+ System.out.print("-");
+ } finally {
+ manager.releaseAll(owner4);
+ end.call();
+ }
+ }
+ }, "Thread #4");
+
+ Thread deadlock1 = new Thread(new Runnable() {
+ public void run() {
+ try {
+ manager.writeLock(owner5, res2);
+ manager.writeLock(owner5, res1);
+ } catch (LockException le) {
+ assertEquals(le.getCode(),
LockException.CODE_DEADLOCK_VICTIM);
+ System.out.print("-");
+ } finally {
+ manager.releaseAll(owner5);
+ end.call();
+ }
+ }
+ }, "Deadlock1 Thread");
+
+ Thread deadlock2 = new Thread(new Runnable() {
+ public void run() {
+ try {
+ manager.readLock(owner6, res1);
+ manager.readLock(owner6, res2);
+ } catch (LockException le) {
+ assertEquals(le.getCode(),
LockException.CODE_DEADLOCK_VICTIM);
+ System.out.print("-");
+ } finally {
+ manager.releaseAll(owner6);
+ end.call();
+ }
+ }
+ }, "Deadlock1 Thread");
+
+ Thread reader = new Thread(new Runnable() {
+ public void run() {
+ try {
+ manager.readLock("reader", res1);
+ manager.readLock("reader", res2);
+ manager.readLock("reader", res3);
+ } catch (LockException ie) {
+ System.out.print("-");
+ } finally {
+ manager.releaseAll("reader");
+ 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();
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]