1 23 24 package org.apache.commons.transaction.locking; 25 26 import java.util.ArrayList ; 27 import java.util.Collection ; 28 import java.util.Collections ; 29 import java.util.HashMap ; 30 import java.util.HashSet ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Set ; 35 36 import org.apache.commons.transaction.util.LoggerFacade; 37 38 127 public class GenericLock implements MultiLevelLock2 { 128 129 protected Object resourceId; 130 protected Map owners = Collections.synchronizedMap(new HashMap ()); 134 protected List waitingOwners = Collections.synchronizedList(new ArrayList ()); 139 private int maxLockLevel; 140 protected LoggerFacade logger; 141 protected int waiters = 0; 142 143 150 public GenericLock(Object resourceId, int maxLockLevel, LoggerFacade logger) { 151 if (maxLockLevel < 1) 152 throw new IllegalArgumentException ( 153 "The maximum lock level must be at least 1 (" + maxLockLevel + " was specified)"); 154 this.resourceId = resourceId; 155 this.maxLockLevel = maxLockLevel; 156 this.logger = logger; 157 } 158 159 public boolean equals(Object o) { 160 if (o instanceof GenericLock) { 161 return ((GenericLock)o).resourceId.equals(resourceId); 162 } 163 return false; 164 } 165 166 public int hashCode() { 167 return resourceId.hashCode(); 168 } 169 170 173 public boolean test(Object ownerId, int targetLockLevel, int compatibility) { 174 boolean success = tryLock(ownerId, targetLockLevel, compatibility, false, true); 175 return success; 176 } 177 178 181 public boolean has(Object ownerId, int lockLevel) { 182 int level = getLockLevel(ownerId); 183 return (lockLevel <= level); 184 } 185 186 190 public synchronized boolean acquire(Object ownerId, int targetLockLevel, boolean wait, 191 boolean reentrant, long timeoutMSecs) throws InterruptedException { 192 return acquire(ownerId, targetLockLevel, wait, reentrant ? COMPATIBILITY_REENTRANT 193 : COMPATIBILITY_NONE, timeoutMSecs); 194 } 195 196 199 public synchronized boolean acquire(Object ownerId, int targetLockLevel, boolean wait, 200 int compatibility, long timeoutMSecs) throws InterruptedException { 201 return acquire(ownerId, targetLockLevel, wait, compatibility, false, timeoutMSecs); 202 } 203 204 210 public synchronized boolean acquire(Object ownerId, int targetLockLevel, boolean preferred, 211 long timeoutMSecs) throws InterruptedException { 212 return acquire(ownerId, targetLockLevel, true, COMPATIBILITY_REENTRANT, preferred, 213 timeoutMSecs); 214 } 215 216 221 public synchronized boolean acquire( 222 Object ownerId, 223 int targetLockLevel, 224 boolean wait, 225 int compatibility, 226 boolean preferred, 227 long timeoutMSecs) 228 throws InterruptedException { 229 230 if (logger.isFinerEnabled()) { 231 logger.logFiner( 232 ownerId.toString() 233 + " trying to acquire lock for " 234 + resourceId.toString() 235 + " at level " 236 + targetLockLevel 237 + " at " 238 + System.currentTimeMillis()); 239 } 240 241 if (tryLock(ownerId, targetLockLevel, compatibility, preferred)) { 242 243 if (logger.isFinerEnabled()) { 244 logger.logFiner( 245 ownerId.toString() 246 + " actually acquired lock for " 247 + resourceId.toString() 248 + " at " 249 + System.currentTimeMillis()); 250 } 251 252 return true; 253 } else { 254 if (!wait) { 255 return false; 256 } else { 257 long started = System.currentTimeMillis(); 258 for (long remaining = timeoutMSecs; 259 remaining > 0; 260 remaining = timeoutMSecs - (System.currentTimeMillis() - started)) { 261 262 if (logger.isFinerEnabled()) { 263 logger.logFiner( 264 ownerId.toString() 265 + " waiting on " 266 + resourceId.toString() 267 + " for msecs " 268 + timeoutMSecs 269 + " at " 270 + System.currentTimeMillis()); 271 } 272 273 LockOwner waitingOwner = new LockOwner(ownerId, targetLockLevel, compatibility, 274 preferred); 275 try { 276 registerWaiter(waitingOwner); 277 if (preferred) { 278 LockOwner oldLock = null; 280 try { 281 oldLock = (LockOwner) owners.get(ownerId); 283 setLockLevel(ownerId, null, targetLockLevel, compatibility, 286 preferred); 287 288 wait(remaining); 290 291 } finally { 292 if (oldLock != null) { 298 owners.put(ownerId, oldLock); 299 } else { 300 owners.remove(ownerId); 301 } 302 } 303 304 } else { 305 wait(remaining); 306 } 307 } finally { 308 unregisterWaiter(waitingOwner); 309 } 310 311 if (tryLock(ownerId, targetLockLevel, compatibility, preferred)) { 312 313 if (logger.isFinerEnabled()) { 314 logger.logFiner( 315 ownerId.toString() 316 + " waiting on " 317 + resourceId.toString() 318 + " eventually got the lock at " 319 + System.currentTimeMillis()); 320 } 321 322 return true; 323 } 324 } 325 return false; 326 } 327 } 328 } 329 330 protected void registerWaiter(LockOwner waitingOwner) { 331 synchronized (waitingOwners) { 332 unregisterWaiter(waitingOwner); 333 waiters++; 334 waitingOwners.add(waitingOwner); 335 } 336 } 337 338 protected void unregisterWaiter(LockOwner waitingOwner) { 339 synchronized (waitingOwners) { 340 if (waitingOwners.remove(waitingOwner)) 341 waiters--; 342 } 343 } 344 345 348 public synchronized boolean release(Object ownerId) { 349 if (owners.remove(ownerId) != null) { 350 if (logger.isFinerEnabled()) { 351 logger.logFiner( 352 ownerId.toString() 353 + " releasing lock for " 354 + resourceId.toString() 355 + " at " 356 + System.currentTimeMillis()); 357 } 358 notifyAll(); 359 return true; 360 } 361 return false; 362 } 363 364 367 public int getLockLevel(Object ownerId) { 368 LockOwner owner = (LockOwner) owners.get(ownerId); 369 if (owner == null) { 370 return 0; 371 } else { 372 return owner.lockLevel; 373 } 374 } 375 376 381 public Object getResourceId() { 382 return resourceId; 383 } 384 385 390 public int getLevelMinLock() { 391 return 0; 392 } 393 394 399 public int getLevelMaxLock() { 400 return maxLockLevel; 401 } 402 403 public Object getOwner() { 404 LockOwner owner = getMaxLevelOwner(); 405 if (owner == null) 406 return null; 407 return owner.ownerId; 408 } 409 410 public synchronized String toString() { 411 StringBuffer buf = new StringBuffer (); 412 buf.append(resourceId.toString()).append(":\n"); 413 414 for (Iterator it = owners.values().iterator(); it.hasNext();) { 415 LockOwner owner = (LockOwner) it.next(); 416 buf.append("- ").append(owner.toString()).append("\n"); 417 } 418 419 if (waiters != 0) { 420 buf.append(waiters).append(" waiting:\n"); 421 for (Iterator it = waitingOwners.iterator(); it.hasNext();) { 422 LockOwner owner = (LockOwner) it.next(); 423 buf.append("- ").append(owner.toString()).append("\n"); 424 } 425 } 426 427 return buf.toString(); 428 } 429 430 protected synchronized LockOwner getMaxLevelOwner() { 431 return getMaxLevelOwner(null, -1, false); 432 } 433 434 protected synchronized LockOwner getMaxLevelOwner(LockOwner reentrantOwner, boolean preferred) { 435 return getMaxLevelOwner(reentrantOwner, -1, preferred); 436 } 437 438 protected synchronized LockOwner getMaxLevelOwner(int supportLockLevel, boolean preferred) { 439 return getMaxLevelOwner(null, supportLockLevel, preferred); 440 } 441 442 protected synchronized LockOwner getMaxLevelOwner(LockOwner reentrantOwner, 443 int supportLockLevel, boolean preferred) { 444 LockOwner maxOwner = null; 445 for (Iterator it = owners.values().iterator(); it.hasNext();) { 446 LockOwner owner = (LockOwner) it.next(); 447 if (owner.lockLevel != supportLockLevel && !owner.equals(reentrantOwner) 448 && (maxOwner == null || maxOwner.lockLevel < owner.lockLevel) 449 && !(preferred && owner.intention)) { 452 maxOwner = owner; 453 } 454 } 455 return maxOwner; 456 } 457 458 protected synchronized void setLockLevel(Object ownerId, LockOwner lock, int targetLockLevel, 459 int compatibility, boolean intention) { 460 if (lock != null) { 462 if (logger.isFinestEnabled()) { 463 logger.logFinest( 464 ownerId.toString() 465 + " upgrading lock for " 466 + resourceId.toString() 467 + " to level " 468 + targetLockLevel 469 + " at " 470 + System.currentTimeMillis()); 471 } 472 } else { 473 if (logger.isFinestEnabled()) { 474 logger.logFinest( 475 ownerId.toString() 476 + " getting new lock for " 477 + resourceId.toString() 478 + " at level " 479 + targetLockLevel 480 + " at " 481 + System.currentTimeMillis()); 482 } 483 } 484 owners.put(ownerId, new LockOwner(ownerId, targetLockLevel, compatibility, intention)); 485 } 486 487 protected boolean tryLock(Object ownerId, int targetLockLevel, int compatibility, 488 boolean preferred) { 489 return tryLock(ownerId, targetLockLevel, compatibility, preferred, false); 490 } 491 492 protected synchronized boolean tryLock(Object ownerId, int targetLockLevel, int compatibility, 493 boolean preferred, boolean tryOnly) { 494 495 LockOwner myLock = (LockOwner) owners.get(ownerId); 496 497 LockOwner highestOwner; 499 if (compatibility == COMPATIBILITY_REENTRANT) { 500 if (myLock != null && targetLockLevel <= myLock.lockLevel) { 501 return true; 503 } else { 504 highestOwner = getMaxLevelOwner(myLock, preferred); 506 } 507 } else if (compatibility == COMPATIBILITY_SUPPORT) { 508 highestOwner = getMaxLevelOwner(targetLockLevel, preferred); 511 512 } else if (compatibility == COMPATIBILITY_REENTRANT_AND_SUPPORT) { 513 if (myLock != null && targetLockLevel <= myLock.lockLevel) { 514 return true; 516 } else { 517 highestOwner = getMaxLevelOwner(myLock, targetLockLevel, preferred); 519 } 520 } else { 521 highestOwner = getMaxLevelOwner(); 522 } 523 524 int i; 525 int currentLockLevel; 527 if (highestOwner != null) { 528 currentLockLevel = highestOwner.lockLevel; 529 } else { 530 currentLockLevel = getLevelMinLock(); 531 } 532 533 if (isCompatible(targetLockLevel, currentLockLevel)) { 535 if (!tryOnly) { 536 setLockLevel(ownerId, myLock, targetLockLevel, compatibility, false); 538 } 539 return true; 540 } else { 541 return false; 542 } 543 } 544 545 protected boolean isCompatible(int targetLockLevel, int currentLockLevel) { 546 return (targetLockLevel <= getLevelMaxLock() - currentLockLevel); 547 } 548 549 protected Set getConflictingOwners(Object ownerId, int targetLockLevel, int compatibility) { 550 551 LockOwner myLock = (LockOwner) owners.get(ownerId); 552 if (myLock != null && targetLockLevel <= myLock.lockLevel) { 553 return null; 555 } 556 557 LockOwner testLock = new LockOwner(ownerId, targetLockLevel, compatibility, false); 558 List ownersCopy; 559 synchronized (owners) { 560 ownersCopy = new ArrayList (owners.values()); 561 } 562 return getConflictingOwners(testLock, ownersCopy); 563 564 } 565 566 protected Collection getConflictingWaiters(Object ownerId) { 567 LockOwner owner = (LockOwner) owners.get(ownerId); 568 if (owner != null) { 569 List waiterCopy; 570 synchronized (waitingOwners) { 571 waiterCopy = new ArrayList (waitingOwners); 572 } 573 Collection conflicts = getConflictingOwners(owner, waiterCopy); 574 return conflicts; 575 } 576 return null; 577 } 578 579 protected Set getConflictingOwners(LockOwner myOwner, Collection ownersToTest) { 580 581 if (myOwner == null) return null; 582 583 Set conflicts = new HashSet (); 584 585 for (Iterator it = ownersToTest.iterator(); it.hasNext();) { 587 LockOwner owner = (LockOwner) it.next(); 588 589 if ((myOwner.compatibility == COMPATIBILITY_REENTRANT || myOwner.compatibility == COMPATIBILITY_REENTRANT_AND_SUPPORT) 591 && owner.ownerId.equals(myOwner.ownerId)) 592 continue; 593 594 int onwerLockLevel = owner.lockLevel; 596 597 if (myOwner.compatibility == COMPATIBILITY_SUPPORT 598 || myOwner.compatibility == COMPATIBILITY_REENTRANT_AND_SUPPORT 599 && myOwner.lockLevel == onwerLockLevel) 600 continue; 601 602 if (!isCompatible(myOwner.lockLevel, onwerLockLevel)) { 603 conflicts.add(owner.ownerId); 604 } 605 } 606 return (conflicts.isEmpty() ? null : conflicts); 607 } 608 609 protected static class LockOwner { 610 public final Object ownerId; 611 public final int lockLevel; 612 public final boolean intention; 613 public final int compatibility; 614 615 public LockOwner(Object ownerId, int lockLevel, int compatibility, boolean intention) { 616 this.ownerId = ownerId; 617 this.lockLevel = lockLevel; 618 this.intention = intention; 619 this.compatibility = compatibility; 620 } 621 622 public String toString() { 623 StringBuffer buf = new StringBuffer (); 624 buf.append(ownerId.toString()).append(": level ").append(lockLevel).append(", complevel ") 625 .append(compatibility).append(intention ? ", intention/preferred" : ""); 626 return buf.toString(); 627 } 628 629 public boolean equals(Object o) { 630 if (o instanceof LockOwner) { 631 return ((LockOwner)o).ownerId.equals(ownerId); 632 } 633 return false; 634 } 635 636 public int hashCode() { 637 return ownerId.hashCode(); 638 } 639 } 640 641 } 642 | Popular Tags |