KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > latch > SharedLatchImpl


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: SharedLatchImpl.java,v 1.9 2006/11/02 23:28:55 cwl Exp $
7  */

8
9 package com.sleepycat.je.latch;
10
11 import java.util.ArrayList JavaDoc;
12 import java.util.Iterator JavaDoc;
13 import java.util.List JavaDoc;
14
15 import com.sleepycat.je.DatabaseException;
16 import com.sleepycat.je.RunRecoveryException;
17 import com.sleepycat.je.dbi.EnvironmentImpl;
18
19 /**
20  * Simple thread-based non-transactional reader-writer/shared-exclusive latch.
21  *
22  * Latches provide simple exclusive or shared transient locks on objects.
23  * Latches are expected to be held for short, defined periods of time. No
24  * deadlock detection is provided so it is the caller's responsibility to
25  * sequence latch acquisition in an ordered fashion to avoid deadlocks.
26  *
27  * Nested latches for a single thread are supported, but upgrading a shared
28  * latch to an exclusive latch is not. This implementation is based on the
29  * section Reader-Writer Locks in the book Java Threads by Scott Oaks, 2nd
30  * Edition, Chapter 8.
31  *
32  * This SharedLatch implementation is only used when Java 5
33  * ReentrantReadWriteLocks are not available.
34  */

