KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > hp > hpl > jena > rdf > model > impl > ModelLockImpl


1 /*
2  * (c) Copyright 2003, 2004, 2005 Hewlett-Packard Development Company, LP
3  * [See end of file]
4  */

5
6 package com.hp.hpl.jena.rdf.model.impl ;
7 import com.hp.hpl.jena.rdf.model.ModelLock ;
8 import com.hp.hpl.jena.shared.JenaException;
9
10 import EDU.oswego.cs.dl.util.concurrent.WriterPreferenceReadWriteLock;
11 import EDU.oswego.cs.dl.util.concurrent.SynchronizedInt;
12 import java.util.*;
13 import org.apache.commons.logging.*;
14
15 /**
16  * Model lock implmenetation using a Multiple Reader, Single Writer policy.
17  * All the locking work is done by the imported WriterPreferenceReadWriteLock.
18  * Ths class adds:
19  * <ul>
20  * <li>The same thread that acquired a lock should release it</li>
21  * <li>Lock promotion (turing read locks into write locks) is deteched as an error</li>
22  * <ul>
23  * @see com.hp.hpl.jena.rdf.model.ModelLock
24  *
25  * @author Andy Seaborne
26  * @version $Id: ModelLockImpl.java,v 1.8 2005/02/21 12:14:35 andy_seaborne Exp $
27  */

