001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: IterDeadlockTest.java,v 1.7.2.2 2008/01/07 15:14:24 cwl Exp $
007: */
008:
009: package com.sleepycat.collections.test;
010:
011: import com.sleepycat.compat.DbCompat;
012: import com.sleepycat.je.Database;
013: import com.sleepycat.je.DatabaseConfig;
014: import com.sleepycat.je.DeadlockException;
015: import com.sleepycat.je.Environment;
016: import com.sleepycat.bind.ByteArrayBinding;
017: import com.sleepycat.collections.TransactionRunner;
018: import com.sleepycat.collections.TransactionWorker;
019: import com.sleepycat.collections.StoredIterator;
020: import com.sleepycat.collections.StoredSortedMap;
021: import java.util.Iterator;
022: import java.util.ListIterator;
023: import junit.framework.Test;
024: import junit.framework.TestCase;
025: import junit.framework.TestSuite;
026:
027: /**
028: * Tests the fix for [#10516], where the StoredIterator constructor was not
029: * closing the cursor when an exception occurred. For example, a deadlock
030: * exception might occur if the constructor was unable to move the cursor to
031: * the first element.
032: * @author Mark Hayes
033: */
034: public class IterDeadlockTest extends TestCase {
035:
036: private static final byte[] ONE = { 1 };
037:
038: public static void main(String[] args) throws Exception {
039:
040: junit.framework.TestResult tr = junit.textui.TestRunner
041: .run(suite());
042: if (tr.errorCount() > 0 || tr.failureCount() > 0) {
043: System.exit(1);
044: } else {
045: System.exit(0);
046: }
047: }
048:
049: public static Test suite() throws Exception {
050:
051: TestSuite suite = new TestSuite(IterDeadlockTest.class);
052: return suite;
053: }
054:
055: private Environment env;
056: private Database store1;
057: private Database store2;
058: private StoredSortedMap map1;
059: private StoredSortedMap map2;
060: private ByteArrayBinding binding = new ByteArrayBinding();
061:
062: public IterDeadlockTest(String name) {
063:
064: super (name);
065: }
066:
067: public void setUp() throws Exception {
068:
069: env = TestEnv.TXN.open("IterDeadlockTest");
070: store1 = openDb("store1.db");
071: store2 = openDb("store2.db");
072: map1 = new StoredSortedMap(store1, binding, binding, true);
073: map2 = new StoredSortedMap(store2, binding, binding, true);
074: }
075:
076: public void tearDown() {
077:
078: if (store1 != null) {
079: try {
080: store1.close();
081: } catch (Exception e) {
082: System.out
083: .println("Ignored exception during tearDown: "
084: + e);
085: }
086: }
087: if (store2 != null) {
088: try {
089: store2.close();
090: } catch (Exception e) {
091: System.out
092: .println("Ignored exception during tearDown: "
093: + e);
094: }
095: }
096: if (env != null) {
097: try {
098: env.close();
099: } catch (Exception e) {
100: System.out
101: .println("Ignored exception during tearDown: "
102: + e);
103: }
104: }
105: /* Allow GC of DB objects in the test case. */
106: env = null;
107: store1 = null;
108: store2 = null;
109: map1 = null;
110: map2 = null;
111: }
112:
113: private Database openDb(String file) throws Exception {
114:
115: DatabaseConfig config = new DatabaseConfig();
116: DbCompat.setTypeBtree(config);
117: config.setTransactional(true);
118: config.setAllowCreate(true);
119:
120: return DbCompat.openDatabase(env, null, file, null, config);
121: }
122:
123: public void testIterDeadlock() throws Exception {
124:
125: final Object parent = new Object();
126: final Object child1 = new Object();
127: final Object child2 = new Object();
128: final TransactionRunner runner = new TransactionRunner(env);
129: runner.setMaxRetries(0);
130:
131: /* Write a record in each db. */
132: runner.run(new TransactionWorker() {
133: public void doWork() throws Exception {
134: assertNull(map1.put(ONE, ONE));
135: assertNull(map2.put(ONE, ONE));
136: }
137: });
138:
139: /*
140: * A thread to open iterator 1, then wait to be notified, then open
141: * iterator 2.
142: */
143: final Thread thread1 = new Thread(new Runnable() {
144: public void run() {
145: try {
146: runner.run(new TransactionWorker() {
147: public void doWork() throws Exception {
148: synchronized (child1) {
149: ListIterator i1 = (ListIterator) map1
150: .values().iterator();
151: i1.next();
152: i1.set(ONE); /* Write lock. */
153: StoredIterator.close(i1);
154: synchronized (parent) {
155: parent.notify();
156: }
157: child1.wait();
158: Iterator i2 = map2.values().iterator();
159: assertTrue(i2.hasNext());
160: StoredIterator.close(i2);
161: }
162: }
163: });
164: } catch (DeadlockException expected) {
165: } catch (Exception e) {
166: e.printStackTrace();
167: fail(e.toString());
168: }
169: }
170: });
171:
172: /*
173: * A thread to open iterator 2, then wait to be notified, then open
174: * iterator 1.
175: */
176: final Thread thread2 = new Thread(new Runnable() {
177: public void run() {
178: try {
179: runner.run(new TransactionWorker() {
180: public void doWork() throws Exception {
181: synchronized (child2) {
182: ListIterator i2 = (ListIterator) map2
183: .values().iterator();
184: i2.next();
185: i2.set(ONE); /* Write lock. */
186: StoredIterator.close(i2);
187: synchronized (parent) {
188: parent.notify();
189: }
190: child2.wait();
191: Iterator i1 = map1.values().iterator();
192: assertTrue(i1.hasNext());
193: StoredIterator.close(i1);
194: }
195: }
196: });
197: } catch (DeadlockException expected) {
198: } catch (Exception e) {
199: e.printStackTrace();
200: fail(e.toString());
201: }
202: }
203: });
204:
205: /*
206: * Open iterator 1 in thread 1, then iterator 2 in thread 2, then let
207: * the threads run to open the other iterators and cause a deadlock.
208: */
209: synchronized (parent) {
210: thread1.start();
211: parent.wait();
212: thread2.start();
213: parent.wait();
214: synchronized (child1) {
215: child1.notify();
216: }
217: synchronized (child2) {
218: child2.notify();
219: }
220: thread1.join();
221: thread2.join();
222: }
223:
224: /*
225: * Before the fix for [#10516] we would get an exception indicating
226: * that cursors were not closed, when closing the stores below.
227: */
228: store1.close();
229: store1 = null;
230: store2.close();
231: store2 = null;
232: env.close();
233: env = null;
234: }
235: }
|