001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: LockTest.java,v 1.44.2.4 2008/01/07 15:14:34 cwl Exp $
007: */
008:
009: package com.sleepycat.je.txn;
010:
011: import java.io.File;
012: import java.util.ArrayList;
013: import java.util.HashSet;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Set;
017:
018: import junit.framework.TestCase;
019:
020: import com.sleepycat.je.DatabaseException;
021: import com.sleepycat.je.EnvironmentConfig;
022: import com.sleepycat.je.TransactionConfig;
023: import com.sleepycat.je.config.EnvironmentParams;
024: import com.sleepycat.je.dbi.EnvironmentImpl;
025: import com.sleepycat.je.dbi.MemoryBudget;
026: import com.sleepycat.je.util.TestUtils;
027:
028: public class LockTest extends TestCase {
029: private EnvironmentImpl envImpl;
030: private File envHome;
031:
032: public LockTest() {
033: envHome = new File(System.getProperty(TestUtils.DEST_DIR));
034: }
035:
036: public void setUp() throws DatabaseException {
037:
038: EnvironmentConfig envConfig = TestUtils.initEnvConfig();
039: envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
040: "6");
041: envConfig.setAllowCreate(true);
042: envImpl = new EnvironmentImpl(envHome, envConfig);
043:
044: }
045:
046: public void tearDown() throws DatabaseException {
047:
048: envImpl.close();
049: }
050:
051: public void testLockConflicts() throws Exception {
052:
053: Locker txn1 = new BasicLocker(envImpl);
054: Locker txn2 = new BasicLocker(envImpl);
055: Locker txn3 = new BasicLocker(envImpl);
056: MemoryBudget mb = envImpl.getMemoryBudget();
057: try {
058: /*
059: * Start fresh. Ask for a read lock from txn1 twice,
060: * should only be one owner. Then add multiple
061: * would-be-writers as waiters.
062: */
063: Lock lock = new Lock();
064: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
065: txn1, false, mb, 0));
066: assertEquals(LockGrantType.EXISTING, lock.lock(
067: LockType.READ, txn1, false, mb, 0));
068: assertEquals(1, lock.nOwners());
069: assertEquals(0, lock.nWaiters());
070:
071: /* ask for a read lock from txn 2, get it. */
072: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
073: txn2, false, mb, 0));
074: /* txn1's write request must wait */
075: assertEquals(LockGrantType.WAIT_PROMOTION, lock.lock(
076: LockType.WRITE, txn1, false, mb, 0));
077: /* txn2's write request must wait */
078: assertEquals(LockGrantType.WAIT_PROMOTION, lock.lock(
079: LockType.WRITE, txn2, false, mb, 0));
080: assertEquals(2, lock.nOwners());
081: assertEquals(2, lock.nWaiters());
082:
083: /* Start fresh. Get a write lock, then get a read lock. */
084: lock = new Lock();
085:
086: assertEquals(LockGrantType.NEW, lock.lock(LockType.WRITE,
087: txn1, false, mb, 0));
088: assertEquals(LockGrantType.EXISTING, lock.lock(
089: LockType.READ, txn1, false, mb, 0));
090: assertEquals(1, lock.nOwners());
091: assertEquals(0, lock.nWaiters());
092:
093: /* Start fresh. Get a read lock, upgrade to a write lock. */
094: lock = new Lock();
095: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
096: txn1, false, mb, 0));
097: assertEquals(LockGrantType.PROMOTION, lock.lock(
098: LockType.WRITE, txn1, false, mb, 0));
099: assertEquals(1, lock.nOwners());
100: assertEquals(0, lock.nWaiters());
101:
102: /*
103: * Start fresh. Get a read lock, then ask for a non-blocking
104: * write lock. The latter should be denied.
105: */
106: lock = new Lock();
107:
108: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
109: txn1, false, mb, 0));
110: assertEquals(LockGrantType.DENIED, lock.lock(
111: LockType.WRITE, txn2, true, mb, 0));
112: assertEquals(1, lock.nOwners());
113: assertEquals(0, lock.nWaiters());
114:
115: /* Two write requsts, should be one owner. */
116: lock = new Lock();
117: assertEquals(LockGrantType.NEW, lock.lock(LockType.WRITE,
118: txn1, false, mb, 0));
119: assertEquals(LockGrantType.EXISTING, lock.lock(
120: LockType.WRITE, txn1, false, mb, 0));
121: assertEquals(1, lock.nOwners());
122: assertEquals(0, lock.nWaiters());
123:
124: /*
125: * Ensure that a read request behind a write request that waits
126: * also waits. blocking requests.
127: */
128: lock = new Lock();
129:
130: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
131: txn1, false, mb, 0));
132:
133: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
134: LockType.WRITE, txn2, false, mb, 0));
135:
136: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
137: LockType.READ, txn3, false, mb, 0));
138:
139: assertEquals(1, lock.nOwners());
140: assertEquals(2, lock.nWaiters());
141:
142: /* Check non blocking requests */
143: lock = new Lock();
144:
145: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
146: txn1, false, mb, 0));
147:
148: /* Since non-blocking request, this fails and doesn't go
149: on the wait queue. */
150: assertEquals(LockGrantType.DENIED, lock.lock(
151: LockType.WRITE, txn2, true, mb, 0));
152: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
153: txn3, true, mb, 0));
154: assertEquals(2, lock.nOwners());
155: assertEquals(0, lock.nWaiters());
156:
157: lock = new Lock();
158:
159: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
160: txn1, false, mb, 0));
161: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
162: txn2, false, mb, 0));
163: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
164: txn3, false, mb, 0));
165: assertEquals(3, lock.nOwners());
166: assertEquals(0, lock.nWaiters());
167: } finally {
168: txn1.operationEnd();
169: txn2.operationEnd();
170: txn3.operationEnd();
171: }
172: }
173:
174: public void testOwners() throws Exception {
175:
176: Locker txn1 = new BasicLocker(envImpl);
177: Locker txn2 = new BasicLocker(envImpl);
178: Locker txn3 = new BasicLocker(envImpl);
179: Locker txn4 = new BasicLocker(envImpl);
180: MemoryBudget mb = envImpl.getMemoryBudget();
181:
182: try {
183: /*
184: * Build up 3 owners and waiters for a lock, to test the
185: * lazy initialization and optimization for single owner/waiter.
186: */
187: Lock lock = new Lock();
188: /* should be no writer. */
189: assertTrue(lock.getWriteOwnerLocker() == null);
190:
191: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
192: txn1, false, mb, 0));
193: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
194: txn2, false, mb, 0));
195: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
196: txn3, false, mb, 0));
197:
198: /* should be no writer. */
199: assertTrue(lock.getWriteOwnerLocker() == null);
200:
201: /* expect 3 owners, 0 waiters. */
202: Set expectedOwners = new HashSet();
203: expectedOwners.add(new LockInfo(txn1, LockType.READ));
204: expectedOwners.add(new LockInfo(txn2, LockType.READ));
205: expectedOwners.add(new LockInfo(txn3, LockType.READ));
206: checkOwners(expectedOwners, lock, 0);
207:
208: /* release the first locker. */
209: lock.release(txn1, mb, 0);
210: expectedOwners = new HashSet();
211: expectedOwners.add(new LockInfo(txn2, LockType.READ));
212: expectedOwners.add(new LockInfo(txn3, LockType.READ));
213: checkOwners(expectedOwners, lock, 0);
214:
215: /* Add more. */
216: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
217: txn4, false, mb, 0));
218: expectedOwners = new HashSet();
219: expectedOwners.add(new LockInfo(txn2, LockType.READ));
220: expectedOwners.add(new LockInfo(txn3, LockType.READ));
221: expectedOwners.add(new LockInfo(txn4, LockType.READ));
222: checkOwners(expectedOwners, lock, 0);
223:
224: /* release */
225: lock.release(txn2, mb, 0);
226: expectedOwners = new HashSet();
227: expectedOwners.add(new LockInfo(txn3, LockType.READ));
228: expectedOwners.add(new LockInfo(txn4, LockType.READ));
229: checkOwners(expectedOwners, lock, 0);
230:
231: /* release */
232: lock.release(txn3, mb, 0);
233: expectedOwners = new HashSet();
234: expectedOwners.add(new LockInfo(txn4, LockType.READ));
235: /* only 1 lock, in the owner set, but not a write owner. */
236: assertTrue(lock.getWriteOwnerLocker() == null);
237:
238: /* release */
239: lock.release(txn4, mb, 0);
240: expectedOwners = new HashSet();
241: checkOwners(expectedOwners, lock, 0);
242:
243: /* Add owners again. */
244: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
245: txn1, false, mb, 0));
246: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
247: txn2, false, mb, 0));
248: expectedOwners = new HashSet();
249: expectedOwners.add(new LockInfo(txn1, LockType.READ));
250: expectedOwners.add(new LockInfo(txn2, LockType.READ));
251: checkOwners(expectedOwners, lock, 0);
252:
253: } catch (Exception e) {
254: e.printStackTrace();
255: throw e;
256: } finally {
257: txn1.operationEnd();
258: txn2.operationEnd();
259: txn3.operationEnd();
260: txn4.operationEnd();
261: }
262: }
263:
264: public void testWaiters() throws Exception {
265:
266: Locker txn1 = new AutoTxn(envImpl, new TransactionConfig());
267: Locker txn2 = new AutoTxn(envImpl, new TransactionConfig());
268: Locker txn3 = new AutoTxn(envImpl, new TransactionConfig());
269: Locker txn4 = new AutoTxn(envImpl, new TransactionConfig());
270: Locker txn5 = new AutoTxn(envImpl, new TransactionConfig());
271: MemoryBudget mb = envImpl.getMemoryBudget();
272:
273: try {
274: /*
275: * Build up 1 owners and 3waiters for a lock, to test the
276: * lazy initialization and optimization for single owner/waiter.
277: */
278: Lock lock = new Lock();
279: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
280: txn1, false, mb, 0));
281: assertEquals(LockGrantType.NEW, lock.lock(LockType.READ,
282: txn2, false, mb, 0));
283: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
284: LockType.WRITE, txn3, false, mb, 0));
285: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
286: LockType.WRITE, txn4, false, mb, 0));
287: assertEquals(LockGrantType.WAIT_PROMOTION, lock.lock(
288: LockType.WRITE, txn1, false, mb, 0));
289:
290: /* should be no writer. */
291: assertTrue(lock.getWriteOwnerLocker() == null);
292:
293: /* expect 2 owners, 3 waiters. */
294: Set expectedOwners = new HashSet();
295: expectedOwners.add(new LockInfo(txn1, LockType.READ));
296: expectedOwners.add(new LockInfo(txn2, LockType.READ));
297: checkOwners(expectedOwners, lock, 3);
298:
299: List waiters = new ArrayList();
300: waiters.add(new LockInfo(txn1, LockType.WRITE));
301: waiters.add(new LockInfo(txn3, LockType.WRITE));
302: waiters.add(new LockInfo(txn4, LockType.WRITE));
303: checkWaiters(waiters, lock);
304:
305: /* release a waiter, shouldn't change anything. */
306: lock.release(txn4, mb, 0);
307: checkWaiters(waiters, lock);
308:
309: /*
310: * Release the other read lock, expect txn1 to be promoted to a
311: * write lock.
312: */
313: lock.release(txn2, mb, 0);
314: expectedOwners = new HashSet();
315: expectedOwners.add(new LockInfo(txn1, LockType.WRITE));
316: checkOwners(expectedOwners, lock, 2);
317:
318: waiters.remove(0);
319: checkWaiters(waiters, lock);
320:
321: /* release */
322: lock.release(txn1, mb, 0);
323: expectedOwners = new HashSet();
324: expectedOwners.add(new LockInfo(txn3, LockType.WRITE));
325: checkOwners(expectedOwners, lock, 1);
326:
327: waiters.remove(0);
328: checkWaiters(waiters, lock);
329:
330: /*
331: * Add multiple read lock waiters so that we can promoting multiple
332: * waiters.
333: */
334: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
335: LockType.READ, txn1, false, mb, 0));
336: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
337: LockType.READ, txn2, false, mb, 0));
338: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
339: LockType.READ, txn5, false, mb, 0));
340:
341: checkOwners(expectedOwners, lock, 4);
342: waiters.add(new LockInfo(txn1, LockType.READ));
343: waiters.add(new LockInfo(txn2, LockType.READ));
344: waiters.add(new LockInfo(txn5, LockType.READ));
345: checkWaiters(waiters, lock);
346:
347: /* flush one of the waiters. */
348: lock.flushWaiter(txn5, mb, 0);
349: waiters.remove(3);
350: checkWaiters(waiters, lock);
351:
352: /* re-add. */
353: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
354: LockType.READ, txn5, false, mb, 0));
355: waiters.add(new LockInfo(txn5, LockType.READ));
356:
357: /* release txn3 */
358: lock.release(txn3, mb, 0);
359: expectedOwners = new HashSet();
360: expectedOwners.add(new LockInfo(txn4, LockType.WRITE));
361: checkOwners(expectedOwners, lock, 3);
362: waiters.remove(0);
363: checkWaiters(waiters, lock);
364:
365: /* release txn4, expect all read locks to promote. */
366: lock.release(txn4, mb, 0);
367: expectedOwners = new HashSet();
368: expectedOwners.add(new LockInfo(txn1, LockType.READ));
369: expectedOwners.add(new LockInfo(txn2, LockType.READ));
370: expectedOwners.add(new LockInfo(txn5, LockType.READ));
371: checkOwners(expectedOwners, lock, 0);
372: waiters.clear();
373: checkWaiters(waiters, lock);
374:
375: } catch (Exception e) {
376: e.printStackTrace();
377: throw e;
378: } finally {
379: txn1.operationEnd();
380: txn2.operationEnd();
381: txn3.operationEnd();
382: txn4.operationEnd();
383: txn5.operationEnd();
384: }
385: }
386:
387: public void testPromotion() throws Exception {
388:
389: Locker txn1 = new AutoTxn(envImpl, new TransactionConfig());
390: Locker txn2 = new AutoTxn(envImpl, new TransactionConfig());
391: Locker txn3 = new AutoTxn(envImpl, new TransactionConfig());
392: Locker txn4 = new AutoTxn(envImpl, new TransactionConfig());
393: Locker txn5 = new AutoTxn(envImpl, new TransactionConfig());
394: MemoryBudget mb = envImpl.getMemoryBudget();
395:
396: try {
397: /*
398: * Build up 1 owners and 3 read waiters for a lock. Then
399: * check that all the waiters promote properly.
400: */
401: Lock lock = new Lock();
402: assertEquals(LockGrantType.NEW, lock.lock(LockType.WRITE,
403: txn1, false, mb, 0));
404: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
405: LockType.READ, txn2, false, mb, 0));
406: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
407: LockType.READ, txn3, false, mb, 0));
408: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
409: LockType.READ, txn4, false, mb, 0));
410:
411: /* Check that 1 owner, 3 waiters exist. */
412: Set expectedOwners = new HashSet();
413: expectedOwners.add(new LockInfo(txn1, LockType.WRITE));
414: checkOwners(expectedOwners, lock, 3);
415:
416: List waiters = new ArrayList();
417: waiters.add(new LockInfo(txn2, LockType.READ));
418: waiters.add(new LockInfo(txn3, LockType.READ));
419: waiters.add(new LockInfo(txn4, LockType.READ));
420: checkWaiters(waiters, lock);
421:
422: /* Release the writer, expect all 3 waiters to promote. */
423: lock.release(txn1, mb, 0);
424: expectedOwners = new HashSet();
425: expectedOwners.add(new LockInfo(txn2, LockType.READ));
426: expectedOwners.add(new LockInfo(txn3, LockType.READ));
427: expectedOwners.add(new LockInfo(txn4, LockType.READ));
428: checkOwners(expectedOwners, lock, 0);
429: waiters.clear();
430: checkWaiters(waiters, lock);
431: } catch (Exception e) {
432: e.printStackTrace();
433: throw e;
434: } finally {
435: txn1.operationEnd();
436: txn2.operationEnd();
437: txn3.operationEnd();
438: txn4.operationEnd();
439: txn5.operationEnd();
440: }
441: }
442:
443: /**
444: * Tests conflicts between range locks and all other lock types.
445: */
446: public void testRangeConflicts() throws Exception {
447:
448: /* No owner */
449: checkConflict(null, LockType.RANGE_READ, LockGrantType.NEW);
450: checkConflict(null, LockType.RANGE_WRITE, LockGrantType.NEW);
451: checkConflict(null, LockType.RANGE_INSERT, LockGrantType.NEW);
452:
453: /* Owner has READ */
454: checkConflict(LockType.READ, LockType.RANGE_READ,
455: LockGrantType.NEW);
456: checkConflict(LockType.READ, LockType.RANGE_WRITE,
457: LockGrantType.WAIT_NEW);
458: checkConflict(LockType.READ, LockType.RANGE_INSERT,
459: LockGrantType.NEW);
460:
461: /* Owner has WRITE */
462: checkConflict(LockType.WRITE, LockType.RANGE_READ,
463: LockGrantType.WAIT_NEW);
464: checkConflict(LockType.WRITE, LockType.RANGE_WRITE,
465: LockGrantType.WAIT_NEW);
466: checkConflict(LockType.WRITE, LockType.RANGE_INSERT,
467: LockGrantType.NEW);
468:
469: /* Owner has RANGE_READ */
470: checkConflict(LockType.RANGE_READ, LockType.READ,
471: LockGrantType.NEW);
472: checkConflict(LockType.RANGE_READ, LockType.WRITE,
473: LockGrantType.WAIT_NEW);
474: checkConflict(LockType.RANGE_READ, LockType.RANGE_READ,
475: LockGrantType.NEW);
476: checkConflict(LockType.RANGE_READ, LockType.RANGE_WRITE,
477: LockGrantType.WAIT_NEW);
478: checkConflict(LockType.RANGE_READ, LockType.RANGE_INSERT,
479: LockGrantType.WAIT_NEW);
480:
481: /* Owner has RANGE_WRITE */
482: checkConflict(LockType.RANGE_WRITE, LockType.READ,
483: LockGrantType.WAIT_NEW);
484: checkConflict(LockType.RANGE_WRITE, LockType.WRITE,
485: LockGrantType.WAIT_NEW);
486: checkConflict(LockType.RANGE_WRITE, LockType.RANGE_READ,
487: LockGrantType.WAIT_NEW);
488: checkConflict(LockType.RANGE_WRITE, LockType.RANGE_WRITE,
489: LockGrantType.WAIT_NEW);
490: checkConflict(LockType.RANGE_WRITE, LockType.RANGE_INSERT,
491: LockGrantType.WAIT_NEW);
492:
493: /* Owner has RANGE_INSERT */
494: checkConflict(LockType.RANGE_INSERT, LockType.READ,
495: LockGrantType.NEW);
496: checkConflict(LockType.RANGE_INSERT, LockType.WRITE,
497: LockGrantType.NEW);
498: checkConflict(LockType.RANGE_INSERT, LockType.RANGE_READ,
499: LockGrantType.WAIT_RESTART);
500: checkConflict(LockType.RANGE_INSERT, LockType.RANGE_WRITE,
501: LockGrantType.WAIT_RESTART);
502: checkConflict(LockType.RANGE_INSERT, LockType.RANGE_INSERT,
503: LockGrantType.NEW);
504: }
505:
506: /**
507: * Tests that when the first request is held and the second request is
508: * requested, the second grant type is returned.
509: */
510: private void checkConflict(LockType firstRequest,
511: LockType secondRequest, LockGrantType secondGrantType)
512: throws Exception {
513:
514: Locker txn1 = new AutoTxn(envImpl, new TransactionConfig());
515: Locker txn2 = new AutoTxn(envImpl, new TransactionConfig());
516: MemoryBudget mb = envImpl.getMemoryBudget();
517:
518: try {
519: Lock lock = new Lock();
520:
521: if (firstRequest != null) {
522: assertEquals(LockGrantType.NEW, lock.lock(firstRequest,
523: txn1, false, mb, 0));
524: }
525: LockGrantType typeGranted = lock.lock(secondRequest, txn2,
526: false, mb, 0);
527: assertEquals(secondGrantType, typeGranted);
528:
529: boolean wait = (typeGranted == LockGrantType.WAIT_NEW
530: || typeGranted == LockGrantType.WAIT_PROMOTION || typeGranted == LockGrantType.WAIT_RESTART);
531: boolean given = (typeGranted == LockGrantType.NEW);
532: boolean restart = (typeGranted == LockGrantType.WAIT_RESTART);
533:
534: Set expectedOwners = new HashSet();
535: List expectedWaiters = new ArrayList();
536:
537: if (firstRequest != null) {
538: expectedOwners.add(new LockInfo(txn1, firstRequest));
539: }
540: if (given) {
541: expectedOwners.add(new LockInfo(txn2, secondRequest));
542: } else if (wait) {
543: if (restart) {
544: expectedWaiters.add(new LockInfo(txn2,
545: LockType.RESTART));
546: } else {
547: expectedWaiters.add(new LockInfo(txn2,
548: secondRequest));
549: }
550: }
551:
552: checkOwners(expectedOwners, lock, expectedWaiters.size());
553: checkWaiters(expectedWaiters, lock);
554:
555: lock.release(txn1, mb, 0);
556: if (wait) {
557: if (restart) {
558: checkOwners(new HashSet(), lock, 0);
559: } else {
560: checkOwners(new HashSet(expectedWaiters), lock, 0);
561: }
562: }
563: lock.release(txn2, mb, 0);
564: assertEquals(0, lock.nOwners());
565: assertEquals(0, lock.nWaiters());
566: } catch (Exception e) {
567: e.printStackTrace();
568: throw e;
569: } finally {
570: txn1.operationEnd();
571: txn2.operationEnd();
572: }
573: }
574:
575: /**
576: * Tests upgrades between range locks and all other lock types.
577: */
578: public void testRangeUpgrades() throws Exception {
579:
580: /* Owner has READ */
581: checkUpgrade(LockType.READ, LockType.RANGE_READ,
582: LockGrantType.EXISTING, LockType.RANGE_READ);
583: checkUpgrade(LockType.READ, LockType.RANGE_WRITE,
584: LockGrantType.PROMOTION, LockType.RANGE_WRITE);
585: checkUpgrade(LockType.READ, LockType.RANGE_INSERT, null,
586: LockType.READ);
587:
588: /* Owner has WRITE */
589: checkUpgrade(LockType.WRITE, LockType.RANGE_READ,
590: LockGrantType.EXISTING, LockType.RANGE_WRITE);
591: checkUpgrade(LockType.WRITE, LockType.RANGE_WRITE,
592: LockGrantType.EXISTING, LockType.RANGE_WRITE);
593: checkUpgrade(LockType.WRITE, LockType.RANGE_INSERT, null,
594: LockType.WRITE);
595:
596: /* Owner has RANGE_READ */
597: checkUpgrade(LockType.RANGE_READ, LockType.READ,
598: LockGrantType.EXISTING, LockType.RANGE_READ);
599: checkUpgrade(LockType.RANGE_READ, LockType.WRITE,
600: LockGrantType.PROMOTION, LockType.RANGE_WRITE);
601: checkUpgrade(LockType.RANGE_READ, LockType.RANGE_READ,
602: LockGrantType.EXISTING, LockType.RANGE_READ);
603: checkUpgrade(LockType.RANGE_READ, LockType.RANGE_WRITE,
604: LockGrantType.PROMOTION, LockType.RANGE_WRITE);
605: checkUpgrade(LockType.RANGE_READ, LockType.RANGE_INSERT, null,
606: LockType.RANGE_READ);
607:
608: /* Owner has RANGE_WRITE */
609: checkUpgrade(LockType.RANGE_WRITE, LockType.READ,
610: LockGrantType.EXISTING, LockType.RANGE_WRITE);
611: checkUpgrade(LockType.RANGE_WRITE, LockType.WRITE,
612: LockGrantType.EXISTING, LockType.RANGE_WRITE);
613: checkUpgrade(LockType.RANGE_WRITE, LockType.RANGE_READ,
614: LockGrantType.EXISTING, LockType.RANGE_WRITE);
615: checkUpgrade(LockType.RANGE_WRITE, LockType.RANGE_WRITE,
616: LockGrantType.EXISTING, LockType.RANGE_WRITE);
617: checkUpgrade(LockType.RANGE_WRITE, LockType.RANGE_INSERT, null,
618: LockType.RANGE_WRITE);
619:
620: /* Owner has RANGE_INSERT */
621: checkUpgrade(LockType.RANGE_INSERT, LockType.READ, null,
622: LockType.RANGE_INSERT);
623: checkUpgrade(LockType.RANGE_INSERT, LockType.WRITE, null,
624: LockType.RANGE_INSERT);
625: checkUpgrade(LockType.RANGE_INSERT, LockType.RANGE_READ, null,
626: LockType.RANGE_INSERT);
627: checkUpgrade(LockType.RANGE_INSERT, LockType.RANGE_WRITE, null,
628: LockType.RANGE_INSERT);
629: checkUpgrade(LockType.RANGE_INSERT, LockType.RANGE_INSERT,
630: LockGrantType.EXISTING, LockType.RANGE_INSERT);
631: }
632:
633: /**
634: * Tests that when the first request is held and the second request is
635: * requested, the second grant type is returned and the final type is then
636: * held. A null secondGrantType arg means that an assertion is expected.
637: */
638: private void checkUpgrade(LockType firstRequest,
639: LockType secondRequest, LockGrantType secondGrantType,
640: LockType finalType) throws Exception {
641:
642: Locker txn1 = new AutoTxn(envImpl, new TransactionConfig());
643: MemoryBudget mb = envImpl.getMemoryBudget();
644:
645: try {
646: Lock lock = new Lock();
647:
648: assertEquals(LockGrantType.NEW, lock.lock(firstRequest,
649: txn1, false, mb, 0));
650: LockGrantType typeGranted = null;
651: try {
652: typeGranted = lock.lock(secondRequest, txn1, false, mb,
653: 0);
654: if (secondGrantType == null) {
655: fail("expected AssertionError");
656: }
657: } catch (AssertionError e) {
658: if (secondGrantType != null) {
659: fail(e.toString());
660: }
661: }
662: assertEquals(secondGrantType, typeGranted);
663:
664: Set expectedOwners = new HashSet();
665: expectedOwners.add(new LockInfo(txn1, finalType));
666: checkOwners(expectedOwners, lock, 0);
667: lock.release(txn1, mb, 0);
668: assertEquals(0, lock.nOwners());
669: assertEquals(0, lock.nWaiters());
670: } catch (Exception e) {
671: e.printStackTrace();
672: throw e;
673: } finally {
674: txn1.operationEnd();
675: }
676: }
677:
678: /**
679: * Tests that when a range read/write is requested, and a range insert is
680: * waiting but not held, a WAIT_RESTART occurs. This requires that the
681: * waiter list is examined by Lock.lock().
682: */
683: public void testRangeInsertWaiterConflict() throws Exception {
684:
685: Locker txn1 = new AutoTxn(envImpl, new TransactionConfig());
686: Locker txn2 = new AutoTxn(envImpl, new TransactionConfig());
687: Locker txn3 = new AutoTxn(envImpl, new TransactionConfig());
688: MemoryBudget mb = envImpl.getMemoryBudget();
689:
690: try {
691: Lock lock = new Lock();
692: assertEquals(LockGrantType.NEW, lock.lock(
693: LockType.RANGE_READ, txn1, false, mb, 0));
694: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
695: LockType.RANGE_INSERT, txn2, false, mb, 0));
696: assertEquals(LockGrantType.WAIT_RESTART, lock.lock(
697: LockType.RANGE_READ, txn3, false, mb, 0));
698:
699: /* Check that 1 owner, 1 waiter exist. */
700:
701: Set expectedOwners = new HashSet();
702: expectedOwners.add(new LockInfo(txn1, LockType.RANGE_READ));
703: checkOwners(expectedOwners, lock, 2);
704:
705: List waiters = new ArrayList();
706: waiters.add(new LockInfo(txn2, LockType.RANGE_INSERT));
707: waiters.add(new LockInfo(txn3, LockType.RESTART));
708: checkWaiters(waiters, lock);
709: } catch (Exception e) {
710: e.printStackTrace();
711: throw e;
712: } finally {
713: txn1.operationEnd();
714: txn2.operationEnd();
715: txn3.operationEnd();
716: }
717: }
718:
719: private void checkOwners(Set expectedOwners, Lock lock,
720: int numExpectedWaiters) {
721:
722: /* check number of owners. */
723: Set owners = lock.getOwnersClone();
724: assertEquals(expectedOwners.size(), owners.size());
725:
726: /* check number of waiters. */
727: assertEquals(numExpectedWaiters, lock.nWaiters());
728:
729: /* Make sure that isOwner returns the right thing. */
730: Iterator iter = expectedOwners.iterator();
731: while (iter.hasNext()) {
732: LockInfo info = (LockInfo) iter.next();
733:
734: /* Make sure it's an owner, of the right type of lock. */
735: assertEquals(info.getLockType().isWriteLock(), lock
736: .isOwnedWriteLock(info.getLocker()));
737: assertTrue(lock.isOwner(info.getLocker(), info
738: .getLockType()));
739: }
740: }
741:
742: private void checkWaiters(List expectedWaiters, Lock lock) {
743: List waiters = lock.getWaitersListClone();
744: assertEquals(expectedWaiters.size(), waiters.size());
745:
746: /* check order of the list. */
747: for (int i = 0; i < expectedWaiters.size(); i++) {
748: LockInfo info = (LockInfo) expectedWaiters.get(i);
749: LockInfo waiterInfo = (LockInfo) waiters.get(i);
750: assertEquals("i=" + i, info.getLocker(), waiterInfo
751: .getLocker());
752: assertEquals("i=" + i, info.getLockType(), waiterInfo
753: .getLockType());
754: assertFalse(lock.isOwner(info.getLocker(), info
755: .getLockType()));
756: assertTrue(lock.isWaiter(info.getLocker()));
757: }
758: }
759:
760: public void testTransfer() throws Exception {
761:
762: Locker txn1 = new AutoTxn(envImpl, new TransactionConfig());
763: Locker txn2 = new AutoTxn(envImpl, new TransactionConfig());
764: Locker txn3 = new AutoTxn(envImpl, new TransactionConfig());
765: Locker txn4 = new AutoTxn(envImpl, new TransactionConfig());
766: Locker txn5 = new AutoTxn(envImpl, new TransactionConfig());
767: MemoryBudget mb = envImpl.getMemoryBudget();
768:
769: try {
770: /* Transfer from one locker to another locker. */
771: Long nid = new Long(1);
772: Lock lock = new Lock();
773: assertEquals(LockGrantType.NEW, lock.lock(LockType.WRITE,
774: txn1, false, mb, 0));
775: assertEquals(LockGrantType.WAIT_NEW, lock.lock(
776: LockType.READ, txn2, false, mb, 0));
777: assertTrue(lock.isOwner(txn1, LockType.WRITE));
778: assertFalse(lock.isOwner(txn2, LockType.READ));
779:
780: lock.transfer(nid, txn1, txn2, mb, 0);
781: assertFalse(lock.isOwner(txn1, LockType.WRITE));
782: assertFalse(lock.isOwner(txn1, LockType.READ));
783: assertTrue(lock.isOwnedWriteLock(txn2));
784:
785: /* Transfer to multiple lockers. */
786: Locker[] destLockers = new Locker[3];
787: destLockers[0] = txn3;
788: destLockers[1] = txn4;
789: destLockers[2] = txn5;
790: lock.demote(txn2);
791: lock.transferMultiple(nid, txn2, destLockers, mb, 0);
792: assertFalse(lock.isOwner(txn2, LockType.WRITE));
793: assertFalse(lock.isOwner(txn2, LockType.READ));
794:
795: for (int i = 0; i < destLockers.length; i++) {
796: assertTrue(lock.isOwner(destLockers[i], LockType.READ));
797: assertFalse(lock
798: .isOwner(destLockers[i], LockType.WRITE));
799: }
800:
801: } finally {
802: txn1.operationEnd();
803: txn2.operationEnd();
804: txn3.operationEnd();
805: txn4.operationEnd();
806: txn5.operationEnd();
807: }
808: }
809: }
|