35 public class SharedLatchImpl implements SharedLatch {
36
37     private String JavaDoc name = null;
38     private List JavaDoc waiters = new ArrayList JavaDoc();
39     private LatchStats stats = new LatchStats();
40     /* The object that the latch protects. */
41     private EnvironmentImpl env = null;
42     private boolean noteLatch;
43     private boolean exclusiveOnly;
44
45     /**
46      * Create a shared latch.
47      */

48     public SharedLatchImpl(String JavaDoc name, EnvironmentImpl env) {
49     this.name = name;
50     this.env = env;
51     this.exclusiveOnly = false;
52     }
53
54     /**
55      * Indicate whether this latch can only be set exclusively (not shared).
56      */

57     public void setExclusiveOnly(boolean exclusiveOnly) {
58     this.exclusiveOnly = exclusiveOnly;
59     }
60
61     /**
62      * Set the latch name, used for latches in objects instantiated from the
63      * log.
64      */

65     synchronized public void setName(String JavaDoc name) {
66         this.name = name;
67     }
68
69     /**
70      * If noteLatch is true, then track latch usage in the latchTable.
71      * Return true so this can be called under an assert.
72      */

73     synchronized public boolean setNoteLatch(boolean noteLatch) {
74     this.noteLatch = noteLatch;
75     return true;
76     }
77
78     /**
79      * Acquire a latch for exclusive/write access. Nesting is allowed, that
80      * is, the latch may be acquired more than once by the same thread for
81      * exclusive access. However, if the thread already holds the latch for
82      * shared access, it cannot be upgraded and LatchException will be thrown.
83      *
84      * Wait for the latch if some other thread is holding it. If there are
85      * threads waiting for access, they will be granted the latch on a FIFO
86      * basis. When the method returns, the latch is held for exclusive access.
87      *
88      * @throws LatchException if the latch is already held by the current
89      * thread for shared access.
90      *
91      * @throws RunRecoveryException if an InterruptedException exception
92      * occurs.
93      */

94     public synchronized void acquireExclusive()
95     throws DatabaseException {
96
97         try {
98             Thread JavaDoc thread = Thread.currentThread();
99             int index = indexOf(thread);
100             Owner owner;
101             if (index < 0) {
102                 owner = new Owner(thread, Owner.EXCLUSIVE);
103                 waiters.add(owner);
104             } else {
105         throw new LatchException
106             (getNameString() + " reentrancy/upgrade not allowed");
107             }
108             if (waiters.size() == 1) {
109                 stats.nAcquiresNoWaiters++;
110             } else {
111                 stats.nAcquiresWithContention++;
112                 while (waiters.get(0) != owner) {
113                     wait();
114                 }
115             }
116             owner.nAcquires += 1;
117             assert (noteLatch ? noteLatch() : true); // intentional side effect
118
} catch (InterruptedException JavaDoc e) {
119         throw new RunRecoveryException(env, e);
120     } finally {
121         assert EnvironmentImpl.maybeForceYield();
122     }
123     }
124
125     public synchronized boolean acquireExclusiveNoWait()
126     throws DatabaseException {
127
128         try {
129             Thread JavaDoc thread = Thread.currentThread();
130             int index = indexOf(thread);
131             if (index < 0) {
132         if (waiters.size() == 0) {
133             Owner owner = new Owner(thread, Owner.EXCLUSIVE);
134             waiters.add(owner);
135             owner.nAcquires += 1;
136             stats.nAcquiresNoWaiters++;
137             /* Intentional side effect. */
138             assert (noteLatch ? noteLatch() : true);
139             return true;
140         } else {
141             return false;
142         }
143             } else {
144         throw new LatchException
145             (getNameString() + " reentrancy/upgrade not allowed");
146         }
147     } finally {
148         assert EnvironmentImpl.maybeForceYield();
149     }
150     }
151
152     /**
153      * Acquire a latch for shared/read access. Nesting is allowed, that is,
154      * the latch may be acquired more than once by the same thread.
155      *
156      * @throws RunRecoveryException if an InterruptedException exception
157      * occurs.
158      */

159     public synchronized void acquireShared()
160         throws DatabaseException {
161
162     if (exclusiveOnly) {
163         acquireExclusive();
164         return;
165     }
166
167         try {
168             Thread JavaDoc thread = Thread.currentThread();
169             int index = indexOf(thread);
170             Owner owner;
171             if (index < 0) {
172                 owner = new Owner(thread, Owner.SHARED);
173                 waiters.add(owner);
174             } else {
175                 owner = (Owner) waiters.get(index);
176             }
177             while (indexOf(thread) > firstWriter()) {
178                 wait();
179             }
180             owner.nAcquires += 1;
181             stats.nAcquireSharedSuccessful++;
182             assert (noteLatch ? noteLatch() : true); // intentional side effect
183
} catch (InterruptedException JavaDoc e) {
184         throw new RunRecoveryException(env, e);
185     } finally {
186         assert EnvironmentImpl.maybeForceYield();
187     }
188     }
189
190     public synchronized boolean isOwner() {
191     try {
192         Thread JavaDoc thread = Thread.currentThread();
193         int index = indexOf(thread);
194         if (index < 0 ||
195         index > firstWriter()) {
196         return false;
197         }
198         return true;
199     } finally {
200         assert EnvironmentImpl.maybeForceYield();
201     }
202     }
203
204     /**
205      * Release an exclusive or shared latch. If there are other thread(s)
206      * waiting for the latch, they are woken up and granted the latch.
207      */

208     public synchronized void release()
209     throws LatchNotHeldException {
210
211         try {
212             Thread JavaDoc thread = Thread.currentThread();
213             int index = indexOf(thread);
214             if (index < 0 || index > firstWriter()) {
215         return;
216             }
217             Owner owner = (Owner) waiters.get(index);
218             owner.nAcquires -= 1;
219             if (owner.nAcquires == 0) {
220                 waiters.remove(index);
221         /* Intentional side effect. */
222         assert (noteLatch ? unNoteLatch() : true);
223                 notifyAll();
224             }
225             stats.nReleases++;
226     } finally {
227         assert EnvironmentImpl.maybeForceYield();
228     }
229     }
230
231     public void releaseIfOwner()
232     throws LatchNotHeldException {
233
234     release();
235     }
236
237     /**
238      * Returns the index of the first Owner for the given thread, or -1 if
239      * none.
240      */

241     private int indexOf(Thread JavaDoc thread) {
242
243         Iterator JavaDoc i = waiters.iterator();
244         for (int index = 0; i.hasNext(); index += 1) {
245             Owner owner = (Owner) i.next();
246             if (owner.thread == thread) {
247                 return index;
248             }
249         }
250         return -1;
251     }
252
253     /**
254      * Returns the index of the first Owner waiting for a write lock, or
255      * Integer.MAX_VALUE if none.
256      */

257     private int firstWriter() {
258
259         Iterator JavaDoc i = waiters.iterator();
260         for (int index = 0; i.hasNext(); index += 1) {
261             Owner owner = (Owner) i.next();
262             if (owner.type == Owner.EXCLUSIVE) {
263                 return index;
264             }
265         }
266         return Integer.MAX_VALUE;
267     }
268
269     /**
270      * Holds the state of a single owner thread.
271      */

272     private static class Owner {
273
274         static final int SHARED = 0;
275         static final int EXCLUSIVE = 1;
276
277         Thread JavaDoc thread;
278         int type;
279         int nAcquires;
280
281         Owner(Thread JavaDoc thread, int type) {
282             this.thread = thread;
283             this.type = type;
284         }
285     }
286
287     /*
288      * For concocting exception messages
289      */

290     private String JavaDoc getNameString() {
291
292         return LatchSupport.latchTable.getNameString(name);
293     }
294
295     /**
296      * Only call under the assert system. This records latching by thread.
297      */

298     private boolean noteLatch()
299     throws LatchException {
300
301         return LatchSupport.latchTable.noteLatch(this);
302     }
303
304     /**
305      * Only call under the assert system. This records latching by thread.
306      */

307     private boolean unNoteLatch()
308     throws LatchNotHeldException {
309
310         return LatchSupport.latchTable.unNoteLatch(this, name);
311     }
312
313     public synchronized boolean isWriteLockedByCurrentThread() {
314     if (waiters.size() > 0) {
315         Owner curOwner = (Owner) waiters.get(0);
316         return (curOwner.thread == Thread.currentThread() &&
317             curOwner.type == Owner.EXCLUSIVE);
318     } else {
319         return false;
320     }
321     }
322
323     /*******
324      ** Not needed to implement SharedLatch but left in case we need the
325      ** API in the future.
326      ******/

327
328     /**
329      * Return true if the current thread holds this latch.
330      *
331      * @return true if we hold this latch. False otherwise.
332      */

333     /***********
334     public boolean isOwner() {
335
336         return Thread.currentThread() == owner();
337     }
338     ***********/

339
340     /**
341      * Used only for unit tests.
342      *
343      * @return the thread that currently holds the latch for exclusive access.
344      */

345     /***********
346     public synchronized Thread owner() {
347
348     return (waiters.size() > 0) ? ((Owner) waiters.get(0)).thread : null;
349     }
350     ***********/

351
352     /**
353      * Return the number of threads waiting.
354      *
355      * @return the number of threads waiting for the latch.
356      */

357     /***********
358     public synchronized int nWaiters() {
359
360         int n = waiters.size();
361         return (n > 0) ? (n - 1) : 0;
362     }
363     ***********/

364
365     /**
366      * Used for debugging latches.
367      *
368      * @return a LatchStats object with information about this latch.
369      */

370     /***********
371     public LatchStats getLatchStats() {
372
373     return stats;
374     }
375     ***********/

376
377     /**
378      * Formats a latch owner and waiters.
379      */

380     /***********
381     public synchronized String toString() {
382
383         return LatchSupport.latchTable.toString(name, owner(), waiters, 1);
384     }
385     ***********/

386 }
387
Popular Tags