1 |
| |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| package org.jboss.cache.transaction; |
8 |
| |
9 |
| import junit.framework.AssertionFailedError; |
10 |
| import junit.framework.Test; |
11 |
| import junit.framework.TestCase; |
12 |
| import junit.framework.TestSuite; |
13 |
| import org.jboss.cache.CacheImpl; |
14 |
| import org.jboss.cache.DefaultCacheFactory; |
15 |
| import org.jboss.cache.Fqn; |
16 |
| import org.jboss.cache.config.Configuration; |
17 |
| import org.jboss.cache.lock.IsolationLevel; |
18 |
| import org.jboss.cache.lock.TimeoutException; |
19 |
| |
20 |
| import javax.transaction.NotSupportedException; |
21 |
| import javax.transaction.SystemException; |
22 |
| import javax.transaction.Transaction; |
23 |
| import java.util.concurrent.CountDownLatch; |
24 |
| import java.util.concurrent.TimeUnit; |
25 |
| |
26 |
| |
27 |
| |
28 |
| |
29 |
| |
30 |
| |
31 |
| |
32 |
| |
33 |
| public class IsolationLevelReadCommittedNodeCreationRollbackTest extends TestCase |
34 |
| { |
35 |
| |
36 |
| private CacheImpl cache = null; |
37 |
| private final Fqn FQN = Fqn.fromString("/a/b/c"); |
38 |
| private final String KEY = "key"; |
39 |
| private final String VALUE = "value"; |
40 |
| |
41 |
| private volatile boolean writerFailed; |
42 |
| private volatile boolean readerFailed; |
43 |
| private volatile AssertionFailedError writerError; |
44 |
| private volatile AssertionFailedError readerError; |
45 |
| |
46 |
1
| protected void setUp() throws Exception
|
47 |
| { |
48 |
1
| super.setUp();
|
49 |
| |
50 |
1
| writerFailed = false;
|
51 |
1
| readerFailed = false;
|
52 |
| |
53 |
1
| writerError = null;
|
54 |
1
| readerError = null;
|
55 |
| |
56 |
1
| cache = (CacheImpl) DefaultCacheFactory.getInstance().createCache(false);
|
57 |
1
| cache.getConfiguration().setCacheMode(Configuration.CacheMode.LOCAL);
|
58 |
1
| cache.getConfiguration().setIsolationLevel(IsolationLevel.READ_COMMITTED);
|
59 |
1
| cache.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
|
60 |
1
| cache.start();
|
61 |
| } |
62 |
| |
63 |
| |
64 |
1
| protected void tearDown() throws Exception
|
65 |
| { |
66 |
1
| super.tearDown();
|
67 |
| |
68 |
1
| cache.stop();
|
69 |
1
| cache.destroy();
|
70 |
1
| cache = null;
|
71 |
| } |
72 |
| |
73 |
| |
74 |
1
| public void testNodeCreationRollback() throws Exception
|
75 |
| { |
76 |
1
| final CountDownLatch secondCanWrite = new CountDownLatch(1);
|
77 |
1
| final CountDownLatch secondCanRead = new CountDownLatch(1);
|
78 |
1
| final CountDownLatch secondDone = new CountDownLatch(1);
|
79 |
1
| final CountDownLatch firstCanRollback = new CountDownLatch(1);
|
80 |
1
| final CountDownLatch firstDone = new CountDownLatch(1);
|
81 |
| |
82 |
1
| final Fqn PARENT = Fqn.fromString("/a");
|
83 |
| |
84 |
| |
85 |
| |
86 |
1
| Thread firstThread = new Thread(new Runnable()
|
87 |
| { |
88 |
1
| public void run()
|
89 |
| { |
90 |
1
| try
|
91 |
| { |
92 |
1
| Transaction tx = startTransaction();
|
93 |
| |
94 |
1
| System.out.println("Writing /a/1");
|
95 |
| |
96 |
| |
97 |
1
| Fqn a1 = new Fqn(PARENT, "1");
|
98 |
1
| cache.put(a1, KEY, VALUE);
|
99 |
| |
100 |
| |
101 |
1
| secondCanWrite.countDown();
|
102 |
| |
103 |
| |
104 |
1
| firstCanRollback.await(3000, TimeUnit.MILLISECONDS);
|
105 |
| |
106 |
1
| System.out.println("rolling back");
|
107 |
| |
108 |
1
| tx.rollback();
|
109 |
| |
110 |
1
| assertNull("a1 empty", cache.get(a1, KEY));
|
111 |
| |
112 |
| |
113 |
1
| secondCanRead.countDown();
|
114 |
| } |
115 |
| catch (AssertionFailedError e) |
116 |
| { |
117 |
0
| writerError = e;
|
118 |
| } |
119 |
| catch (Throwable t) |
120 |
| { |
121 |
0
| t.printStackTrace();
|
122 |
0
| writerFailed = true;
|
123 |
| } |
124 |
| finally |
125 |
| { |
126 |
1
| System.out.println("first thread exits");
|
127 |
1
| secondCanWrite.countDown();
|
128 |
1
| secondCanRead.countDown();
|
129 |
1
| firstDone.countDown();
|
130 |
| } |
131 |
| } |
132 |
| }, "FIRST"); |
133 |
1
| firstThread.start();
|
134 |
| |
135 |
| |
136 |
| |
137 |
1
| Thread secondThread = new Thread(new Runnable()
|
138 |
| { |
139 |
1
| public void run()
|
140 |
| { |
141 |
1
| try
|
142 |
| { |
143 |
| |
144 |
1
| secondCanWrite.await();
|
145 |
| |
146 |
1
| System.out.println("writing a2");
|
147 |
| |
148 |
| |
149 |
1
| Fqn a2 = new Fqn(PARENT, "2");
|
150 |
1
| try
|
151 |
| { |
152 |
1
| cache.put(a2, KEY, VALUE);
|
153 |
| } |
154 |
| catch (TimeoutException good) |
155 |
| { |
156 |
| |
157 |
0
| System.out.println("Prevented from writing a2 -- " +
|
158 |
| good.getLocalizedMessage()); |
159 |
0
| return;
|
160 |
| } |
161 |
| |
162 |
| |
163 |
1
| firstCanRollback.countDown();
|
164 |
| |
165 |
| |
166 |
1
| secondCanRead.await();
|
167 |
| |
168 |
| |
169 |
1
| assertEquals("Known issue JBCACHE-407 -- write lock not acquired on " +
|
170 |
| "creation of an empty node", VALUE, cache.get(a2, KEY)); |
171 |
| } |
172 |
| catch (AssertionFailedError e) |
173 |
| { |
174 |
1
| readerError = e;
|
175 |
| } |
176 |
| catch (Throwable t) |
177 |
| { |
178 |
0
| t.printStackTrace();
|
179 |
0
| readerFailed = true;
|
180 |
| } |
181 |
| finally |
182 |
| { |
183 |
1
| System.out.println("second thread exits");
|
184 |
1
| firstCanRollback.countDown();
|
185 |
1
| secondDone.countDown();
|
186 |
| } |
187 |
| } |
188 |
| }, "SECOND"); |
189 |
1
| secondThread.start();
|
190 |
| |
191 |
| |
192 |
1
| secondDone.await();
|
193 |
1
| firstDone.await();
|
194 |
| |
195 |
| |
196 |
1
| if (readerError != null)
|
197 |
| { |
198 |
1
| throw readerError;
|
199 |
| } |
200 |
| |
201 |
0
| if (writerError != null)
|
202 |
| { |
203 |
0
| throw writerError;
|
204 |
| } |
205 |
| |
206 |
0
| if (readerFailed)
|
207 |
| { |
208 |
0
| fail("The second thread exited incorrectly. Watch the log for previous stack traces");
|
209 |
| } |
210 |
| |
211 |
0
| if (writerFailed)
|
212 |
| { |
213 |
0
| fail("The first thread exited incorrectly. Watch the log for previous stack traces");
|
214 |
| } |
215 |
| } |
216 |
| |
217 |
| |
218 |
1
| private Transaction startTransaction() throws SystemException, NotSupportedException
|
219 |
| { |
220 |
1
| DummyTransactionManager mgr = DummyTransactionManager.getInstance();
|
221 |
1
| mgr.begin();
|
222 |
1
| return mgr.getTransaction();
|
223 |
| } |
224 |
| |
225 |
| |
226 |
1
| public static Test suite()
|
227 |
| { |
228 |
| |
229 |
1
| return new TestSuite(IsolationLevelReadCommittedNodeCreationRollbackTest.class);
|
230 |
| |
231 |
| } |
232 |
| |
233 |
| |
234 |
| } |