1 21 22 package org.apache.derby.impl.services.locks; 23 24 import org.apache.derby.iapi.services.locks.Latch; 25 import org.apache.derby.iapi.services.locks.Lockable; 26 import org.apache.derby.iapi.services.locks.C_LockFactory; 27 import org.apache.derby.iapi.services.monitor.Monitor; 28 29 import org.apache.derby.iapi.error.StandardException; 30 31 import org.apache.derby.iapi.services.sanity.SanityManager; 32 import org.apache.derby.iapi.services.diag.DiagnosticUtil; 33 34 import org.apache.derby.iapi.reference.Property; 35 import org.apache.derby.iapi.reference.SQLState; 36 37 import java.util.Hashtable ; 38 import java.util.Enumeration ; 39 40 41 67 68 public final class LockSet extends Hashtable 69 { 70 73 private final SinglePool factory; 74 75 80 protected int deadlockTimeout = Property.DEADLOCK_TIMEOUT_DEFAULT * 1000; 81 protected int waitTimeout = Property.WAIT_TIMEOUT_DEFAULT * 1000; 82 83 85 private boolean deadlockTrace; 88 89 private Hashtable lockTraces; 94 protected int blockCount; 96 97 100 101 protected LockSet(SinglePool factory) { 102 super(); 103 this.factory = factory; 104 } 105 106 107 110 111 124 public Lock lockObject(Object compatabilitySpace, Lockable ref, Object qualifier, int timeout, Latch latch) 125 throws StandardException 126 { 127 if (SanityManager.DEBUG) { 128 129 if (SanityManager.DEBUG_ON("memoryLeakTrace")) { 130 131 if (size() > 1000) 132 System.out.println("memoryLeakTrace:LockSet: " + size()); 133 } 134 } 135 136 Control gc; 137 LockControl control; 138 Lock lockItem; 139 String lockDebug = null; 140 141 synchronized (this) { 142 143 gc = getControl(ref); 144 145 if (gc == null) { 146 147 Lock gl = new Lock(compatabilitySpace, ref, qualifier); 149 150 gl.grant(); 151 152 put(ref, gl); 153 154 return gl; 155 } 156 157 control = gc.getLockControl(); 158 if (control != gc) { 159 put(ref, control); 160 } 161 162 163 if (SanityManager.DEBUG) { 164 SanityManager.ASSERT(ref.equals(control.getLockable())); 165 166 if (getControl(control.getLockable()) != control) 168 { 169 SanityManager.THROWASSERT( 170 "lockObject mismatched lock items " + 171 getControl(control.getLockable()) + " " + control); 172 } 173 } 174 175 lockItem = control.addLock(this, compatabilitySpace, qualifier); 176 177 if (lockItem.getCount() != 0) { 178 return lockItem; 179 } 180 181 if (timeout == C_LockFactory.NO_WAIT) { 182 183 control.giveUpWait(lockItem, this); 185 186 if (SanityManager.DEBUG) 187 { 188 if (SanityManager.DEBUG_ON("DeadlockTrace")) 189 { 190 191 SanityManager.showTrace(new Throwable ()); 192 193 197 lockDebug = 198 DiagnosticUtil.toDiagString(lockItem) + 199 "\nCould not grant lock with zero timeout, here's the table" + 200 this.toDebugString(); 201 } 202 } 203 204 return null; 205 } 206 207 if (latch != null) 209 unlock(latch, 1); 210 211 212 } 214 boolean deadlockWait = false; 215 int actualTimeout; 216 217 if (timeout == C_LockFactory.WAIT_FOREVER) 218 { 219 deadlockWait = true; 221 if ((actualTimeout = deadlockTimeout) == C_LockFactory.WAIT_FOREVER) 222 actualTimeout = Property.DEADLOCK_TIMEOUT_DEFAULT * 1000; 223 } 224 else 225 { 226 227 if (timeout == C_LockFactory.TIMED_WAIT) 228 timeout = actualTimeout = waitTimeout; 229 else 230 actualTimeout = timeout; 231 232 233 247 248 if (deadlockTimeout >= 0) { 249 250 if (actualTimeout < 0) { 251 deadlockWait = true; 253 actualTimeout = deadlockTimeout; 254 } else if (deadlockTimeout < actualTimeout) { 255 256 258 deadlockWait = true; 259 actualTimeout = deadlockTimeout; 260 261 timeout -= deadlockTimeout; 263 } 264 } 265 } 266 267 268 ActiveLock waitingLock = (ActiveLock) lockItem; 269 lockItem = null; 270 271 if (deadlockTrace) 272 { 273 lockTraces.put(waitingLock, new Throwable ()); 277 } 278 279 int earlyWakeupCount = 0; 280 long startWaitTime = 0; 281 282 try { 283 forever: for (;;) { 284 285 byte wakeupReason = waitingLock.waitForGrant(actualTimeout); 286 287 ActiveLock nextWaitingLock = null; 288 Object [] deadlockData = null; 289 290 try { 291 boolean willQuitWait; 292 Enumeration timeoutLockTable = null; 293 long currentTime = 0; 294 295 synchronized (this) { 296 297 if (control.isGrantable( 298 control.firstWaiter() == waitingLock, 299 compatabilitySpace, 300 qualifier)) { 301 302 control.grant(waitingLock); 304 305 nextWaitingLock = 307 control.getNextWaiter(waitingLock, true, this); 308 309 315 if (latch != null) { 316 lockObject( 317 compatabilitySpace, latch.getLockable(), 318 latch.getQualifier(), 319 C_LockFactory.WAIT_FOREVER, 320 (Latch) null); 321 } 322 return waitingLock; 323 } 324 325 waitingLock.clearPotentiallyGranted(); 327 328 willQuitWait = 329 (wakeupReason != Constants.WAITING_LOCK_GRANT); 330 331 StandardException deadlockException = null; 332 333 if (((wakeupReason == Constants.WAITING_LOCK_IN_WAIT) && 334 deadlockWait) || 335 (wakeupReason == Constants.WAITING_LOCK_DEADLOCK)) 336 { 337 338 deadlockData = 342 Deadlock.look( 343 factory, this, control, waitingLock, 344 wakeupReason); 345 346 if (deadlockData == null) { 347 deadlockWait = false; 349 350 actualTimeout = timeout; 351 startWaitTime = 0; 352 willQuitWait = false; 353 } else { 354 willQuitWait = true; 355 } 356 } 357 358 nextWaitingLock = 359 control.getNextWaiter( 360 waitingLock, willQuitWait, this); 361 362 363 if (willQuitWait) { 366 367 371 if (latch != null) { 372 lockObject( 373 compatabilitySpace, latch.getLockable(), 374 latch.getQualifier(), 375 C_LockFactory.WAIT_FOREVER, (Latch) null); 376 } 377 378 if (SanityManager.DEBUG) 379 { 380 if (SanityManager.DEBUG_ON("DeadlockTrace")) 381 { 382 383 SanityManager.showTrace(new Throwable ()); 384 385 389 lockDebug = 390 DiagnosticUtil.toDiagString(waitingLock) + 391 "\nGot deadlock/timeout, here's the table" + 392 this.toDebugString(); 393 } 394 } 395 396 if (deadlockTrace && (deadlockData == null)) 397 { 398 currentTime = System.currentTimeMillis(); 403 timeoutLockTable = 404 factory.makeVirtualLockTable(); 405 } 406 } 407 408 } 410 415 if (willQuitWait) 416 { 417 if (SanityManager.DEBUG) 418 { 419 if (lockDebug != null) 420 { 421 String type = 422 ((deadlockData != null) ? 423 "deadlock:" : "timeout:"); 424 425 SanityManager.DEBUG_PRINT( 426 type, 427 "wait on lockitem caused " + type + 428 lockDebug); 429 } 430 431 } 432 433 if (deadlockData == null) 434 { 435 437 if (deadlockTrace) 438 { 439 442 443 throw Timeout.buildException( 444 waitingLock, timeoutLockTable, currentTime); 445 } 446 else 447 { 448 StandardException se = 449 StandardException.newException( 450 SQLState.LOCK_TIMEOUT); 451 452 throw se; 453 } 454 } 455 else 456 { 457 459 throw Deadlock.buildException( 460 factory, deadlockData); 461 } 462 } 463 } finally { 464 if (nextWaitingLock != null) { 465 nextWaitingLock.wakeUp(Constants.WAITING_LOCK_GRANT); 466 nextWaitingLock = null; 467 } 468 } 469 470 if (actualTimeout != C_LockFactory.WAIT_FOREVER) { 471 472 if (wakeupReason != Constants.WAITING_LOCK_IN_WAIT) 473 earlyWakeupCount++; 474 475 if (earlyWakeupCount > 5) { 476 477 long now = System.currentTimeMillis(); 478 479 if (startWaitTime != 0) { 480 481 long sleepTime = now - startWaitTime; 482 483 actualTimeout -= sleepTime; 484 } 485 486 startWaitTime = now; 487 } 488 } 489 490 491 } } finally { 493 if (deadlockTrace) 494 { 495 lockTraces.remove(waitingLock); 499 } 500 } 501 } 502 503 511 void unlock(Latch item, int unlockCount) { 512 513 if (SanityManager.DEBUG) { 514 if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) { 515 520 SanityManager.DEBUG( 521 Constants.LOCK_TRACE, 522 "Release lock: " + DiagnosticUtil.toDiagString(item)); 523 } 524 } 525 526 boolean tryGrant = false; 527 ActiveLock nextGrant = null; 528 529 synchronized (this) { 530 531 Control control = getControl(item.getLockable()); 532 533 if (SanityManager.DEBUG) { 534 535 if (item.getLockable() == null) 537 { 538 SanityManager.THROWASSERT( 539 "item.getLockable() = null." + 540 "unlockCount " + unlockCount + 541 "item = " + DiagnosticUtil.toDiagString(item)); 542 } 543 544 if (control == null) 546 { 547 SanityManager.THROWASSERT( 548 "control = null." + 549 "unlockCount " + unlockCount + 550 "item = " + DiagnosticUtil.toDiagString(item)); 551 } 552 553 if (getControl(control.getLockable()) != control) 554 { 555 SanityManager.THROWASSERT( 556 "unlock mismatched lock items " + 557 getControl(control.getLockable()) + " " + control); 558 } 559 560 if ((unlockCount != 0) && (unlockCount > item.getCount())) 561 SanityManager.THROWASSERT("unlockCount " + unlockCount + 562 " larger than actual lock count " + item.getCount() + " item " + item); 563 } 564 565 tryGrant = control.unlock(item, unlockCount); 566 item = null; 567 568 boolean mayBeEmpty = true; 569 if (tryGrant) { 570 nextGrant = control.firstWaiter(); 571 if (nextGrant != null) { 572 mayBeEmpty = false; 573 if (!nextGrant.setPotentiallyGranted()) 574 nextGrant = null; 575 } 576 } 577 578 if (mayBeEmpty) { 579 if (control.isEmpty()) { 580 remove(control.getLockable()); 582 } 583 return; 584 } 585 } 587 if (tryGrant && (nextGrant != null)) { 588 nextGrant.wakeUp(Constants.WAITING_LOCK_GRANT); 589 } 590 } 591 592 595 597 void setDeadlockTrace(boolean val) 598 { 599 deadlockTrace = val; 601 602 if (val && lockTraces == null) 603 { 604 lockTraces = new Hashtable (); 605 } 606 else if (!val && lockTraces != null) 607 { 608 lockTraces = null; 609 } 610 } 611 613 public String toDebugString() 614 { 615 if (SanityManager.DEBUG) 616 { 617 String str = new String (); 618 619 int i = 0; 620 for (Enumeration e = this.elements(); 621 e.hasMoreElements(); 622 i++) 623 { 624 str += "\n lock[" + i + "]: " + 625 DiagnosticUtil.toDiagString(e.nextElement()); 626 } 627 628 return(str); 629 } 630 else 631 { 632 return(null); 633 } 634 } 635 636 640 641 synchronized LockSet shallowClone() 642 { 643 LockSet clone = new LockSet(factory); 644 645 for (Enumeration e = keys(); e.hasMoreElements(); ) 646 { 647 Lockable lockable = (Lockable)e.nextElement(); 648 Control control = getControl(lockable); 649 650 clone.put(lockable, control.shallowClone()); 651 } 652 653 return clone; 654 } 655 657 661 void oneMoreWaiter() { 662 blockCount++; 663 } 664 665 void oneLessWaiter() { 666 blockCount--; 667 } 668 669 boolean anyoneBlocked() { 670 if (SanityManager.DEBUG) { 671 SanityManager.ASSERT( 672 blockCount >= 0, "blockCount should not be negative"); 673 } 674 675 return blockCount != 0; 677 } 678 679 public final Control getControl(Lockable ref) { 680 return (Control) get(ref); 681 } 682 } 683 | Popular Tags |