001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.lockmanager.api;
006:
007: import EDU.oswego.cs.dl.util.concurrent.BrokenBarrierException;
008: import EDU.oswego.cs.dl.util.concurrent.CyclicBarrier;
009: import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
010: import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
011:
012: import com.tc.exception.TCLockUpgradeNotSupportedError;
013: import com.tc.exception.TCRuntimeException;
014: import com.tc.logging.NullTCLogger;
015: import com.tc.logging.TCLogger;
016: import com.tc.management.ClientLockStatManager;
017: import com.tc.object.lockmanager.api.TestRemoteLockManager.LockResponder;
018: import com.tc.object.lockmanager.impl.ClientLockManagerImpl;
019: import com.tc.object.session.SessionID;
020: import com.tc.object.session.SessionManager;
021: import com.tc.object.session.SessionProvider;
022: import com.tc.object.session.TestSessionManager;
023: import com.tc.object.tx.WaitInvocation;
024: import com.tc.util.concurrent.NoExceptionLinkedQueue;
025: import com.tc.util.concurrent.ThreadUtil;
026:
027: import java.util.ArrayList;
028: import java.util.Collection;
029: import java.util.Collections;
030: import java.util.HashSet;
031: import java.util.Iterator;
032: import java.util.LinkedList;
033: import java.util.List;
034: import java.util.Set;
035:
036: import junit.framework.TestCase;
037:
038: /**
039: * @author steve
040: */
041: public class ClientLockManagerTest extends TestCase {
042: private ClientLockManager lockManager;
043:
044: private TestRemoteLockManager rmtLockManager;
045:
046: private TestSessionManager sessionManager;
047:
048: protected void setUp() throws Exception {
049: super .setUp();
050: sessionManager = new TestSessionManager();
051: rmtLockManager = new TestRemoteLockManager(sessionManager);
052: lockManager = new ClientLockManagerImpl(new NullTCLogger(),
053: rmtLockManager, sessionManager,
054: ClientLockStatManager.NULL_CLIENT_LOCK_STAT_MANAGER);
055: rmtLockManager.setClientLockManager(lockManager);
056: }
057:
058: public void testNestedSynchronousWrite() {
059: final LockID lockID_1 = new LockID("1");
060: final LockID lockID_2 = new LockID("2");
061: final ThreadID threadID_1 = new ThreadID(1);
062: final ThreadID threadID_2 = new ThreadID(2);
063:
064: rmtLockManager.resetFlushCount();
065:
066: assertEquals(0, rmtLockManager.getFlushCount());
067: lockManager.lock(lockID_1, threadID_1, LockLevel.WRITE);
068: lockManager.lock(lockID_1, threadID_1, LockLevel.READ);
069: lockManager.lock(lockID_1, threadID_1,
070: LockLevel.SYNCHRONOUS_WRITE);
071: lockManager.lock(lockID_1, threadID_1, LockLevel.WRITE);
072: lockManager.lock(lockID_1, threadID_1,
073: LockLevel.SYNCHRONOUS_WRITE);
074: assertEquals(0, rmtLockManager.getFlushCount());
075: lockManager.unlock(lockID_1, threadID_1);
076: assertEquals(1, rmtLockManager.getFlushCount());
077: lockManager.unlock(lockID_1, threadID_1);
078: assertEquals(1, rmtLockManager.getFlushCount());
079: lockManager.unlock(lockID_1, threadID_1);
080: assertEquals(2, rmtLockManager.getFlushCount());
081: lockManager.unlock(lockID_1, threadID_1);
082: assertEquals(2, rmtLockManager.getFlushCount());
083: lockManager.unlock(lockID_1, threadID_1);
084: assertEquals(3, rmtLockManager.getFlushCount());
085:
086: rmtLockManager.resetFlushCount();
087: rmtLockManager.makeLocksGreedy();
088:
089: assertEquals(0, rmtLockManager.getFlushCount());
090: lockManager.lock(lockID_2, threadID_2, LockLevel.WRITE);
091: lockManager.lock(lockID_2, threadID_2, LockLevel.READ);
092: lockManager.lock(lockID_2, threadID_2,
093: LockLevel.SYNCHRONOUS_WRITE);
094: lockManager.lock(lockID_2, threadID_2, LockLevel.WRITE);
095: lockManager.lock(lockID_2, threadID_2,
096: LockLevel.SYNCHRONOUS_WRITE);
097: assertEquals(0, rmtLockManager.getFlushCount());
098: lockManager.unlock(lockID_2, threadID_2);
099: assertEquals(1, rmtLockManager.getFlushCount());
100: lockManager.unlock(lockID_2, threadID_2);
101: assertEquals(1, rmtLockManager.getFlushCount());
102: lockManager.unlock(lockID_2, threadID_2);
103: assertEquals(2, rmtLockManager.getFlushCount());
104: lockManager.unlock(lockID_2, threadID_2);
105: lockManager.unlock(lockID_2, threadID_2);
106: assertEquals(2, rmtLockManager.getFlushCount());
107: rmtLockManager.resetFlushCount();
108: rmtLockManager.makeLocksNotGreedy();
109: }
110:
111: public void testSynchronousWriteUnlock() {
112: final LockID lockID_1 = new LockID("1");
113: final LockID lockID_2 = new LockID("2");
114: final ThreadID threadID_1 = new ThreadID(1);
115: final ThreadID threadID_2 = new ThreadID(2);
116:
117: rmtLockManager.resetFlushCount();
118:
119: assertEquals(0, rmtLockManager.getFlushCount());
120: lockManager.lock(lockID_1, threadID_1,
121: LockLevel.SYNCHRONOUS_WRITE);
122: assertEquals(0, rmtLockManager.getFlushCount());
123: lockManager.unlock(lockID_1, threadID_1);
124: assertEquals(1, rmtLockManager.getFlushCount());
125:
126: rmtLockManager.makeLocksGreedy();
127:
128: lockManager.lock(lockID_2, threadID_2,
129: LockLevel.SYNCHRONOUS_WRITE);
130: assertEquals(1, rmtLockManager.getFlushCount());
131: lockManager.unlock(lockID_2, threadID_2);
132: assertEquals(2, rmtLockManager.getFlushCount());
133:
134: rmtLockManager.resetFlushCount();
135: rmtLockManager.makeLocksNotGreedy();
136: }
137:
138: public void testSynchronousWriteWait() {
139:
140: final LockID lockID_1 = new LockID("1");
141: final LockID lockID_2 = new LockID("2");
142: final ThreadID threadID_1 = new ThreadID(1);
143: final ThreadID threadID_2 = new ThreadID(2);
144:
145: rmtLockManager.resetFlushCount();
146:
147: assertEquals(0, rmtLockManager.getFlushCount());
148: lockManager.lock(lockID_1, threadID_1,
149: LockLevel.SYNCHRONOUS_WRITE);
150: assertEquals(0, rmtLockManager.getFlushCount());
151:
152: WaitInvocation waitInvocation = new WaitInvocation();
153: NoExceptionLinkedQueue barrier = new NoExceptionLinkedQueue();
154: WaitLockRequest waitLockRequest = new WaitLockRequest(lockID_1,
155: threadID_1, LockLevel.SYNCHRONOUS_WRITE, waitInvocation);
156: LockWaiter waiterThread = new LockWaiter(barrier,
157: waitLockRequest, new Object());
158: waiterThread.start();
159: Object o = barrier.take();
160: assertNotNull(o);
161:
162: assertEquals(1, rmtLockManager.getFlushCount());
163:
164: rmtLockManager.makeLocksGreedy();
165:
166: lockManager.lock(lockID_2, threadID_2,
167: LockLevel.SYNCHRONOUS_WRITE);
168: assertEquals(1, rmtLockManager.getFlushCount());
169:
170: waitInvocation = new WaitInvocation();
171: waitLockRequest = new WaitLockRequest(lockID_2, threadID_2,
172: LockLevel.SYNCHRONOUS_WRITE, waitInvocation);
173: waiterThread = new LockWaiter(barrier, waitLockRequest,
174: new Object());
175: waiterThread.start();
176: o = barrier.take();
177: assertNotNull(o);
178:
179: assertEquals(2, rmtLockManager.getFlushCount());
180:
181: rmtLockManager.resetFlushCount();
182: rmtLockManager.makeLocksNotGreedy();
183: }
184:
185: public void testTryLock() {
186: class TryLockRemoteLockManager extends TestRemoteLockManager {
187: private CyclicBarrier requestBarrier;
188: private CyclicBarrier awardBarrier;
189:
190: public TryLockRemoteLockManager(
191: SessionProvider sessionProvider,
192: CyclicBarrier requestBarrier,
193: CyclicBarrier awardBarrier) {
194: super (sessionProvider);
195: this .requestBarrier = requestBarrier;
196: this .awardBarrier = awardBarrier;
197: }
198:
199: public void tryRequestLock(LockID lockID,
200: ThreadID threadID, WaitInvocation timeout,
201: int lockType) {
202: try {
203: requestBarrier.barrier();
204: awardBarrier.barrier();
205: } catch (BrokenBarrierException e) {
206: throw new TCRuntimeException(e);
207: } catch (InterruptedException e) {
208: throw new TCRuntimeException(e);
209: }
210: }
211: }
212:
213: class TryLockClientLockManager extends ClientLockManagerImpl {
214: private CyclicBarrier awardBarrier;
215:
216: public TryLockClientLockManager(TCLogger logger,
217: RemoteLockManager remoteLockManager,
218: SessionManager sessionManager,
219: CyclicBarrier awardBarrier) {
220: super (
221: logger,
222: remoteLockManager,
223: sessionManager,
224: ClientLockStatManager.NULL_CLIENT_LOCK_STAT_MANAGER);
225: this .awardBarrier = awardBarrier;
226: }
227:
228: public void awardLock(SessionID sessionID, LockID lockID,
229: ThreadID threadID, int level) {
230: try {
231: awardBarrier.barrier();
232: super .awardLock(sessionID, lockID, threadID, level);
233: } catch (BrokenBarrierException e) {
234: throw new TCRuntimeException(e);
235: } catch (InterruptedException e) {
236: throw new TCRuntimeException(e);
237: }
238: }
239: }
240:
241: final CyclicBarrier requestBarrier = new CyclicBarrier(2);
242: final CyclicBarrier awardBarrier = new CyclicBarrier(2);
243:
244: rmtLockManager = new TryLockRemoteLockManager(sessionManager,
245: requestBarrier, awardBarrier);
246: lockManager = new TryLockClientLockManager(new NullTCLogger(),
247: rmtLockManager, sessionManager, awardBarrier);
248:
249: final LockID lockID1 = new LockID("1");
250: final ThreadID txID = new ThreadID(1);
251:
252: Thread t1 = new Thread(new Runnable() {
253: public void run() {
254: try {
255: requestBarrier.barrier();
256: lockManager.awardLock(
257: sessionManager.getSessionID(), lockID1,
258: ThreadID.VM_ID, LockLevel
259: .makeGreedy(LockLevel.WRITE));
260: } catch (BrokenBarrierException e) {
261: throw new TCRuntimeException(e);
262: } catch (InterruptedException e) {
263: throw new TCRuntimeException(e);
264: }
265: }
266: });
267: t1.start();
268:
269: lockManager.tryLock(lockID1, txID, new WaitInvocation(0),
270: LockLevel.WRITE);
271:
272: }
273:
274: public void testGreedyLockRequest() {
275: final LockID lockID1 = new LockID("1");
276: final ThreadID tx1 = new ThreadID(1);
277: final ThreadID tx2 = new ThreadID(2);
278: final NoExceptionLinkedQueue queue = new NoExceptionLinkedQueue();
279:
280: rmtLockManager.lockResponder = new LockResponder() {
281:
282: public void respondToLockRequest(LockRequest request) {
283: queue.put(request);
284: lockManager.awardLock(sessionManager.getSessionID(),
285: request.lockID(), ThreadID.VM_ID, LockLevel
286: .makeGreedy(request.lockLevel()));
287: }
288: };
289:
290: lockManager.lock(lockID1, tx1, LockLevel.WRITE); // Goes to RemoteLockManager
291:
292: LockRequest request = (LockRequest) queue.poll(1000l);
293: assertNotNull(request);
294: assertEquals(tx1, request.threadID());
295: assertEquals(lockID1, request.lockID());
296: assertEquals(LockLevel.WRITE, request.lockLevel());
297:
298: // None of these should end up in RemoteLockManager
299: lockManager.lock(lockID1, tx1, LockLevel.READ);
300: lockManager.unlock(lockID1, tx1);
301: lockManager.unlock(lockID1, tx1);
302: lockManager.lock(lockID1, tx1, LockLevel.READ);
303: lockManager.lock(lockID1, tx2, LockLevel.READ);
304:
305: assertNull(queue.poll(1000l));
306: }
307:
308: public void testNotified() throws Exception {
309: final LockID lockID1 = new LockID("1");
310: final LockID lockID2 = new LockID("2");
311: final ThreadID tx1 = new ThreadID(1);
312: final ThreadID tx2 = new ThreadID(2);
313: final Set heldLocks = new HashSet();
314: final Set waiters = new HashSet();
315:
316: heldLocks.add(new LockRequest(lockID1, tx1, LockLevel.WRITE));
317: lockManager.lock(lockID1, tx1, LockLevel.WRITE);
318: assertNotNull(rmtLockManager.lockRequestCalls.poll(1));
319:
320: NoExceptionLinkedQueue barrier = new NoExceptionLinkedQueue();
321: WaitInvocation waitInvocation = new WaitInvocation();
322:
323: // In order to wait on a lock, we must first request and be granted the
324: // write lock. The TestRemoteLockManager
325: // takes care of awarding the lock when we ask for it.
326: //
327: // We don't add this lock request to the set of held locks because the
328: // call to wait moves it to being not
329: // held anymore.
330: lockManager.lock(lockID2, tx2, LockLevel.WRITE);
331: assertNotNull(rmtLockManager.lockRequestCalls.poll(1));
332:
333: WaitLockRequest waitLockRequest = new WaitLockRequest(lockID2,
334: tx2, LockLevel.WRITE, waitInvocation);
335: waiters.add(waitLockRequest);
336: final LockWaiter waiterThread = new LockWaiter(barrier,
337: waitLockRequest, new Object());
338: waiterThread.start();
339:
340: barrier.take();
341: assertTrue(barrier.isEmpty());
342: if (!waiterThread.exceptions.isEmpty()) {
343: for (Iterator i = waiterThread.exceptions.iterator(); i
344: .hasNext();) {
345: ((Throwable) i.next()).printStackTrace();
346: }
347: fail("Waiter thread had exceptions!");
348: }
349:
350: // pause the lock manager in preparation for pulling interrogating the
351: // state...
352: pauseAndStart();
353:
354: Set s = new HashSet();
355: lockManager.addAllHeldLocksTo(s);
356: assertEquals(heldLocks, s);
357:
358: s.clear();
359: lockManager.addAllWaitersTo(s);
360: assertEquals(waiters, s);
361: s.clear();
362:
363: lockManager.addAllPendingLockRequestsTo(s);
364: assertTrue(s.size() == 0);
365:
366: // Make sure there are no pending lock requests
367: rmtLockManager.lockResponder = rmtLockManager.NULL_LOCK_RESPONDER;
368: assertTrue(rmtLockManager.lockRequestCalls.isEmpty());
369:
370: lockManager.unpause();
371:
372: // now call notified() and make sure that the appropriate waits become
373: // pending requests
374: lockManager.notified(waitLockRequest.lockID(), waitLockRequest
375: .threadID());
376:
377: pauseAndStart();
378: // The held locks should be the same
379: s.clear();
380: lockManager.addAllHeldLocksTo(s);
381: assertEquals(heldLocks, s);
382:
383: // the lock waits should be empty
384: s.clear();
385: lockManager.addAllWaitersTo(s);
386: assertEquals(Collections.EMPTY_SET, s);
387:
388: lockManager.addAllPendingLockRequestsTo(s);
389: assertTrue(s.size() == 1);
390: LockRequest lr = (LockRequest) s.iterator().next();
391: assertNotNull(lr);
392: assertEquals(waitLockRequest.lockID(), lr.lockID());
393: assertEquals(waitLockRequest.threadID(), lr.threadID());
394: assertTrue(waitLockRequest.lockLevel() == lr.lockLevel());
395:
396: lockManager.unpause();
397:
398: // now make sure that if you award the lock, the right stuff happens
399: lockManager.awardLock(sessionManager.getSessionID(),
400: waitLockRequest.lockID(), waitLockRequest.threadID(),
401: waitLockRequest.lockLevel());
402: heldLocks.add(waitLockRequest);
403:
404: pauseAndStart();
405: // the held locks should contain the newly awarded, previously notified
406: // lock.
407: s.clear();
408: lockManager.addAllHeldLocksTo(s);
409: assertEquals(heldLocks, s);
410:
411: // there should still be no waiters
412: s.clear();
413: lockManager.addAllWaitersTo(s);
414: assertEquals(Collections.EMPTY_SET, s);
415:
416: // the lock should have been awarded and no longer pending
417: assertTrue(rmtLockManager.lockRequestCalls.isEmpty());
418: lockManager.addAllPendingLockRequestsTo(null);
419: assertTrue(rmtLockManager.lockRequestCalls.isEmpty());
420: }
421:
422: public void testAddAllOutstandingLocksTo() throws Exception {
423:
424: // XXX: The current TestRemoteLockManager doesn't handle multiple
425: // read-locks by different transactions properly,
426: // so this test doesn't test that case.
427: final LockID lockID = new LockID("my lock");
428: final ThreadID tx1 = new ThreadID(1);
429: final int writeLockLevel = LockLevel.WRITE;
430:
431: final LockID readLock = new LockID("my read lock");
432: final ThreadID tx2 = new ThreadID(2);
433: final int readLockLevel = LockLevel.READ;
434:
435: // final LockID synchWriteLock = new LockID("my synch write lock");
436: // final ThreadID tx3 = new ThreadID(3);
437: // final int synchWriteLockLevel = LockLevel.SYNCHRONOUS_WRITE;
438:
439: Set lockRequests = new HashSet();
440: lockRequests.add(new LockRequest(lockID, tx1, writeLockLevel));
441: lockRequests.add(new LockRequest(readLock, tx2, readLockLevel));
442: // lockRequests.add(new LockRequest(synchWriteLock, tx3, synchWriteLockLevel));
443:
444: lockManager.lock(lockID, tx1, writeLockLevel);
445: lockManager.lock(readLock, tx2, readLockLevel);
446: // lockManager.lock(synchWriteLock, tx3, synchWriteLockLevel);
447:
448: Set s = new HashSet();
449: try {
450: lockManager.addAllHeldLocksTo(s);
451: fail("Expected an assertion error.");
452: } catch (AssertionError e) {
453: // expected
454: }
455:
456: pauseAndStart();
457: lockManager.addAllHeldLocksTo(s);
458: assertEquals(lockRequests.size(), s.size());
459: assertEquals(lockRequests, s);
460:
461: lockManager.unpause();
462: lockManager.unlock(lockID, tx1);
463: lockManager.unlock(readLock, tx2);
464: // lockManager.unlock(synchWriteLock, tx3);
465: pauseAndStart();
466: assertEquals(0, lockManager.addAllHeldLocksTo(new HashSet())
467: .size());
468: }
469:
470: public void testAddAllOutstandingWaitersTo() throws Exception {
471: final LockID lockID = new LockID("my lock");
472: final ThreadID tx1 = new ThreadID(1);
473: final WaitInvocation waitInvocation = new WaitInvocation();
474: final Object waitObject = new Object();
475: final NoExceptionLinkedQueue barrier = new NoExceptionLinkedQueue();
476: lockManager.lock(lockID, tx1, LockLevel.WRITE);
477: Thread t = new LockWaiter(barrier, lockID, tx1, waitInvocation,
478: waitObject);
479: t.start();
480: barrier.take();
481: ThreadUtil.reallySleep(200);
482:
483: Set s = new HashSet();
484: try {
485: lockManager.addAllWaitersTo(s);
486: fail("Expected an assertion error.");
487: } catch (AssertionError e) {
488: // expected
489: }
490:
491: pauseAndStart();
492: lockManager.addAllWaitersTo(s);
493: List waiters = new LinkedList(s);
494: assertEquals(1, waiters.size());
495: WaitLockRequest waitRequest = (WaitLockRequest) waiters.get(0);
496: assertEquals(lockID, waitRequest.lockID());
497: assertEquals(tx1, waitRequest.threadID());
498: assertEquals(waitInvocation, waitRequest.getWaitInvocation());
499:
500: // The lock this waiter was in when wait was called should no longer be
501: // outstanding.
502: assertEquals(0, lockManager.addAllHeldLocksTo(new HashSet())
503: .size());
504: }
505:
506: public void testPauseBlocks() throws Exception {
507: final LinkedQueue flowControl = new LinkedQueue();
508: final LinkedQueue lockComplete = new LinkedQueue();
509: final LinkedQueue unlockComplete = new LinkedQueue();
510: final LockID lockID = new LockID("1");
511: final ThreadID txID = new ThreadID(1);
512: final int lockType = LockLevel.WRITE;
513:
514: Thread locker = new Thread("LOCKER") {
515: public void run() {
516: try {
517: flowControl.put("locker: Calling lock");
518: lockManager.lock(lockID, txID, lockType);
519: lockComplete.put("locker: lock complete.");
520:
521: // wait until I'm allowed to unlock...
522: System.out.println(flowControl.take());
523: lockManager.unlock(lockID, txID);
524: unlockComplete.put("locker: unlock complete.");
525:
526: // wait until I'm allowed to call lock() again
527: System.out.println(flowControl.take());
528: rmtLockManager.lockResponder = rmtLockManager.NULL_LOCK_RESPONDER;
529: lockManager.lock(lockID, txID, lockType);
530: System.out
531: .println("locker: Done calling lock again");
532:
533: } catch (Throwable e) {
534: e.printStackTrace();
535: fail();
536: }
537: }
538: };
539:
540: assertFalse(lockManager.isStarting());
541: pauseAndStart();
542: locker.start();
543:
544: // wait until the locker has a chance to start up...
545: System.out.println(flowControl.take());
546:
547: ThreadUtil.reallySleep(500);
548:
549: // make sure it hasn't returned from the lock call.
550: assertTrue(lockComplete.peek() == null);
551: // unpause...
552: assertTrue(lockManager.isStarting());
553: lockManager.unpause();
554: assertFalse(lockManager.isStarting());
555: // make sure the call to lock(..) completes
556: System.out.println(lockComplete.take());
557: System.out.println("Done testing lock(..)");
558:
559: // now pause again and allow the locker to call unlock...
560: pauseAndStart();
561: flowControl
562: .put("test: lock manager paused, it's ok for locker to call unlock(..)");
563: ThreadUtil.reallySleep(500);
564: assertTrue(unlockComplete.peek() == null);
565: // now unpause and make sure the locker returns from unlock(..)
566: lockManager.unpause();
567: unlockComplete.take();
568: System.out.println("Done testing unlock(..)");
569:
570: // TODO: test awardLock() and the other public methods I didn't have
571: // time to
572: // test...
573: }
574:
575: public void testResendBasics() throws Exception {
576: final List requests = new ArrayList();
577: final LinkedQueue flowControl = new LinkedQueue();
578: final SynchronizedBoolean respond = new SynchronizedBoolean(
579: true);
580: rmtLockManager.lockResponder = new LockResponder() {
581: public void respondToLockRequest(final LockRequest request) {
582: new Thread() {
583: public void run() {
584: requests.add(request);
585: if (respond.get()) {
586: lockManager.awardLock(sessionManager
587: .getSessionID(), request.lockID(),
588: request.threadID(), request
589: .lockLevel());
590: }
591: try {
592: flowControl
593: .put("responder: respondToLockRequest complete. Lock awarded: "
594: + respond.get());
595: } catch (InterruptedException e) {
596: e.printStackTrace();
597: fail();
598: }
599: }
600: }.start();
601: }
602: };
603:
604: final ThreadID tid0 = new ThreadID(0);
605: final ThreadID tid1 = new ThreadID(1);
606: final LockID lid0 = new LockID("0");
607: final LockID lid1 = new LockID("1");
608:
609: LockRequest lr0 = new LockRequest(lid0, tid0, LockLevel.WRITE);
610: LockRequest lr1 = new LockRequest(lid1, tid1, LockLevel.WRITE);
611:
612: // request a lock that gets a response
613: Thread t = new LockGetter(lid0, tid0, LockLevel.WRITE);
614: t.start();
615: // wait until the lock responder finishes...
616: System.out.println(flowControl.take());
617: assertEquals(1, requests.size());
618: assertEquals(lr0, requests.get(0));
619:
620: // now request a lock that doesn't get a response.
621: requests.clear();
622: respond.set(false);
623:
624: t = new LockGetter(lid1, tid1, LockLevel.WRITE);
625: t.start();
626: System.out.println(flowControl.take());
627:
628: assertEquals(1, requests.size());
629: assertEquals(lr1, requests.get(0));
630:
631: // resend outstanding lock requests and respond to them.
632: requests.clear();
633: respond.set(true);
634: pauseAndStart();
635: lockManager.addAllPendingLockRequestsTo(requests);
636: lockManager.unpause();
637: assertEquals(1, requests.size());
638: assertEquals(lr1, requests.get(0));
639:
640: // there should be no outstanding lock requests.
641: // calling requestOutstanding() should cause no lock requests.
642:
643: requests.clear();
644: rmtLockManager.lockResponder = rmtLockManager.LOOPBACK_LOCK_RESPONDER;
645:
646: }
647:
648: public void testAwardWhenNotPending() throws Exception {
649: LockID lockID = new LockID("1");
650: ThreadID txID = new ThreadID(1);
651: try {
652: lockManager.awardLock(sessionManager.getSessionID(),
653: lockID, txID, LockLevel.WRITE);
654: fail("Should have thrown an error");
655: } catch (AssertionError e) {
656: // expected
657: }
658: }
659:
660: public void testBasics() throws Exception {
661: final ThreadID tid0 = new ThreadID(0);
662: final LockID lid0 = new LockID("0");
663:
664: final ThreadID tid1 = new ThreadID(1);
665:
666: System.out.println("Get lock0 for tx0");
667: lockManager.lock(lid0, tid0, LockLevel.WRITE);
668: System.out.println("Got lock0 for tx0");
669: lockManager.lock(lid0, tid0, LockLevel.WRITE);
670: System.out
671: .println("Got lock0 for tx0 AGAIN so the recursion lock is correct");
672: final boolean[] done = new boolean[1];
673: done[0] = false;
674: Thread t = new Thread() {
675: public void run() {
676: lockManager.lock(lid0, tid1, LockLevel.WRITE);
677: System.out.println("Got lock0 for tx1");
678: done[0] = true;
679: }
680: };
681: t.start();
682: ThreadUtil.reallySleep(500);
683: assertFalse(done[0]);
684: lockManager.unlock(lid0, tid0);
685: ThreadUtil.reallySleep(500);
686: assertFalse(done[0]);
687: lockManager.unlock(lid0, tid0);
688: ThreadUtil.reallySleep(500);
689: assertTrue(done[0]);
690: }
691:
692: public void testBasicUnlock() throws Exception {
693: assertEquals(0, rmtLockManager.getLockRequestCount());
694: assertEquals(0, rmtLockManager.getUnlockRequestCount());
695: ThreadID tid0 = new ThreadID(0);
696: LockID lid0 = new LockID("0");
697:
698: lockManager.lock(lid0, tid0, LockLevel.READ);
699: assertEquals(1, rmtLockManager.getLockRequestCount());
700: assertEquals(0, rmtLockManager.getUnlockRequestCount());
701:
702: lockManager.unlock(lid0, tid0);
703: assertEquals(1, rmtLockManager.getLockRequestCount());
704: assertEquals(1, rmtLockManager.getUnlockRequestCount());
705:
706: lockManager.lock(lid0, tid0, LockLevel.WRITE);
707: assertEquals(2, rmtLockManager.getLockRequestCount());
708: assertEquals(1, rmtLockManager.getUnlockRequestCount());
709:
710: lockManager.unlock(lid0, tid0);
711: assertEquals(2, rmtLockManager.getLockRequestCount());
712: assertEquals(2, rmtLockManager.getUnlockRequestCount());
713: }
714:
715: public void testLockUpgradeMakesRemoteRequest() throws Exception {
716: assertEquals(0, rmtLockManager.getLockRequestCount());
717: ThreadID tid0 = new ThreadID(0);
718: LockID lid0 = new LockID("0");
719:
720: lockManager.lock(lid0, tid0, LockLevel.READ);
721: assertEquals(1, rmtLockManager.getLockRequestCount());
722:
723: // upgrade lock
724: try {
725: lockManager.lock(lid0, tid0, LockLevel.WRITE);
726: throw new AssertionError(
727: "Should have thrown a TCLockUpgradeNotSupportedError.");
728: } catch (TCLockUpgradeNotSupportedError e) {
729: // expected
730: }
731: assertEquals(1, rmtLockManager.getLockRequestCount());
732: }
733:
734: public void testNestedReadLocksGrantsLocally() throws Exception {
735: assertEquals(0, rmtLockManager.getLockRequestCount());
736: ThreadID tid0 = new ThreadID(0);
737: LockID lid0 = new LockID("0");
738:
739: lockManager.lock(lid0, tid0, LockLevel.READ);
740: assertEquals(1, rmtLockManager.getLockRequestCount());
741:
742: final int count = 25;
743:
744: for (int i = 0; i < count; i++) {
745: // get nested read locks
746: lockManager.lock(lid0, tid0, LockLevel.READ);
747: assertEquals(1, rmtLockManager.getLockRequestCount());
748: }
749:
750: for (int i = 0; i < count; i++) {
751: lockManager.unlock(lid0, tid0);
752: assertEquals(1, rmtLockManager.getLockRequestCount());
753: assertEquals(0, rmtLockManager.getUnlockRequestCount());
754: }
755:
756: lockManager.unlock(lid0, tid0);
757: assertEquals(1, rmtLockManager.getLockRequestCount());
758: assertEquals(1, rmtLockManager.getUnlockRequestCount());
759: }
760:
761: public void testUnlockAfterDowngrade() throws Exception {
762: assertEquals(0, rmtLockManager.getLockRequestCount());
763: assertEquals(0, rmtLockManager.getUnlockRequestCount());
764: ThreadID tid0 = new ThreadID(0);
765: LockID lid0 = new LockID("0");
766:
767: lockManager.lock(lid0, tid0, LockLevel.WRITE);
768: assertEquals(1, rmtLockManager.getLockRequestCount());
769: assertEquals(0, rmtLockManager.getUnlockRequestCount());
770:
771: // downgrade lock
772: lockManager.lock(lid0, tid0, LockLevel.READ);
773: assertEquals(1, rmtLockManager.getLockRequestCount());
774: assertEquals(0, rmtLockManager.getUnlockRequestCount());
775:
776: lockManager.unlock(lid0, tid0);
777: assertEquals(1, rmtLockManager.getLockRequestCount());
778: assertEquals(0, rmtLockManager.getUnlockRequestCount());
779:
780: lockManager.unlock(lid0, tid0);
781: assertEquals(1, rmtLockManager.getLockRequestCount());
782: assertEquals(1, rmtLockManager.getUnlockRequestCount());
783: }
784:
785: private void pauseAndStart() {
786: lockManager.pause();
787: lockManager.starting();
788: }
789:
790: public static void main(String[] args) {
791: //
792: }
793:
794: public class LockWaiter extends Thread implements WaitListener {
795: private final LockID lid;
796:
797: private final ThreadID tid;
798:
799: private final WaitInvocation call;
800:
801: private final NoExceptionLinkedQueue preWaitSignalQueue;
802:
803: private final Object waitObject;
804:
805: private final List exceptions = new LinkedList();
806:
807: private LockWaiter(NoExceptionLinkedQueue preWaitSignalQueue,
808: WaitLockRequest request, Object waitObject) {
809: this (preWaitSignalQueue, request.lockID(), request
810: .threadID(), request.getWaitInvocation(),
811: waitObject);
812: }
813:
814: private LockWaiter(NoExceptionLinkedQueue preWaitSignalQueue,
815: LockID lid, ThreadID threadID, WaitInvocation call,
816: Object waitObject) {
817: this .preWaitSignalQueue = preWaitSignalQueue;
818: this .lid = lid;
819: this .tid = threadID;
820: this .waitObject = waitObject;
821: this .call = call;
822: }
823:
824: public void run() {
825: try {
826: lockManager.wait(lid, tid, call, waitObject, this );
827: } catch (Throwable t) {
828: exceptions.add(t);
829: }
830: }
831:
832: public void handleWaitEvent() {
833: preWaitSignalQueue.put(new Object());
834: }
835:
836: public Collection getExceptions() {
837: return this .exceptions;
838: }
839: }
840:
841: private class LockGetter extends Thread {
842: LockID lid;
843: ThreadID tid;
844: int lockType;
845:
846: private LockGetter(LockID lid, ThreadID tid, int lockType) {
847: this .lid = lid;
848: this .tid = tid;
849: this .lockType = lockType;
850: }
851:
852: public void run() {
853: lockManager.lock(lid, tid, lockType);
854: }
855: }
856: }
|