1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002, 2014 Oracle and/or its affiliates. All rights reserved. 5 * 6 */ 7 8 package com.sleepycat.je.txn; 9 10 import static org.junit.Assert.assertEquals; 11 import static org.junit.Assert.assertFalse; 12 import static org.junit.Assert.assertSame; 13 import static org.junit.Assert.assertTrue; 14 import static org.junit.Assert.fail; 15 16 import java.io.File; 17 import java.util.concurrent.atomic.AtomicInteger; 18 19 import com.sleepycat.je.Durability; 20 import org.junit.Before; 21 import org.junit.Test; 22 23 import com.sleepycat.je.DatabaseException; 24 import com.sleepycat.je.DbInternal; 25 import com.sleepycat.je.Environment; 26 import com.sleepycat.je.EnvironmentConfig; 27 import com.sleepycat.je.LockConflictException; 28 import com.sleepycat.je.TransactionConfig; 29 import com.sleepycat.je.config.EnvironmentParams; 30 import com.sleepycat.je.dbi.DatabaseImpl; 31 import com.sleepycat.je.dbi.DbTree; 32 import com.sleepycat.je.dbi.EnvironmentImpl; 33 import com.sleepycat.je.junit.JUnitThread; 34 import com.sleepycat.je.util.DualTestCase; 35 import com.sleepycat.je.util.TestUtils; 36 import com.sleepycat.util.test.SharedTestUtils; 37 38 public class LockManagerTest extends DualTestCase { 39 40 private Locker txn1; 41 private Locker txn2; 42 private Locker txn3; 43 private Locker txn4; 44 private Long nid; 45 private AtomicInteger sequence; 46 47 private Environment env; 48 private final File envHome; 49 LockManagerTest()50 public LockManagerTest() { 51 envHome = SharedTestUtils.getTestDir(); 52 } 53 54 @Before setUp()55 public void setUp() 56 throws Exception { 57 58 super.setUp(); 59 EnvironmentConfig envConfig = TestUtils.initEnvConfig(); 60 envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(), "6"); 61 envConfig.setConfigParam(EnvironmentParams.N_LOCK_TABLES.getName(), 62 "11"); 63 envConfig.setAllowCreate(true); 64 envConfig.setTransactional(true); 65 env = create(envHome, envConfig); 66 67 nid = new Long(1); 68 sequence = new AtomicInteger(0); 69 } 70 initLockers()71 private void initLockers() 72 throws DatabaseException { 73 74 EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 75 76 txn1 = BasicLocker.createBasicLocker(envImpl); 77 txn2 = BasicLocker.createBasicLocker(envImpl); 78 txn3 = BasicLocker.createBasicLocker(envImpl); 79 txn4 = BasicLocker.createBasicLocker(envImpl); 80 } 81 initTxns(TransactionConfig config, EnvironmentImpl envImpl)82 private void initTxns(TransactionConfig config, EnvironmentImpl envImpl) 83 throws DatabaseException { 84 85 txn1 = Txn.createLocalTxn(envImpl, config); 86 txn2 = Txn.createLocalTxn(envImpl, config); 87 txn3 = Txn.createLocalTxn(envImpl, config); 88 txn4 = Txn.createLocalTxn(envImpl, config); 89 } 90 closeEnv()91 private void closeEnv() 92 throws DatabaseException { 93 94 txn1.operationEnd(); 95 txn2.operationEnd(); 96 txn3.operationEnd(); 97 txn4.operationEnd(); 98 99 close(env); 100 } 101 102 /* 103 * SR15926 showed a bug where node IDs that are > 0x80000000 produce 104 * negative lock table indexes becuase of the modulo arithmetic in 105 * LockManager.getLockTableIndex(). 106 * 107 * Since node IDs are no longer used for locking, this test is somewhat 108 * outdated. However, it is still a good idea to check that we can lock 109 * an LSN value with the sign bit set. 110 */ 111 @Test testSR15926LargeNodeIds()112 public void testSR15926LargeNodeIds() 113 throws Exception { 114 115 initLockers(); 116 117 final LockManager lockManager = DbInternal.getEnvironmentImpl(env). 118 getTxnManager().getLockManager(); 119 120 try { 121 lockManager.lock(0x80000000L, txn1, LockType.WRITE, 122 0, false, false, null); 123 } catch (Exception e) { 124 fail("shouldn't get exception " + e); 125 } finally { 126 closeEnv(); 127 } 128 } 129 130 @Test testNegatives()131 public void testNegatives() 132 throws Exception { 133 134 initLockers(); 135 136 final LockManager lockManager = DbInternal.getEnvironmentImpl(env). 137 getTxnManager().getLockManager(); 138 139 try { 140 assertFalse(lockManager.isOwner(nid, txn1, LockType.READ)); 141 assertFalse(lockManager.isOwner(nid, txn1, LockType.WRITE)); 142 assertFalse(lockManager.isLocked(nid)); 143 assertFalse(lockManager.isWaiter(nid, txn1)); 144 lockManager.lock(1, txn1, LockType.READ, 0, false, false, null); 145 146 /* already holds this lock */ 147 assertEquals(LockGrantType.EXISTING, 148 lockManager.lock(1, txn1, LockType.READ, 0, 149 false, false, null)); 150 assertFalse(lockManager.isOwner(nid, txn2, LockType.READ)); 151 assertFalse(lockManager.isOwner(nid, txn2, LockType.WRITE)); 152 assertTrue(lockManager.isLocked(nid)); 153 assertTrue(lockManager.nOwners(new Long(2)) == -1); 154 assertTrue(lockManager.nWaiters(new Long(2)) == -1); 155 156 /* lock 2 doesn't exist, shouldn't affect any the existing lock */ 157 lockManager.release(2L, txn1); 158 txn1.removeLock(2L); 159 assertTrue(lockManager.isLocked(nid)); 160 161 /* txn2 is not the owner, shouldn't release lock 1. */ 162 lockManager.release(1L, txn2); 163 txn2.removeLock(1L); 164 assertTrue(lockManager.isLocked(nid)); 165 assertTrue(lockManager.isOwner(nid, txn1, LockType.READ)); 166 assertTrue(lockManager.nOwners(nid) == 1); 167 168 /* Now really release. */ 169 lockManager.release(1L, txn1); 170 txn1.removeLock(1L); 171 assertFalse(lockManager.isLocked(nid)); 172 assertFalse(lockManager.isOwner(nid, txn1, LockType.READ)); 173 assertFalse(lockManager.nOwners(nid) == 1); 174 175 lockManager.lock(1, txn1, LockType.WRITE, 0, false, false, null); 176 /* holds write and subsequent request for READ is ok */ 177 lockManager.lock(1, txn1, LockType.READ, 0, false, false, null); 178 /* already holds this lock */ 179 assertTrue(lockManager.lock(1, txn1, LockType.WRITE, 180 0, false, false, null) == 181 LockGrantType.EXISTING); 182 assertFalse(lockManager.isWaiter(nid, txn1)); 183 } catch (Exception e) { 184 e.printStackTrace(); 185 throw e; 186 } finally { 187 closeEnv(); 188 } 189 } 190 191 /** 192 * Acquire three read locks and make sure that they share nicely. 193 */ 194 @Test testMultipleReaders()195 public void testMultipleReaders() 196 throws Throwable { 197 198 initLockers(); 199 200 final LockManager lockManager = DbInternal.getEnvironmentImpl(env). 201 getTxnManager().getLockManager(); 202 203 JUnitThread tester1 = 204 new JUnitThread("testMultipleReaders1") { 205 public void testBody() { 206 try { 207 lockManager.lock(1, txn1, LockType.READ, 0, 208 false, false, null); 209 assertTrue 210 (lockManager.isOwner(nid, txn1, LockType.READ)); 211 sequence.incrementAndGet(); 212 while (sequence.get() < 3) { 213 Thread.yield(); 214 } 215 lockManager.release(1L, txn1); 216 txn1.removeLock(1L); 217 } catch (DatabaseException DBE) { 218 DBE.printStackTrace(); 219 fail("caught DatabaseException " + DBE); 220 } 221 } 222 }; 223 224 JUnitThread tester2 = 225 new JUnitThread("testMultipleReaders2") { 226 public void testBody() { 227 try { 228 lockManager.lock(1, txn2, LockType.READ, 0, 229 false, false, null); 230 assertTrue 231 (lockManager.isOwner(nid, txn2, LockType.READ)); 232 sequence.incrementAndGet(); 233 while (sequence.get() < 3) { 234 Thread.yield(); 235 } 236 lockManager.release(1L, txn2); 237 txn2.removeLock(1L); 238 } catch (DatabaseException DBE) { 239 DBE.printStackTrace(); 240 fail("caught DatabaseException " + DBE); 241 } 242 } 243 }; 244 245 JUnitThread tester3 = 246 new JUnitThread("testMultipleReaders3") { 247 public void testBody() { 248 try { 249 lockManager.lock(1, txn3, LockType.READ, 0, 250 false, false, null); 251 assertTrue 252 (lockManager.isOwner(nid, txn3, LockType.READ)); 253 sequence.incrementAndGet(); 254 while (sequence.get() < 3) { 255 Thread.yield(); 256 } 257 lockManager.release(1L, txn3); 258 txn3.removeLock(1L); 259 } catch (DatabaseException DBE) { 260 DBE.printStackTrace(); 261 fail("caught DatabaseException " + DBE); 262 } 263 } 264 }; 265 266 tester1.start(); 267 tester2.start(); 268 tester3.start(); 269 tester1.finishTest(); 270 tester2.finishTest(); 271 tester3.finishTest(); 272 closeEnv(); 273 } 274 275 /** 276 * Grab two read locks, hold them, and make sure that a write lock 277 * waits for them to be released. 278 */ 279 @Test testMultipleReadersSingleWrite1()280 public void testMultipleReadersSingleWrite1() 281 throws Throwable { 282 283 initLockers(); 284 285 final LockManager lockManager = DbInternal.getEnvironmentImpl(env). 286 getTxnManager().getLockManager(); 287 288 JUnitThread tester1 = 289 new JUnitThread("testMultipleReaders1") { 290 public void testBody() { 291 try { 292 lockManager.lock(1, txn1, LockType.READ, 0, 293 false, false, null); 294 assertTrue 295 (lockManager.isOwner(nid, txn1, LockType.READ)); 296 while (lockManager.nWaiters(nid) < 1) { 297 Thread.yield(); 298 } 299 assertTrue(lockManager.isWaiter(nid, txn3)); 300 assertFalse(lockManager.isWaiter(nid, txn1)); 301 lockManager.release(1L, txn1); 302 txn1.removeLock(1L); 303 assertFalse 304 (lockManager.isOwner(nid, txn1, LockType.READ)); 305 } catch (DatabaseException DBE) { 306 DBE.printStackTrace(); 307 fail("caught DatabaseException " + DBE); 308 } 309 } 310 }; 311 312 JUnitThread tester2 = 313 new JUnitThread("testMultipleReaders2") { 314 public void testBody() { 315 try { 316 lockManager.lock(1, txn2, LockType.READ, 0, 317 false, false, null); 318 assertTrue 319 (lockManager.isOwner(nid, txn2, LockType.READ)); 320 while (lockManager.nWaiters(nid) < 1) { 321 Thread.yield(); 322 } 323 assertTrue(lockManager.isWaiter(nid, txn3)); 324 lockManager.release(1L, txn2); 325 txn2.removeLock(1L); 326 assertFalse 327 (lockManager.isOwner(nid, txn2, LockType.READ)); 328 } catch (DatabaseException DBE) { 329 DBE.printStackTrace(); 330 fail("caught DatabaseException " + DBE); 331 } 332 } 333 }; 334 335 JUnitThread tester3 = 336 new JUnitThread("testMultipleReaders3") { 337 public void testBody() { 338 try { 339 while (lockManager.nOwners(nid) < 2) { 340 Thread.yield(); 341 } 342 lockManager.lock(1, txn3, LockType.WRITE, 0, 343 false, false, null); 344 assertTrue 345 (lockManager.isOwner(nid, txn3, LockType.WRITE)); 346 } catch (DatabaseException DBE) { 347 DBE.printStackTrace(); 348 fail("caught DatabaseException " + DBE); 349 } 350 } 351 }; 352 353 tester1.start(); 354 tester2.start(); 355 tester3.start(); 356 tester1.finishTest(); 357 tester2.finishTest(); 358 tester3.finishTest(); 359 closeEnv(); 360 } 361 362 /** 363 * Acquire two read locks, put a write locker behind the two 364 * read lockers, and then queue a read locker behind the writer. 365 * Ensure that the third reader is not granted until the writer 366 * releases the lock. 367 */ 368 @Test testMultipleReadersSingleWrite2()369 public void testMultipleReadersSingleWrite2() 370 throws Throwable { 371 372 initLockers(); 373 374 final LockManager lockManager = DbInternal.getEnvironmentImpl(env). 375 getTxnManager().getLockManager(); 376 377 JUnitThread tester1 = 378 new JUnitThread("testMultipleReaders1") { 379 public void testBody() { 380 try { 381 lockManager.lock(1, txn1, LockType.READ, 0, 382 false, false, null); 383 assertTrue 384 (lockManager.isOwner(nid, txn1, LockType.READ)); 385 while (lockManager.nWaiters(nid) < 2) { 386 Thread.yield(); 387 } 388 lockManager.release(1L, txn1); 389 txn1.removeLock(1L); 390 } catch (DatabaseException DBE) { 391 DBE.printStackTrace(); 392 fail("caught DatabaseException " + DBE); 393 } 394 } 395 }; 396 397 JUnitThread tester2 = 398 new JUnitThread("testMultipleReaders2") { 399 public void testBody() { 400 try { 401 lockManager.lock(1, txn2, LockType.READ, 0, 402 false, false, null); 403 assertTrue 404 (lockManager.isOwner(nid, txn2, LockType.READ)); 405 while (lockManager.nWaiters(nid) < 2) { 406 Thread.yield(); 407 } 408 lockManager.release(1L, txn2); 409 txn2.removeLock(1L); 410 } catch (DatabaseException DBE) { 411 DBE.printStackTrace(); 412 fail("caught DatabaseException " + DBE); 413 } 414 } 415 }; 416 417 JUnitThread tester3 = 418 new JUnitThread("testMultipleReaders3") { 419 public void testBody() { 420 try { 421 while (lockManager.nOwners(nid) < 2) { 422 Thread.yield(); 423 } 424 lockManager.lock(1, txn3, LockType.WRITE, 0, 425 false, false, null); 426 while (lockManager.nWaiters(nid) < 1) { 427 Thread.yield(); 428 } 429 assertTrue 430 (lockManager.isOwner(nid, txn3, LockType.WRITE)); 431 lockManager.release(1L, txn3); 432 txn3.removeLock(1L); 433 } catch (DatabaseException DBE) { 434 DBE.printStackTrace(); 435 fail("caught DatabaseException " + DBE); 436 } 437 } 438 }; 439 440 JUnitThread tester4 = 441 new JUnitThread("testMultipleReaders4") { 442 public void testBody() { 443 try { 444 while (lockManager.nWaiters(nid) < 1) { 445 Thread.yield(); 446 } 447 lockManager.lock(1, txn4, LockType.READ, 0, 448 false, false, null); 449 assertTrue 450 (lockManager.isOwner(nid, txn4, LockType.READ)); 451 lockManager.release(1L, txn4); 452 txn4.removeLock(1L); 453 } catch (DatabaseException DBE) { 454 DBE.printStackTrace(); 455 fail("caught DatabaseException " + DBE); 456 } 457 } 458 }; 459 460 tester1.start(); 461 tester2.start(); 462 tester3.start(); 463 tester4.start(); 464 tester1.finishTest(); 465 tester2.finishTest(); 466 tester3.finishTest(); 467 tester4.finishTest(); 468 closeEnv(); 469 } 470 471 /** 472 * Acquire two read locks for two transactions, then request a write 473 * lock for a third transaction. Then request a write lock for one 474 * of the first transactions that already has a read lock (i.e. 475 * request an upgrade lock). Make sure it butts in front of the 476 * existing wait lock. 477 */ 478 @Test testUpgradeLock()479 public void testUpgradeLock() 480 throws Throwable { 481 482 initLockers(); 483 484 final LockManager lockManager = DbInternal.getEnvironmentImpl(env). 485 getTxnManager().getLockManager(); 486 487 JUnitThread tester1 = 488 new JUnitThread("testUpgradeLock1") { 489 public void testBody() { 490 try { 491 lockManager.lock(1, txn1, LockType.READ, 0, 492 false, false, null); 493 assertTrue 494 (lockManager.isOwner(nid, txn1, LockType.READ)); 495 while (lockManager.nWaiters(nid) < 2) { 496 Thread.yield(); 497 } 498 lockManager.release(1L, txn1); 499 txn1.removeLock(1L); 500 } catch (DatabaseException DBE) { 501 DBE.printStackTrace(); 502 fail("caught DatabaseException " + DBE); 503 } 504 } 505 }; 506 507 JUnitThread tester2 = 508 new JUnitThread("testUpgradeLock2") { 509 public void testBody() { 510 try { 511 lockManager.lock(1, txn2, LockType.READ, 0, 512 false, false, null); 513 assertTrue 514 (lockManager.isOwner(nid, txn2, LockType.READ)); 515 while (lockManager.nWaiters(nid) < 1) { 516 Thread.yield(); 517 } 518 lockManager.lock(1, txn2, LockType.WRITE, 0, 519 false, false, null); 520 assertTrue(lockManager.nWaiters(nid) == 1); 521 lockManager.release(1L, txn2); 522 txn2.removeLock(1L); 523 } catch (DatabaseException DBE) { 524 DBE.printStackTrace(); 525 fail("caught DatabaseException " + DBE); 526 } 527 } 528 }; 529 530 JUnitThread tester3 = 531 new JUnitThread("testUpgradeLock3") { 532 public void testBody() { 533 try { 534 while (lockManager.nOwners(nid) < 2) { 535 Thread.yield(); 536 } 537 lockManager.lock(1, txn3, LockType.WRITE, 0, 538 false, false, null); 539 assertTrue 540 (lockManager.isOwner(nid, txn3, LockType.WRITE)); 541 lockManager.release(1L, txn3); 542 txn3.removeLock(1L); 543 } catch (DatabaseException DBE) { 544 DBE.printStackTrace(); 545 fail("caught DatabaseException " + DBE); 546 } 547 } 548 }; 549 550 tester1.start(); 551 tester2.start(); 552 tester3.start(); 553 tester1.finishTest(); 554 tester2.finishTest(); 555 tester3.finishTest(); 556 closeEnv(); 557 } 558 559 /** 560 * Acquire a read lock, then request a write lock for a second 561 * transaction in non-blocking mode. Make sure it fails. 562 */ 563 @Test testNonBlockingLock1()564 public void testNonBlockingLock1() 565 throws Throwable { 566 567 initLockers(); 568 569 final LockManager lockManager = DbInternal.getEnvironmentImpl(env). 570 getTxnManager().getLockManager(); 571 572 JUnitThread tester1 = 573 new JUnitThread("testNonBlocking1") { 574 public void testBody() { 575 try { 576 lockManager.lock(1, txn1, LockType.READ, 0, 577 false, false, null); 578 assertTrue 579 (lockManager.isOwner(nid, txn1, LockType.READ)); 580 while (sequence.get() < 1) { 581 Thread.yield(); 582 } 583 lockManager.release(1L, txn1); 584 txn1.removeLock(1L); 585 } catch (DatabaseException DBE) { 586 DBE.printStackTrace(); 587 fail("caught DatabaseException " + DBE); 588 } 589 } 590 }; 591 592 JUnitThread tester2 = 593 new JUnitThread("testNonBlocking2") { 594 public void testBody() { 595 try { 596 /* wait for tester1 */ 597 while (lockManager.nOwners(nid) < 1) { 598 Thread.yield(); 599 } 600 LockGrantType grant = lockManager.lock 601 (1, txn2, LockType.WRITE, 0, true, false, null); 602 assertSame(LockGrantType.DENIED, grant); 603 assertFalse 604 (lockManager.isOwner(nid, txn2, LockType.WRITE)); 605 assertFalse 606 (lockManager.isOwner(nid, txn2, LockType.READ)); 607 assertTrue(lockManager.nWaiters(nid) == 0); 608 assertTrue(lockManager.nOwners(nid) == 1); 609 sequence.incrementAndGet(); 610 /* wait for tester1 to release the lock */ 611 while (lockManager.nOwners(nid) > 0) { 612 Thread.yield(); 613 } 614 assertTrue 615 (lockManager.lock(1, txn2, LockType.WRITE, 0, 616 false, false, null) == 617 LockGrantType.NEW); 618 assertTrue 619 (lockManager.isOwner(nid, txn2, LockType.WRITE)); 620 assertTrue 621 (lockManager.isOwner(nid, txn2, LockType.READ)); 622 assertTrue(lockManager.nWaiters(nid) == 0); 623 assertTrue(lockManager.nOwners(nid) == 1); 624 lockManager.release(1L, txn2); 625 txn2.removeLock(1L); 626 } catch (DatabaseException DBE) { 627 DBE.printStackTrace(); 628 fail("caught DatabaseException " + DBE); 629 } 630 } 631 }; 632 633 tester1.start(); 634 tester2.start(); 635 tester1.finishTest(); 636 tester2.finishTest(); 637 closeEnv(); 638 } 639 640 /** 641 * Acquire a write lock, then request a read lock for a second 642 * transaction in non-blocking mode. Make sure it fails. 643 */ 644 @Test testNonBlockingLock2()645 public void testNonBlockingLock2() 646 throws Throwable { 647 648 initLockers(); 649 650 final LockManager lockManager = DbInternal.getEnvironmentImpl(env). 651 getTxnManager().getLockManager(); 652 653 JUnitThread tester1 = 654 new JUnitThread("testNonBlocking1") { 655 public void testBody() { 656 try { 657 lockManager.lock(1, txn1, LockType.WRITE, 0, 658 false, false, null); 659 assertTrue 660 (lockManager.isOwner(nid, txn1, LockType.WRITE)); 661 sequence.incrementAndGet(); 662 while (sequence.get() < 2) { 663 Thread.yield(); 664 } 665 lockManager.release(1L, txn1); 666 txn1.removeLock(1L); 667 } catch (DatabaseException DBE) { 668 DBE.printStackTrace(); 669 fail("caught DatabaseException " + DBE); 670 } 671 } 672 }; 673 674 JUnitThread tester2 = 675 new JUnitThread("testNonBlocking2") { 676 public void testBody() { 677 try { 678 /* wait for tester1 */ 679 while (sequence.get() < 1) { 680 Thread.yield(); 681 } 682 LockGrantType grant = lockManager.lock 683 (1, txn2, LockType.READ, 0, true, false, null); 684 assertSame(LockGrantType.DENIED, grant); 685 assertFalse 686 (lockManager.isOwner(nid, txn2, LockType.READ)); 687 assertFalse 688 (lockManager.isOwner(nid, txn2, LockType.WRITE)); 689 assertTrue(lockManager.nWaiters(nid) == 0); 690 assertTrue(lockManager.nOwners(nid) == 1); 691 sequence.incrementAndGet(); 692 /* wait for tester1 to release the lock */ 693 while (lockManager.nOwners(nid) > 0) { 694 Thread.yield(); 695 } 696 assertTrue 697 (lockManager.lock(1, txn2, LockType.READ, 0, 698 false, false, null) == 699 LockGrantType.NEW); 700 assertTrue 701 (lockManager.isOwner(nid, txn2, LockType.READ)); 702 assertFalse 703 (lockManager.isOwner(nid, txn2, LockType.WRITE)); 704 assertTrue(lockManager.nWaiters(nid) == 0); 705 assertTrue(lockManager.nOwners(nid) == 1); 706 lockManager.release(1L, txn2); 707 txn2.removeLock(1L); 708 } catch (DatabaseException DBE) { 709 DBE.printStackTrace(); 710 fail("caught DatabaseException " + DBE); 711 } 712 } 713 }; 714 715 tester1.start(); 716 tester2.start(); 717 tester1.finishTest(); 718 tester2.finishTest(); 719 closeEnv(); 720 } 721 722 /** 723 * Acquire a write lock, then request a read lock for a second 724 * transaction in blocking mode. Make sure it waits. 725 */ 726 @Test testWaitingLock()727 public void testWaitingLock() 728 throws Throwable { 729 730 initLockers(); 731 732 final LockManager lockManager = DbInternal.getEnvironmentImpl(env). 733 getTxnManager().getLockManager(); 734 735 JUnitThread tester1 = 736 new JUnitThread("testBlocking1") { 737 public void testBody() { 738 try { 739 lockManager.lock(1, txn1, LockType.WRITE, 0, 740 false, false, null); 741 assertTrue 742 (lockManager.isOwner(nid, txn1, LockType.WRITE)); 743 sequence.incrementAndGet(); 744 while (sequence.get() < 2) { 745 Thread.yield(); 746 } 747 lockManager.release(1L, txn1); 748 txn1.removeLock(1L); 749 } catch (DatabaseException DBE) { 750 DBE.printStackTrace(); 751 fail("caught DatabaseException " + DBE); 752 } 753 } 754 }; 755 756 JUnitThread tester2 = 757 new JUnitThread("testBlocking2") { 758 public void testBody() { 759 try { 760 /* wait for tester1 */ 761 while (sequence.get() < 1) { 762 Thread.yield(); 763 } 764 try { 765 lockManager.lock(1, txn2, LockType.READ, 500, 766 false, false, null); 767 fail("didn't time out"); 768 } catch (LockConflictException e) { 769 assertTrue 770 (TestUtils.skipVersion(e).startsWith("Lock ")); 771 } 772 assertFalse 773 (lockManager.isOwner(nid, txn2, LockType.READ)); 774 assertFalse 775 (lockManager.isOwner(nid, txn2, LockType.WRITE)); 776 assertTrue(lockManager.nWaiters(nid) == 0); 777 assertTrue(lockManager.nOwners(nid) == 1); 778 sequence.incrementAndGet(); 779 /* wait for tester1 to release the lock */ 780 while (lockManager.nOwners(nid) > 0) { 781 Thread.yield(); 782 } 783 assertTrue 784 (lockManager.lock(1, txn2, LockType.READ, 0, 785 false, false, null) == 786 LockGrantType.NEW); 787 assertTrue 788 (lockManager.isOwner(nid, txn2, LockType.READ)); 789 assertFalse 790 (lockManager.isOwner(nid, txn2, LockType.WRITE)); 791 assertTrue(lockManager.nWaiters(nid) == 0); 792 assertTrue(lockManager.nOwners(nid) == 1); 793 lockManager.release(1L, txn2); 794 txn2.removeLock(1L); 795 } catch (DatabaseException DBE) { 796 DBE.printStackTrace(); 797 fail("caught DatabaseException " + DBE); 798 } 799 } 800 }; 801 802 tester1.start(); 803 tester2.start(); 804 tester1.finishTest(); 805 tester2.finishTest(); 806 closeEnv(); 807 } 808 809 /** 810 * Test that LockConflictException has the correct owners and waiters when 811 * it is thrown due to a timeout. 812 * 813 * Create five threads, the first two of which take a read lock and the 814 * second two of which try for a write lock backed up behind the two 815 * read locks. Then have a fifth thread try for a read lock which backs 816 * up behind all of them. The first two threads (read lockers) are owners 817 * and the second two threads are waiters. When the fifth thread catches 818 * the LockConflictException make sure that it contains the txn ids for the 819 * two readers in the owners array and the txn ids for the two writers 820 * in the waiters array. 821 */ 822 @Test testLockConflictInfo()823 public void testLockConflictInfo() 824 throws Throwable { 825 826 EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 827 final LockManager lockManager = 828 envImpl.getTxnManager().getLockManager(); 829 TransactionConfig config = new TransactionConfig(); 830 831 initTxns(config, envImpl); 832 833 final Txn txn5 = Txn.createLocalTxn(envImpl, config); 834 835 sequence.set(0); 836 JUnitThread tester1 = 837 new JUnitThread("testMultipleReaders1") { 838 public void testBody() { 839 try { 840 lockManager.lock(1, txn1, LockType.READ, 0, 841 false, false, null); 842 assertTrue 843 (lockManager.isOwner(nid, txn1, LockType.READ)); 844 while (sequence.get() < 1) { 845 Thread.yield(); 846 } 847 lockManager.release(1L, txn1); 848 txn1.removeLock(1L); 849 } catch (DatabaseException DBE) { 850 DBE.printStackTrace(); 851 fail("caught DatabaseException " + DBE); 852 } 853 } 854 }; 855 856 JUnitThread tester2 = 857 new JUnitThread("testMultipleReaders2") { 858 public void testBody() { 859 try { 860 lockManager.lock(1, txn2, LockType.READ, 0, 861 false, false, null); 862 assertTrue 863 (lockManager.isOwner(nid, txn2, LockType.READ)); 864 while (sequence.get() < 1) { 865 Thread.yield(); 866 } 867 lockManager.release(1L, txn2); 868 txn2.removeLock(1L); 869 } catch (DatabaseException DBE) { 870 DBE.printStackTrace(); 871 fail("caught DatabaseException " + DBE); 872 } 873 } 874 }; 875 876 JUnitThread tester3 = 877 new JUnitThread("testMultipleReaders3") { 878 public void testBody() { 879 try { 880 while (lockManager.nOwners(nid) < 2) { 881 Thread.yield(); 882 } 883 lockManager.lock(1, txn3, LockType.WRITE, 0, 884 false, false, null); 885 while (sequence.get() < 1) { 886 Thread.yield(); 887 } 888 assertTrue 889 (lockManager.isOwner(nid, txn3, LockType.WRITE)); 890 lockManager.release(1L, txn3); 891 txn3.removeLock(1L); 892 } catch (DatabaseException DBE) { 893 DBE.printStackTrace(); 894 fail("caught DatabaseException " + DBE); 895 } 896 } 897 }; 898 899 JUnitThread tester4 = 900 new JUnitThread("testMultipleReaders4") { 901 public void testBody() { 902 try { 903 while (lockManager.nOwners(nid) < 2) { 904 Thread.yield(); 905 } 906 lockManager.lock(1, txn4, LockType.WRITE, 0, 907 false, false, null); 908 while (sequence.get() < 1) { 909 Thread.yield(); 910 } 911 assertTrue 912 (lockManager.isOwner(nid, txn4, LockType.WRITE)); 913 lockManager.release(1L, txn4); 914 txn4.removeLock(1L); 915 } catch (DatabaseException DBE) { 916 DBE.printStackTrace(); 917 fail("caught DatabaseException " + DBE); 918 } 919 } 920 }; 921 922 JUnitThread tester5 = 923 new JUnitThread("testMultipleReaders5") { 924 public void testBody() { 925 try { 926 while (lockManager.nWaiters(nid) < 1) { 927 Thread.yield(); 928 } 929 lockManager.lock(1, txn5, LockType.READ, 900, 930 false, false, null); 931 fail("expected LockConflictException"); 932 } catch (LockConflictException e) { 933 934 long[] owners = e.getOwnerTxnIds(); 935 long[] waiters = e.getWaiterTxnIds(); 936 937 assertTrue((owners[0] == txn1.getId() && 938 owners[1] == txn2.getId()) || 939 (owners[1] == txn1.getId() && 940 owners[0] == txn2.getId())); 941 942 assertTrue((waiters[0] == txn3.getId() && 943 waiters[1] == txn4.getId()) || 944 (waiters[1] == txn3.getId() && 945 waiters[0] == txn4.getId())); 946 947 } catch (DatabaseException DBE) { 948 fail("expected LockConflictException"); 949 DBE.printStackTrace(System.out); 950 } 951 sequence.set(1); 952 } 953 }; 954 955 tester1.start(); 956 tester2.start(); 957 tester3.start(); 958 tester4.start(); 959 tester5.start(); 960 tester1.finishTest(); 961 tester2.finishTest(); 962 tester3.finishTest(); 963 tester4.finishTest(); 964 tester5.finishTest(); 965 ((Txn) txn1).abort(false); 966 ((Txn) txn2).abort(false); 967 ((Txn) txn3).abort(false); 968 ((Txn) txn4).abort(false); 969 txn5.abort(false); 970 closeEnv(); 971 } 972 973 /** 974 * When a true deadlock occurs, check that we have detected it and added 975 * information about it to the exception message. 976 * 977 * The deadlock is: 978 * 979 * + T1 locks L1 then L2 980 * + T2 locks L2 then L1 981 * 982 * T1 waits forever for L2, while T2 does not wait forever for L1, so the 983 * deadlock is detected in T2 due to the timeout. 984 */ 985 @Test testDeadlockMessage()986 public void testDeadlockMessage() 987 throws Throwable { 988 989 final EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 990 991 final LockManager lockManager = 992 envImpl.getTxnManager().getLockManager(); 993 994 final TransactionConfig config = 995 new TransactionConfig().setDurability(Durability.COMMIT_NO_SYNC); 996 997 initTxns(config, envImpl); 998 999 JUnitThread tester1 = 1000 new JUnitThread("testDeadlockMessage1") { 1001 public void testBody() throws Throwable { 1002 try { 1003 /* Lock L1, should always be granted */ 1004 lockManager.lock( 1005 1L, txn1, LockType.WRITE, 1, 1006 false, false, null); 1007 1008 assertTrue( 1009 lockManager.isOwner(1L, txn1, LockType.WRITE)); 1010 1011 /* Wait for T2 to lock L2. */ 1012 while (lockManager.nOwners(2L) < 1) { 1013 Thread.yield(); 1014 } 1015 1016 /* 1017 * Try to lock L2, wait forever. Lock is granted after 1018 * T2 aborts and releases L2. 1019 */ 1020 lockManager.lock( 1021 2L, txn1, LockType.WRITE, 0, 1022 false, false, null); 1023 } finally { 1024 lockManager.release(1L, txn1); 1025 lockManager.release(2L, txn1); 1026 txn1.removeLock(1L); 1027 txn1.removeLock(2L); 1028 } 1029 } 1030 }; 1031 1032 JUnitThread tester2 = 1033 new JUnitThread("testDeadlockMessage2") { 1034 public void testBody() throws Throwable { 1035 try { 1036 /* Lock L1, should always be granted */ 1037 lockManager.lock( 1038 2L, txn2, LockType.WRITE, 0, 1039 false, false, null); 1040 1041 assertTrue( 1042 lockManager.isOwner(2L, txn2, LockType.WRITE)); 1043 1044 /* Wait for T1 to lock L1. */ 1045 while (lockManager.nOwners(1L) < 1) { 1046 Thread.yield(); 1047 } 1048 1049 /* Wait for T1 to wait for L2. */ 1050 while (lockManager.nWaiters(2L) < 1) { 1051 Thread.yield(); 1052 } 1053 1054 /* 1055 * Try to lock L1, don't wait forever. LockConflict 1056 * occurs with deadlock information. 1057 */ 1058 lockManager.lock( 1059 1L, txn2, LockType.WRITE, 25, 1060 false, false, null); 1061 1062 fail("expected LockConflictException"); 1063 1064 } catch (LockConflictException e) { 1065 1066 final String msg = e.getMessage(); 1067 1068 assertTrue( 1069 msg, 1070 msg.contains("" + txn1 + " waits for ")); 1071 1072 assertTrue( 1073 msg, 1074 msg.contains("" + txn2 + " waits for ")); 1075 1076 assertTrue( 1077 msg, 1078 msg.contains("" + txn2 + " owns ")); 1079 } finally { 1080 lockManager.release(2L, txn2); 1081 txn2.removeLock(2L); 1082 } 1083 } 1084 }; 1085 1086 tester1.start(); 1087 tester2.start(); 1088 tester1.finishTest(); 1089 tester2.finishTest(); 1090 ((Txn) txn1).abort(false); 1091 ((Txn) txn2).abort(false); 1092 ((Txn) txn3).abort(false); 1093 ((Txn) txn4).abort(false); 1094 closeEnv(); 1095 } 1096 1097 /** 1098 * Test lock stealing. 1099 * 1100 * Create five threads, with the first two taking a read lock and the 1101 * second two trying for a write lock backed up behind the two read locks. 1102 * Then have a fifth importunate thread try for a write lock which will 1103 * flush the first two owners. The first two threads (read lockers) are 1104 * owners and the second two threads are waiters. When the importunate 1105 * thread steals the lock, make sure that the other two owners become 1106 * onlyAbortable. 1107 */ 1108 @Test testImportunateTxn1()1109 public void testImportunateTxn1() 1110 throws Throwable { 1111 1112 EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 1113 1114 /* LockPreemptedException is thrown only if replicated. */ 1115 if (!envImpl.isReplicated()) { 1116 close(env); 1117 return; 1118 } 1119 1120 /* 1121 * Use an arbitrary DatabaseImpl so that the Txn.lock method can be 1122 * called below with a non-null database param. Although this is a 1123 * LockManager test, lock preemption requires calling Txn.lock. 1124 */ 1125 final DatabaseImpl dbImpl = 1126 envImpl.getDbTree().getDb(DbTree.NAME_DB_ID); 1127 1128 final LockManager lockManager = 1129 envImpl.getTxnManager().getLockManager(); 1130 TransactionConfig config = new TransactionConfig(); 1131 1132 initTxns(config, envImpl); 1133 1134 final Txn txn5 = Txn.createLocalTxn(envImpl, config); 1135 txn5.setImportunate(true); 1136 1137 sequence.set(0); 1138 JUnitThread tester1 = 1139 new JUnitThread("testImportunateTxn1.1") { 1140 public void testBody() { 1141 try { 1142 txn1.setLockTimeout(0); 1143 txn1.lock(1, LockType.READ, false, dbImpl); 1144 assertTrue 1145 (lockManager.isOwner(nid, txn1, LockType.READ)); 1146 while (sequence.get() < 1) { 1147 Thread.yield(); 1148 } 1149 assertTrue(txn1.isPreempted()); 1150 sequence.incrementAndGet(); 1151 } catch (DatabaseException DBE) { 1152 DBE.printStackTrace(); 1153 fail("caught DatabaseException " + DBE); 1154 } 1155 } 1156 }; 1157 1158 JUnitThread tester2 = 1159 new JUnitThread("testImportunateTxn1.2") { 1160 public void testBody() { 1161 try { 1162 txn2.setLockTimeout(0); 1163 txn2.lock(1, LockType.READ, false, dbImpl); 1164 assertTrue 1165 (lockManager.isOwner(nid, txn2, LockType.READ)); 1166 while (sequence.get() < 1) { 1167 Thread.yield(); 1168 } 1169 assertTrue(txn1.isPreempted()); 1170 sequence.incrementAndGet(); 1171 } catch (DatabaseException DBE) { 1172 DBE.printStackTrace(); 1173 fail("caught DatabaseException " + DBE); 1174 } 1175 } 1176 }; 1177 1178 JUnitThread tester3 = 1179 new JUnitThread("testImportunateTxn1.3") { 1180 public void testBody() { 1181 try { 1182 while (lockManager.nOwners(nid) < 2) { 1183 Thread.yield(); 1184 } 1185 txn3.setLockTimeout(0); 1186 txn3.lock(1, LockType.WRITE, false, dbImpl); 1187 while (sequence.get() < 1) { 1188 Thread.yield(); 1189 } 1190 assertTrue 1191 (lockManager.isOwner(nid, txn3, LockType.WRITE)); 1192 lockManager.release(1L, txn3); 1193 txn3.removeLock(1L); 1194 } catch (DatabaseException DBE) { 1195 DBE.printStackTrace(); 1196 fail("caught DatabaseException " + DBE); 1197 } 1198 } 1199 }; 1200 1201 JUnitThread tester4 = 1202 new JUnitThread("testImportunateTxn1.4") { 1203 public void testBody() { 1204 try { 1205 while (lockManager.nOwners(nid) < 2) { 1206 Thread.yield(); 1207 } 1208 txn4.setLockTimeout(0); 1209 txn4.lock(1, LockType.WRITE, false, dbImpl); 1210 while (sequence.get() < 1) { 1211 Thread.yield(); 1212 } 1213 assertTrue 1214 (lockManager.isOwner(nid, txn4, LockType.WRITE)); 1215 lockManager.release(1L, txn4); 1216 txn4.removeLock(1L); 1217 } catch (DatabaseException DBE) { 1218 DBE.printStackTrace(); 1219 fail("caught DatabaseException " + DBE); 1220 } 1221 } 1222 }; 1223 1224 JUnitThread tester5 = 1225 new JUnitThread("testImportunateTxn1.5") { 1226 public void testBody() { 1227 try { 1228 while (lockManager.nWaiters(nid) < 1) { 1229 Thread.yield(); 1230 } 1231 txn5.setImportunate(true); 1232 txn5.setLockTimeout(900); 1233 txn5.lock(1, LockType.WRITE, false, dbImpl); 1234 sequence.set(1); 1235 while (sequence.get() < 3) { 1236 Thread.yield(); 1237 } 1238 lockManager.release(1L, txn5); 1239 txn5.removeLock(1L); 1240 } catch (DatabaseException DBE) { 1241 DBE.printStackTrace(System.out); 1242 fail("unexpected DatabaseException"); 1243 } 1244 } 1245 }; 1246 1247 tester1.start(); 1248 tester2.start(); 1249 tester3.start(); 1250 tester4.start(); 1251 tester5.start(); 1252 tester1.finishTest(); 1253 tester2.finishTest(); 1254 tester3.finishTest(); 1255 tester4.finishTest(); 1256 tester5.finishTest(); 1257 ((Txn) txn1).abort(false); 1258 ((Txn) txn2).abort(false); 1259 ((Txn) txn3).abort(false); 1260 ((Txn) txn4).abort(false); 1261 txn5.abort(false); 1262 closeEnv(); 1263 } 1264 1265 /** 1266 * Test lock stealing. 1267 * 1268 * Create five threads, with the first two taking a read lock and the 1269 * second two trying for a write lock backed up behind the two read locks. 1270 * Then have a fifth importunate thread take a read lock and try for a 1271 * write lock (upgrade) which will flush the first two read lock owners. 1272 * The first two threads (read lockers) are owners and the second two 1273 * threads are waiters. When the importunate thread steals the lock, make 1274 * sure that the other two owners become onlyAbortable. 1275 */ 1276 @Test testImportunateTxn2()1277 public void testImportunateTxn2() 1278 throws Throwable { 1279 1280 EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 1281 1282 /* LockPreemptedException is thrown only if replicated. */ 1283 if (!envImpl.isReplicated()) { 1284 close(env); 1285 return; 1286 } 1287 1288 /* 1289 * Use an arbitrary DatabaseImpl so that the Txn.lock method can be 1290 * called below with a non-null database param. Although this is a 1291 * LockManager test, lock preemption requires calling Txn.lock. 1292 */ 1293 final DatabaseImpl dbImpl = 1294 envImpl.getDbTree().getDb(DbTree.NAME_DB_ID); 1295 1296 final LockManager lockManager = 1297 envImpl.getTxnManager().getLockManager(); 1298 TransactionConfig config = new TransactionConfig(); 1299 1300 initTxns(config, envImpl); 1301 1302 final Txn txn5 = Txn.createLocalTxn(envImpl, config); 1303 txn5.setImportunate(true); 1304 1305 sequence.set(0); 1306 JUnitThread tester1 = 1307 new JUnitThread("testImportunateTxn1.1") { 1308 public void testBody() { 1309 try { 1310 txn1.setLockTimeout(0); 1311 txn1.lock(1, LockType.READ, false, dbImpl); 1312 assertTrue 1313 (lockManager.isOwner(nid, txn1, LockType.READ)); 1314 while (sequence.get() < 1) { 1315 Thread.yield(); 1316 } 1317 assertTrue(txn1.isPreempted()); 1318 sequence.incrementAndGet(); 1319 } catch (DatabaseException DBE) { 1320 DBE.printStackTrace(); 1321 fail("caught DatabaseException " + DBE); 1322 } 1323 } 1324 }; 1325 1326 JUnitThread tester2 = 1327 new JUnitThread("testImportunateTxn1.2") { 1328 public void testBody() { 1329 try { 1330 txn2.setLockTimeout(0); 1331 txn2.lock(1, LockType.READ, false, dbImpl); 1332 assertTrue 1333 (lockManager.isOwner(nid, txn2, LockType.READ)); 1334 while (sequence.get() < 1) { 1335 Thread.yield(); 1336 } 1337 assertTrue(txn2.isPreempted()); 1338 sequence.incrementAndGet(); 1339 } catch (DatabaseException DBE) { 1340 DBE.printStackTrace(); 1341 fail("caught DatabaseException " + DBE); 1342 } 1343 } 1344 }; 1345 1346 JUnitThread tester3 = 1347 new JUnitThread("testImportunateTxn1.3") { 1348 public void testBody() { 1349 try { 1350 while (lockManager.nOwners(nid) < 3) { 1351 Thread.yield(); 1352 } 1353 txn3.setLockTimeout(0); 1354 txn3.lock(1, LockType.WRITE, false, dbImpl); 1355 while (sequence.get() < 1) { 1356 Thread.yield(); 1357 } 1358 assertTrue 1359 (lockManager.isOwner(nid, txn3, LockType.WRITE)); 1360 lockManager.release(1L, txn3); 1361 txn3.removeLock(1L); 1362 } catch (DatabaseException DBE) { 1363 DBE.printStackTrace(); 1364 fail("caught DatabaseException " + DBE); 1365 } 1366 } 1367 }; 1368 1369 JUnitThread tester4 = 1370 new JUnitThread("testImportunateTxn1.4") { 1371 public void testBody() { 1372 try { 1373 while (lockManager.nOwners(nid) < 3) { 1374 Thread.yield(); 1375 } 1376 txn4.setLockTimeout(0); 1377 txn4.lock(1, LockType.WRITE, false, dbImpl); 1378 while (sequence.get() < 1) { 1379 Thread.yield(); 1380 } 1381 assertTrue 1382 (lockManager.isOwner(nid, txn4, LockType.WRITE)); 1383 lockManager.release(1L, txn4); 1384 txn4.removeLock(1L); 1385 } catch (DatabaseException DBE) { 1386 DBE.printStackTrace(); 1387 fail("caught DatabaseException " + DBE); 1388 } 1389 } 1390 }; 1391 1392 JUnitThread tester5 = 1393 new JUnitThread("testImportunateTxn1.5") { 1394 public void testBody() { 1395 try { 1396 txn5.setLockTimeout(0); 1397 txn5.lock(1, LockType.READ, false, dbImpl); 1398 while (lockManager.nWaiters(nid) < 1) { 1399 Thread.yield(); 1400 } 1401 txn5.setImportunate(true); 1402 txn5.setLockTimeout(900); 1403 txn5.lock(1, LockType.WRITE, false, dbImpl); 1404 sequence.set(1); 1405 while (sequence.get() < 3) { 1406 Thread.yield(); 1407 } 1408 lockManager.release(1L, txn5); 1409 txn5.removeLock(1L); 1410 } catch (DatabaseException DBE) { 1411 DBE.printStackTrace(System.out); 1412 fail("unexpected DatabaseException"); 1413 } 1414 } 1415 }; 1416 1417 tester1.start(); 1418 tester2.start(); 1419 tester3.start(); 1420 tester4.start(); 1421 tester5.start(); 1422 tester1.finishTest(); 1423 tester2.finishTest(); 1424 tester3.finishTest(); 1425 tester4.finishTest(); 1426 tester5.finishTest(); 1427 ((Txn) txn1).abort(false); 1428 ((Txn) txn2).abort(false); 1429 ((Txn) txn3).abort(false); 1430 ((Txn) txn4).abort(false); 1431 txn5.abort(false); 1432 closeEnv(); 1433 } 1434 } 1435