KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > cache > lock > LockTest


1 package org.jboss.cache.lock;
2
3 import java.util.concurrent.CyclicBarrier JavaDoc;
4 import java.util.concurrent.Semaphore JavaDoc;
5 import java.util.concurrent.TimeUnit JavaDoc;
6 import java.util.concurrent.locks.Lock JavaDoc;
7 import junit.framework.Test;
8 import junit.framework.TestCase;
9 import junit.framework.TestSuite;
10 import org.jboss.cache.misc.TestingUtil;
11
12 /**
13  * Various tests that test isolation level semantics provided by locks
14  *
15  * @author Bela Ban
16  * @version $Id: LockTest.java,v 1.9 2006/12/08 18:50:49 genman Exp $
17  */

18 public class LockTest extends TestCase {
19    int value=10;
20    Throwable JavaDoc t1_ex, t2_ex;
21    long start=0;
22    final long TIMEOUT=5000;
23    final long SLEEP=500;
24
25    volatile boolean committed;
26
27    public LockTest(String JavaDoc name) {
28       super(name);
29    }
30
31
32
33    public void tearDown() throws Exception JavaDoc {
34       super.tearDown();
35       t1_ex=t2_ex=null;
36       committed = false;
37    }
38
39
40    static class MyFIFOSemaphore extends Semaphore JavaDoc {
41       public MyFIFOSemaphore(int permits) {
42          super(permits);
43       }
44
45       public void acquire() throws InterruptedException JavaDoc {
46          super.acquire();
47       }
48
49       public void release() {
50          super.release();
51       }
52    }
53
54
55    /**
56     * Thread1 reads data, thread2 changes and - before thread2 commits - t1 should see t2's changes.
57     * Timeline:
58     * <ol>
59     * T1 reads data - 10
60     * T2 writes data - 20
61     * T1 reads data - 20 (see's T2's uncommitted modfication)
62     * T2 commits (releases its lock)
63     * T1 reads data - 20
64     * </ol>
65     */

66    public void testReadUncommitted() throws Throwable JavaDoc {
67       final LockStrategy s=new LockStrategyReadUncommitted();
68       final Semaphore JavaDoc sem=new MyFIFOSemaphore(1);
69       final CyclicBarrier JavaDoc barrier=new CyclicBarrier JavaDoc(2);
70
71       Thread JavaDoc t1=new Thread JavaDoc("t1") {
72          Lock JavaDoc lock=null;
73
74          public void run() {
75             try {
76                sem.acquire(); // we're first to the semaphore
77

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

166
167
168    // removed in favor of o.j.c.transaction.IsolationLevelReadCommittedTest.testReadCommitted()
169
// The lock interceptor makes one request a read lock before *each* read.
170

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

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

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

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