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