0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package org.apache.commons.transaction.locking;
0018:
0019: import java.io.PrintWriter;
0020:
0021: import junit.framework.Test;
0022: import junit.framework.TestCase;
0023: import junit.framework.TestSuite;
0024:
0025: import org.apache.commons.transaction.util.LoggerFacade;
0026: import org.apache.commons.transaction.util.PrintWriterLogger;
0027: import org.apache.commons.transaction.util.RendezvousBarrier;
0028: import org.apache.commons.transaction.util.TurnBarrier;
0029:
0030: /**
0031: * Tests for generic locks.
0032: *
0033: * @version $Id: GenericLockTest.java 493628 2007-01-07 01:42:48Z joerg $
0034: */
0035: public class GenericLockTest extends TestCase {
0036:
0037: private static final LoggerFacade sLogger = new PrintWriterLogger(
0038: new PrintWriter(System.out), GenericLockTest.class
0039: .getName(), false);
0040:
0041: protected static final int READ_LOCK = 1;
0042: protected static final int WRITE_LOCK = 2;
0043:
0044: private static final int CONCURRENT_TESTS = 25;
0045:
0046: protected static final long TIMEOUT = 1000000;
0047:
0048: private static int deadlockCnt = 0;
0049: private static String first = null;
0050:
0051: public static Test suite() {
0052: TestSuite suite = new TestSuite(GenericLockTest.class);
0053: return suite;
0054: }
0055:
0056: public static void main(java.lang.String[] args) {
0057: junit.textui.TestRunner.run(suite());
0058: }
0059:
0060: public GenericLockTest(String testName) {
0061: super (testName);
0062: }
0063:
0064: // we do not wait, as we only want the check the results and do not want real locking
0065: protected boolean acquireNoWait(GenericLock lock, String owner,
0066: int targetLockLevel) {
0067: try {
0068: return lock
0069: .acquire(owner, targetLockLevel, false, true, -1);
0070: } catch (InterruptedException e) {
0071: return false;
0072: }
0073: }
0074:
0075: public void testBasic() throws Throwable {
0076:
0077: sLogger.logInfo("\n\nChecking basic map features\n\n");
0078:
0079: String owner1 = "owner1";
0080: String owner2 = "owner2";
0081: String owner3 = "owner3";
0082:
0083: // a read / write lock
0084: GenericLock lock = new GenericLock("Test read write lock",
0085: WRITE_LOCK, sLogger);
0086:
0087: // of course more than one can read
0088: boolean canRead1 = acquireNoWait(lock, owner1, READ_LOCK);
0089: assertTrue(canRead1);
0090: boolean canRead2 = acquireNoWait(lock, owner2, READ_LOCK);
0091: assertTrue(canRead2);
0092:
0093: // as there already are read locks, this write should not be possible
0094: boolean canWrite3 = acquireNoWait(lock, owner3, WRITE_LOCK);
0095: assertFalse(canWrite3);
0096:
0097: // release one read lock
0098: lock.release(owner2);
0099: // this should not change anything with the write as there is still one read lock left
0100: canWrite3 = acquireNoWait(lock, owner3, WRITE_LOCK);
0101: assertFalse(canWrite3);
0102:
0103: // release the other and final read lock as well
0104: lock.release(owner1);
0105: // no we should be able to get write access
0106: canWrite3 = acquireNoWait(lock, owner3, WRITE_LOCK);
0107: assertTrue(canWrite3);
0108: // but of course no more read access
0109: canRead2 = acquireNoWait(lock, owner2, READ_LOCK);
0110: assertFalse(canRead2);
0111:
0112: // relase the write lock and make sure we can read again
0113: lock.release(owner3);
0114: canRead2 = acquireNoWait(lock, owner2, READ_LOCK);
0115: assertTrue(canRead2);
0116:
0117: // now we do something weired, we try to block all locks lower than write...
0118: boolean canBlock3 = lock.acquire(owner3, WRITE_LOCK, false,
0119: GenericLock.COMPATIBILITY_SUPPORT, -1);
0120: // which of course does not work, as there already is an incompatible read lock
0121: assertFalse(canBlock3);
0122:
0123: // ok, release read lock (no we have no more locks) and try again
0124: lock.release(owner2);
0125: canBlock3 = lock.acquire(owner3, WRITE_LOCK, false,
0126: GenericLock.COMPATIBILITY_SUPPORT, -1);
0127: // which now should work creating an ordinary lock
0128: assertTrue(canBlock3);
0129:
0130: // as this just an ordinary lock, we should not get a read lock:
0131: canRead1 = acquireNoWait(lock, owner1, READ_LOCK);
0132: assertFalse(canRead1);
0133:
0134: // this is the trick now, we *can* get an addtional write lock with this request as it has
0135: // the same level as the write lock already set. This works, as we do not care for the
0136: // write lock level, but only want to inhibit the read lock:
0137: boolean canBlock2 = lock.acquire(owner2, WRITE_LOCK, false,
0138: GenericLock.COMPATIBILITY_SUPPORT, -1);
0139: assertTrue(canBlock2);
0140:
0141: // now if we release one of the blocks supporting each other we still should not get a
0142: // read lock
0143: lock.release(owner3);
0144: canRead1 = acquireNoWait(lock, owner1, READ_LOCK);
0145: assertFalse(canRead1);
0146:
0147: // but of course after we release the second as well
0148: lock.release(owner2);
0149: canRead1 = acquireNoWait(lock, owner1, READ_LOCK);
0150: assertTrue(canRead1);
0151: }
0152:
0153: public void testTimeout() {
0154:
0155: sLogger.logInfo("\n\nChecking timeouts\n\n");
0156:
0157: ReadWriteLockManager lockManager = new ReadWriteLockManager(
0158: sLogger, 1000);
0159: boolean timedOut = false;
0160: try {
0161: lockManager.readLock("owner1", "resource");
0162: lockManager.writeLock("owner2", "resource");
0163: } catch (LockException le) {
0164: assertEquals(le.getCode(), LockException.CODE_TIMED_OUT);
0165: timedOut = true;
0166: }
0167: assertTrue(timedOut);
0168: lockManager = new ReadWriteLockManager(sLogger, 100);
0169: timedOut = false;
0170: try {
0171: lockManager.readLock("owner1", "resource");
0172: lockManager.writeLock("owner2", "resource");
0173: } catch (LockException le) {
0174: assertEquals(le.getCode(), LockException.CODE_TIMED_OUT);
0175: timedOut = true;
0176: }
0177: assertTrue(timedOut);
0178: lockManager = new ReadWriteLockManager(sLogger, 0);
0179: timedOut = false;
0180: try {
0181: lockManager.readLock("owner1", "resource");
0182: lockManager.writeLock("owner2", "resource");
0183: } catch (LockException le) {
0184: assertEquals(le.getCode(), LockException.CODE_TIMED_OUT);
0185: timedOut = true;
0186: }
0187: assertTrue(timedOut);
0188: }
0189:
0190: public void testDeadlock() throws Throwable {
0191:
0192: sLogger.logInfo("\n\nChecking deadlock detection\n\n");
0193:
0194: final String owner1 = "owner1";
0195: final String owner2 = "owner2";
0196:
0197: final String res1 = "res1";
0198: final String res2 = "res2";
0199:
0200: // a read / write lock
0201: final ReadWriteLockManager manager = new ReadWriteLockManager(
0202: sLogger, TIMEOUT);
0203:
0204: final RendezvousBarrier restart = new RendezvousBarrier(
0205: "restart", TIMEOUT, sLogger);
0206:
0207: for (int i = 0; i < CONCURRENT_TESTS; i++) {
0208:
0209: System.out.print(".");
0210:
0211: final RendezvousBarrier deadlockBarrier1 = new RendezvousBarrier(
0212: "deadlock1" + i, TIMEOUT, sLogger);
0213:
0214: Thread deadlock = new Thread(new Runnable() {
0215: public void run() {
0216: try {
0217: // first both threads get a lock, this one on res2
0218: manager.writeLock(owner2, res2);
0219: synchronized (deadlockBarrier1) {
0220: deadlockBarrier1.meet();
0221: deadlockBarrier1.reset();
0222: }
0223: // if I am first, the other thread will be dead, i.e.
0224: // exactly one
0225: manager.writeLock(owner2, res1);
0226: } catch (LockException le) {
0227: assertEquals(le.getCode(),
0228: LockException.CODE_DEADLOCK_VICTIM);
0229: deadlockCnt++;
0230: } catch (InterruptedException ie) {
0231: } finally {
0232: manager.releaseAll(owner2);
0233: try {
0234: synchronized (restart) {
0235: restart.meet();
0236: restart.reset();
0237: }
0238: } catch (InterruptedException ie) {
0239: }
0240: }
0241: }
0242: }, "Deadlock Thread");
0243:
0244: deadlock.start();
0245:
0246: try {
0247: // first both threads get a lock, this one on res2
0248: manager.readLock(owner1, res1);
0249: synchronized (deadlockBarrier1) {
0250: deadlockBarrier1.meet();
0251: deadlockBarrier1.reset();
0252: }
0253: // if I am first, the other thread will be dead, i.e. exactly
0254: // one
0255: manager.readLock(owner1, res2);
0256: } catch (LockException le) {
0257: assertEquals(le.getCode(),
0258: LockException.CODE_DEADLOCK_VICTIM);
0259: deadlockCnt++;
0260: } finally {
0261: manager.releaseAll(owner1);
0262: synchronized (restart) {
0263: restart.meet();
0264: restart.reset();
0265: }
0266: }
0267:
0268: // XXX in special scenarios the current implementation might cause both
0269: // owners to be deadlock victims
0270: if (deadlockCnt != 1) {
0271: sLogger
0272: .logWarning("More than one thread was deadlock victim!");
0273: }
0274: assertTrue(deadlockCnt >= 1);
0275: deadlockCnt = 0;
0276: }
0277: }
0278:
0279: /*
0280: *
0281: * Test detection of an indirect deadlock:
0282: *
0283: * Owner Owner Owner
0284: * Step #1 #2 #3
0285: * 1 read res1 (ok)
0286: * 2 read res2 (ok)
0287: * 3 read res3 (ok)
0288: * 4 write res2 (blocked because of #2)
0289: * 5 write res1
0290: * (blocked
0291: * because of #1)
0292: * 6 write res3
0293: * (blocked
0294: * because #3)
0295: *
0296: * - Thread#1 waits for Thread#3 on res3
0297: * - Thread#2 waits for Thread#1 on res1
0298: * - Thread#3 waits for Thread#2 on res2
0299: *
0300: * This needs recursion of the deadlock detection algorithm
0301: *
0302: */
0303: public void testIndirectDeadlock() throws Throwable {
0304:
0305: sLogger
0306: .logInfo("\n\nChecking detection of indirect deadlock \n\n");
0307:
0308: final String jamowner1 = "jamowner1";
0309: final String jamowner2 = "jamowner2";
0310:
0311: final String owner1 = "owner1";
0312: final String owner2 = "owner2";
0313: final String owner3 = "owner3";
0314:
0315: final String res1 = "res1";
0316: final String res2 = "res2";
0317: final String res3 = "res3";
0318:
0319: // a read / write lock
0320: final ReadWriteLockManager manager = new ReadWriteLockManager(
0321: sLogger, TIMEOUT);
0322:
0323: final RendezvousBarrier restart = new RendezvousBarrier(
0324: "restart", 5, TIMEOUT, sLogger);
0325:
0326: final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger,
0327: 1);
0328:
0329: for (int i = 0; i < CONCURRENT_TESTS; i++) {
0330:
0331: System.out.print(".");
0332:
0333: // thread that accesses lock of res1 just to cause interference and
0334: // possibly detect concurrency problems
0335: Thread jamThread1 = new Thread(new Runnable() {
0336: public void run() {
0337: try {
0338: for (int i = 0; i < 10; i++) {
0339: manager.readLock(jamowner1, res1);
0340: Thread.sleep(10);
0341: manager.releaseAll(jamowner1);
0342: Thread.sleep(10);
0343: manager.writeLock(jamowner1, res1);
0344: Thread.sleep(10);
0345: manager.releaseAll(jamowner1);
0346: Thread.sleep(10);
0347: }
0348: } catch (LockException le) {
0349: fail("Jam Thread should not fail");
0350: } catch (InterruptedException ie) {
0351: } finally {
0352: manager.releaseAll(jamowner1);
0353: synchronized (restart) {
0354: try {
0355: synchronized (restart) {
0356: restart.meet();
0357: restart.reset();
0358: }
0359: } catch (InterruptedException ie) {
0360: }
0361: }
0362: }
0363: }
0364: }, "Jam Thread #1");
0365:
0366: jamThread1.start();
0367:
0368: // thread that accesses lock of res1 just to cause interference and
0369: // possibly detect concurrency problems
0370: Thread jamThread2 = new Thread(new Runnable() {
0371: public void run() {
0372: try {
0373: for (int i = 0; i < 10; i++) {
0374: manager.writeLock(jamowner2, res1);
0375: Thread.sleep(10);
0376: manager.releaseAll(jamowner2);
0377: Thread.sleep(10);
0378: manager.readLock(jamowner2, res1);
0379: Thread.sleep(10);
0380: manager.releaseAll(jamowner2);
0381: Thread.sleep(10);
0382: }
0383: } catch (LockException le) {
0384: fail("Jam Thread should not fail");
0385: } catch (InterruptedException ie) {
0386: } finally {
0387: manager.releaseAll(jamowner2);
0388: synchronized (restart) {
0389: try {
0390: synchronized (restart) {
0391: restart.meet();
0392: restart.reset();
0393: }
0394: } catch (InterruptedException ie) {
0395: }
0396: }
0397: }
0398: }
0399: }, "Jam Thread #2");
0400:
0401: jamThread2.start();
0402:
0403: Thread t1 = new Thread(new Runnable() {
0404: public void run() {
0405: try {
0406: cb.waitForTurn(2);
0407: manager.readLock(owner2, res2);
0408: cb.signalTurn(3);
0409: cb.waitForTurn(5);
0410: synchronized (manager.getLock(res1)) {
0411: cb.signalTurn(6);
0412: manager.writeLock(owner2, res1);
0413: }
0414: } catch (LockException le) {
0415: assertEquals(le.getCode(),
0416: LockException.CODE_DEADLOCK_VICTIM);
0417: deadlockCnt++;
0418: } catch (InterruptedException ie) {
0419: } finally {
0420: manager.releaseAll(owner2);
0421: synchronized (restart) {
0422: try {
0423: synchronized (restart) {
0424: restart.meet();
0425: restart.reset();
0426: }
0427: } catch (InterruptedException ie) {
0428: }
0429: }
0430: }
0431: }
0432: }, "Thread #1");
0433:
0434: t1.start();
0435:
0436: Thread t2 = new Thread(new Runnable() {
0437: public void run() {
0438: try {
0439: cb.waitForTurn(3);
0440: manager.readLock(owner3, res3);
0441: synchronized (manager.getLock(res2)) {
0442: cb.signalTurn(5);
0443: manager.writeLock(owner3, res2);
0444: }
0445: } catch (LockException le) {
0446: assertEquals(le.getCode(),
0447: LockException.CODE_DEADLOCK_VICTIM);
0448: deadlockCnt++;
0449: } catch (InterruptedException ie) {
0450: } finally {
0451: manager.releaseAll(owner3);
0452: synchronized (restart) {
0453: try {
0454: synchronized (restart) {
0455: restart.meet();
0456: restart.reset();
0457: }
0458: } catch (InterruptedException ie) {
0459: }
0460: }
0461: }
0462: }
0463: }, "Thread #2");
0464:
0465: t2.start();
0466:
0467: try {
0468: cb.waitForTurn(1);
0469: manager.readLock(owner1, res1);
0470: cb.signalTurn(2);
0471: cb.waitForTurn(6);
0472: manager.writeLock(owner1, res3);
0473: } catch (LockException le) {
0474: assertEquals(le.getCode(),
0475: LockException.CODE_DEADLOCK_VICTIM);
0476: deadlockCnt++;
0477: } catch (InterruptedException ie) {
0478: } finally {
0479: manager.releaseAll(owner1);
0480: synchronized (restart) {
0481: try {
0482: synchronized (restart) {
0483: restart.meet();
0484: restart.reset();
0485: }
0486: } catch (InterruptedException ie) {
0487: }
0488: }
0489: }
0490:
0491: // XXX in special scenarios the current implementation might cause more than one
0492: // owner to be a deadlock victim
0493: if (deadlockCnt != 1) {
0494: sLogger
0495: .logWarning("\nMore than one thread was deadlock victim!\n");
0496: }
0497: assertTrue(deadlockCnt >= 1);
0498: deadlockCnt = 0;
0499: cb.reset();
0500: }
0501: }
0502:
0503: /*
0504: *
0505: * Test shows the following
0506: * - upgrade works with read locks no matter if they are acquired before or later (1-4)
0507: * - write is blocked by read (5)
0508: * - read is blocked by intention lock (6)
0509: * - write lock coming from an intention lock always has preference over others (7)
0510: *
0511: *
0512: * Owner Owner Owner
0513: * Step #1 #2 #3
0514: * 1 read (ok)
0515: * 2 upgrade (ok)
0516: * 3 release (ok)
0517: * 4 read (ok)
0518: * 5 write (blocked
0519: * because of #1)
0520: * 6 read (blocked
0521: * because intention of #2)
0522: * 7 release resumed
0523: * 8 release resumed
0524: * 9 release
0525: */
0526: public void testUpgrade() throws Throwable {
0527:
0528: sLogger.logInfo("\n\nChecking upgrade and preference lock\n\n");
0529:
0530: final String owner1 = "owner1";
0531: final String owner2 = "owner2";
0532: final String owner3 = "owner3";
0533:
0534: final String res1 = "res1";
0535:
0536: // a read / write lock
0537: final ReadWriteUpgradeLockManager manager = new ReadWriteUpgradeLockManager(
0538: sLogger, TIMEOUT);
0539:
0540: final RendezvousBarrier restart = new RendezvousBarrier(
0541: "restart", 3, TIMEOUT, sLogger);
0542:
0543: final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger,
0544: 1);
0545:
0546: for (int i = 0; i < CONCURRENT_TESTS; i++) {
0547:
0548: System.out.print(".");
0549:
0550: Thread t1 = new Thread(new Runnable() {
0551: public void run() {
0552: try {
0553: cb.waitForTurn(2);
0554: manager.upgradeLock(owner2, res1);
0555: cb.signalTurn(3);
0556: cb.waitForTurn(5);
0557: synchronized (manager.getLock(res1)) {
0558: cb.signalTurn(6);
0559: manager.writeLock(owner2, res1);
0560: }
0561: // we must always be first as we will be preferred over
0562: // as I had the upgrade
0563: // lock before
0564: synchronized (this ) {
0565: if (first == null)
0566: first = owner2;
0567: }
0568: manager.releaseAll(owner2);
0569: synchronized (restart) {
0570: restart.meet();
0571: restart.reset();
0572: }
0573: } catch (InterruptedException ie) {
0574: }
0575: }
0576: }, "Thread #1");
0577:
0578: t1.start();
0579:
0580: Thread t2 = new Thread(new Runnable() {
0581: public void run() {
0582: try {
0583: // I wait until the others are blocked
0584: // when I release my single read lock, thread #1 always
0585: // should be the
0586: // next to get the lock as it is preferred over the main
0587: // thread
0588: // that only waits for a read lock
0589: cb.waitForTurn(6);
0590: synchronized (manager.getLock(res1)) {
0591: cb.signalTurn(7);
0592: manager.readLock(owner3, res1);
0593: }
0594: synchronized (this ) {
0595: if (first == null)
0596: first = owner3;
0597: }
0598: manager.releaseAll(owner3);
0599: synchronized (restart) {
0600: restart.meet();
0601: restart.reset();
0602: }
0603: } catch (InterruptedException ie) {
0604: }
0605: }
0606: }, "Thread #2");
0607:
0608: t2.start();
0609:
0610: cb.waitForTurn(1);
0611: manager.readLock(owner1, res1);
0612: cb.signalTurn(2);
0613: cb.waitForTurn(3);
0614: manager.release(owner1, res1);
0615: manager.readLock(owner1, res1);
0616: cb.signalTurn(5);
0617: cb.waitForTurn(7);
0618: synchronized (manager.getLock(res1)) {
0619: manager.releaseAll(owner1);
0620: }
0621: synchronized (restart) {
0622: restart.meet();
0623: restart.reset();
0624: }
0625:
0626: assertEquals(first, owner2);
0627: first = null;
0628: cb.reset();
0629: }
0630:
0631: }
0632:
0633: /*
0634: *
0635: * Test shows that two preference locks that are imcompatible do not cause a lock out
0636: * which was the case with GenericLock 1.5
0637: * Before the fix this test would dealock
0638: *
0639: * Owner Owner Owner
0640: * Step #1 #2 #3
0641: * 1 read (ok)
0642: * 2 write preferred
0643: * (blocked
0644: * because of #1)
0645: * 3 write preferred
0646: * (blocked
0647: * because of #1 and #2)
0648: * 4 release
0649: * 5 resumed or resumed
0650: * (as both are preferred, problem
0651: * is that that would exclude each other
0652: * in the algorithm used)
0653: * 6 released or released
0654: * 7 resumed or resumed
0655: * 8 released or released
0656: *
0657: *
0658: */
0659: public void testPreference() throws Throwable {
0660:
0661: sLogger
0662: .logInfo("\n\nChecking incompatible preference locks\n\n");
0663:
0664: final String owner1 = "owner1";
0665: final String owner2 = "owner2";
0666: final String owner3 = "owner3";
0667:
0668: final String res1 = "res1";
0669:
0670: final ReadWriteLock lock = new ReadWriteLock(res1, sLogger);
0671:
0672: final RendezvousBarrier restart = new RendezvousBarrier(
0673: "restart", 3, TIMEOUT, sLogger);
0674:
0675: final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger,
0676: 1);
0677:
0678: for (int i = 0; i < CONCURRENT_TESTS; i++) {
0679:
0680: System.out.print(".");
0681:
0682: Thread t1 = new Thread(new Runnable() {
0683: public void run() {
0684: try {
0685: cb.waitForTurn(2);
0686: synchronized (lock) {
0687: cb.signalTurn(3);
0688: lock
0689: .acquire(
0690: owner2,
0691: ReadWriteLock.WRITE_LOCK,
0692: true,
0693: GenericLock.COMPATIBILITY_REENTRANT,
0694: true, TIMEOUT);
0695: }
0696: lock.release(owner2);
0697: synchronized (restart) {
0698: restart.meet();
0699: restart.reset();
0700: }
0701: } catch (InterruptedException ie) {
0702: }
0703: }
0704: }, "Thread #1");
0705:
0706: t1.start();
0707:
0708: Thread t2 = new Thread(new Runnable() {
0709: public void run() {
0710: try {
0711: cb.waitForTurn(3);
0712: synchronized (lock) {
0713: cb.signalTurn(4);
0714: lock
0715: .acquire(
0716: owner3,
0717: ReadWriteLock.WRITE_LOCK,
0718: true,
0719: GenericLock.COMPATIBILITY_REENTRANT,
0720: true, TIMEOUT);
0721: }
0722: lock.release(owner3);
0723: synchronized (restart) {
0724: restart.meet();
0725: restart.reset();
0726: }
0727: } catch (InterruptedException ie) {
0728: }
0729: }
0730: }, "Thread #2");
0731:
0732: t2.start();
0733:
0734: cb.waitForTurn(1);
0735: lock.acquireRead(owner1, TIMEOUT);
0736: cb.signalTurn(2);
0737: cb.waitForTurn(4);
0738: synchronized (lock) {
0739: lock.release(owner1);
0740: }
0741: synchronized (restart) {
0742: restart.meet();
0743: restart.reset();
0744: }
0745:
0746: cb.reset();
0747: }
0748:
0749: }
0750:
0751: public void testGlobalTimeout() throws Throwable {
0752:
0753: sLogger.logInfo("\n\nChecking global timeouts\n\n");
0754:
0755: final String owner1 = "owner1";
0756: final String owner2 = "owner2";
0757:
0758: final String res1 = "res1";
0759:
0760: final GenericLockManager manager = new GenericLockManager(1,
0761: sLogger, TIMEOUT, -1);
0762:
0763: final RendezvousBarrier restart = new RendezvousBarrier(
0764: "restart", 2, TIMEOUT, sLogger);
0765:
0766: final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger,
0767: 1);
0768:
0769: for (int i = 0; i < CONCURRENT_TESTS; i++) {
0770:
0771: System.out.print(".");
0772:
0773: Thread t1 = new Thread(new Runnable() {
0774: public void run() {
0775: try {
0776: cb.waitForTurn(2);
0777: manager.lock(owner2, res1, 1, true);
0778: cb.signalTurn(3);
0779: manager.releaseAll(owner2);
0780: synchronized (restart) {
0781: restart.meet();
0782: restart.reset();
0783: }
0784: } catch (InterruptedException ie) {
0785: }
0786: }
0787: }, "Thread #1");
0788:
0789: t1.start();
0790:
0791: cb.waitForTurn(1);
0792: manager.startGlobalTimeout(owner1, 500);
0793: manager.lock(owner1, res1, 1, true);
0794: cb.signalTurn(2);
0795: cb.waitForTurn(3);
0796: boolean failed = false;
0797: try {
0798: manager.tryLock(owner1, res1, 1, true);
0799: } catch (LockException le) {
0800: failed = true;
0801: }
0802: assertTrue(failed);
0803: manager.releaseAll(owner1);
0804: failed = false;
0805: try {
0806: manager.tryLock(owner1, res1, 1, true);
0807: } catch (LockException le) {
0808: failed = true;
0809: }
0810: assertFalse(failed);
0811: manager.releaseAll(owner1);
0812: synchronized (restart) {
0813: restart.meet();
0814: restart.reset();
0815: }
0816:
0817: cb.reset();
0818: }
0819:
0820: }
0821:
0822: public void testStress() throws Throwable {
0823:
0824: sLogger.logInfo("\n\nStress checking locks\n\n");
0825:
0826: final String owner1 = "owner1";
0827: final String owner2 = "owner2";
0828: final String owner3 = "owner3";
0829: final String owner4 = "owner4";
0830: final String owner5 = "owner5";
0831: final String owner6 = "owner6";
0832: final String owner7 = "owner7";
0833: final String owner8 = "owner8";
0834: final String owner9 = "owner9";
0835: final String owner10 = "owner10";
0836:
0837: final String res1 = "res1";
0838: final String res2 = "res2";
0839: final String res3 = "res3";
0840:
0841: // choose low timeout so sometimes an owner times out
0842: final ReadWriteUpgradeLockManager manager = new ReadWriteUpgradeLockManager(
0843: sLogger, 100);
0844:
0845: final RendezvousBarrier restart = new RendezvousBarrier(
0846: "restart", 5, TIMEOUT, sLogger);
0847: final RendezvousBarrier start = new RendezvousBarrier("start",
0848: 5, TIMEOUT, sLogger);
0849:
0850: for (int i = 0; i < CONCURRENT_TESTS; i++) {
0851:
0852: System.out.print(".");
0853:
0854: Thread t1 = new Thread(new Runnable() {
0855: public void run() {
0856: try {
0857: try {
0858: synchronized (start) {
0859: start.meet();
0860: start.reset();
0861: }
0862: manager.readLock(owner1, res1);
0863: manager.readLock(owner1, res2);
0864: manager.upgradeLock(owner1, res3);
0865: manager.writeLock(owner1, res3);
0866: } catch (LockException ie) {
0867: } finally {
0868: manager.releaseAll(owner1);
0869: synchronized (restart) {
0870: restart.meet();
0871: restart.reset();
0872: }
0873: }
0874: } catch (InterruptedException ie) {
0875: }
0876: }
0877: }, "Thread #1");
0878: t1.start();
0879:
0880: Thread t2 = new Thread(new Runnable() {
0881: public void run() {
0882: try {
0883: try {
0884: synchronized (start) {
0885: start.meet();
0886: start.reset();
0887: }
0888: manager.readLock(owner2, res1);
0889: manager.readLock(owner2, res2);
0890: manager.upgradeLock(owner2, res3);
0891: manager.writeLock(owner2, res3);
0892: } catch (LockException ie) {
0893: } finally {
0894: manager.releaseAll(owner2);
0895: synchronized (restart) {
0896: restart.meet();
0897: restart.reset();
0898: }
0899: }
0900: } catch (InterruptedException ie) {
0901: }
0902: }
0903: }, "Thread #2");
0904: t2.start();
0905:
0906: Thread t3 = new Thread(new Runnable() {
0907: public void run() {
0908: try {
0909: try {
0910: synchronized (start) {
0911: start.meet();
0912: start.reset();
0913: }
0914: manager.readLock(owner3, res1);
0915: manager.readLock(owner3, res2);
0916: manager.upgradeLock(owner3, res3);
0917: manager.writeLock(owner3, res3);
0918: } catch (LockException ie) {
0919: } finally {
0920: manager.releaseAll(owner3);
0921: synchronized (restart) {
0922: restart.meet();
0923: restart.reset();
0924: }
0925: }
0926: } catch (InterruptedException ie) {
0927: }
0928: }
0929: }, "Thread #3");
0930: t3.start();
0931:
0932: Thread t4 = new Thread(new Runnable() {
0933: public void run() {
0934: try {
0935: try {
0936: synchronized (start) {
0937: start.meet();
0938: start.reset();
0939: }
0940: manager.readLock(owner4, res1);
0941: manager.readLock(owner4, res2);
0942: manager.upgradeLock(owner4, res3);
0943: manager.writeLock(owner4, res3);
0944: } catch (LockException ie) {
0945: } finally {
0946: manager.releaseAll(owner4);
0947: synchronized (restart) {
0948: restart.meet();
0949: restart.reset();
0950: }
0951: }
0952: } catch (InterruptedException ie) {
0953: }
0954: }
0955: }, "Thread #4");
0956: t4.start();
0957:
0958: try {
0959: try {
0960: synchronized (start) {
0961: start.meet();
0962: start.reset();
0963: }
0964: manager.readLock("reader", res1);
0965: manager.readLock("reader", res2);
0966: manager.readLock("reader", res3);
0967:
0968: } catch (LockException ie) {
0969: } finally {
0970: manager.releaseAll("reader");
0971: try {
0972: synchronized (restart) {
0973: restart.meet();
0974: restart.reset();
0975: }
0976: } catch (InterruptedException ie) {
0977: }
0978: }
0979: } catch (InterruptedException ie) {
0980: }
0981: }
0982:
0983: }
0984:
0985: public void testChaos() throws Throwable {
0986:
0987: sLogger
0988: .logInfo("\n\nChaos testing locks for internal deadlocks resp. concurrent mods\n\n");
0989:
0990: final String owner1 = "owner1";
0991: final String owner2 = "owner2";
0992: final String owner3 = "owner3";
0993: final String owner4 = "owner4";
0994: final String owner5 = "owner5";
0995: final String owner6 = "owner6";
0996: final String owner7 = "owner7";
0997: final String owner8 = "owner8";
0998: final String owner9 = "owner9";
0999: final String owner10 = "owner10";
1000:
1001: final String res1 = "res1";
1002: final String res2 = "res2";
1003: final String res3 = "res3";
1004:
1005: // choose low timeout so sometimes an owner times out
1006: final ReadWriteUpgradeLockManager manager = new ReadWriteUpgradeLockManager(
1007: sLogger, 100);
1008:
1009: int concurrentThreads = 7;
1010: int threads = CONCURRENT_TESTS * concurrentThreads;
1011:
1012: final RendezvousBarrier end = new RendezvousBarrier("end",
1013: threads + 1, TIMEOUT, sLogger);
1014:
1015: sLogger.logInfo("\n\nStarting " + threads + " threads\n\n");
1016:
1017: for (int i = 0; i < CONCURRENT_TESTS; i++) {
1018:
1019: final int cnt = i;
1020:
1021: System.out.print(".");
1022:
1023: Thread t1 = new Thread(new Runnable() {
1024: public void run() {
1025: try {
1026: manager.readLock(owner1, res1);
1027: manager.readLock(owner1, res2);
1028: manager.upgradeLock(owner1, res3);
1029: manager.writeLock(owner1, res3);
1030: } catch (LockException ie) {
1031: System.out.print("-");
1032: } finally {
1033: manager.releaseAll(owner1);
1034: end.call();
1035: }
1036: }
1037: }, "Thread #1");
1038:
1039: Thread t2 = new Thread(new Runnable() {
1040: public void run() {
1041: try {
1042: manager.readLock(owner2, res1);
1043: manager.readLock(owner2, res2);
1044: manager.upgradeLock(owner2, res3);
1045: manager.writeLock(owner2, res3);
1046: } catch (LockException ie) {
1047: System.out.print("-");
1048: } finally {
1049: manager.releaseAll(owner2);
1050: end.call();
1051: }
1052: }
1053: }, "Thread #2");
1054:
1055: Thread t3 = new Thread(new Runnable() {
1056: public void run() {
1057: try {
1058: manager.startGlobalTimeout(owner3, 10 + cnt);
1059: manager.readLock(owner3, res1);
1060: manager.readLock(owner3, res2);
1061: manager.upgradeLock(owner3, res3);
1062: manager.writeLock(owner3, res3);
1063: } catch (LockException le) {
1064: if (le.getCode() == LockException.CODE_TIMED_OUT) {
1065: System.out.print("*");
1066: } else {
1067: System.out.print("-");
1068: }
1069: } finally {
1070: manager.releaseAll(owner3);
1071: end.call();
1072: }
1073: }
1074: }, "Thread #3");
1075:
1076: Thread t4 = new Thread(new Runnable() {
1077: public void run() {
1078: try {
1079: manager.readLock(owner4, res1);
1080: manager.readLock(owner4, res2);
1081: manager.upgradeLock(owner4, res3);
1082: manager.writeLock(owner4, res3);
1083: } catch (LockException le) {
1084: System.out.print("-");
1085: } finally {
1086: manager.releaseAll(owner4);
1087: end.call();
1088: }
1089: }
1090: }, "Thread #4");
1091:
1092: Thread deadlock1 = new Thread(new Runnable() {
1093: public void run() {
1094: try {
1095: manager.writeLock(owner5, res2);
1096: manager.writeLock(owner5, res1);
1097: } catch (LockException le) {
1098: assertEquals(le.getCode(),
1099: LockException.CODE_DEADLOCK_VICTIM);
1100: System.out.print("-");
1101: } finally {
1102: manager.releaseAll(owner5);
1103: end.call();
1104: }
1105: }
1106: }, "Deadlock1 Thread");
1107:
1108: Thread deadlock2 = new Thread(new Runnable() {
1109: public void run() {
1110: try {
1111: manager.readLock(owner6, res1);
1112: manager.readLock(owner6, res2);
1113: } catch (LockException le) {
1114: assertEquals(le.getCode(),
1115: LockException.CODE_DEADLOCK_VICTIM);
1116: System.out.print("-");
1117: } finally {
1118: manager.releaseAll(owner6);
1119: end.call();
1120: }
1121: }
1122: }, "Deadlock1 Thread");
1123:
1124: Thread reader = new Thread(new Runnable() {
1125: public void run() {
1126: try {
1127: manager.readLock("reader", res1);
1128: manager.readLock("reader", res2);
1129: manager.readLock("reader", res3);
1130: } catch (LockException ie) {
1131: System.out.print("-");
1132: } finally {
1133: manager.releaseAll("reader");
1134: end.call();
1135: }
1136: }
1137: }, "Reader Thread");
1138:
1139: t4.start();
1140: t3.start();
1141: reader.start();
1142: t1.start();
1143: deadlock2.start();
1144: t2.start();
1145: deadlock1.start();
1146: }
1147: // wait until all threads have really terminated
1148: end.meet();
1149:
1150: }
1151: }
|