KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > odmg > locking > InMemoryLockMapImpl


1 package org.apache.ojb.odmg.locking;
2
3 /* Copyright 2002-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 import org.apache.ojb.broker.Identity;
19 import org.apache.ojb.broker.PersistenceBroker;
20 import org.apache.ojb.broker.util.configuration.Configuration;
21 import org.apache.ojb.broker.util.configuration.ConfigurationException;
22 import org.apache.ojb.odmg.TransactionImpl;
23 import org.apache.ojb.odmg.TxManagerFactory;
24
25 import java.util.Collection JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Vector JavaDoc;
30
31 /**
32  *
33  * We use a HashMap and synchronize blocks of access for a get "check" then put
34  * operation. We cannot use the hashtable as you could check in one synchronized call
35  * then put in another while a different thread is doing the same thing.
36  *
37  * @deprecated
38  * @author <a HREF="mailto:mattbaird@yahoo.com">Matthew Baird<a>
39  * update for use of Hashmap with synchronization.
40  * implemented timed out lock removal algo.
41  * @author <a HREF="mailto:thma@apache.org">Thomas Mahler<a>
42  * original author.
43  * @version $Id: InMemoryLockMapImpl.java,v 1.14.2.3 2005/12/21 22:29:51 tomdz Exp $
44  */