28
29 public class ModelLockImpl implements ModelLock
30 {
31     // One instance per model.
32

33     static Log log = LogFactory.getLog(ModelLockImpl.class) ;
34     
35     // Map of threads to lock state for this model lock
36
Map threadStates = new HashMap() ;
37     // We keep this is a variable because it is tested outside of a lock.
38
int threadStatesSize = threadStates.size() ;
39     
40     //ReentrantWriterPreferenceReadWriteLock lock = new ReentrantWriterPreferenceReadWriteLock();
41
WriterPreferenceReadWriteLock lock = new WriterPreferenceReadWriteLock();
42     
43     SynchronizedInt activeReadLocks = new SynchronizedInt(0);
44     SynchronizedInt activeWriteLocks = new SynchronizedInt(0);
45
46     ModelLockImpl() {
47         if ( log.isDebugEnabled() )
48             log.debug("ModelLockImpl() : "+Thread.currentThread().getName()) ;
49     }
50
51
52     /** Application controlled locking - enter a critical section.
53      * Locking is reentrant so an application can have nested critical sections.
54      * Typical code:
55      * <pre>
56      * try {
57      * enterCriticalSection(ModelLock.READ) ;
58      * ... application code ...
59      * } finally { leaveCriticalSection() ; }
60      * </pre>
61      * @see com.hp.hpl.jena.rdf.model.ModelLock
62      */

63
64     final public void enterCriticalSection(boolean readLockRequested)
65     {
66         // Don't make {enter|leave}CriticalSection synchronized - deadlock will occur.
67
// The current thread will hold the model lock thread
68
// and will attempt to grab the MRSW lock.
69
// But if it waits, no other thread will even get
70
// to release the lock as it can't enter leaveCriticalSection
71

72         ModelLockState state = getLockState() ;
73         
74         // At this point we have the state object which is unique per
75
// model per thread. Thus, we can do updates to via state.???
76
// because we know no other thread is active on it.
77

78         if ( log.isDebugEnabled() )
79             log.debug(Thread.currentThread().getName()+" >> enterCS: "+report(state)) ;
80             
81         // If we have a read lock, but no write locks, then the thread is attempting
82
// a lock promotion. We do not allow this.
83
if (state.readLocks > 0 && state.writeLocks == 0 && !readLockRequested)
84         {
85             // Increment the readlock so a later leaveCriticialSection
86
// keeps the counters aligned.
87
state.readLocks++ ;
88             activeReadLocks.increment() ;
89
90             if ( log.isDebugEnabled() )
91                 log.debug(Thread.currentThread().getName()+" << enterCS: promotion attempt: "+report(state)) ;
92             
93             throw new JenaException("enterCriticalSection: Write lock request while holding read lock - potential deadlock");
94         }
95
96         // Trying to get a read lock after a write lock - get a write lock instead.
97
if ( state.writeLocks > 0 && readLockRequested )
98             readLockRequested = false ;
99
100         try {
101             if (readLockRequested)
102             {
103                 if (state.readLocks == 0)
104                     lock.readLock().acquire();
105                 state.readLocks ++ ;
106                 activeReadLocks.increment() ;
107             }
108             else
109             {
110                 if (state.writeLocks == 0)
111                     lock.writeLock().acquire();
112                 state.writeLocks ++ ;
113                 activeWriteLocks.increment() ;
114             }
115         }
116         catch (InterruptedException JavaDoc intEx)
117         {
118         }
119         finally
120         {
121             if ( log.isDebugEnabled() )
122                 log.debug(Thread.currentThread().getName()+" << enterCS: "+report(state)) ;
123         }
124     }
125
126     /** Application controlled locking - leave a critical section.
127      * @see #enterCriticalSection
128      * @see com.hp.hpl.jena.rdf.model.ModelLock
129      */

130
131     final public void leaveCriticalSection()
132     {
133          
134         ModelLockState state = getLockState() ;
135
136         if ( log.isDebugEnabled() )
137             log.debug(Thread.currentThread().getName()+" >> leaveCS: "+report(state)) ;
138
139         try {
140             if ( state.readLocks > 0)
141             {
142                 state.readLocks -- ;
143                 activeReadLocks.decrement() ;
144                 
145                 if ( state.readLocks == 0 )
146                     lock.readLock().release() ;
147                 
148                 state.clean() ;
149                 return ;
150             }
151         
152             if ( state.writeLocks > 0)
153             {
154                 state.writeLocks -- ;
155                 activeWriteLocks.decrement() ;
156                 
157                 if ( state.writeLocks == 0 )
158                     lock.writeLock().release() ;
159
160                 state.clean() ;
161                 return ;
162             }
163         
164             // No lock held.
165

166             throw new JenaException("leaveCriticalSection: No lock held ("+Thread.currentThread().getName()+")") ;
167         } finally
168         {
169             if ( log.isDebugEnabled() )
170                 log.debug(Thread.currentThread().getName()+" << leaveCS: "+report(state)) ;
171         }
172     }
173
174     private String JavaDoc report(ModelLockState state)
175     {
176         StringBuffer JavaDoc sb = new StringBuffer JavaDoc() ;
177         sb.append("Thread R/W: ") ;
178         sb.append(Integer.toString(state.readLocks)) ;
179         sb.append("/") ;
180         sb.append(Integer.toString(state.writeLocks)) ;
181         sb.append(" :: Model R/W: ") ;
182         sb.append(Integer.toString(activeReadLocks.get())) ;
183         sb.append("/") ;
184         sb.append(Integer.toString(activeWriteLocks.get())) ;
185         sb.append(" (thread: ") ;
186         sb.append(state.thread.getName()) ;
187         sb.append(")") ;
188         return sb.toString() ;
189     }
190
191     // Model internal functions -----------------------------
192

193     synchronized ModelLockState getLockState()
194     {
195         Thread JavaDoc thisThread = Thread.currentThread() ;
196         ModelLockState state = (ModelLockState)threadStates.get(thisThread) ;
197         if ( state == null )
198         {
199             state = new ModelLockState(this) ;
200             threadStates.put(thisThread, state) ;
201             threadStatesSize = threadStates.size() ;
202         }
203         return state ;
204     }
205
206     synchronized void removeLockState(Thread JavaDoc thread)
207     {
208         threadStates.remove(thread) ;
209     }
210
211     static class ModelLockState
212     {
213         // Counters for this lock object.
214
// Instances of ModelLockState are held per thread per model.
215
// These do not need to be atomic because a thread is the
216
// only accessor of its own counters
217

218         int readLocks = 0 ;
219         int writeLocks = 0 ;
220         ModelLockImpl modelLock ;
221         Thread JavaDoc thread ;
222
223         // Need to pass in the containing model lock
224
// because we want a lock on it.
225
ModelLockState(ModelLockImpl lock)
226         {
227             modelLock = lock ;
228             thread = Thread.currentThread() ;
229         }
230
231         void clean()
232         {
233             if (modelLock.activeReadLocks.get() == 0 && modelLock.activeWriteLocks.get() == 0)
234             {
235                 // A bit simple - but it churns (ModelLocalState creation) in the
236
// case of a thread looping around a critical section.
237
// The alternative, to delay now and do a more sophisticated global GC
238
// could require a global pause which is worse.
239
modelLock.removeLockState(thread) ;
240             }
241         }
242     }
243 }
244
245 /*
246  * (c) Copyright 2003, 2004, 2005 Hewlett-Packard Development Company, LP
247  * All rights reserved.
248  *
249  * Redistribution and use in source and binary forms, with or without
250  * modification, are permitted provided that the following conditions
251  * are met:
252  * 1. Redistributions of source code must retain the above copyright
253  * notice, this list of conditions and the following disclaimer.
254  * 2. Redistributions in binary form must reproduce the above copyright
255  * notice, this list of conditions and the following disclaimer in the
256  * documentation and/or other materials provided with the distribution.
257  * 3. The name of the author may not be used to endorse or promote products
258  * derived from this software without specific prior written permission.
259  *
260  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
261  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
262  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
263  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
264  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
265  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
266  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
267  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
270  */

271
272
Popular Tags