1 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 ; 32 import java.util.Enumeration ; 33 import java.util.Dictionary ; 34 import java.util.HashMap ; 35 import java.util.Iterator ; 36 37 46 class LockSpace extends Hashtable { 47 48 private final Object compatSpace; 49 private final Dictionary holder; 51 52 private HashMap spareGroups[] = new HashMap [3]; 53 54 private Object callbackGroup; 56 private int limit; 57 private int nextLimitCall; 58 private Limit callback; 59 60 LockSpace(Dictionary holder, Object compatSpace) { 61 super(); 62 this.compatSpace = compatSpace; 63 this.holder = holder; 64 } 65 66 69 protected synchronized void addLock(Object group, Lock lock) 70 throws StandardException { 71 72 Lock lockInGroup = null; 73 74 HashMap dl = (HashMap ) 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 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 120 121 synchronized void unlockGroup(LockSet lset, Object group) { 122 HashMap dl = (HashMap ) remove(group); 123 if (dl == null) 124 return; 125 126 for (Iterator 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 getGroupMap(Object group) { 139 HashMap [] sg = spareGroups; 140 HashMap 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 (5, 0.8f); 151 152 put(group, dl); 153 return dl; 154 } 155 private void saveGroup(HashMap dl) { 156 HashMap [] 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 169 synchronized void unlockGroup(LockSet lset, Object group, Matchable key) { 170 HashMap dl = (HashMap ) get(group); 171 if (dl == null) 172 return; 174 boolean allUnlocked = true; 175 for (Iterator 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 oldGroup, Object newGroup) { 198 HashMap from = (HashMap ) get(oldGroup); 199 if (from == null) 200 return; 201 202 HashMap to = (HashMap ) get(newGroup); 203 if (to == null) { 204 put(newGroup, from); 206 clearLimit(oldGroup); 207 remove(oldGroup); 208 return; 209 } 210 211 if (to.size() < from.size()) { 212 213 mergeGroups(to, from); 215 216 Object 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 from, HashMap into) { 230 231 for (Iterator e = from.keySet().iterator(); e.hasNext(); ) { 232 233 Object lock = e.next(); 234 235 Object lockI = into.get(lock); 236 237 if (lockI == null) { 238 into.put(lock, lock); 240 } else { 241 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 qualifier, Object group) { 252 253 HashMap dl = (HashMap ) 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 lockInGroup.count--; 293 dl.put(lockInGroup, lockInGroup); 294 return 1; 295 } 296 297 300 synchronized boolean areLocksHeld(Object group) { 301 return (get(group) != null); 302 } 303 304 synchronized boolean isLockHeld(Object group, Lockable ref, Object qualifier) { 305 306 HashMap dl = (HashMap ) get(group); 308 if (dl == null) 309 return false; 310 311 Object heldLock = dl.get(new Lock(compatSpace, ref, qualifier)); 312 return (heldLock != null); 313 } 314 315 synchronized void setLimit(Object group, int limit, Limit callback) { 316 callbackGroup = group; 317 this.nextLimitCall = this.limit = limit; 318 this.callback = callback; 319 } 320 321 324 synchronized void clearLimit(Object 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 347 synchronized int deadlockCount(int bail) { 348 349 int count = 0; 350 351 for (Enumeration groups = elements(); groups.hasMoreElements(); ) { 352 HashMap group = (HashMap ) groups.nextElement(); 353 for (Iterator 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 369 370 class LockList implements Enumeration { 371 372 private Enumeration lockGroup; 373 374 LockList(Enumeration lockGroup) { 375 this.lockGroup = lockGroup; 376 } 377 378 public boolean hasMoreElements() { 379 return lockGroup.hasMoreElements(); 380 } 381 382 public Object nextElement() { 383 return ((Lock) lockGroup.nextElement()).getLockable(); 384 } 385 } 386 | Popular Tags |