001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: TransactionTest.java,v 1.46.2.6 2008/01/07 15:14:24 cwl Exp $
007: */
008:
009: package com.sleepycat.collections.test;
010:
011: import java.io.File;
012: import java.util.Iterator;
013: import java.util.List;
014: import java.util.SortedSet;
015:
016: import junit.framework.Test;
017: import junit.framework.TestCase;
018: import junit.framework.TestSuite;
019:
020: import com.sleepycat.collections.CurrentTransaction;
021: import com.sleepycat.collections.StoredCollections;
022: import com.sleepycat.collections.StoredContainer;
023: import com.sleepycat.collections.StoredIterator;
024: import com.sleepycat.collections.StoredList;
025: import com.sleepycat.collections.StoredSortedMap;
026: import com.sleepycat.collections.TransactionRunner;
027: import com.sleepycat.collections.TransactionWorker;
028: import com.sleepycat.compat.DbCompat;
029: import com.sleepycat.je.CursorConfig;
030: import com.sleepycat.je.Database;
031: import com.sleepycat.je.DatabaseConfig;
032: import com.sleepycat.je.DatabaseEntry;
033: import com.sleepycat.je.DatabaseException;
034: import com.sleepycat.je.Environment;
035: import com.sleepycat.je.EnvironmentConfig;
036: import com.sleepycat.je.Transaction;
037: import com.sleepycat.je.TransactionConfig;
038: import com.sleepycat.je.util.TestUtils;
039: import com.sleepycat.util.RuntimeExceptionWrapper;
040:
041: /**
042: * @author Mark Hayes
043: */
044: public class TransactionTest extends TestCase {
045:
046: private static final Long ONE = new Long(1);
047: private static final Long TWO = new Long(2);
048: private static final Long THREE = new Long(3);
049:
050: /**
051: * Runs a command line collection test.
052: * @see #usage
053: */
054: public static void main(String[] args) throws Exception {
055:
056: if (args.length == 1
057: && (args[0].equals("-h") || args[0].equals("-help"))) {
058: usage();
059: } else {
060: junit.framework.TestResult tr = junit.textui.TestRunner
061: .run(suite());
062: if (tr.errorCount() > 0 || tr.failureCount() > 0) {
063: System.exit(1);
064: } else {
065: System.exit(0);
066: }
067: }
068: }
069:
070: private static void usage() {
071:
072: System.out
073: .println("Usage: java com.sleepycat.collections.test.TransactionTest"
074: + " [-h | -help]\n");
075: System.exit(2);
076: }
077:
078: public static Test suite() throws Exception {
079:
080: TestSuite suite = new TestSuite(TransactionTest.class);
081: return suite;
082: }
083:
084: private Environment env;
085: private CurrentTransaction currentTxn;
086: private Database store;
087: private StoredSortedMap map;
088: private TestStore testStore = TestStore.BTREE_UNIQ;
089:
090: public TransactionTest(String name) {
091:
092: super (name);
093: }
094:
095: public void setUp() throws Exception {
096:
097: DbTestUtil.printTestName(DbTestUtil.qualifiedTestName(this ));
098: env = TestEnv.TXN.open("TransactionTests");
099: currentTxn = CurrentTransaction.getInstance(env);
100: store = testStore.open(env, dbName(0));
101: map = new StoredSortedMap(store, testStore.getKeyBinding(),
102: testStore.getValueBinding(), true);
103: }
104:
105: public void tearDown() {
106:
107: try {
108: if (store != null) {
109: store.close();
110: }
111: if (env != null) {
112: env.close();
113: }
114: } catch (Exception e) {
115: System.out.println("Ignored exception during tearDown: "
116: + e);
117: } finally {
118: /* Ensure that GC can cleanup. */
119: store = null;
120: env = null;
121: currentTxn = null;
122: map = null;
123: testStore = null;
124: }
125: }
126:
127: private String dbName(int i) {
128:
129: return "txn-test-" + getName() + '-' + i;
130: }
131:
132: public void testGetters() throws Exception {
133:
134: assertNotNull(env);
135: assertNotNull(currentTxn);
136: assertNull(currentTxn.getTransaction());
137:
138: currentTxn.beginTransaction(null);
139: assertNotNull(currentTxn.getTransaction());
140: currentTxn.commitTransaction();
141: assertNull(currentTxn.getTransaction());
142:
143: currentTxn.beginTransaction(null);
144: assertNotNull(currentTxn.getTransaction());
145: currentTxn.abortTransaction();
146: assertNull(currentTxn.getTransaction());
147:
148: // read-uncommitted property should be inherited
149:
150: assertTrue(!isReadUncommitted(map));
151: assertTrue(!isReadUncommitted(map.values()));
152: assertTrue(!isReadUncommitted(map.keySet()));
153: assertTrue(!isReadUncommitted(map.entrySet()));
154:
155: StoredSortedMap other = (StoredSortedMap) StoredCollections
156: .configuredMap(map, CursorConfig.READ_UNCOMMITTED);
157: assertTrue(isReadUncommitted(other));
158: assertTrue(isReadUncommitted(other.values()));
159: assertTrue(isReadUncommitted(other.keySet()));
160: assertTrue(isReadUncommitted(other.entrySet()));
161: assertTrue(!isReadUncommitted(map));
162: assertTrue(!isReadUncommitted(map.values()));
163: assertTrue(!isReadUncommitted(map.keySet()));
164: assertTrue(!isReadUncommitted(map.entrySet()));
165:
166: // read-committed property should be inherited
167:
168: assertTrue(!isReadCommitted(map));
169: assertTrue(!isReadCommitted(map.values()));
170: assertTrue(!isReadCommitted(map.keySet()));
171: assertTrue(!isReadCommitted(map.entrySet()));
172:
173: other = (StoredSortedMap) StoredCollections.configuredMap(map,
174: CursorConfig.READ_COMMITTED);
175: assertTrue(isReadCommitted(other));
176: assertTrue(isReadCommitted(other.values()));
177: assertTrue(isReadCommitted(other.keySet()));
178: assertTrue(isReadCommitted(other.entrySet()));
179: assertTrue(!isReadCommitted(map));
180: assertTrue(!isReadCommitted(map.values()));
181: assertTrue(!isReadCommitted(map.keySet()));
182: assertTrue(!isReadCommitted(map.entrySet()));
183: }
184:
185: public void testTransactional() throws Exception {
186:
187: // is transactional because DB_AUTO_COMMIT was passed to
188: // Database.open()
189: //
190: assertTrue(map.isTransactional());
191: store.close();
192: store = null;
193:
194: // is not transactional
195: //
196: DatabaseConfig dbConfig = new DatabaseConfig();
197: DbCompat.setTypeBtree(dbConfig);
198: dbConfig.setAllowCreate(true);
199: Database db = DbCompat.openDatabase(env, null, dbName(1), null,
200: dbConfig);
201: map = new StoredSortedMap(db, testStore.getKeyBinding(),
202: testStore.getValueBinding(), true);
203: assertTrue(!map.isTransactional());
204: map.put(ONE, ONE);
205: readCheck(map, ONE, ONE);
206: db.close();
207:
208: // is transactional
209: //
210: dbConfig.setTransactional(true);
211: currentTxn.beginTransaction(null);
212: db = DbCompat.openDatabase(env, currentTxn.getTransaction(),
213: dbName(2), null, dbConfig);
214: currentTxn.commitTransaction();
215: map = new StoredSortedMap(db, testStore.getKeyBinding(),
216: testStore.getValueBinding(), true);
217: assertTrue(map.isTransactional());
218: currentTxn.beginTransaction(null);
219: map.put(ONE, ONE);
220: readCheck(map, ONE, ONE);
221: currentTxn.commitTransaction();
222: db.close();
223: }
224:
225: public void testExceptions() throws Exception {
226:
227: try {
228: currentTxn.commitTransaction();
229: fail();
230: } catch (IllegalStateException expected) {
231: }
232:
233: try {
234: currentTxn.abortTransaction();
235: fail();
236: } catch (IllegalStateException expected) {
237: }
238: }
239:
240: public void testNested() throws Exception {
241:
242: if (!DbCompat.NESTED_TRANSACTIONS) {
243: return;
244: }
245: assertNull(currentTxn.getTransaction());
246:
247: Transaction txn1 = currentTxn.beginTransaction(null);
248: assertNotNull(txn1);
249: assertTrue(txn1 == currentTxn.getTransaction());
250:
251: assertNull(map.get(ONE));
252: assertNull(map.put(ONE, ONE));
253: assertEquals(ONE, map.get(ONE));
254:
255: Transaction txn2 = currentTxn.beginTransaction(null);
256: assertNotNull(txn2);
257: assertTrue(txn2 == currentTxn.getTransaction());
258: assertTrue(txn1 != txn2);
259:
260: assertNull(map.put(TWO, TWO));
261: assertEquals(TWO, map.get(TWO));
262:
263: Transaction txn3 = currentTxn.beginTransaction(null);
264: assertNotNull(txn3);
265: assertTrue(txn3 == currentTxn.getTransaction());
266: assertTrue(txn1 != txn2);
267: assertTrue(txn1 != txn3);
268: assertTrue(txn2 != txn3);
269:
270: assertNull(map.put(THREE, THREE));
271: assertEquals(THREE, map.get(THREE));
272:
273: Transaction txn = currentTxn.abortTransaction();
274: assertTrue(txn == txn2);
275: assertTrue(txn == currentTxn.getTransaction());
276: assertNull(map.get(THREE));
277: assertEquals(TWO, map.get(TWO));
278:
279: txn3 = currentTxn.beginTransaction(null);
280: assertNotNull(txn3);
281: assertTrue(txn3 == currentTxn.getTransaction());
282: assertTrue(txn1 != txn2);
283: assertTrue(txn1 != txn3);
284: assertTrue(txn2 != txn3);
285:
286: assertNull(map.put(THREE, THREE));
287: assertEquals(THREE, map.get(THREE));
288:
289: txn = currentTxn.commitTransaction();
290: assertTrue(txn == txn2);
291: assertTrue(txn == currentTxn.getTransaction());
292: assertEquals(THREE, map.get(THREE));
293: assertEquals(TWO, map.get(TWO));
294:
295: txn = currentTxn.commitTransaction();
296: assertTrue(txn == txn1);
297: assertTrue(txn == currentTxn.getTransaction());
298: assertEquals(THREE, map.get(THREE));
299: assertEquals(TWO, map.get(TWO));
300: assertEquals(ONE, map.get(ONE));
301:
302: txn = currentTxn.commitTransaction();
303: assertNull(txn);
304: assertNull(currentTxn.getTransaction());
305: assertEquals(THREE, map.get(THREE));
306: assertEquals(TWO, map.get(TWO));
307: assertEquals(ONE, map.get(ONE));
308: }
309:
310: public void testRunnerCommit() throws Exception {
311:
312: commitTest(false);
313: }
314:
315: public void testExplicitCommit() throws Exception {
316:
317: commitTest(true);
318: }
319:
320: private void commitTest(final boolean explicit) throws Exception {
321:
322: final TransactionRunner runner = new TransactionRunner(env);
323: runner.setAllowNestedTransactions(DbCompat.NESTED_TRANSACTIONS);
324:
325: assertNull(currentTxn.getTransaction());
326:
327: runner.run(new TransactionWorker() {
328: public void doWork() throws Exception {
329: final Transaction txn1 = currentTxn.getTransaction();
330: assertNotNull(txn1);
331: assertNull(map.put(ONE, ONE));
332: assertEquals(ONE, map.get(ONE));
333:
334: runner.run(new TransactionWorker() {
335: public void doWork() throws Exception {
336: final Transaction txn2 = currentTxn
337: .getTransaction();
338: assertNotNull(txn2);
339: if (DbCompat.NESTED_TRANSACTIONS) {
340: assertTrue(txn1 != txn2);
341: } else {
342: assertTrue(txn1 == txn2);
343: }
344: assertNull(map.put(TWO, TWO));
345: assertEquals(TWO, map.get(TWO));
346: assertEquals(ONE, map.get(ONE));
347: if (DbCompat.NESTED_TRANSACTIONS && explicit) {
348: currentTxn.commitTransaction();
349: }
350: }
351: });
352:
353: Transaction txn3 = currentTxn.getTransaction();
354: assertSame(txn1, txn3);
355:
356: assertEquals(TWO, map.get(TWO));
357: assertEquals(ONE, map.get(ONE));
358: }
359: });
360:
361: assertNull(currentTxn.getTransaction());
362: }
363:
364: public void testRunnerAbort() throws Exception {
365:
366: abortTest(false);
367: }
368:
369: public void testExplicitAbort() throws Exception {
370:
371: abortTest(true);
372: }
373:
374: private void abortTest(final boolean explicit) throws Exception {
375:
376: final TransactionRunner runner = new TransactionRunner(env);
377: runner.setAllowNestedTransactions(DbCompat.NESTED_TRANSACTIONS);
378:
379: assertNull(currentTxn.getTransaction());
380:
381: runner.run(new TransactionWorker() {
382: public void doWork() throws Exception {
383: final Transaction txn1 = currentTxn.getTransaction();
384: assertNotNull(txn1);
385: assertNull(map.put(ONE, ONE));
386: assertEquals(ONE, map.get(ONE));
387:
388: if (DbCompat.NESTED_TRANSACTIONS) {
389: try {
390: runner.run(new TransactionWorker() {
391: public void doWork() throws Exception {
392: final Transaction txn2 = currentTxn
393: .getTransaction();
394: assertNotNull(txn2);
395: assertTrue(txn1 != txn2);
396: assertNull(map.put(TWO, TWO));
397: assertEquals(TWO, map.get(TWO));
398: if (explicit) {
399: currentTxn.abortTransaction();
400: } else {
401: throw new IllegalArgumentException(
402: "test-abort");
403: }
404: }
405: });
406: assertTrue(explicit);
407: } catch (IllegalArgumentException e) {
408: assertTrue(!explicit);
409: assertEquals("test-abort", e.getMessage());
410: }
411: }
412:
413: Transaction txn3 = currentTxn.getTransaction();
414: assertSame(txn1, txn3);
415:
416: assertEquals(ONE, map.get(ONE));
417: assertNull(map.get(TWO));
418: }
419: });
420:
421: assertNull(currentTxn.getTransaction());
422: }
423:
424: public void testReadCommittedCollection() throws Exception {
425:
426: StoredSortedMap degree2Map = (StoredSortedMap) StoredCollections
427: .configuredSortedMap(map, CursorConfig.READ_COMMITTED);
428:
429: // original map is not read-committed
430: assertTrue(!isReadCommitted(map));
431:
432: // all read-committed containers are read-uncommitted
433: assertTrue(isReadCommitted(degree2Map));
434: assertTrue(isReadCommitted(StoredCollections.configuredMap(map,
435: CursorConfig.READ_COMMITTED)));
436: assertTrue(isReadCommitted(StoredCollections
437: .configuredCollection(map.values(),
438: CursorConfig.READ_COMMITTED)));
439: assertTrue(isReadCommitted(StoredCollections.configuredSet(map
440: .keySet(), CursorConfig.READ_COMMITTED)));
441: assertTrue(isReadCommitted(StoredCollections
442: .configuredSortedSet((SortedSet) map.keySet(),
443: CursorConfig.READ_COMMITTED)));
444:
445: if (DbCompat.RECNO_METHOD) {
446: // create a list just so we can call configuredList()
447: Database listStore = TestStore.RECNO_RENUM.open(env, null);
448: List list = new StoredList(listStore,
449: TestStore.VALUE_BINDING, true);
450: assertTrue(isReadCommitted(StoredCollections
451: .configuredList(list, CursorConfig.READ_COMMITTED)));
452: listStore.close();
453: }
454:
455: map.put(ONE, ONE);
456: doReadCommitted(degree2Map, null);
457: }
458:
459: private static boolean isReadCommitted(Object container) {
460: StoredContainer storedContainer = (StoredContainer) container;
461: /* We can't use getReadCommitted until is is added to DB core. */
462: return storedContainer.getCursorConfig() != null
463: && storedContainer.getCursorConfig().getReadCommitted();
464: }
465:
466: public void testReadCommittedTransaction() throws Exception {
467:
468: TransactionConfig config = new TransactionConfig();
469: config.setReadCommitted(true);
470: doReadCommitted(map, config);
471: }
472:
473: private void doReadCommitted(final StoredSortedMap degree2Map,
474: TransactionConfig txnConfig) throws Exception {
475:
476: map.put(ONE, ONE);
477: TransactionRunner runner = new TransactionRunner(env);
478: runner.setTransactionConfig(txnConfig);
479: assertNull(currentTxn.getTransaction());
480: runner.run(new TransactionWorker() {
481: public void doWork() throws Exception {
482: assertNotNull(currentTxn.getTransaction());
483:
484: /* Do a read-committed get(), the lock is not retained. */
485: assertEquals(ONE, degree2Map.get(ONE));
486:
487: /*
488: * If we were not using read-committed, the following write of
489: * key ONE with an auto-commit transaction would self-deadlock
490: * since two transactions in the same thread would be
491: * attempting to lock the same key, one for write and one for
492: * read. This test passes if we do not deadlock.
493: */
494: DatabaseEntry key = new DatabaseEntry();
495: DatabaseEntry value = new DatabaseEntry();
496: testStore.getKeyBinding().objectToEntry(ONE, key);
497: testStore.getValueBinding().objectToEntry(TWO, value);
498: store.put(null, key, value);
499: }
500: });
501: assertNull(currentTxn.getTransaction());
502: }
503:
504: public void testReadUncommittedCollection() throws Exception {
505:
506: StoredSortedMap dirtyMap = (StoredSortedMap) StoredCollections
507: .configuredSortedMap(map, CursorConfig.READ_UNCOMMITTED);
508:
509: // original map is not read-uncommitted
510: assertTrue(!isReadUncommitted(map));
511:
512: // all read-uncommitted containers are read-uncommitted
513: assertTrue(isReadUncommitted(dirtyMap));
514: assertTrue(isReadUncommitted(StoredCollections.configuredMap(
515: map, CursorConfig.READ_UNCOMMITTED)));
516: assertTrue(isReadUncommitted(StoredCollections
517: .configuredCollection(map.values(),
518: CursorConfig.READ_UNCOMMITTED)));
519: assertTrue(isReadUncommitted(StoredCollections.configuredSet(
520: map.keySet(), CursorConfig.READ_UNCOMMITTED)));
521: assertTrue(isReadUncommitted(StoredCollections
522: .configuredSortedSet((SortedSet) map.keySet(),
523: CursorConfig.READ_UNCOMMITTED)));
524:
525: if (DbCompat.RECNO_METHOD) {
526: // create a list just so we can call configuredList()
527: Database listStore = TestStore.RECNO_RENUM.open(env, null);
528: List list = new StoredList(listStore,
529: TestStore.VALUE_BINDING, true);
530: assertTrue(isReadUncommitted(StoredCollections
531: .configuredList(list, CursorConfig.READ_UNCOMMITTED)));
532: listStore.close();
533: }
534:
535: doReadUncommitted(dirtyMap);
536: }
537:
538: private static boolean isReadUncommitted(Object container) {
539: StoredContainer storedContainer = (StoredContainer) container;
540: return storedContainer.getCursorConfig() != null
541: && storedContainer.getCursorConfig()
542: .getReadUncommitted();
543: }
544:
545: public void testReadUncommittedTransaction() throws Exception {
546:
547: TransactionRunner runner = new TransactionRunner(env);
548: TransactionConfig config = new TransactionConfig();
549: config.setReadUncommitted(true);
550: runner.setTransactionConfig(config);
551: assertNull(currentTxn.getTransaction());
552: runner.run(new TransactionWorker() {
553: public void doWork() throws Exception {
554: assertNotNull(currentTxn.getTransaction());
555: doReadUncommitted(map);
556: }
557: });
558: assertNull(currentTxn.getTransaction());
559: }
560:
561: // <!-- begin JE only -->
562:
563: /**
564: * Tests that the CurrentTransaction static WeakHashMap does indeed allow
565: * GC to reclaim tine environment when it is closed. At one point this was
566: * not working because the value object in the map has a reference to the
567: * environment. This was fixed by wrapping the value in a WeakReference.
568: * [#15444]
569: *
570: * This test only succeeds intermittently, probably due to its reliance
571: * on the GC call.
572: */
573: public void testCurrentTransactionGC() throws Exception {
574:
575: /*
576: * This test can have indeterminate results because it depends on
577: * a finalize count, so it's not part of the default run.
578: */
579: if (!TestUtils.runLongTests()) {
580: return;
581: }
582:
583: final StringBuffer finalizedFlag = new StringBuffer();
584:
585: class MyEnv extends Environment {
586:
587: MyEnv(File home, EnvironmentConfig config)
588: throws DatabaseException {
589:
590: super (home, config);
591: }
592:
593: protected void finalize() {
594: finalizedFlag.append('.');
595: }
596: }
597:
598: MyEnv myEnv = new MyEnv(env.getHome(), env.getConfig());
599: CurrentTransaction myCurrTxn = CurrentTransaction
600: .getInstance(myEnv);
601:
602: store.close();
603: store = null;
604: map = null;
605:
606: env.close();
607: env = null;
608:
609: myEnv.close();
610: myEnv = null;
611:
612: myCurrTxn = null;
613: currentTxn = null;
614:
615: byte[] x = null;
616: try {
617: x = new byte[Integer.MAX_VALUE - 1];
618: } catch (OutOfMemoryError expected) {
619: }
620: assertNull(x);
621:
622: for (int i = 0; i < 10; i += 1) {
623: System.gc();
624: }
625:
626: assertTrue(finalizedFlag.length() > 0);
627: }
628:
629: // <!-- end JE only -->
630:
631: private synchronized void doReadUncommitted(StoredSortedMap dirtyMap)
632: throws Exception {
633:
634: // start thread one
635: ReadUncommittedThreadOne t1 = new ReadUncommittedThreadOne(env,
636: this );
637: t1.start();
638: wait();
639:
640: // put ONE
641: synchronized (t1) {
642: t1.notify();
643: }
644: wait();
645: readCheck(dirtyMap, ONE, ONE);
646: assertTrue(!dirtyMap.isEmpty());
647:
648: // abort ONE
649: synchronized (t1) {
650: t1.notify();
651: }
652: t1.join();
653: readCheck(dirtyMap, ONE, null);
654: assertTrue(dirtyMap.isEmpty());
655:
656: // start thread two
657: ReadUncommittedThreadTwo t2 = new ReadUncommittedThreadTwo(env,
658: this );
659: t2.start();
660: wait();
661:
662: // put TWO
663: synchronized (t2) {
664: t2.notify();
665: }
666: wait();
667: readCheck(dirtyMap, TWO, TWO);
668: assertTrue(!dirtyMap.isEmpty());
669:
670: // commit TWO
671: synchronized (t2) {
672: t2.notify();
673: }
674: t2.join();
675: readCheck(dirtyMap, TWO, TWO);
676: assertTrue(!dirtyMap.isEmpty());
677: }
678:
679: private static class ReadUncommittedThreadOne extends Thread {
680:
681: private CurrentTransaction currentTxn;
682: private TransactionTest parent;
683: private StoredSortedMap map;
684:
685: private ReadUncommittedThreadOne(Environment env,
686: TransactionTest parent) {
687:
688: this .currentTxn = CurrentTransaction.getInstance(env);
689: this .parent = parent;
690: this .map = parent.map;
691: }
692:
693: public synchronized void run() {
694:
695: try {
696: assertNull(currentTxn.getTransaction());
697: assertNotNull(currentTxn.beginTransaction(null));
698: assertNotNull(currentTxn.getTransaction());
699: readCheck(map, ONE, null);
700: synchronized (parent) {
701: parent.notify();
702: }
703: wait();
704:
705: // put ONE
706: assertNull(map.put(ONE, ONE));
707: readCheck(map, ONE, ONE);
708: synchronized (parent) {
709: parent.notify();
710: }
711: wait();
712:
713: // abort ONE
714: assertNull(currentTxn.abortTransaction());
715: assertNull(currentTxn.getTransaction());
716: } catch (Exception e) {
717: throw new RuntimeExceptionWrapper(e);
718: }
719: }
720: }
721:
722: private static class ReadUncommittedThreadTwo extends Thread {
723:
724: private Environment env;
725: private CurrentTransaction currentTxn;
726: private TransactionTest parent;
727: private StoredSortedMap map;
728:
729: private ReadUncommittedThreadTwo(Environment env,
730: TransactionTest parent) {
731:
732: this .env = env;
733: this .currentTxn = CurrentTransaction.getInstance(env);
734: this .parent = parent;
735: this .map = parent.map;
736: }
737:
738: public synchronized void run() {
739:
740: try {
741: final TransactionRunner runner = new TransactionRunner(
742: env);
743: final Object thread = this ;
744: assertNull(currentTxn.getTransaction());
745:
746: runner.run(new TransactionWorker() {
747: public void doWork() throws Exception {
748: assertNotNull(currentTxn.getTransaction());
749: readCheck(map, TWO, null);
750: synchronized (parent) {
751: parent.notify();
752: }
753: thread.wait();
754:
755: // put TWO
756: assertNull(map.put(TWO, TWO));
757: readCheck(map, TWO, TWO);
758: synchronized (parent) {
759: parent.notify();
760: }
761: thread.wait();
762:
763: // commit TWO
764: }
765: });
766: assertNull(currentTxn.getTransaction());
767: } catch (Exception e) {
768: throw new RuntimeExceptionWrapper(e);
769: }
770: }
771: }
772:
773: private static void readCheck(StoredSortedMap checkMap, Object key,
774: Object expect) {
775: if (expect == null) {
776: assertNull(checkMap.get(key));
777: assertTrue(checkMap.tailMap(key).isEmpty());
778: assertTrue(!checkMap.tailMap(key).containsKey(key));
779: assertTrue(!checkMap.keySet().contains(key));
780: assertTrue(checkMap.duplicates(key).isEmpty());
781: Iterator i = checkMap.keySet().iterator();
782: try {
783: while (i.hasNext()) {
784: assertTrue(!key.equals(i.next()));
785: }
786: } finally {
787: StoredIterator.close(i);
788: }
789: } else {
790: assertEquals(expect, checkMap.get(key));
791: assertEquals(expect, checkMap.tailMap(key).get(key));
792: assertTrue(!checkMap.tailMap(key).isEmpty());
793: assertTrue(checkMap.tailMap(key).containsKey(key));
794: assertTrue(checkMap.keySet().contains(key));
795: assertTrue(checkMap.values().contains(expect));
796: assertTrue(!checkMap.duplicates(key).isEmpty());
797: assertTrue(checkMap.duplicates(key).contains(expect));
798: Iterator i = checkMap.keySet().iterator();
799: try {
800: boolean found = false;
801: while (i.hasNext()) {
802: if (expect.equals(i.next())) {
803: found = true;
804: }
805: }
806: assertTrue(found);
807: } finally {
808: StoredIterator.close(i);
809: }
810: }
811: }
812: }
|