001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.transaction.locking;
018
019import java.io.PrintWriter;
020
021import junit.framework.Test;
022import junit.framework.TestCase;
023import junit.framework.TestSuite;
024
025import org.apache.commons.transaction.util.LoggerFacade;
026import org.apache.commons.transaction.util.PrintWriterLogger;
027import org.apache.commons.transaction.util.RendezvousBarrier;
028import org.apache.commons.transaction.util.TurnBarrier;
029
030/**
031 * Tests for generic locks. 
032 *
033 * @version $Id: GenericLockTest.java 493628 2007-01-07 01:42:48Z joerg $
034 */
035public class GenericLockTest extends TestCase {
036
037    private static final LoggerFacade sLogger = new PrintWriterLogger(new PrintWriter(System.out),
038            GenericLockTest.class.getName(), false);
039
040    protected static final int READ_LOCK = 1;
041    protected static final int WRITE_LOCK = 2;
042    
043    private static final int CONCURRENT_TESTS = 25;
044    
045    protected static final long TIMEOUT = 1000000;
046    
047    private static int deadlockCnt = 0;
048    private static String first = null;
049
050    public static Test suite() {
051        TestSuite suite = new TestSuite(GenericLockTest.class);
052        return suite;
053    }
054
055    public static void main(java.lang.String[] args) {
056        junit.textui.TestRunner.run(suite());
057    }
058
059    public GenericLockTest(String testName) {
060        super(testName);
061    }
062
063    // we do not wait, as we only want the check the results and do not want real locking
064    protected boolean acquireNoWait(GenericLock lock, String owner, int targetLockLevel)  {
065        try {
066            return lock.acquire(owner, targetLockLevel, false, true, -1);
067        } catch (InterruptedException e) {
068            return false;
069        }
070    }
071
072    public void testBasic() throws Throwable {
073
074        sLogger.logInfo("\n\nChecking basic map features\n\n");
075
076        String owner1 = "owner1";
077        String owner2 = "owner2";
078        String owner3 = "owner3";
079        
080        // a read / write lock
081        GenericLock lock = new GenericLock("Test read write lock", WRITE_LOCK, sLogger);
082        
083        // of course more than one can read
084        boolean canRead1 = acquireNoWait(lock, owner1, READ_LOCK);
085        assertTrue(canRead1);
086        boolean canRead2 = acquireNoWait(lock, owner2, READ_LOCK);
087        assertTrue(canRead2);
088        
089        // as there already are read locks, this write should not be possible
090        boolean canWrite3 = acquireNoWait(lock, owner3, WRITE_LOCK);
091        assertFalse(canWrite3);
092        
093        // release one read lock
094        lock.release(owner2);
095        // this should not change anything with the write as there is still one read lock left
096        canWrite3 = acquireNoWait(lock, owner3, WRITE_LOCK);
097        assertFalse(canWrite3);
098
099        // release the other and final read lock as well
100        lock.release(owner1);
101        // no we should be able to get write access
102        canWrite3 = acquireNoWait(lock, owner3, WRITE_LOCK);
103        assertTrue(canWrite3);
104        // but of course no more read access
105        canRead2 = acquireNoWait(lock, owner2, READ_LOCK);
106        assertFalse(canRead2);
107        
108        // relase the write lock and make sure we can read again
109        lock.release(owner3);
110        canRead2 = acquireNoWait(lock, owner2, READ_LOCK);
111        assertTrue(canRead2);
112        
113        // now we do something weired, we try to block all locks lower than write...
114        boolean canBlock3 = lock.acquire(owner3, WRITE_LOCK, false, GenericLock.COMPATIBILITY_SUPPORT, -1);
115        // which of course does not work, as there already is an incompatible read lock
116        assertFalse(canBlock3);
117        
118        // ok, release read lock (no we have no more locks) and try again
119        lock.release(owner2);
120        canBlock3 = lock.acquire(owner3, WRITE_LOCK, false, GenericLock.COMPATIBILITY_SUPPORT, -1);
121        // which now should work creating an ordinary lock
122        assertTrue(canBlock3);
123        
124        // as this just an ordinary lock, we should not get a read lock:
125        canRead1 = acquireNoWait(lock, owner1, READ_LOCK);
126        assertFalse(canRead1);
127        
128        // this is the trick now, we *can* get an addtional write lock with this request as it has
129        // the same level as the write lock already set. This works, as we do not care for the
130        // write lock level, but only want to inhibit the read lock:
131        boolean canBlock2 = lock.acquire(owner2, WRITE_LOCK, false, GenericLock.COMPATIBILITY_SUPPORT, -1);
132        assertTrue(canBlock2);
133        
134        // now if we release one of the blocks supporting each other we still should not get a
135        // read lock
136        lock.release(owner3);
137        canRead1 = acquireNoWait(lock, owner1, READ_LOCK);
138        assertFalse(canRead1);
139
140        // but of course after we release the second as well
141        lock.release(owner2);
142        canRead1 = acquireNoWait(lock, owner1, READ_LOCK);
143        assertTrue(canRead1);
144    }
145
146    public void testTimeout() {
147        
148        sLogger.logInfo("\n\nChecking timeouts\n\n");
149
150        ReadWriteLockManager lockManager = new ReadWriteLockManager(sLogger, 1000);
151        boolean timedOut = false;
152        try {
153            lockManager.readLock("owner1", "resource");
154            lockManager.writeLock("owner2", "resource");
155        } catch (LockException le) {
156            assertEquals(le.getCode(), LockException.CODE_TIMED_OUT);
157            timedOut = true;
158        }
159        assertTrue(timedOut);
160        lockManager = new ReadWriteLockManager(sLogger, 100);
161        timedOut = false;
162        try {
163            lockManager.readLock("owner1", "resource");
164            lockManager.writeLock("owner2", "resource");
165        } catch (LockException le) {
166            assertEquals(le.getCode(), LockException.CODE_TIMED_OUT);
167            timedOut = true;
168        }
169        assertTrue(timedOut);
170        lockManager = new ReadWriteLockManager(sLogger, 0);
171        timedOut = false;
172        try {
173            lockManager.readLock("owner1", "resource");
174            lockManager.writeLock("owner2", "resource");
175        } catch (LockException le) {
176            assertEquals(le.getCode(), LockException.CODE_TIMED_OUT);
177            timedOut = true;
178        }
179        assertTrue(timedOut);
180    }
181    
182
183    public void testDeadlock() throws Throwable {
184
185        sLogger.logInfo("\n\nChecking deadlock detection\n\n");
186
187        final String owner1 = "owner1";
188        final String owner2 = "owner2";
189
190        final String res1 = "res1";
191        final String res2 = "res2";
192
193        // a read / write lock
194        final ReadWriteLockManager manager = new ReadWriteLockManager(sLogger, TIMEOUT);
195        
196        final RendezvousBarrier restart = new RendezvousBarrier("restart",
197                TIMEOUT, sLogger);
198
199        for (int i = 0; i < CONCURRENT_TESTS; i++) {
200
201           System.out.print(".");
202            
203            final RendezvousBarrier deadlockBarrier1 = new RendezvousBarrier("deadlock1" + i,
204                    TIMEOUT, sLogger);
205
206            Thread deadlock = new Thread(new Runnable() {
207                public void run() {
208                    try {
209                        // first both threads get a lock, this one on res2
210                        manager.writeLock(owner2, res2);
211                        synchronized (deadlockBarrier1) {
212                            deadlockBarrier1.meet();
213                            deadlockBarrier1.reset();
214                        }
215                        // if I am first, the other thread will be dead, i.e.
216                        // exactly one
217                        manager.writeLock(owner2, res1);
218                    } catch (LockException le) {
219                        assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM);
220                        deadlockCnt++;
221                    } catch (InterruptedException ie) {
222                    } finally {
223                        manager.releaseAll(owner2);
224                        try {
225                            synchronized (restart) {
226                                restart.meet();
227                                restart.reset();
228                            }
229                            } catch (InterruptedException ie) {}
230                    }
231                }
232            }, "Deadlock Thread");
233
234            deadlock.start();
235
236            try {
237                // first both threads get a lock, this one on res2
238                manager.readLock(owner1, res1);
239                synchronized (deadlockBarrier1) {
240                    deadlockBarrier1.meet();
241                    deadlockBarrier1.reset();
242                }
243                //          if I am first, the other thread will be dead, i.e. exactly
244                // one
245                manager.readLock(owner1, res2);
246            } catch (LockException le) {
247                assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM);
248                deadlockCnt++;
249            } finally {
250                manager.releaseAll(owner1);
251                synchronized (restart) {
252                    restart.meet();
253                    restart.reset();
254                }
255            }
256
257            // XXX in special scenarios the current implementation might cause both
258            // owners to be deadlock victims
259            if (deadlockCnt != 1) {
260                sLogger.logWarning("More than one thread was deadlock victim!");
261            }
262            assertTrue(deadlockCnt >= 1);
263            deadlockCnt = 0;
264        }
265    }
266
267    /*
268     * 
269     * Test detection of an indirect deadlock:
270     * 
271     *                  Owner           Owner           Owner
272     * Step             #1              #2              #3
273     * 1                read res1 (ok)
274     * 2                                read res2 (ok)
275     * 3                                                read res3 (ok)
276     * 4                                                write res2 (blocked because of #2)
277     * 5                                write res1
278     *                                  (blocked 
279     *                                  because of #1)
280     * 6                write res3
281     *                  (blocked 
282     *                   because #3)
283     * 
284     * - Thread#1 waits for Thread#3 on res3
285     * - Thread#2 waits for Thread#1 on res1
286     * - Thread#3 waits for Thread#2 on res2
287     *
288     * This needs recursion of the deadlock detection algorithm
289     *  
290     */
291    public void testIndirectDeadlock() throws Throwable {
292
293        sLogger.logInfo("\n\nChecking detection of indirect deadlock \n\n");
294
295        final String jamowner1 = "jamowner1";
296        final String jamowner2 = "jamowner2";
297
298        final String owner1 = "owner1";
299        final String owner2 = "owner2";
300        final String owner3 = "owner3";
301
302        final String res1 = "res1";
303        final String res2 = "res2";
304        final String res3 = "res3";
305
306        // a read / write lock
307        final ReadWriteLockManager manager = new ReadWriteLockManager(sLogger,
308                TIMEOUT);
309
310        final RendezvousBarrier restart = new RendezvousBarrier("restart", 5, TIMEOUT, sLogger);
311
312        final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger, 1);
313
314        for (int i = 0; i < CONCURRENT_TESTS; i++) {
315            
316            System.out.print(".");
317
318            // thread that accesses lock of res1 just to cause interference and
319            // possibly detect concurrency problems
320            Thread jamThread1 = new Thread(new Runnable() {
321                public void run() {
322                    try {
323                        for (int i = 0; i < 10; i++) {
324                            manager.readLock(jamowner1, res1);
325                            Thread.sleep(10);
326                            manager.releaseAll(jamowner1);
327                            Thread.sleep(10);
328                            manager.writeLock(jamowner1, res1);
329                            Thread.sleep(10);
330                            manager.releaseAll(jamowner1);
331                            Thread.sleep(10);
332                        }
333                    } catch (LockException le) {
334                        fail("Jam Thread should not fail");
335                    } catch (InterruptedException ie) {
336                    } finally {
337                        manager.releaseAll(jamowner1);
338                        synchronized (restart) {
339                            try {
340                                synchronized (restart) {
341                                    restart.meet();
342                                    restart.reset();
343                                }
344                                } catch (InterruptedException ie) {}
345                        }
346                    }
347                }
348            }, "Jam Thread #1");
349
350            jamThread1.start();
351
352            // thread that accesses lock of res1 just to cause interference and
353            // possibly detect concurrency problems
354            Thread jamThread2 = new Thread(new Runnable() {
355                public void run() {
356                    try {
357                        for (int i = 0; i < 10; i++) {
358                            manager.writeLock(jamowner2, res1);
359                            Thread.sleep(10);
360                            manager.releaseAll(jamowner2);
361                            Thread.sleep(10);
362                            manager.readLock(jamowner2, res1);
363                            Thread.sleep(10);
364                            manager.releaseAll(jamowner2);
365                            Thread.sleep(10);
366                        }
367                    } catch (LockException le) {
368                        fail("Jam Thread should not fail");
369                    } catch (InterruptedException ie) {
370                    } finally {
371                        manager.releaseAll(jamowner2);
372                        synchronized (restart) {
373                            try {
374                                synchronized (restart) {
375                                    restart.meet();
376                                    restart.reset();
377                                }
378                                } catch (InterruptedException ie) {}
379                        }
380                    }
381                }
382            }, "Jam Thread #2");
383
384            jamThread2.start();
385
386            Thread t1 = new Thread(new Runnable() {
387                public void run() {
388                    try {
389                        cb.waitForTurn(2);
390                        manager.readLock(owner2, res2);
391                        cb.signalTurn(3);
392                        cb.waitForTurn(5);
393                        synchronized (manager.getLock(res1)) {
394                            cb.signalTurn(6);
395                            manager.writeLock(owner2, res1);
396                        }
397                    } catch (LockException le) {
398                        assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM);
399                        deadlockCnt++;
400                    } catch (InterruptedException ie) {
401                    } finally {
402                        manager.releaseAll(owner2);
403                        synchronized (restart) {
404                            try {
405                                synchronized (restart) {
406                                    restart.meet();
407                                    restart.reset();
408                                }
409                                } catch (InterruptedException ie) {}
410                        }
411                    }
412                }
413            }, "Thread #1");
414
415            t1.start();
416
417            Thread t2 = new Thread(new Runnable() {
418                public void run() {
419                    try {
420                        cb.waitForTurn(3);
421                        manager.readLock(owner3, res3);
422                        synchronized (manager.getLock(res2)) {
423                            cb.signalTurn(5);
424                            manager.writeLock(owner3, res2);
425                        }
426                    } catch (LockException le) {
427                        assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM);
428                        deadlockCnt++;
429                    } catch (InterruptedException ie) {
430                    } finally {
431                        manager.releaseAll(owner3);
432                        synchronized (restart) {
433                            try {
434                                synchronized (restart) {
435                                    restart.meet();
436                                    restart.reset();
437                                }
438                                } catch (InterruptedException ie) {}
439                        }
440                    }
441                }
442            }, "Thread #2");
443
444            t2.start();
445
446            try {
447                cb.waitForTurn(1);
448                manager.readLock(owner1, res1);
449                cb.signalTurn(2);
450                cb.waitForTurn(6);
451                manager.writeLock(owner1, res3);
452            } catch (LockException le) {
453                assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM);
454                deadlockCnt++;
455            } catch (InterruptedException ie) {
456            } finally {
457                manager.releaseAll(owner1);
458                synchronized (restart) {
459                    try {
460                        synchronized (restart) {
461                            restart.meet();
462                            restart.reset();
463                        }
464                    } catch (InterruptedException ie) {
465                    }
466                }
467            }
468
469            // XXX in special scenarios the current implementation might cause more than one
470            // owner to be a deadlock victim
471            if (deadlockCnt != 1) {
472                sLogger.logWarning("\nMore than one thread was deadlock victim!\n");
473            }
474            assertTrue(deadlockCnt >= 1);
475            deadlockCnt = 0;
476            cb.reset();
477        }
478    }
479
480    /*
481     * 
482     * Test shows the following
483     * - upgrade works with read locks no matter if they are acquired before or later (1-4)
484     * - write is blocked by read (5)
485     * - read is blocked by intention lock (6)
486     * - write lock coming from an intention lock always has preference over others (7)
487     * 
488     * 
489     *                  Owner           Owner           Owner
490     * Step             #1              #2              #3
491     * 1                read (ok)
492     * 2                                upgrade (ok)
493     * 3                release (ok)
494     * 4                read (ok)
495     * 5                                write (blocked 
496     *                                  because of #1)
497     * 6                                                read (blocked 
498     *                                                  because intention of #2)        
499     * 7                release         resumed
500     * 8                                release         resumed
501     * 9                                                release
502     */
503    public void testUpgrade() throws Throwable {
504
505        sLogger.logInfo("\n\nChecking upgrade and preference lock\n\n");
506        
507        final String owner1 = "owner1";
508        final String owner2 = "owner2";
509        final String owner3 = "owner3";
510
511        final String res1 = "res1";
512
513        // a read / write lock
514        final ReadWriteUpgradeLockManager manager = new ReadWriteUpgradeLockManager(sLogger,
515                TIMEOUT);
516
517        final RendezvousBarrier restart = new RendezvousBarrier("restart", 3, TIMEOUT, sLogger);
518
519        final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger, 1);
520
521        for (int i = 0; i < CONCURRENT_TESTS; i++) {
522            
523            System.out.print(".");
524
525            Thread t1 = new Thread(new Runnable() {
526                public void run() {
527                    try {
528                        cb.waitForTurn(2);
529                        manager.upgradeLock(owner2, res1);
530                        cb.signalTurn(3);
531                        cb.waitForTurn(5);
532                        synchronized (manager.getLock(res1)) {
533                            cb.signalTurn(6);
534                            manager.writeLock(owner2, res1);
535                        }
536                        // we must always be first as we will be preferred over
537                        // as I had the upgrade
538                        // lock before
539                        synchronized (this) {
540                            if (first == null)
541                                first = owner2;
542                        }
543                        manager.releaseAll(owner2);
544                        synchronized (restart) {
545                            restart.meet();
546                            restart.reset();
547                        }
548                    } catch (InterruptedException ie) {
549                    }
550                }
551            }, "Thread #1");
552
553            t1.start();
554
555            Thread t2 = new Thread(new Runnable() {
556                public void run() {
557                    try {
558                        // I wait until the others are blocked
559                        // when I release my single read lock, thread #1 always
560                        // should be the
561                        // next to get the lock as it is preferred over the main
562                        // thread
563                        // that only waits for a read lock
564                        cb.waitForTurn(6);
565                        synchronized (manager.getLock(res1)) {
566                            cb.signalTurn(7);
567                            manager.readLock(owner3, res1);
568                        }
569                        synchronized (this) {
570                            if (first == null)
571                                first = owner3;
572                        }
573                        manager.releaseAll(owner3);
574                        synchronized (restart) {
575                            restart.meet();
576                            restart.reset();
577                        }
578                    } catch (InterruptedException ie) {
579                    }
580                }
581            }, "Thread #2");
582
583            t2.start();
584
585            cb.waitForTurn(1);
586            manager.readLock(owner1, res1);
587            cb.signalTurn(2);
588            cb.waitForTurn(3);
589            manager.release(owner1, res1);
590            manager.readLock(owner1, res1);
591            cb.signalTurn(5);
592            cb.waitForTurn(7);
593            synchronized (manager.getLock(res1)) {
594                manager.releaseAll(owner1);
595            }
596            synchronized (restart) {
597                restart.meet();
598                restart.reset();
599            }
600
601            assertEquals(first, owner2);
602            first = null;
603            cb.reset();
604        }
605
606    }
607    
608    /*
609     * 
610     * Test shows that two preference locks that are imcompatible do not cause a lock out
611     * which was the case with GenericLock 1.5
612     * Before the fix this test would dealock
613     * 
614     *                  Owner           Owner           Owner
615     * Step             #1              #2              #3
616     * 1                read (ok)
617     * 2                                write preferred 
618     *                                  (blocked 
619     *                                  because of #1)
620     * 3                                                write preferred 
621     *                                                  (blocked 
622     *                                                  because of #1 and #2)
623     * 4                release
624     * 5                                resumed   or    resumed 
625     *                                  (as both are preferred, problem
626     *                                   is that that would exclude each other
627     *                                   in the algorithm used)
628     * 6                                released   or   released
629     * 7                                resumed   or    resumed 
630     * 8                                released   or   released
631     * 
632     * 
633     */
634    public void testPreference() throws Throwable {
635
636        sLogger.logInfo("\n\nChecking incompatible preference locks\n\n");
637        
638        final String owner1 = "owner1";
639        final String owner2 = "owner2";
640        final String owner3 = "owner3";
641
642        final String res1 = "res1";
643
644        final ReadWriteLock lock = new ReadWriteLock(res1, sLogger);
645
646        final RendezvousBarrier restart = new RendezvousBarrier("restart", 3, TIMEOUT, sLogger);
647
648        final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger, 1);
649
650        for (int i = 0; i < CONCURRENT_TESTS; i++) {
651            
652            System.out.print(".");
653
654            Thread t1 = new Thread(new Runnable() {
655                public void run() {
656                    try {
657                        cb.waitForTurn(2);
658                        synchronized (lock) {
659                            cb.signalTurn(3);
660                            lock.acquire(owner2, ReadWriteLock.WRITE_LOCK, true,
661                                    GenericLock.COMPATIBILITY_REENTRANT, true, TIMEOUT);
662                        }
663                        lock.release(owner2);
664                        synchronized (restart) {
665                            restart.meet();
666                            restart.reset();
667                        }
668                    } catch (InterruptedException ie) {
669                    }
670                }
671            }, "Thread #1");
672
673            t1.start();
674
675            Thread t2 = new Thread(new Runnable() {
676                public void run() {
677                    try {
678                        cb.waitForTurn(3);
679                        synchronized (lock) {
680                            cb.signalTurn(4);
681                            lock.acquire(owner3, ReadWriteLock.WRITE_LOCK, true,
682                                    GenericLock.COMPATIBILITY_REENTRANT, true, TIMEOUT);
683                        }
684                        lock.release(owner3);
685                        synchronized (restart) {
686                            restart.meet();
687                            restart.reset();
688                        }
689                    } catch (InterruptedException ie) {
690                    }
691                }
692            }, "Thread #2");
693
694            t2.start();
695
696            cb.waitForTurn(1);
697            lock.acquireRead(owner1, TIMEOUT);
698            cb.signalTurn(2);
699            cb.waitForTurn(4);
700            synchronized (lock) {
701                lock.release(owner1);
702            }
703            synchronized (restart) {
704                restart.meet();
705                restart.reset();
706            }
707
708            cb.reset();
709        }
710
711    }
712    
713    public void testGlobalTimeout() throws Throwable {
714
715        sLogger.logInfo("\n\nChecking global timeouts\n\n");
716        
717        final String owner1 = "owner1";
718        final String owner2 = "owner2";
719
720        final String res1 = "res1";
721
722        final GenericLockManager manager = new GenericLockManager(1, sLogger, TIMEOUT, -1);
723
724        final RendezvousBarrier restart = new RendezvousBarrier("restart", 2, TIMEOUT, sLogger);
725
726        final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger, 1);
727
728        for (int i = 0; i < CONCURRENT_TESTS; i++) {
729            
730            System.out.print(".");
731
732            Thread t1 = new Thread(new Runnable() {
733                public void run() {
734                    try {
735                        cb.waitForTurn(2);
736                        manager.lock(owner2, res1, 1, true);
737                        cb.signalTurn(3);
738                        manager.releaseAll(owner2);
739                        synchronized (restart) {
740                            restart.meet();
741                            restart.reset();
742                        }
743                    } catch (InterruptedException ie) {
744                    }
745                }
746            }, "Thread #1");
747
748            t1.start();
749
750            cb.waitForTurn(1);
751            manager.startGlobalTimeout(owner1, 500);
752            manager.lock(owner1, res1, 1, true);
753            cb.signalTurn(2);
754            cb.waitForTurn(3);
755            boolean failed = false;
756            try {
757                manager.tryLock(owner1, res1, 1, true);
758            } catch (LockException le) {
759                failed = true;
760            }
761            assertTrue(failed);
762            manager.releaseAll(owner1);
763            failed = false;
764            try {
765                manager.tryLock(owner1, res1, 1, true);
766            } catch (LockException le) {
767                failed = true;
768            }
769            assertFalse(failed);
770            manager.releaseAll(owner1);
771            synchronized (restart) {
772                restart.meet();
773                restart.reset();
774            }
775
776            cb.reset();
777        }
778
779    }
780
781    public void testStress() throws Throwable {
782
783        sLogger.logInfo("\n\nStress checking locks\n\n");
784        
785        final String owner1 = "owner1";
786        final String owner2 = "owner2";
787        final String owner3 = "owner3";
788        final String owner4 = "owner4";
789        final String owner5 = "owner5";
790        final String owner6 = "owner6";
791        final String owner7 = "owner7";
792        final String owner8 = "owner8";
793        final String owner9 = "owner9";
794        final String owner10 = "owner10";
795
796        final String res1 = "res1";
797        final String res2 = "res2";
798        final String res3 = "res3";
799
800        // choose low timeout so sometimes an owner times out
801        final ReadWriteUpgradeLockManager manager = new ReadWriteUpgradeLockManager(sLogger, 100);
802
803        final RendezvousBarrier restart = new RendezvousBarrier("restart", 5, TIMEOUT, sLogger);
804        final RendezvousBarrier start = new RendezvousBarrier("start", 5, TIMEOUT, sLogger);
805
806        for (int i = 0; i < CONCURRENT_TESTS; i++) {
807            
808            System.out.print(".");
809
810            Thread t1 = new Thread(new Runnable() {
811                public void run() {
812                    try {
813                        try {
814                            synchronized (start) {
815                                start.meet();
816                                start.reset();
817                            }
818                            manager.readLock(owner1, res1);
819                            manager.readLock(owner1, res2);
820                            manager.upgradeLock(owner1, res3);
821                            manager.writeLock(owner1, res3);
822                        } catch (LockException ie) {
823                        } finally {
824                            manager.releaseAll(owner1);
825                            synchronized (restart) {
826                                restart.meet();
827                                restart.reset();
828                            }
829                        }
830                    } catch (InterruptedException ie) {
831                    }
832                }
833            }, "Thread #1");
834            t1.start();
835
836            Thread t2 = new Thread(new Runnable() {
837                public void run() {
838                    try {
839                        try {
840                            synchronized (start) {
841                                start.meet();
842                                start.reset();
843                            }
844                            manager.readLock(owner2, res1);
845                            manager.readLock(owner2, res2);
846                            manager.upgradeLock(owner2, res3);
847                            manager.writeLock(owner2, res3);
848                        } catch (LockException ie) {
849                        } finally {
850                            manager.releaseAll(owner2);
851                            synchronized (restart) {
852                                restart.meet();
853                                restart.reset();
854                            }
855                        }
856                    } catch (InterruptedException ie) {
857                    }
858                }
859            }, "Thread #2");
860            t2.start();
861
862            Thread t3 = new Thread(new Runnable() {
863                public void run() {
864                    try {
865                        try {
866                            synchronized (start) {
867                                start.meet();
868                                start.reset();
869                            }
870                            manager.readLock(owner3, res1);
871                            manager.readLock(owner3, res2);
872                            manager.upgradeLock(owner3, res3);
873                            manager.writeLock(owner3, res3);
874                        } catch (LockException ie) {
875                        } finally {
876                            manager.releaseAll(owner3);
877                            synchronized (restart) {
878                                restart.meet();
879                                restart.reset();
880                            }
881                        }
882                    } catch (InterruptedException ie) {
883                    }
884                }
885            }, "Thread #3");
886            t3.start();
887
888            Thread t4 = new Thread(new Runnable() {
889                public void run() {
890                    try {
891                        try {
892                            synchronized (start) {
893                                start.meet();
894                                start.reset();
895                            }
896                            manager.readLock(owner4, res1);
897                            manager.readLock(owner4, res2);
898                            manager.upgradeLock(owner4, res3);
899                            manager.writeLock(owner4, res3);
900                        } catch (LockException ie) {
901                        } finally {
902                            manager.releaseAll(owner4);
903                            synchronized (restart) {
904                                restart.meet();
905                                restart.reset();
906                            }
907                        }
908                    } catch (InterruptedException ie) {
909                    }
910                }
911            }, "Thread #4");
912            t4.start();
913
914            try {
915                try {
916                    synchronized (start) {
917                        start.meet();
918                        start.reset();
919                    }
920                    manager.readLock("reader", res1);
921                    manager.readLock("reader", res2);
922                    manager.readLock("reader", res3);
923
924                } catch (LockException ie) {
925                } finally {
926                    manager.releaseAll("reader");
927                    try {
928                        synchronized (restart) {
929                            restart.meet();
930                            restart.reset();
931                        }
932                    } catch (InterruptedException ie) {
933                    }
934                }
935            } catch (InterruptedException ie) {
936            }
937        }
938
939    }
940
941    public void testChaos() throws Throwable {
942
943        sLogger.logInfo("\n\nChaos testing locks for internal deadlocks resp. concurrent mods\n\n");
944
945        final String owner1 = "owner1";
946        final String owner2 = "owner2";
947        final String owner3 = "owner3";
948        final String owner4 = "owner4";
949        final String owner5 = "owner5";
950        final String owner6 = "owner6";
951        final String owner7 = "owner7";
952        final String owner8 = "owner8";
953        final String owner9 = "owner9";
954        final String owner10 = "owner10";
955
956        final String res1 = "res1";
957        final String res2 = "res2";
958        final String res3 = "res3";
959
960        // choose low timeout so sometimes an owner times out
961        final ReadWriteUpgradeLockManager manager = new ReadWriteUpgradeLockManager(sLogger, 100);
962
963        int concurrentThreads = 7;
964        int threads = CONCURRENT_TESTS * concurrentThreads;
965        
966        final RendezvousBarrier end = new RendezvousBarrier("end", threads + 1, TIMEOUT, sLogger);
967        
968        sLogger.logInfo("\n\nStarting "+threads+" threads\n\n");
969
970        for (int i = 0; i < CONCURRENT_TESTS; i++) {
971
972            final int cnt = i;
973            
974            System.out.print(".");
975
976            Thread t1 = new Thread(new Runnable() {
977                public void run() {
978                    try {
979                        manager.readLock(owner1, res1);
980                        manager.readLock(owner1, res2);
981                        manager.upgradeLock(owner1, res3);
982                        manager.writeLock(owner1, res3);
983                    } catch (LockException ie) {
984                        System.out.print("-");
985                    } finally {
986                        manager.releaseAll(owner1);
987                        end.call();
988                    }
989                }
990            }, "Thread #1");
991
992            Thread t2 = new Thread(new Runnable() {
993                public void run() {
994                    try {
995                        manager.readLock(owner2, res1);
996                        manager.readLock(owner2, res2);
997                        manager.upgradeLock(owner2, res3);
998                        manager.writeLock(owner2, res3);
999                    } catch (LockException ie) {
1000                        System.out.print("-");
1001                    } finally {
1002                        manager.releaseAll(owner2);
1003                        end.call();
1004                    }
1005                }
1006            }, "Thread #2");
1007
1008            Thread t3 = new Thread(new Runnable() {
1009                public void run() {
1010                    try {
1011                        manager.startGlobalTimeout(owner3, 10 + cnt);
1012                        manager.readLock(owner3, res1);
1013                        manager.readLock(owner3, res2);
1014                        manager.upgradeLock(owner3, res3);
1015                        manager.writeLock(owner3, res3);
1016                    } catch (LockException le) {
1017                        if (le.getCode() == LockException.CODE_TIMED_OUT) {
1018                            System.out.print("*");
1019                        } else {
1020                            System.out.print("-");
1021                        }
1022                    } finally {
1023                        manager.releaseAll(owner3);
1024                        end.call();
1025                    }
1026                }
1027            }, "Thread #3");
1028
1029            Thread t4 = new Thread(new Runnable() {
1030                public void run() {
1031                    try {
1032                        manager.readLock(owner4, res1);
1033                        manager.readLock(owner4, res2);
1034                        manager.upgradeLock(owner4, res3);
1035                        manager.writeLock(owner4, res3);
1036                    } catch (LockException le) {
1037                        System.out.print("-");
1038                    } finally {
1039                        manager.releaseAll(owner4);
1040                        end.call();
1041                    }
1042                }
1043            }, "Thread #4");
1044
1045                Thread deadlock1 = new Thread(new Runnable() {
1046                public void run() {
1047                    try {
1048                        manager.writeLock(owner5, res2);
1049                        manager.writeLock(owner5, res1);
1050                    } catch (LockException le) {
1051                        assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM);
1052                        System.out.print("-");
1053                    } finally {
1054                        manager.releaseAll(owner5);
1055                        end.call();
1056                    }
1057                }
1058            }, "Deadlock1 Thread");
1059
1060            Thread deadlock2 = new Thread(new Runnable() {
1061                public void run() {
1062                    try {
1063                        manager.readLock(owner6, res1);
1064                        manager.readLock(owner6, res2);
1065                    } catch (LockException le) {
1066                        assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM);
1067                        System.out.print("-");
1068                    } finally {
1069                        manager.releaseAll(owner6);
1070                        end.call();
1071                    }
1072                }
1073            }, "Deadlock1 Thread");
1074
1075            Thread reader = new Thread(new Runnable() {
1076                public void run() {
1077                    try {
1078                        manager.readLock("reader", res1);
1079                        manager.readLock("reader", res2);
1080                        manager.readLock("reader", res3);
1081                    } catch (LockException ie) {
1082                        System.out.print("-");
1083                    } finally {
1084                        manager.releaseAll("reader");
1085                        end.call();
1086                    }
1087                }
1088            }, "Reader Thread");
1089
1090
1091            t4.start();
1092            t3.start();
1093            reader.start();
1094            t1.start();
1095            deadlock2.start();
1096            t2.start();
1097            deadlock1.start();
1098        }
1099        // wait until all threads have really terminated
1100        end.meet();
1101
1102    }
1103}