| 1 23 24 package org.apache.commons.transaction.locking; 25 26 import java.io.PrintWriter ; 27 28 import junit.framework.Test; 29 import junit.framework.TestCase; 30 import junit.framework.TestSuite; 31 32 import org.apache.commons.transaction.util.LoggerFacade; 33 import org.apache.commons.transaction.util.PrintWriterLogger; 34 import org.apache.commons.transaction.util.RendezvousBarrier; 35 import org.apache.commons.transaction.util.TurnBarrier; 36 37 42 public class GenericLockTest extends TestCase { 43 44 private static final LoggerFacade sLogger = new PrintWriterLogger(new PrintWriter (System.out), 45 GenericLockTest.class.getName(), false); 46 47 protected static final int READ_LOCK = 1; 48 protected static final int WRITE_LOCK = 2; 49 50 private static final int CONCURRENT_TESTS = 25; 51 52 protected static final long TIMEOUT = 1000000; 53 54 private static int deadlockCnt = 0; 55 private static String first = null; 56 57 public static Test suite() { 58 TestSuite suite = new TestSuite(GenericLockTest.class); 59 return suite; 60 } 61 62 public static void main(java.lang.String [] args) { 63 junit.textui.TestRunner.run(suite()); 64 } 65 66 public GenericLockTest(String testName) { 67 super(testName); 68 } 69 70 protected boolean acquireNoWait(GenericLock lock, String owner, int targetLockLevel) { 72 try { 73 return lock.acquire(owner, targetLockLevel, false, true, -1); 74 } catch (InterruptedException e) { 75 return false; 76 } 77 } 78 79 public void testBasic() throws Throwable { 80 81 sLogger.logInfo("\n\nChecking basic map features\n\n"); 82 83 String owner1 = "owner1"; 84 String owner2 = "owner2"; 85 String owner3 = "owner3"; 86 87 GenericLock lock = new GenericLock("Test read write lock", WRITE_LOCK, sLogger); 89 90 boolean canRead1 = acquireNoWait(lock, owner1, READ_LOCK); 92 assertTrue(canRead1); 93 boolean canRead2 = acquireNoWait(lock, owner2, READ_LOCK); 94 assertTrue(canRead2); 95 96 boolean canWrite3 = acquireNoWait(lock, owner3, WRITE_LOCK); 98 assertFalse(canWrite3); 99 100 lock.release(owner2); 102 canWrite3 = acquireNoWait(lock, owner3, WRITE_LOCK); 104 assertFalse(canWrite3); 105 106 lock.release(owner1); 108 canWrite3 = acquireNoWait(lock, owner3, WRITE_LOCK); 110 assertTrue(canWrite3); 111 canRead2 = acquireNoWait(lock, owner2, READ_LOCK); 113 assertFalse(canRead2); 114 115 lock.release(owner3); 117 canRead2 = acquireNoWait(lock, owner2, READ_LOCK); 118 assertTrue(canRead2); 119 120 boolean canBlock3 = lock.acquire(owner3, WRITE_LOCK, false, GenericLock.COMPATIBILITY_SUPPORT, -1); 122 assertFalse(canBlock3); 124 125 lock.release(owner2); 127 canBlock3 = lock.acquire(owner3, WRITE_LOCK, false, GenericLock.COMPATIBILITY_SUPPORT, -1); 128 assertTrue(canBlock3); 130 131 canRead1 = acquireNoWait(lock, owner1, READ_LOCK); 133 assertFalse(canRead1); 134 135 boolean canBlock2 = lock.acquire(owner2, WRITE_LOCK, false, GenericLock.COMPATIBILITY_SUPPORT, -1); 139 assertTrue(canBlock2); 140 141 lock.release(owner3); 144 canRead1 = acquireNoWait(lock, owner1, READ_LOCK); 145 assertFalse(canRead1); 146 147 lock.release(owner2); 149 canRead1 = acquireNoWait(lock, owner1, READ_LOCK); 150 assertTrue(canRead1); 151 } 152 153 public void testTimeout() { 154 155 sLogger.logInfo("\n\nChecking timeouts\n\n"); 156 157 ReadWriteLockManager lockManager = new ReadWriteLockManager(sLogger, 1000); 158 boolean timedOut = false; 159 try { 160 lockManager.readLock("owner1", "resource"); 161 lockManager.writeLock("owner2", "resource"); 162 } catch (LockException le) { 163 assertEquals(le.getCode(), LockException.CODE_TIMED_OUT); 164 timedOut = true; 165 } 166 assertTrue(timedOut); 167 lockManager = new ReadWriteLockManager(sLogger, 100); 168 timedOut = false; 169 try { 170 lockManager.readLock("owner1", "resource"); 171 lockManager.writeLock("owner2", "resource"); 172 } catch (LockException le) { 173 assertEquals(le.getCode(), LockException.CODE_TIMED_OUT); 174 timedOut = true; 175 } 176 assertTrue(timedOut); 177 lockManager = new ReadWriteLockManager(sLogger, 0); 178 timedOut = false; 179 try { 180 lockManager.readLock("owner1", "resource"); 181 lockManager.writeLock("owner2", "resource"); 182 } catch (LockException le) { 183 assertEquals(le.getCode(), LockException.CODE_TIMED_OUT); 184 timedOut = true; 185 } 186 assertTrue(timedOut); 187 } 188 189 190 public void testDeadlock() throws Throwable { 191 192 sLogger.logInfo("\n\nChecking deadlock detection\n\n"); 193 194 final String owner1 = "owner1"; 195 final String owner2 = "owner2"; 196 197 final String res1 = "res1"; 198 final String res2 = "res2"; 199 200 final ReadWriteLockManager manager = new ReadWriteLockManager(sLogger, TIMEOUT); 202 203 final RendezvousBarrier restart = new RendezvousBarrier("restart", 204 TIMEOUT, sLogger); 205 206 for (int i = 0; i < CONCURRENT_TESTS; i++) { 207 208 System.out.print("."); 209 210 final RendezvousBarrier deadlockBarrier1 = new RendezvousBarrier("deadlock1" + i, 211 TIMEOUT, sLogger); 212 213 Thread deadlock = new Thread (new Runnable () { 214 public void run() { 215 try { 216 manager.writeLock(owner2, res2); 218 synchronized (deadlockBarrier1) { 219 deadlockBarrier1.meet(); 220 deadlockBarrier1.reset(); 221 } 222 manager.writeLock(owner2, res1); 225 } catch (LockException le) { 226 assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM); 227 deadlockCnt++; 228 } catch (InterruptedException ie) { 229 } finally { 230 manager.releaseAll(owner2); 231 try { 232 synchronized (restart) { 233 restart.meet(); 234 restart.reset(); 235 } 236 } catch (InterruptedException ie) {} 237 } 238 } 239 }, "Deadlock Thread"); 240 241 deadlock.start(); 242 243 try { 244 manager.readLock(owner1, res1); 246 synchronized (deadlockBarrier1) { 247 deadlockBarrier1.meet(); 248 deadlockBarrier1.reset(); 249 } 250 manager.readLock(owner1, res2); 253 } catch (LockException le) { 254 assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM); 255 deadlockCnt++; 256 } finally { 257 manager.releaseAll(owner1); 258 synchronized (restart) { 259 restart.meet(); 260 restart.reset(); 261 } 262 } 263 264 if (deadlockCnt != 1) { 267 sLogger.logWarning("More than one thread was deadlock victim!"); 268 } 269 assertTrue(deadlockCnt >= 1); 270 deadlockCnt = 0; 271 } 272 } 273 274 298 public void testIndirectDeadlock() throws Throwable { 299 300 sLogger.logInfo("\n\nChecking detection of indirect deadlock \n\n"); 301 302 final String jamowner1 = "jamowner1"; 303 final String jamowner2 = "jamowner2"; 304 305 final String owner1 = "owner1"; 306 final String owner2 = "owner2"; 307 final String owner3 = "owner3"; 308 309 final String res1 = "res1"; 310 final String res2 = "res2"; 311 final String res3 = "res3"; 312 313 final ReadWriteLockManager manager = new ReadWriteLockManager(sLogger, 315 TIMEOUT); 316 317 final RendezvousBarrier restart = new RendezvousBarrier("restart", 5, TIMEOUT, sLogger); 318 319 final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger, 1); 320 321 for (int i = 0; i < CONCURRENT_TESTS; i++) { 322 323 System.out.print("."); 324 325 Thread jamThread1 = new Thread (new Runnable () { 328 public void run() { 329 try { 330 for (int i = 0; i < 10; i++) { 331 manager.readLock(jamowner1, res1); 332 Thread.sleep(10); 333 manager.releaseAll(jamowner1); 334 Thread.sleep(10); 335 manager.writeLock(jamowner1, res1); 336 Thread.sleep(10); 337 manager.releaseAll(jamowner1); 338 Thread.sleep(10); 339 } 340 } catch (LockException le) { 341 fail("Jam Thread should not fail"); 342 } catch (InterruptedException ie) { 343 } finally { 344 manager.releaseAll(jamowner1); 345 synchronized (restart) { 346 try { 347 synchronized (restart) { 348 restart.meet(); 349 restart.reset(); 350 } 351 } catch (InterruptedException ie) {} 352 } 353 } 354 } 355 }, "Jam Thread #1"); 356 357 jamThread1.start(); 358 359 Thread jamThread2 = new Thread (new Runnable () { 362 public void run() { 363 try { 364 for (int i = 0; i < 10; i++) { 365 manager.writeLock(jamowner2, res1); 366 Thread.sleep(10); 367 manager.releaseAll(jamowner2); 368 Thread.sleep(10); 369 manager.readLock(jamowner2, res1); 370 Thread.sleep(10); 371 manager.releaseAll(jamowner2); 372 Thread.sleep(10); 373 } 374 } catch (LockException le) { 375 fail("Jam Thread should not fail"); 376 } catch (InterruptedException ie) { 377 } finally { 378 manager.releaseAll(jamowner2); 379 synchronized (restart) { 380 try { 381 synchronized (restart) { 382 restart.meet(); 383 restart.reset(); 384 } 385 } catch (InterruptedException ie) {} 386 } 387 } 388 } 389 }, "Jam Thread #2"); 390 391 jamThread2.start(); 392 393 Thread t1 = new Thread (new Runnable () { 394 public void run() { 395 try { 396 cb.waitForTurn(2); 397 manager.readLock(owner2, res2); 398 cb.signalTurn(3); 399 cb.waitForTurn(5); 400 synchronized (manager.getLock(res1)) { 401 cb.signalTurn(6); 402 manager.writeLock(owner2, res1); 403 } 404 } catch (LockException le) { 405 assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM); 406 deadlockCnt++; 407 } catch (InterruptedException ie) { 408 } finally { 409 manager.releaseAll(owner2); 410 synchronized (restart) { 411 try { 412 synchronized (restart) { 413 restart.meet(); 414 restart.reset(); 415 } 416 } catch (InterruptedException ie) {} 417 } 418 } 419 } 420 }, "Thread #1"); 421 422 t1.start(); 423 424 Thread t2 = new Thread (new Runnable () { 425 public void run() { 426 try { 427 cb.waitForTurn(3); 428 manager.readLock(owner3, res3); 429 synchronized (manager.getLock(res2)) { 430 cb.signalTurn(5); 431 manager.writeLock(owner3, res2); 432 } 433 } catch (LockException le) { 434 assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM); 435 deadlockCnt++; 436 } catch (InterruptedException ie) { 437 } finally { 438 manager.releaseAll(owner3); 439 synchronized (restart) { 440 try { 441 synchronized (restart) { 442 restart.meet(); 443 restart.reset(); 444 } 445 } catch (InterruptedException ie) {} 446 } 447 } 448 } 449 }, "Thread #2"); 450 451 t2.start(); 452 453 try { 454 cb.waitForTurn(1); 455 manager.readLock(owner1, res1); 456 cb.signalTurn(2); 457 cb.waitForTurn(6); 458 manager.writeLock(owner1, res3); 459 } catch (LockException le) { 460 assertEquals(le.getCode(), LockException.CODE_DEADLOCK_VICTIM); 461 deadlockCnt++; 462 } catch (InterruptedException ie) { 463 } finally { 464 manager.releaseAll(owner1); 465 synchronized (restart) { 466 try { 467 synchronized (restart) { 468 restart.meet(); 469 restart.reset(); 470 } 471 } catch (InterruptedException ie) { 472 } 473 } 474 } 475 476 if (deadlockCnt != 1) { 479 sLogger.logWarning("\nMore than one thread was deadlock victim!\n"); 480 } 481 assertTrue(deadlockCnt >= 1); 482 deadlockCnt = 0; 483 cb.reset(); 484 } 485 } 486 487 510 public void testUpgrade() throws Throwable { 511 512 sLogger.logInfo("\n\nChecking upgrade and preference lock\n\n"); 513 514 final String owner1 = "owner1"; 515 final String owner2 = "owner2"; 516 final String owner3 = "owner3"; 517 518 final String res1 = "res1"; 519 520 final ReadWriteUpgradeLockManager manager = new ReadWriteUpgradeLockManager(sLogger, 522 TIMEOUT); 523 524 final RendezvousBarrier restart = new RendezvousBarrier("restart", 3, TIMEOUT, sLogger); 525 526 final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger, 1); 527 528 for (int i = 0; i < CONCURRENT_TESTS; i++) { 529 530 System.out.print("."); 531 532 Thread t1 = new Thread (new Runnable () { 533 public void run() { 534 try { 535 cb.waitForTurn(2); 536 manager.upgradeLock(owner2, res1); 537 cb.signalTurn(3); 538 cb.waitForTurn(5); 539 synchronized (manager.getLock(res1)) { 540 cb.signalTurn(6); 541 manager.writeLock(owner2, res1); 542 } 543 synchronized (this) { 547 if (first == null) 548 first = owner2; 549 } 550 manager.releaseAll(owner2); 551 synchronized (restart) { 552 restart.meet(); 553 restart.reset(); 554 } 555 } catch (InterruptedException ie) { 556 } 557 } 558 }, "Thread #1"); 559 560 t1.start(); 561 562 Thread t2 = new Thread (new Runnable () { 563 public void run() { 564 try { 565 cb.waitForTurn(6); 572 synchronized (manager.getLock(res1)) { 573 cb.signalTurn(7); 574 manager.readLock(owner3, res1); 575 } 576 synchronized (this) { 577 if (first == null) 578 first = owner3; 579 } 580 manager.releaseAll(owner3); 581 synchronized (restart) { 582 restart.meet(); 583 restart.reset(); 584 } 585 } catch (InterruptedException ie) { 586 } 587 } 588 }, "Thread #2"); 589 590 t2.start(); 591 592 cb.waitForTurn(1); 593 manager.readLock(owner1, res1); 594 cb.signalTurn(2); 595 cb.waitForTurn(3); 596 manager.release(owner1, res1); 597 manager.readLock(owner1, res1); 598 cb.signalTurn(5); 599 cb.waitForTurn(7); 600 synchronized (manager.getLock(res1)) { 601 manager.releaseAll(owner1); 602 } 603 synchronized (restart) { 604 restart.meet(); 605 restart.reset(); 606 } 607 608 assertEquals(first, owner2); 609 first = null; 610 cb.reset(); 611 } 612 613 } 614 615 641 public void testPreference() throws Throwable { 642 643 sLogger.logInfo("\n\nChecking incompatible preference locks\n\n"); 644 645 final String owner1 = "owner1"; 646 final String owner2 = "owner2"; 647 final String owner3 = "owner3"; 648 649 final String res1 = "res1"; 650 651 final ReadWriteLock lock = new ReadWriteLock(res1, sLogger); 652 653 final RendezvousBarrier restart = new RendezvousBarrier("restart", 3, TIMEOUT, sLogger); 654 655 final TurnBarrier cb = new TurnBarrier("cb1", TIMEOUT, sLogger, 1); 656 657 for (int i = 0; i < CONCURRENT_TESTS; i++) { 658 659 System.out.print("."); 660 661 Thread t1 = new Thread (new Runnable () { 662 public void run() { 663 try { 664 cb.waitForTurn(2); 665 synchronized (lock) { 666 cb.signalTurn(3); 667 lock.acquire(owner2, ReadWriteLock.WRITE_LOCK, true, 668 GenericLock.COMPATIBILITY_REENTRANT, true, TIMEOUT); 669 } 670 lock.release(owner2); 671 synchronized (restart) { 672 restart.meet(); 673 restart.reset(); 674 } 675 } catch (InterruptedException ie) { 676 } 677 } 678 }, "Thread #1"); 679 680 t1.start(); 681 682 Thread t2 = new Thread (new Runnable () { 683 public void run() { 684 try { 685
|