KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > controller > scheduler > schema > TransactionExclusiveLock


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Emmanuel Cecchet.
22  * Contributor(s): _________________________.
23  */

24
25 package org.objectweb.cjdbc.controller.scheduler.schema;
26
27 import java.util.ArrayList JavaDoc;
28
29 import org.objectweb.cjdbc.common.sql.AbstractRequest;
30
31 /**
32  * A <code>TransactionExclusiveLock</code> is an exclusive lock that let the
33  * owner of the lock acquire several times the lock (but it needs to be released
34  * only once). Acquire supports timeout and graceful withdrawal of timed out
35  * requests.
36  *
37  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
38  * @version 1.0
39  */

40 public class TransactionExclusiveLock
41 {
42   private boolean isLocked = false;
43
44   /** Transaction id of the lock holder. */
45   private long locker;
46
47   /** <code>ArrayList</code> of <code>WaitingListElement</code>. */
48   private ArrayList JavaDoc waitingList = new ArrayList JavaDoc();
49
50   /**
51    * The element stored in the waiting list is the waiting thread and the
52    * transaction id of the request waiting.
53    */

54   private class WaitingListElement
55   {
56     /** Waiting thread */
57     Thread JavaDoc thread;
58
59     /** Transaction id of the request waiting. */
60     long transactionId;
61
62     /**
63      * Creates a new <code>WaitingListElement</code> instance.
64      *
65      * @param thread the waiting thread.
66      * @param transactionId the transaction id of the request waiting.
67      */

68     WaitingListElement(Thread JavaDoc thread, long transactionId)
69     {
70       this.thread = thread;
71       this.transactionId = transactionId;
72     }
73
74     /**
75      * Returns the transaction id of the request waiting.
76      *
77      * @return an <code>int</code> value
78      */

79     public long getTransactionId()
80     {
81       return transactionId;
82     }
83
84     /**
85      * Returns the waiting thread.
86      *
87      * @return a <code>Thread</code> value
88      */

89     public Thread JavaDoc getThread()
90     {
91       return thread;
92     }
93   }
94
95   /**
96    * Acquires an exclusive lock on this table. If the lock is already held by
97    * the same transaction as the given request, this method is non-blocking else
98    * the caller is blocked until the transaction holding the lock releases it at
99    * commit/rollback time.
100    *
101    * @param request request asking for the lock (timeout field is used and
102    * updated upon waiting)
103    * @return boolean true is the lock has been successfully acquired, false on
104    * timeout or error
105    * @see #release()
106    */

107   public boolean acquire(AbstractRequest request)
108   {
109     long tid = request.getTransactionId();
110
111     synchronized (Thread.currentThread())
112     {
113       WaitingListElement wle = null;
114       synchronized (this)
115       {
116         if (!isLocked)
117         { // Lock is free, take it
118
locker = tid;
119           isLocked = true;
120           return true;
121         }
122         else
123         {
124           if ((!request.isAutoCommit()) && (locker == tid))
125             return true; // We already have the lock
126
else
127           { // Wait for the lock
128
wle = new WaitingListElement(Thread.currentThread(), tid);
129             waitingList.add(wle);
130           }
131         }
132       }
133       // At this point, we have to wait for the lock.
134
try
135       {
136         int timeout = request.getTimeout();
137         if (timeout == 0)
138         {
139           Thread.currentThread().wait(); // No timeout
140
// Note: isLocked and locker are already set.
141
return true;
142         }
143         else
144         { // Wait with timeout
145
long start = System.currentTimeMillis();
146           // Convert seconds to milliseconds for wait call
147
long lTimeout = timeout * 1000;
148           Thread.currentThread().wait(lTimeout);
149           long end = System.currentTimeMillis();
150           int remaining = (int) (lTimeout - (end - start));
151           if (remaining > 0)
152           { // Ok
153
request.setTimeout(remaining);
154             // Note: isLocked and locker are already set.
155
return true;
156           }
157           else
158           { // Too late, remove ourselves from the waiting list
159
synchronized (this)
160             {
161               int idx = waitingList.indexOf(wle);
162               if (idx == -1)
163                 // We got the lock before being able to acquire the lock on
164
// this. Give the lock to the next one.
165
release();
166               else
167                 waitingList.remove(idx);
168             }
169             return false;
170           }
171         }
172       }
173       catch (InterruptedException JavaDoc ie)
174       {
175         synchronized (this)
176         { // Something wrong happened, remove ourselves from the waiting list
177
waitingList.remove(Thread.currentThread());
178         }
179         return false;
180       }
181     }
182   }
183
184   /**
185    * Releases the lock on this table.
186    *
187    * @see #acquire(AbstractRequest)
188    */

189   public synchronized void release()
190   {
191     while (!waitingList.isEmpty())
192     {
193       // Wake up the first waiting thread and update locker transaction id
194
WaitingListElement e = (WaitingListElement) waitingList.remove(0);
195       Thread JavaDoc thread = e.getThread();
196       locker = e.getTransactionId();
197       synchronized (thread)
198       {
199         thread.notify();
200         // isLocked remains true
201
return;
202       }
203     }
204     isLocked = false;
205   }
206
207   /**
208    * Returns <code>true</code> if the lock is owned by someone.
209    *
210    * @return <code>boolean</code> value
211    */

212   public boolean isLocked()
213   {
214     return isLocked;
215   }
216
217   /**
218    * Returns the transaction id of the lock owner. The return value is undefined
219    * if the lock is not owned (usually it is the last owner).
220    *
221    * @return int the transaction id.
222    */

223   public long getLocker()
224   {
225     return locker;
226   }
227
228   /**
229    * Returns the waitingList.
230    *
231    * @return an <code>ArrayList</code> of <code>WaitingListElement</code>
232    */

233   public ArrayList JavaDoc getWaitingList()
234   {
235     return waitingList;
236   }
237
238   /**
239    * Returns <code>true</code> if the given transaction id is contained in
240    * this lock waiting queue.
241    *
242    * @param transactionId a transaction id
243    * @return a <code>boolean</code> value
244    */

245   public synchronized boolean isWaiting(long transactionId)
246   {
247     WaitingListElement e;
248     int size = waitingList.size();
249     for (int i = 0; i < size; i++)
250     {
251       e = (WaitingListElement) waitingList.get(i);
252       if (e.getTransactionId() == transactionId)
253         return true;
254     }
255     return false;
256   }
257 }
Popular Tags