45 public class InMemoryLockMapImpl implements LockMap
46 {
47     /**
48      * MBAIRD: a LinkedHashMap returns objects in the order you put them in,
49      * while still maintaining an O(1) lookup like a normal hashmap. We can then
50      * use this to get the oldest entries very quickly, makes cleanup a breeze.
51      */

52     private HashMap JavaDoc locktable = new HashMap JavaDoc();
53
54     private long m_lastCleanupAt = System.currentTimeMillis();
55     private static long CLEANUP_FREQUENCY = 500; // 500 milliseconds.
56
private static int MAX_LOCKS_TO_CLEAN = 50;
57
58     /**
59      * returns the LockEntry for the Writer of object obj.
60      * If now writer exists, null is returned.
61      */

62     public LockEntry getWriter(Object JavaDoc obj)
63     {
64         PersistenceBroker broker = getBroker();
65         Identity oid = new Identity(obj, broker);
66         return getWriter(oid);
67     }
68
69     public LockEntry getWriter(Identity oid)
70     {
71         checkTimedOutLocks();
72         /* TODO: smarter solution in future */
73         // fix/workaround
74
// When Identity needs new id's we must overgive
75
// the a target broker when run with multiple databases
76
// using H/L sequence manager
77
ObjectLocks objectLocks = null;
78         synchronized(locktable)
79         {
80             objectLocks = (ObjectLocks) locktable.get(oid.toString());
81         }
82         if (objectLocks == null)
83         {
84             return null;
85         }
86         else
87         {
88             return objectLocks.getWriter();
89         }
90     }
91
92     /**
93      * obtain a PersistenceBroker instance for persistence operations.
94      */

95     private PersistenceBroker getBroker()
96     {
97         return TxManagerFactory.instance().getCurrentTransaction().getBroker();
98     }
99
100     /**
101      * returns a collection of Reader LockEntries for object obj.
102      * If no LockEntries could be found an empty Vector is returned.
103      */

104     public Collection JavaDoc getReaders(Object JavaDoc obj)
105     {
106         checkTimedOutLocks();
107         Identity oid = new Identity(obj,getBroker());
108         return getReaders(oid);
109     }
110
111     public Collection JavaDoc getReaders(Identity oid)
112     {
113         ObjectLocks objectLocks = null;
114         synchronized (locktable)
115         {
116             objectLocks = (ObjectLocks) locktable.get(oid.toString());
117         }
118         if (objectLocks == null)
119         {
120             return new Vector JavaDoc();
121         }
122         else
123         {
124             return objectLocks.getReaders().values();
125         }
126     }
127
128     /**
129      * Add a reader lock entry for transaction tx on object obj
130      * to the persistent storage.
131      */

132     public boolean addReader(TransactionImpl tx, Object JavaDoc obj)
133     {
134         checkTimedOutLocks();
135
136         Identity oid = new Identity(obj,getBroker());
137         LockEntry reader = new LockEntry(oid.toString(),
138                 tx.getGUID(),
139                 System.currentTimeMillis(),
140                 LockStrategyFactory.getIsolationLevel(obj),
141                 LockEntry.LOCK_READ);
142
143         addReaderInternal(reader);
144         return true;
145     }
146
147     void addReaderInternal(LockEntry reader)
148     {
149         ObjectLocks objectLocks = null;
150         /**
151          * MBAIRD: We need to synchronize the get/put so we don't have two threads
152          * competing to check if something is locked and double-locking it.
153          */

154         synchronized (locktable)
155         {
156             String JavaDoc oidString = reader.getOidString();
157             objectLocks = (ObjectLocks) locktable.get(oidString);
158             if (objectLocks == null)
159             {
160                 objectLocks = new ObjectLocks();
161                 locktable.put(oidString, objectLocks);
162             }
163         }
164         objectLocks.addReader(reader);
165     }
166
167     /**
168      * remove a reader lock entry for transaction tx on object obj
169      * from the persistent storage.
170      */

171     public void removeReader(TransactionImpl tx, Object JavaDoc obj)
172     {
173         checkTimedOutLocks();
174
175         Identity oid = new Identity(obj, getBroker());
176         String JavaDoc oidString = oid.toString();
177         String JavaDoc txGuid = tx.getGUID();
178         removeReaderInternal(oidString, txGuid);
179     }
180
181     private void removeReaderInternal(String JavaDoc oidString, String JavaDoc txGuid)
182     {
183         ObjectLocks objectLocks = null;
184         synchronized (locktable)
185         {
186             objectLocks = (ObjectLocks) locktable.get(oidString);
187         }
188         if (objectLocks == null)
189         {
190             return;
191         }
192         else
193         {
194             /**
195              * MBAIRD, last one out, close the door and turn off the lights.
196              * if no locks (readers or writers) exist for this object, let's remove
197              * it from the locktable.
198              */

199             synchronized (locktable)
200             {
201                 Map JavaDoc readers = objectLocks.getReaders();
202                 readers.remove(txGuid);
203                 if ((objectLocks.getWriter() == null) && (readers.size() == 0))
204                 {
205                     locktable.remove(oidString);
206                 }
207             }
208         }
209     }
210
211     void removeReaderByLock(LockEntry lock)
212     {
213         String JavaDoc oidString = lock.getOidString();
214         String JavaDoc txGuid = lock.getTransactionId();
215         removeReaderInternal(oidString, txGuid);
216     }
217     
218     /**
219      * remove a writer lock entry for transaction tx on object obj
220      * from the persistent storage.
221      */

222     public void removeWriter(LockEntry writer)
223     {
224         checkTimedOutLocks();
225
226         String JavaDoc oidString = writer.getOidString();
227         ObjectLocks objectLocks = null;
228         synchronized (locktable)
229         {
230             objectLocks = (ObjectLocks) locktable.get(oidString);
231         }
232         if (objectLocks == null)
233         {
234             return;
235         }
236         else
237         {
238             /**
239              * MBAIRD, last one out, close the door and turn off the lights.
240              * if no locks (readers or writers) exist for this object, let's remove
241              * it from the locktable.
242              */

243             synchronized (locktable)
244             {
245                 Map JavaDoc readers = objectLocks.getReaders();
246                 objectLocks.setWriter(null);
247                 // no need to check if writer is null, we just set it.
248
if (readers.size() == 0)
249                 {
250                     locktable.remove(oidString);
251                 }
252             }
253         }
254     }
255
256     /**
257      * upgrade a reader lock entry for transaction tx on object obj
258      * and write it to the persistent storage.
259      */

260     public boolean upgradeLock(LockEntry reader)
261     {
262         checkTimedOutLocks();
263
264         String JavaDoc oidString = reader.getOidString();
265         ObjectLocks objectLocks = null;
266         synchronized (locktable)
267         {
268             objectLocks = (ObjectLocks) locktable.get(oidString);
269         }
270
271         if (objectLocks == null)
272         {
273             return false;
274         }
275         else
276         {
277             // add writer entry
278
LockEntry writer = new LockEntry(reader.getOidString(),
279                     reader.getTransactionId(),
280                     System.currentTimeMillis(),
281                     reader.getIsolationLevel(),
282                     LockEntry.LOCK_WRITE);
283             objectLocks.setWriter(writer);
284             // remove reader entry
285
objectLocks.getReaders().remove(reader.getTransactionId());
286             return true;
287         }
288     }
289
290     /**
291      * generate a writer lock entry for transaction tx on object obj
292      * and write it to the persistent storage.
293      */

294     public boolean setWriter(TransactionImpl tx, Object JavaDoc obj)
295     {
296         checkTimedOutLocks();
297
298         Identity oid = new Identity(obj, tx.getBroker());
299         LockEntry writer = new LockEntry(oid.toString(),
300                 tx.getGUID(),
301                 System.currentTimeMillis(),
302                 LockStrategyFactory.getIsolationLevel(obj),
303                 LockEntry.LOCK_WRITE);
304         String JavaDoc oidString = oid.toString();
305         setWriterInternal(writer, oidString);
306         return true;
307     }
308
309     private void setWriterInternal(LockEntry writer, String JavaDoc oidString)
310     {
311         ObjectLocks objectLocks = null;
312         /**
313          * MBAIRD: We need to synchronize the get/put so we don't have two threads
314          * competing to check if something is locked and double-locking it.
315          */

316         synchronized (locktable)
317         {
318             objectLocks = (ObjectLocks) locktable.get(oidString);
319             if (objectLocks == null)
320             {
321                 objectLocks = new ObjectLocks();
322                 locktable.put(oidString, objectLocks);
323             }
324         }
325         objectLocks.setWriter(writer);
326     }
327
328     void setWriterByLock(LockEntry writer)
329     {
330         String JavaDoc oidString = writer.getOidString();
331         setWriterInternal(writer, oidString);
332     }
333
334     /**
335      * check if there is a reader lock entry for transaction tx on object obj
336      * in the persistent storage.
337      */

338     public boolean hasReadLock(TransactionImpl tx, Object JavaDoc obj)
339     {
340         checkTimedOutLocks();
341
342         Identity oid = new Identity(obj,getBroker());
343         String JavaDoc oidString = oid.toString();
344         String JavaDoc txGuid = tx.getGUID();
345         return hasReadLockInternal(oidString, txGuid);
346     }
347
348     private boolean hasReadLockInternal(String JavaDoc oidString, String JavaDoc txGuid)
349     {
350         ObjectLocks objectLocks = null;
351         synchronized (locktable)
352         {
353             objectLocks = (ObjectLocks) locktable.get(oidString);
354         }
355         
356         if (objectLocks == null)
357         {
358             return false;
359         }
360         else
361         {
362             
363             LockEntry reader = objectLocks.getReader(txGuid);
364             if (reader != null)
365             {
366                 return true;
367             }
368             else
369             {
370                 return false;
371             }
372         }
373     }
374
375     boolean hasReadLock(LockEntry entry)
376     {
377         String JavaDoc oidString = entry.getOidString();
378         String JavaDoc txGuid = entry.getTransactionId();
379         return hasReadLockInternal(oidString,txGuid);
380     }
381
382     private void checkTimedOutLocks()
383     {
384         if (System.currentTimeMillis() - m_lastCleanupAt > CLEANUP_FREQUENCY)
385         {
386             removeTimedOutLocks(AbstractLockStrategy.DEFAULT_LOCK_TIMEOUT);
387             m_lastCleanupAt = System.currentTimeMillis();
388         }
389     }
390
391     /**
392     * removes all timed out lock entries from the persistent storage.
393     * The timeout value can be set in the OJB properties file.
394     */

395     private void removeTimedOutLocks(long timeout)
396     {
397         int count = 0;
398         long maxAge = System.currentTimeMillis() - timeout;
399         boolean breakFromLoop = false;
400         ObjectLocks temp = null;
401         synchronized (locktable)
402         {
403             Iterator JavaDoc it = locktable.values().iterator();
404             /**
405              * run this loop while:
406              * - we have more in the iterator
407              * - the breakFromLoop flag hasn't been set
408              * - we haven't removed more than the limit for this cleaning iteration.
409              */

410             while (it.hasNext() && !breakFromLoop && (count <= MAX_LOCKS_TO_CLEAN))
411             {
412                 temp = (ObjectLocks) it.next();
413                 if (temp.getWriter() != null)
414                 {
415                     if (temp.getWriter().getTimestamp() < maxAge)
416                     {
417                         // writer has timed out, set it to null
418
temp.setWriter(null);
419                     }
420                 }
421                 if (temp.getYoungestReader() < maxAge)
422                 {
423                     // all readers are older than timeout.
424
temp.getReaders().clear();
425                     if (temp.getWriter() == null)
426                     {
427                         // all readers and writer are older than timeout,
428
// remove the objectLock from the iterator (which
429
// is backed by the map, so it will be removed.
430
it.remove();
431                     }
432                 }
433                 else
434                 {
435                     // we need to walk each reader.
436
Iterator JavaDoc readerIt = temp.getReaders().values().iterator();
437                     LockEntry readerLock = null;
438                     while (readerIt.hasNext())
439                     {
440                         readerLock = (LockEntry) readerIt.next();
441                         if (readerLock.getTimestamp() < maxAge)
442                         {
443                             // this read lock is old, remove it.
444
readerIt.remove();
445                         }
446                     }
447                 }
448                 count++;
449             }
450         }
451     }
452     
453     /* (non-Javadoc)
454      * @see org.apache.ojb.broker.util.configuration.Configurable#configure(org.apache.ojb.broker.util.configuration.Configuration)
455      */

456     public void configure(Configuration pConfig) throws ConfigurationException
457     {
458         // noop
459

460     }
461     
462     int getSize()
463     {
464         return locktable.size();
465     }
466
467 }
468
Popular Tags