KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > test > cache > test > generic > LockUnitTestCase


1 /*
2 * JBoss, the OpenSource J2EE webOS
3 *
4 * Distributable under LGPL license.
5 * See terms of license at gnu.org.
6 */

7 package org.jboss.test.cache.test.generic;
8
9 import EDU.oswego.cs.dl.util.concurrent.CyclicBarrier;
10 import EDU.oswego.cs.dl.util.concurrent.FIFOSemaphore;
11 import EDU.oswego.cs.dl.util.concurrent.Sync;
12 import junit.framework.Test;
13 import junit.framework.TestCase;
14 import junit.framework.TestSuite;
15 import org.jboss.cache.lock.*;
16
17 /**
18  * Various tests that test isolation level semantics provided by locks
19  *
20  * @author Bela Ban
21  * @version $Id: LockUnitTestCase.java,v 1.4.4.1 2005/04/06 21:23:05 starksm Exp $
22  */

23 public class LockUnitTestCase extends TestCase {
24    int value=10;
25    Throwable JavaDoc t1_ex, t2_ex;
26    long start=0;
27    final long TIMEOUT=5000;
28    final long SLEEP=500;
29
30
31    public LockUnitTestCase(String JavaDoc name) {
32       super(name);
33    }
34
35
36    public void setUp() {
37    }
38
39    public void tearDown() {
40       t1_ex=t2_ex=null;
41    }
42
43
44    class MyFIFOSemaphore extends FIFOSemaphore {
45       public MyFIFOSemaphore(long l) {
46          super(l);
47       }
48
49       public void acquire() throws InterruptedException JavaDoc {
50          // log("acquiring sem (permits=" + permits() + ")");
51
super.acquire();
52          // log("acquired sem (permits=" + permits() + ")");
53
}
54
55       public void release() {
56          // log("releasing sem (permits=" + permits() + ")");
57
super.release();
58          // log("released sem (permits=" + permits() + ")");
59
}
60    }
61
62
63    /**
64     * Thread1 reads data, thread2 changes and - before thread2 commits - t1 should see t2's changes.
65     * Timeline:
66     * <ol>
67     * T1 reads data - 10
68     * T2 writes data - 20
69     * T1 reads data - 20 (see's T2's uncommitted modfication)
70     * T2 commits (releases its lock)
71     * T1 reads data - 20
72     * </ol>
73     */

74    public void testReadUncommitted() throws Throwable JavaDoc {
75       final LockStrategy s=new LockStrategyReadUncommitted();
76       final FIFOSemaphore sem=new MyFIFOSemaphore(1);
77       final CyclicBarrier barrier=new CyclicBarrier(2);
78
79       Thread JavaDoc t1=new Thread JavaDoc("t1") {
80          Sync lock=null;
81
82          public void run() {
83             try {
84                sem.acquire(); // we're first to the semaphore
85

86                // log("waiting on barrier");
87
barrier.barrier(); // wait until t2 joins us
88
// log("passed barrier");
89
lock=s.readLock();
90                lock.attempt(TIMEOUT);
91                log("1st read: value is " + value);
92                assertEquals(10, value);
93                sem.release(); // give t2 time to make the modification
94
_sleep(100);
95
96                sem.acquire(); // to read the uncommitted modification by t2
97
log("2nd read: value is " + value + "; we should see t2's uncommitted change (20)");
98                assertEquals(20, value); // we're seeing the modification by t2 before t2 committed (a.k.a. released the lock)
99
sem.release();
100                _sleep(100);
101
102                sem.acquire(); // to read the committed change by t2
103
log("3rd read: value is still " + value + "; we should see t2's committed change");
104                assertEquals(20, value);
105             }
106             catch(Throwable JavaDoc ex) {
107                t1_ex=ex;
108             }
109             finally {
110                if(lock != null)
111                   lock.release();
112                sem.release();
113             }
114          }
115       };
116
117
118       Thread JavaDoc t2=new Thread JavaDoc("t2") {
119          Sync lock=null;
120
121          public void run() {
122             try {
123                _sleep(100);
124                // log("waiting on barrier");
125
barrier.barrier();
126                // log("passed barrier");
127
sem.acquire();
128                lock=s.writeLock();
129                lock.attempt(TIMEOUT);
130                log("changing value from " + value + " to 20");
131                value=20;
132                sem.release(); // now t1 can read the uncommitted modification
133
_sleep(100);
134
135                sem.acquire(); // to release the lock
136
log("committing the TX");
137                lock.release();
138             }
139             catch(Throwable JavaDoc ex) {
140                t2_ex=ex;
141             }
142             finally {
143                if(lock != null)
144                   lock.release();
145                sem.release();
146             }
147          }
148       };
149
150       t1.start();
151       t2.start();
152       t1.join();
153       t2.join();
154       if(t1_ex != null)
155          throw t1_ex;
156       if(t2_ex != null)
157          throw t2_ex;
158    }
159
160
161
162    /**
163     * Thread1 reads data, thread2 changes and - before thread2 commits - t1 should *not* see t2's changes.
164     * Timeline:
165     * <ol>
166     * T1 reads data - 10
167     * T2 writes data - 20 (*not* visible to T1)
168     * T1 reads data - 10 (should *not* see T2's uncommitted modfication)
169     * T2 commits (releases its lock)
170     * T1 sees T2's committed modification - 20
171     * </ol>
172     * <em>Commented for now, until we get the right semantics</em>
173     */

174 // public void testReadCommitted() throws Throwable {
175
// final LockStrategy s=new LockStrategyReadCommitted();
176
//
177
// Thread t1=new Thread("t1") {
178
// Sync lock=null;
179
//
180
// public void run() {
181
// try {
182
// lock=s.readLock();
183
// lock.attempt(TIMEOUT);
184
// log("1st read: value is " + value);
185
// assertEquals(10, value);
186
// _sleep(SLEEP);
187
//
188
// log("2nd read: value is " + value + "; we should *not* see t2's uncommitted change (20)");
189
// assertEquals(10, value); // we're seeing the modification by t2 before t2 committed (a.k.a. released the lock)
190
// _sleep(SLEEP);
191
//
192
// log("3rd read: value is still " + value + "; we should see t2's committed change");
193
// assertEquals(20, value);
194
// }
195
// catch(Throwable ex) {
196
// t1_ex=ex;
197
// }
198
// finally {
199
// lock.release();
200
// }
201
// }
202
// };
203
//
204
//
205
// Thread t2=new Thread("t2") {
206
// Sync lock=null;
207
//
208
// public void run() {
209
// try {
210
// _sleep(100);
211
// lock=s.writeLock();
212
// lock.attempt(TIMEOUT);
213
// log("changing value from " + value + " to 20");
214
// value=20;
215
// _sleep(SLEEP);
216
//
217
// log("committing the TX");
218
// lock.release();
219
// }
220
// catch(Throwable ex) {
221
// t2_ex=ex;
222
// }
223
// finally {
224
// lock.release();
225
// }
226
// }
227
// };
228
//
229
// t1.start();
230
// t2.start();
231
// t1.join();
232
// t2.join();
233
// if(t1_ex != null)
234
// throw t1_ex;
235
// if(t2_ex != null)
236
// throw t2_ex;
237
// }
238

239
240
241    public void testWriteThanRead() throws Throwable JavaDoc {
242        final LockStrategy s=new LockStrategyReadCommitted();
243
244        Thread JavaDoc t1=new Thread JavaDoc("t1") {
245           Sync lock=null;
246
247           public void run() {
248              try {
249                 _sleep(100);
250                 lock=s.readLock();
251                 lock.attempt(TIMEOUT);
252                 log("1st read: value is " + value);
253                 assertEquals(20, value);
254                 _sleep(SLEEP);
255
256                 log("2nd read: value is " + value + "; we should see t2's uncommitted change (20)");
257                 assertEquals(20, value); // we're seeing the modification by t2 before t2 committed (a.k.a. released the lock)
258
_sleep(SLEEP);
259              }
260              catch(Throwable JavaDoc ex) {
261                 t1_ex=ex;
262              }
263              finally {
264                 lock.release();
265              }
266           }
267        };
268
269
270        Thread JavaDoc t2=new Thread JavaDoc("t2") {
271           Sync lock=null;
272
273           public void run() {
274              try {
275                 lock=s.writeLock();
276                 lock.attempt(TIMEOUT);
277                 log("changing value from " + value + " to 20");
278                 value=20;
279                 _sleep(SLEEP);
280
281                 log("committing the TX");
282                 lock.release();
283              }
284              catch(Throwable JavaDoc ex) {
285                 t2_ex=ex;
286              }
287              finally {
288                 lock.release();
289              }
290           }
291        };
292
293        t2.start();
294        t1.start();
295        t2.join();
296        t1.join();
297        if(t1_ex != null)
298           throw t1_ex;
299        if(t2_ex != null)
300           throw t2_ex;
301     }
302
303
304
305
306    /**
307     * Thread1 reads data, thread2 changes and - before thread2 commits - t1 should *not* see t2's changes.
308     * In addition, Thread1 should *not* see thread2's changes even after thread2 commits, until thread1 commits.
309     * Timeline:
310     * <ol>
311     * T1 reads data - 10
312     * T2 writes data - 20 (*not* visible to T1)
313     * T1 reads data - 10 (should *not* see T2's uncommitted modfication)
314     * T2 commits (releases its lock)
315     * T1 reads data, should *not* see T2's committed modification - 10
316     * T1 commits
317     * T1 starts a new TX - should see 20
318     * </ol>
319     * Note: because we use pessimistic locking, the above sequence will effectively be serialized into sequential
320     * execution: thread1 will acquire the read lock on the data and hold on to it until TX commit, only then will
321     * thread2 be able to access the data with a write lock.
322     */

323    public void testRepeatableRead() throws Throwable JavaDoc {
324       final LockStrategy s=new LockStrategyRepeatableRead();
325
326       Thread JavaDoc t1=new Thread JavaDoc("t1") {
327          Sync lock=null;
328
329          public void run() {
330             try {
331                lock=s.readLock();
332                lock.attempt(TIMEOUT);
333                log("1st read: value is " + value);
334                assertEquals(10, value);
335                _sleep(SLEEP);
336
337                log("2nd read: value is " + value + "; we should *not* see t2's uncommitted change (20)");
338                assertEquals(10, value);
339                _sleep(SLEEP);
340
341                log("3rd read: value is still " + value + "; we should not see t2's committed change");
342                assertEquals(10, value);
343                lock.release();
344
345                _sleep(SLEEP);
346                lock.attempt(TIMEOUT);
347                log("4th read: value is now " + value + "; we should see t2's committed change in our new TX");
348                assertEquals(20, value);
349             }
350             catch(Throwable JavaDoc ex) {
351                t1_ex=ex;
352             }
353             finally {
354                lock.release();
355             }
356          }
357       };
358
359
360       Thread JavaDoc t2=new Thread JavaDoc("t2") {
361          Sync lock=null;
362
363          public void run() {
364             try {
365                _sleep(100);
366                lock=s.writeLock();
367                lock.attempt(TIMEOUT);
368                log("changing value from " + value + " to 20");
369                value=20;
370                _sleep(SLEEP);
371
372                log("committing the TX");
373                lock.release();
374             }
375             catch(Throwable JavaDoc ex) {
376                t2_ex=ex;
377             }
378             finally {
379                lock.release();
380             }
381          }
382       };
383
384       t1.start();
385       t2.start();
386       t1.join();
387       t2.join();
388       if(t1_ex != null)
389          throw t1_ex;
390       if(t2_ex != null)
391          throw t2_ex;
392    }
393
394
395    /**
396     * Because only 1 reader or writer can hold the lock at any given time, since thread1 is the first to get the lock,
397     * it will hold on to it until it commits. The the writer thread (thread2) will have a chance to change the value.
398     * Timeline:
399     * <ol>
400     * T1 reads data - 10
401     * T1 commits
402     * T2 writes data - 20
403     * T2 commits
404     * T1 starts a new TX and reads data - 20
405     * T2 commits (releases its lock)
406     * </ol>
407     */

408    public void testSerializable() throws Throwable JavaDoc {
409       final LockStrategy s=new LockStrategySerializable();
410
411       Thread JavaDoc t1=new Thread JavaDoc("t1") {
412          Sync lock=null;
413
414          public void run() {
415             try {
416                lock=s.readLock();
417                lock.attempt(TIMEOUT);
418                log("1st read: value is " + value);
419                assertEquals(10, value);
420                lock.release();
421                _sleep(SLEEP);
422
423                lock.attempt(TIMEOUT);
424                log("2nd read: value is " + value + "; we should see t2's committed change (20)");
425                assertEquals(20, value);
426             }
427             catch(Throwable JavaDoc ex) {
428                t1_ex=ex;
429             }
430             finally {
431                lock.release();
432             }
433          }
434       };
435
436
437       Thread JavaDoc t2=new Thread JavaDoc("t2") {
438          Sync lock=null;
439
440          public void run() {
441             try {
442                _sleep(100);
443                lock=s.writeLock();
444                lock.attempt(TIMEOUT);
445                log("changing value from " + value + " to 20");
446                value=20;
447                log("committing the TX");
448                lock.release();
449             }
450             catch(Throwable JavaDoc ex) {
451                t2_ex=ex;
452             }
453             finally {
454                lock.release();
455             }
456          }
457       };
458
459       t1.start();
460       t2.start();
461       t1.join();
462       t2.join();
463       if(t1_ex != null)
464          throw t1_ex;
465       if(t2_ex != null)
466          throw t2_ex;
467    }
468
469
470
471    void _sleep(long time) {
472       Thread.yield();
473       try {Thread.sleep(time);} catch(InterruptedException JavaDoc e) {}
474    }
475
476
477    void log(String JavaDoc s) {
478       long now;
479       if(start == 0)
480          start=System.currentTimeMillis();
481       now=System.currentTimeMillis();
482
483       System.out.println("[" + Thread.currentThread().getName() + "] [" + (now - start) + "] " + s);
484     }
485
486
487    public static void main(String JavaDoc[] args) throws Exception JavaDoc {
488       junit.textui.TestRunner.run(suite());
489    }
490
491    // Needed for JUnit.
492
public static Test suite() {
493       TestSuite suite=new TestSuite();
494       suite.addTestSuite(LockUnitTestCase.class);
495       return suite;
496    }
497
498
499
500
501 }
502
503
Popular Tags