KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > scheduler > schema > TransactionExclusiveLock


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
6  * Contact: sequoia@continuent.org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  * Initial developer(s): Emmanuel Cecchet.
21  * Contributor(s): _________________________.
22  */

23
24 package org.continuent.sequoia.controller.scheduler.schema;
25
26 import java.util.Iterator JavaDoc;
27 import java.util.LinkedList JavaDoc;
28
29 import org.continuent.sequoia.controller.requests.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 LinkedList JavaDoc waitingList = new LinkedList 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 (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.addLast(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 * 1000L;
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               for (Iterator JavaDoc iter = waitingList.iterator(); iter.hasNext();)
162               {
163                 WaitingListElement e = (WaitingListElement) iter.next();
164                 if (e.equals(wle))
165                 {
166                   iter.remove();
167                   return false;
168                 }
169               }
170               // Not found, we got the lock before being able to acquire the
171
// lock on "this". Give the lock to the next one.
172
release();
173             }
174             return false;
175           }
176         }
177       }
178       catch (InterruptedException JavaDoc ie)
179       {
180         synchronized (this)
181         { // Something wrong happened, remove ourselves from the waiting list
182
waitingList.remove(Thread.currentThread());
183         }
184         return false;
185       }
186     }
187   }
188
189   /**
190    * Releases the lock on this table.
191    *
192    * @see #acquire(AbstractRequest)
193    */

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

217   public boolean isLocked()
218   {
219     return isLocked;
220   }
221
222   /**
223    * Returns the transaction id of the lock owner. The return value is undefined
224    * if the lock is not owned (usually it is the last owner).
225    *
226    * @return int the transaction id.
227    */

228   public long getLocker()
229   {
230     return locker;
231   }
232
233   /**
234    * Returns the waitingList.
235    *
236    * @return an <code>LinkedList</code> of <code>WaitingListElement</code>
237    */

238   public LinkedList JavaDoc getWaitingList()
239   {
240     return waitingList;
241   }
242
243   /**
244    * Returns <code>true</code> if the given transaction id is contained in
245    * this lock waiting queue.
246    *
247    * @param transactionId a transaction id
248    * @return a <code>boolean</code> value
249    */

250   public synchronized boolean isWaiting(long transactionId)
251   {
252     for (Iterator JavaDoc iter = waitingList.iterator(); iter.hasNext();)
253     {
254       WaitingListElement e = (WaitingListElement) iter.next();
255       if (e.getTransactionId() == transactionId)
256         return true;
257     }
258     return false;
259   }
260 }
Popular Tags