1 package com.quadcap.sql.lock; 2 3 40 41 import java.util.ArrayList ; 42 import java.util.HashMap ; 43 import java.util.Iterator ; 44 45 import java.util.Comparator ; 46 47 import java.sql.SQLException ; 48 49 import javax.concurrent.Sync; 50 51 import com.quadcap.util.Debug; 52 import com.quadcap.util.Util; 53 54 import com.quadcap.util.ConfigNumber; 55 56 57 62 public class LockManager { 63 79 protected static final 80 ConfigNumber trace = ConfigNumber.find("qed.trace.locks", "0"); 81 83 protected static final 84 ConfigNumber lockTimeout = ConfigNumber.find("qed.lock.Timeout", "60"); 85 86 private long transCount = 1; 87 88 final Object locksLock = new Object (); 89 90 91 LockPool locks = new LockPool(); 92 93 94 HeldLockPool held = new HeldLockPool(); 95 96 97 HeldLock tmpHeld = null; 98 99 100 TransactionPool transactions =new TransactionPool(); 101 102 103 SortedArray byTrans; 104 SortedArrayIterator byTransIter; 105 106 109 public LockManager() { 110 Comparator compare = new Comparator () { 111 public int compare(Object a, Object b) { 112 return HeldLock.compare((HeldLock)a, (HeldLock)b); 113 } 114 }; 115 byTrans = new SortedArray(compare); 116 byTransIter = new SortedArrayIterator(byTrans); 117 tmpHeld = held.get(null, null, LockMode.IX); 118 final LockManager lockMgr = this; 119 120 if (trace.bit(4)) { 122 Thread t = new Thread () { 123 public void run() { 124 setName("LockManager Debug"); 125 Debug.println("Lock dump thread running"); 126 while (lockMgr != null) { 127 try { 128 Thread.sleep(10000); 129 synchronized (lockMgr.locksLock) { 130 if (lockMgr.byTrans.size() > 0) { 131 Debug.println("DUMP: " + 132 lockMgr.toString()); 133 } 134 } 135 } catch (Throwable e) { 136 Debug.print(e); 137 } 138 } 139 } 140 }; 141 t.setDaemon(true); 142 t.start(); 143 } 144 } 146 147 151 public final Transaction getTransaction(long transId) { 152 synchronized (locksLock) { 153 Transaction t = (Transaction)transactions.get(transId); 154 if (trace.bit(3)) { 156 Debug.println("getTransaction() = " + t); 157 if (trace.bit(2)) { 158 Debug.println("this = " + this); 159 } 160 } 161 return t; 163 } 164 } 165 166 170 public Transaction findTransaction(long transId) { 171 return transactions.find(transId); 172 } 173 174 177 public void releaseTransaction(Transaction t) { 178 if (trace.bit(3)) { 180 Debug.println("releaseTransaction(" + t + ")"); 181 if (trace.bit(2)) { 182 Debug.println("this = " + this); 183 } 184 } 185 synchronized (locksLock) { 187 try { 188 Iterator tlocks = locksForTransaction(t); 190 if (trace.bit(1)) { 192 Debug.println("releaseTransaction(" + t + ") [1]"); 193 } 194 while (tlocks.hasNext()) { 197 HeldLock h = (HeldLock)tlocks.next(); 198 boolean saveMe = false; 199 if (h.trans.getTransactionId() < t.getTransactionId()) continue; 200 if (h.trans.getTransactionId() > t.getTransactionId()) break; 201 Lock lock = h.lock; 203 int mode = h.mode; 204 tlocks.remove(); 205 if (h.mode == LockMode.NL) continue; 206 if (trace.bit(1)) { 208 Debug.println("[release] lock(" + t + ", " + lock + " in " + 209 LockMode.toString(mode)); 210 } 211 lock.decrHeldCount(mode); 213 Transaction w = lock.headWaitQueue(); 214 while (w != null && w.getWaitMode() == LockMode.NL) { 215 lock.popWaitQueue(); 216 w = lock.headWaitQueue(); 217 } 218 if (w != null && !w.equals(t)) { 219 if (lock.couldLock(w.getWaitMode())) { 220 lock.popWaitQueue(); 221 HeldLock wl = w.getWait(); 222 if (trace.bit(1)) { 224 Debug.println("" + t + " releasing " + lock + 225 ", waking " + wl); 226 } 227 229 wl.mode = wl.waitMode; 230 acquireLock(wl); 231 w.clearWait(); 232 try { 233 Sync c = w.getSync(); 234 c.release(); 235 } catch (InterruptedException ex) { 236 } 237 } 238 } 239 held.release(h); 240 } 241 } finally { 242 transactions.release(t); 243 } 244 if (trace.bit(1)) { 246 Debug.println("releaseTransaction(" + t + ") done"); 247 if (trace.bit(2)) { 248 Debug.println("this = " + this); 249 } 250 } 251 } 253 } 254 255 258 public Iterator transactions() { 259 return transactions.iterator(); 260 } 261 262 266 final Iterator locksForTransaction(Transaction t) { 267 tmpHeld.trans = t; 268 tmpHeld.lock = null; 269 byTransIter.position(tmpHeld); 270 return byTransIter; 271 } 272 273 final HeldLock getLockForTransaction(Transaction t, Lock lock) { 274 tmpHeld.trans = t; 275 tmpHeld.lock = lock; 276 tmpHeld.mode = LockMode.NL; 277 byTransIter.position(tmpHeld); 278 while (byTransIter.hasNext()) { 279 HeldLock h = (HeldLock)byTransIter.next(); 280 if (t.getTransactionId() > h.trans.getTransactionId()) { 281 return null; 282 } 283 if (t.getTransactionId() == h.trans.getTransactionId() && 284 lock.hashCode() == h.lock.hashCode()) { 285 return h; 286 } 287 } 288 return null; 289 } 290 291 295 public final Lock getLock(Transaction t, Lock parent, String name, 296 int mode) 297 throws SQLException 298 { 299 HeldLock h = null; 300 boolean newLock = false; 301 Sync s = null; 302 if (trace.bit(1)) { 304 Debug.println("---- getLock(" + t + ", " + parent + ", " + 305 name + ", " + LockMode.toString(mode) + ")"); 306 } 307 try { 309 synchronized (locksLock) { 310 Lock lock = locks.get(parent, name); 311 checkParentsLockMode(t, lock, mode); 312 313 h = getLockForTransaction(t, lock); 314 if (h != null) { 315 if (LockMode.implies(h.mode, mode)) { 318 return h.lock; 320 } 321 if (LockMode.implies(mode, h.mode)) { 322 if (lock.couldPromote(h.mode, mode)) { 323 promoteLock(h, mode); 324 return h.lock; 326 } else { 327 } 329 } else { 330 throw new RuntimeException ("Transaction " + t + 331 " has lock " + lock + 332 " in mode " + 333 LockMode.toString(h.mode) + 334 ", trying to lock now in mode "+ 335 LockMode.toString(mode)); 336 } 337 } else { 338 newLock = true; 339 h = held.get(t, lock, mode); 342 if (lock.couldLock(mode) && !lock.hasWaiters()) { 343 acquireLock(h); 344 return h.lock; 346 } 347 } 348 h.setWaitMode(mode); 349 try { 350 s = waitForLock(h); 351 } catch (InterruptedException ex) { 352 throw new SQLException ("Interrupted trying to get lock: " + 353 name); 354 } 355 356 } 357 if (trace.bit(0)) { 359 Debug.println(" Waiting for: " + h); 360 if (trace.bit(2)) { 361 Debug.println(byTrans.toString()); 362 } 363 } 364 boolean got = false; 366 try { 367 got = s.attempt(lockTimeout.longValue() * 1000); 368 } catch (InterruptedException ex) { } 369 if (!got) { 370 Debug.println("Lock timed out: " + name + " after " + 371 lockTimeout.longValue() + 372 " seconds"); 373 Debug.println("LockManager: " + this); 374 if (!got) { 378 t.setWait(null); 379 if (newLock) { 380 held.release(h); 381 newLock = false; 382 } 383 throw new SQLException ("Timed out trying to get lock: " + 384 name + " for [T:" + t + "]"); 385 } 386 } 387 if (trace.bit(0)) { 389 Debug.println(" Wait done for: " + h); 390 } 391 return h.lock; 393 } finally { 394 if (trace.bit(1)) { 396 Debug.println("getLock(" + name + ") done"); 397 } 398 } 400 } 401 402 405 final Sync waitForLock(HeldLock h) throws InterruptedException { 406 final Transaction t = h.trans; 407 h.lock.addWaitQueue(t); 412 t.setWait(h); 413 return t.getSync(); 414 } 415 416 420 final void checkParentsLockMode(Transaction t, Lock lock, int mode) { 421 Lock p = lock.getParent(); 422 if (p != null) { 423 HeldLock h = getLockForTransaction(t, p); 424 if (h == null) { 425 Debug.println("Held: " + byTrans + ", lock = " + lock); 427 Debug.println("LockManager: " + this); 428 throw new RuntimeException ("no lock on parent " + p); 430 } 431 if (!couldLockWithParentMode(h.mode, mode)) { 432 Debug.println("lock = " + lock + ", p = " + p + ", h = " + h); 434 Debug.println("LockManager: " + this); 435 throw new RuntimeException ("parent not properly locked: " + h); 437 } 438 checkParentsLockMode(t, p, mode); 439 } 440 } 441 442 final boolean couldLockWithParentMode(int pmode, int mode) { 443 switch (mode) { 444 case LockMode.S: 445 case LockMode.IS: 446 return pmode == LockMode.X || pmode == LockMode.S 447 || pmode == LockMode.IX || pmode == LockMode.IS; 448 case LockMode.X: 449 case LockMode.IX: 450 case LockMode.SIX: 451 return pmode == LockMode.X 452 || pmode == LockMode.IX || pmode == LockMode.SIX; 453 default: 454 throw new RuntimeException ("bad lock mode: " + 455 LockMode.toString(mode)); 456 } 457 } 458 459 void promoteLock(HeldLock h, int mode) { 460 h.lock.decrHeldCount(h.mode); 461 h.lock.incrHeldCount(mode); 462 h.mode = mode; 463 } 464 465 void acquireLock(HeldLock h) { 466 h.lock.incrHeldCount(h.mode); 467 byTrans.add(h); 468 } 469 470 public String toString() { 472 synchronized (locksLock) { 473 StringBuffer sb = new StringBuffer (); 474 sb.append("\nTransactions:\n------------\n"); 475 sb.append(transactions); 476 sb.append("\nHeld:\n----\n"); 477 sb.append(byTrans); 478 sb.append("\nLocks:\n-----\n"); 479 sb.append(locks); 480 sb.append("\n"); 481 return sb.toString(); 482 } 483 } 484 } 486 487 | Popular Tags |