KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: LatchImpl.java,v 1.6 2006/10/30 21:14:19 bostic Exp $
7  */

8
9 package com.sleepycat.je.latch;
10
11 import java.util.ArrayList JavaDoc;
12 import java.util.List JavaDoc;
13
14 import com.sleepycat.je.DatabaseException;
15 import com.sleepycat.je.RunRecoveryException;
16 import com.sleepycat.je.dbi.EnvironmentImpl;
17
18 /**
19  * This implementation is used in non-Java5 JVMs. In Java5 JVMs, the
20  * Java5LockWrapperImpl class is used. The switch hitting is performed in
21  * LatchSupport.
22  *
23  * Simple thread-based non-transactional exclusive non-nestable latch.
24  * <p>
25  * Latches provide simple exclusive transient locks on objects. Latches are
26  * expected to be held for short, defined periods of time. No deadlock
27  * detection is provided so it is the caller's responsibility to sequence latch
28  * acquisition in an ordered fashion to avoid deadlocks.
29  * <p>
30  * A latch can be acquire in wait or no-wait modes. In the former, the caller
31  * will wait for any conflicting holders to release the latch. In the latter,
32  * if the latch is not available, control returns to the caller immediately.
33  */

34 public class LatchImpl implements Latch {
35     private static final String JavaDoc DEFAULT_LATCH_NAME = "LatchImpl";
36
37     private String JavaDoc name = null;
38     private List JavaDoc waiters = null;
39     private LatchStats stats = new LatchStats();
40     /* The object that the latch protects. */
41     private EnvironmentImpl env = null;
42     private Thread JavaDoc owner = null;
43
44     /**
45      * Create a latch.
46      */

47     public LatchImpl(String JavaDoc name, EnvironmentImpl env) {
48     this.name = name;
49     this.env = env;
50     }
51
52     /**
53      * Create a latch with no name, more optimal for shortlived latches.
54      */

55     public LatchImpl(EnvironmentImpl env) {
56     this.env = env;
57         this.name = DEFAULT_LATCH_NAME;
58     }
59
60     /**
61      * Set the latch name, used for latches in objects instantiated from
62      * the log.
63      */

64     synchronized public void setName(String JavaDoc name) {
65         this.name = name;
66     }
67
68     /**
69      * Acquire a latch for exclusive/write access.
70      *
71      * <p>Wait for the latch if some other thread is holding it. If there are
72      * threads waiting for access, they will be granted the latch on a FIFO
73      * basis. When the method returns, the latch is held for exclusive
74      * access.</p>
75      *
76      * @throws LatchException if the latch is already held by the calling
77      * thread.
78      *
79      * @throws RunRecoveryException if an InterruptedException exception
80      * occurs.
81      */

82     public void acquire()
83     throws DatabaseException {
84
85         try {
86             Thread JavaDoc thread = Thread.currentThread();
87             LatchWaiter waitTarget = null;
88
89         synchronized (this) {
90         if (thread == owner) {
91             stats.nAcquiresSelfOwned++;
92             throw new LatchException(getNameString() +
93                          " already held");
94         }
95
96         if (owner == null) {
97             stats.nAcquiresNoWaiters++;
98             owner = thread;
99         } else {
100             if (waiters == null) {
101             waiters = new ArrayList JavaDoc();
102             }
103             waitTarget = new LatchWaiter(thread);
104             waiters.add(waitTarget);
105             stats.nAcquiresWithContention++;
106         }
107         }
108
109         if (waitTarget != null) {
110         synchronized (waitTarget) {
111             while (true) {
112             if (waitTarget.active) {
113                 if (thread == owner) {
114                 break;
115                 } else {
116                 throw new DatabaseException
117                     ("waitTarget.active but not owner");
118                 }
119             } else {
120                 waitTarget.wait();
121                 if (thread == owner) {
122                 break;
123                 } else {
124                 continue;
125                 }
126             }
127             }
128         }
129         }
130
131             assert noteLatch(); // intentional side effect;
132
} catch (InterruptedException JavaDoc e) {
133         throw new RunRecoveryException(env, e);
134     } finally {
135         assert EnvironmentImpl.maybeForceYield();
136     }
137     }
138
139     /**
140      * Acquire a latch for exclusive/write access, but do not block if it's not
141      * available.
142      *
143      * @return true if the latch was acquired, false if it is not available.
144      *
145      * @throws LatchException if the latch is already held by the calling
146      * thread.
147      */

148     public synchronized boolean acquireNoWait()
149     throws LatchException {
150
151         try {
152             Thread JavaDoc thread = Thread.currentThread();
153             if (thread == owner) {
154                 stats.nAcquiresSelfOwned++;
155                 throw new LatchException(getNameString() +
156                                          " already held");
157             }
158             if (owner == null) {
159                 owner = thread;
160                 stats.nAcquireNoWaitSuccessful++;
161                 assert noteLatch(); // intentional side effect;
162
return true;
163             } else {
164                 stats.nAcquireNoWaitUnsuccessful++;
165                 return false;
166             }
167     } finally {
168         assert EnvironmentImpl.maybeForceYield();
169     }
170     }
171
172     /**
173      * Release the latch. If there are other thread(s) waiting for the latch,
174      * one is woken up and granted the latch. If the latch was not owned by
175      * the caller, just return;
176      */

177     public void releaseIfOwner() {
178         doRelease(false);
179     }
180
181     /**
182      * Release the latch. If there are other thread(s) waiting for the latch,
183      * they are woken up and granted the latch.
184      *
185      * @throws LatchNotHeldException if the latch is not currently held.
186      */

187     public void release()
188         throws LatchNotHeldException {
189
190         if (doRelease(true)) {
191             throw new LatchNotHeldException
192                 (getNameString() + " not held");
193         }
194     }
195
196     /**
197      * Do the work of releasing the latch. Wake up any waiters.
198      *
199      * @returns true if this latch was not owned by the caller.
200      */

201     private boolean doRelease(boolean checkHeld) {
202
203         LatchWaiter newOwner = null;
204
205         try {
206             synchronized (this) {
207         Thread JavaDoc thread = Thread.currentThread();
208         if (thread != owner) {
209                     return true;
210         }
211
212         if (waiters != null && waiters.size() > 0) {
213             newOwner = (LatchWaiter) waiters.remove(0);
214             owner = (Thread JavaDoc) newOwner.thread;
215
216         } else {
217             owner = null;
218         }
219         stats.nReleases++;
220         assert unNoteLatch(checkHeld); // intentional side effect.
221
}
222     } finally {
223         assert EnvironmentImpl.maybeForceYield();
224     }
225
226     if (newOwner != null) {
227         synchronized (newOwner) {
228         newOwner.active = true;
229         newOwner.notifyAll();
230         }
231     }
232         return false;
233     }
234
235     /**
236      * Return true if the current thread holds this latch.
237      *
238      * @return true if we hold this latch. False otherwise.
239      */

240     public boolean isOwner() {
241
242         return Thread.currentThread() == owner;
243     }
244
245     /**
246      * Used only for unit tests.
247      *
248      * @return the thread that currently holds the latch for exclusive access.
249      */

250     public Thread JavaDoc owner() {
251
252     return owner;
253     }
254
255     /**
256      * Return the number of threads waiting.
257      *
258      * @return the number of threads waiting for the latch.
259      */

260     public synchronized int nWaiters() {
261
262         return (waiters != null) ? waiters.size() : 0;
263     }
264
265     /**
266      * @return a LatchStats object with information about this latch.
267      */

268     public LatchStats getLatchStats() {
269     LatchStats s = null;
270     try {
271         s = (LatchStats) stats.clone();
272     } catch (CloneNotSupportedException JavaDoc e) {
273         /* Klockwork - ok */
274     }
275     return s;
276     }
277
278     /**
279      * Formats a latch owner and waiters.
280      */

281     public synchronized String JavaDoc toString() {
282
283         return LatchSupport.latchTable.toString(name, owner, waiters, 0);
284     }
285
286     /**
287      * For concocting exception messages
288      */

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

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

306     private boolean unNoteLatch(boolean checkHeld) {
307         
308         /* Only return a false status if we are checking for latch ownership.*/
309         if (checkHeld) {
310             return LatchSupport.latchTable.unNoteLatch(this, name);
311         } else {
312             LatchSupport.latchTable.unNoteLatch(this, name);
313             return true;
314         }
315     }
316     
317     /**
318      * Simple class that encapsulates a Thread to be 'notify()ed'.
319      */

320     static private class LatchWaiter {
321     boolean active;
322     Thread JavaDoc thread;
323
324     LatchWaiter(Thread JavaDoc thread) {
325         this.thread = thread;
326         active = false;
327     }
328
329     public String JavaDoc toString() {
330         return "<LatchWaiter: " + thread + ">";
331     }
332     }
333 }
334
Popular Tags