KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > services > locks > LockSpace


1 /*
2
3    Derby - Class org.apache.derby.impl.services.locks.LockSpace
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. 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  */

21
22 package org.apache.derby.impl.services.locks;
23
24 import org.apache.derby.iapi.services.locks.Lockable;
25 import org.apache.derby.iapi.services.locks.Limit;
26
27 import org.apache.derby.iapi.util.Matchable;
28 import org.apache.derby.iapi.services.sanity.SanityManager;
29 import org.apache.derby.iapi.error.StandardException;
30
31 import java.util.Hashtable JavaDoc;
32 import java.util.Enumeration JavaDoc;
33 import java.util.Dictionary JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.util.Iterator JavaDoc;
36
37 /**
38
39     A LockSpace represents the complete set of locks held within
40     a single compatability space, broken into groups of locks.
41
42     A LockSpace is a hashtable keyed by the group reference,
43     the data for each key is a Hashtable of Lock's.
44
45 */

46 class LockSpace extends Hashtable JavaDoc {
47
48     private final Object JavaDoc compatSpace;
49     // the object I live in
50
private final Dictionary JavaDoc holder;
51
52     private HashMap JavaDoc spareGroups[] = new HashMap JavaDoc[3];
53
54     // the Limit info.
55
private Object JavaDoc callbackGroup;
56     private int limit;
57     private int nextLimitCall;
58     private Limit callback;
59
60     LockSpace(Dictionary JavaDoc holder, Object JavaDoc compatSpace) {
61         super();
62         this.compatSpace = compatSpace;
63         this.holder = holder;
64     }
65
66     /**
67         Add a lock to a group.
68     */

69     protected synchronized void addLock(Object JavaDoc group, Lock lock)
70         throws StandardException {
71
72         Lock lockInGroup = null;
73
74         HashMap JavaDoc dl = (HashMap JavaDoc) get(group);
75         if (dl == null) {
76             dl = getGroupMap(group);
77         } else if (lock.getCount() != 1) {
78             lockInGroup = (Lock) dl.get(lock);
79         }
80
81         if (lockInGroup == null) {
82             lockInGroup = lock.copy();
83             dl.put(lockInGroup, lockInGroup);
84         }
85         lockInGroup.count++;
86
87         if (inLimit)
88             return;
89
90         if (!group.equals(callbackGroup))
91             return;
92
93         int groupSize = dl.size();
94         
95         if (groupSize > nextLimitCall) {
96
97             inLimit = true;
98             callback.reached(compatSpace, group, limit,
99                 new LockList(java.util.Collections.enumeration(dl.keySet())), groupSize);
100             inLimit = false;
101
102             // see when the next callback should occur, if the callback
103
// failed to release a sufficent amount of locks then
104
// delay until another "limit" locks are obtained.
105
int newGroupSize = dl.size();
106             if (newGroupSize < (limit / 2))
107                 nextLimitCall = limit;
108             else if (newGroupSize < (nextLimitCall / 2))
109                 nextLimitCall -= limit;
110             else
111                 nextLimitCall += limit;
112
113         }
114     }
115     
116     private boolean inLimit;
117     /**
118         Unlock all the locks in a group and then remove the group.
119     */

120
121     synchronized void unlockGroup(LockSet lset, Object JavaDoc group) {
122         HashMap JavaDoc dl = (HashMap JavaDoc) remove(group);
123         if (dl == null)
124             return;
125
126         for (Iterator JavaDoc list = dl.keySet().iterator(); list.hasNext(); ) {
127             lset.unlock((Lock) list.next(), 0);
128         }
129
130         if ((callbackGroup == null) && isEmpty())
131             holder.remove(compatSpace);
132         else if (group.equals(callbackGroup))
133             nextLimitCall = limit;
134
135         saveGroup(dl);
136     }
137
138     private HashMap JavaDoc getGroupMap(Object JavaDoc group) {
139         HashMap JavaDoc[] sg = spareGroups;
140         HashMap JavaDoc dl = null;
141         for (int i = 0; i < 3; i++) {
142             dl = sg[i];
143             if (dl != null) {
144                 sg[i] = null;
145                 break;
146             }
147         }
148
149         if (dl == null)
150             dl = new HashMap JavaDoc(5, 0.8f);
151
152         put(group, dl);
153         return dl;
154     }
155     private void saveGroup(HashMap JavaDoc dl) {
156         HashMap JavaDoc[] sg = spareGroups;
157         for (int i = 0; i < 3; i++) {
158             if (sg[i] == null) {
159                 sg[i] = dl;
160                 dl.clear();
161                 break;
162             }
163         }
164     }
165
166     /**
167         Unlock all locks in the group that match the key
168     */

169     synchronized void unlockGroup(LockSet lset, Object JavaDoc group, Matchable key) {
170         HashMap JavaDoc dl = (HashMap JavaDoc) get(group);
171         if (dl == null)
172             return; // no group at all
173

174         boolean allUnlocked = true;
175         for (Iterator JavaDoc e = dl.keySet().iterator(); e.hasNext(); ) {
176
177             Lock lock = (Lock) e.next();
178             if (!key.match(lock.getLockable())) {
179                 allUnlocked = false;
180                 continue;
181             }
182             lset.unlock(lock, 0);
183             e.remove();
184         }
185
186         if (allUnlocked) {
187             remove(group);
188             saveGroup(dl);
189             if ((callbackGroup == null) && isEmpty())
190                 holder.remove(compatSpace);
191             else if (group.equals(callbackGroup))
192                 nextLimitCall = limit;
193
194         }
195     }
196
197     synchronized void transfer(Object JavaDoc oldGroup, Object JavaDoc newGroup) {
198         HashMap JavaDoc from = (HashMap JavaDoc) get(oldGroup);
199         if (from == null)
200             return;
201
202         HashMap JavaDoc to = (HashMap JavaDoc) get(newGroup);
203         if (to == null) {
204             // simple case
205
put(newGroup, from);
206             clearLimit(oldGroup);
207             remove(oldGroup);
208             return;
209         }
210
211         if (to.size() < from.size()) {
212
213             // place the contents of to into from
214
mergeGroups(to, from);
215
216             Object JavaDoc oldTo = put(newGroup, from);
217             if (SanityManager.DEBUG) {
218                 SanityManager.ASSERT(oldTo == to, "inconsistent state in LockSpace");
219             }
220
221         } else {
222             mergeGroups(from, to);
223         }
224         
225         clearLimit(oldGroup);
226         remove(oldGroup);
227     }
228
229     private void mergeGroups(HashMap JavaDoc from, HashMap JavaDoc into) {
230
231         for (Iterator JavaDoc e = from.keySet().iterator(); e.hasNext(); ) {
232
233             Object JavaDoc lock = e.next();
234
235             Object JavaDoc lockI = into.get(lock);
236
237             if (lockI == null) {
238                 // lock is only in from list
239
into.put(lock, lock);
240             } else {
241                 // merge the locks
242
Lock fromL = (Lock) lock;
243                 Lock intoL = (Lock) lockI;
244
245                 intoL.count += fromL.getCount();
246             }
247         }
248
249     }
250
251     synchronized int unlockReference(LockSet lset, Lockable ref, Object JavaDoc qualifier, Object JavaDoc group) {
252
253         // look for locks matching our reference and qualifier.
254
HashMap JavaDoc dl = (HashMap JavaDoc) get(group);
255         if (dl == null)
256             return 0;
257
258         Lock lockInGroup;
259         synchronized (lset) {
260             Control control = lset.getControl(ref);
261             if (control == null)
262                 return 0;
263
264             Lock setLock = control.getLock(compatSpace, qualifier);
265             if (setLock == null)
266                 return 0;
267
268             lockInGroup = (Lock) dl.remove(setLock);
269             if (lockInGroup == null)
270                 return 0;
271             setLock = null;
272
273             lset.unlock(lockInGroup, 1);
274         }
275
276         if (lockInGroup.getCount() == 1) {
277
278             if (dl.isEmpty()) {
279                 remove(group);
280                 saveGroup(dl);
281                 if ((callbackGroup == null) && isEmpty())
282                     holder.remove(compatSpace);
283                 else if (group.equals(callbackGroup))
284                     nextLimitCall = limit;
285
286             }
287
288             return 1;
289         }
290             
291         // the lock item will be left in the group
292
lockInGroup.count--;
293         dl.put(lockInGroup, lockInGroup);
294         return 1;
295     }
296
297     /**
298         Return true if locks are held in a group
299     */

300     synchronized boolean areLocksHeld(Object JavaDoc group) {
301         return (get(group) != null);
302     }
303     
304     synchronized boolean isLockHeld(Object JavaDoc group, Lockable ref, Object JavaDoc qualifier) {
305
306         // look for locks matching our reference and qualifier.
307
HashMap JavaDoc dl = (HashMap JavaDoc) get(group);
308         if (dl == null)
309             return false;
310
311         Object JavaDoc heldLock = dl.get(new Lock(compatSpace, ref, qualifier));
312         return (heldLock != null);
313     }
314
315     synchronized void setLimit(Object JavaDoc group, int limit, Limit callback) {
316         callbackGroup = group;
317         this.nextLimitCall = this.limit = limit;
318         this.callback = callback;
319     }
320
321     /**
322         Clear a limit set by setLimit.
323     */

324     synchronized void clearLimit(Object JavaDoc group) {
325
326         if (group.equals(callbackGroup)) {
327             callbackGroup = null;
328             nextLimitCall = limit = Integer.MAX_VALUE;
329             callback = null;
330
331             if (isEmpty())
332                 holder.remove(compatSpace);
333         }
334     }
335
336     /**
337         Return a count of the number of locks
338         held by this space. The argument bail
339         indicates at which point the counting
340         should bail out and return the current
341         count. This routine will bail if the
342         count is greater than bail. Thus this
343         routine is intended to for deadlock
344         code to find the space with the
345         fewest number of locks.
346     */

347     synchronized int deadlockCount(int bail) {
348
349         int count = 0;
350
351         for (Enumeration JavaDoc groups = elements(); groups.hasMoreElements(); ) {
352             HashMap JavaDoc group = (HashMap JavaDoc) groups.nextElement();
353             for (Iterator JavaDoc locks = group.keySet().iterator(); locks.hasNext(); ) {
354                     Lock lock = (Lock) locks.next();
355                     count += lock.getCount();
356                     if (count > bail)
357                         return count;
358             }
359         }
360         return count;
361
362     }
363 }
364
365 /**
366     An Enumeration that returns the the Lockables
367     in a group.
368 */

369
370 class LockList implements Enumeration JavaDoc {
371
372     private Enumeration JavaDoc lockGroup;
373
374     LockList(Enumeration JavaDoc lockGroup) {
375         this.lockGroup = lockGroup;
376     }
377
378     public boolean hasMoreElements() {
379         return lockGroup.hasMoreElements();
380     }
381
382     public Object JavaDoc nextElement() {
383         return ((Lock) lockGroup.nextElement()).getLockable();
384     }
385 }
386
Popular Tags