1 package org.jboss.cache; 2 3 import org.apache.commons.logging.Log; 4 import org.apache.commons.logging.LogFactory; 5 import org.jboss.cache.buddyreplication.BuddyManager; 6 import org.jboss.cache.config.ConfigurationException; 7 import org.jboss.cache.config.EvictionConfig; 8 import org.jboss.cache.config.EvictionRegionConfig; 9 import org.jboss.cache.eviction.EvictionTimerTask; 10 import org.jboss.cache.eviction.RegionNameConflictException; 11 import org.jboss.cache.lock.NodeLock; 12 import org.jboss.cache.marshall.VersionAwareMarshaller; 13 import org.jgroups.Address; 14 15 import java.util.ArrayList ; 16 import java.util.Collections ; 17 import java.util.HashSet ; 18 import java.util.Iterator ; 19 import java.util.List ; 20 import java.util.Map ; 21 import java.util.Set ; 22 import java.util.Vector ; 23 import java.util.concurrent.ConcurrentHashMap ; 24 25 31 public class RegionManager 32 { 33 38 public static final Fqn DEFAULT_REGION = Fqn.fromString("/_default_"); 39 42 Map <Fqn, Region> regionsRegistry = new ConcurrentHashMap <Fqn, Region>(); 43 boolean defaultInactive; 44 private Log log = LogFactory.getLog(RegionManager.class); 45 CacheImpl cache; 46 private boolean usingEvictions; 47 private EvictionConfig evictionConfig; 48 private EvictionTimerTask evictionTimerTask = new EvictionTimerTask(); 49 50 protected final Set activationChangeNodes = Collections.synchronizedSet(new HashSet ()); 51 52 53 public RegionManager() 54 { 55 } 56 57 public boolean isUsingEvictions() 58 { 59 return usingEvictions; 60 } 61 62 public RegionManager(CacheImpl cache) 63 { 64 this.cache = cache; 65 } 66 67 public boolean isDefaultInactive() 68 { 69 return defaultInactive; 70 } 71 72 public void setDefaultInactive(boolean defaultInactive) 73 { 74 this.defaultInactive = defaultInactive; 75 } 76 77 78 87 public void setContextClassLoaderAsCurrent(Fqn fqn) 88 { 89 if (fqn.isChildOf(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN)) 90 { 91 if (fqn.size() <= 2) 92 { 93 fqn = Fqn.ROOT; 94 } 95 else 96 { 97 fqn = fqn.getFqnChild(2, fqn.size()); 98 } 99 } 100 Region region = getRegion(fqn, false); 101 ClassLoader regionCL = (region == null) ? null : region.getClassLoader(); 102 if (regionCL != null) 103 { 104 Thread.currentThread().setContextClassLoader(regionCL); 105 } 106 107 } 108 109 115 public void setContextClassLoaderAsCurrent(String fqn) 116 { 117 setContextClassLoaderAsCurrent(Fqn.fromString(fqn)); 118 } 119 120 public Region getRegion(Fqn fqn, boolean createIfAbsent) 121 { 122 return getRegion(fqn, Region.Type.ANY, createIfAbsent); 123 } 124 125 public Region getRegion(Fqn fqn, Region.Type type, boolean createIfAbsent) 126 { 127 Fqn fqnToUse = fqn; 128 if (DEFAULT_REGION.equals(fqnToUse)) fqnToUse = Fqn.ROOT; 129 if (regionsRegistry.containsKey(fqnToUse)) 131 { 132 Region r = regionsRegistry.get(fqnToUse); 133 if (type == Region.Type.ANY 134 || (type == Region.Type.MARSHALLING && r.getClassLoader() != null) 135 || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null)) 136 { 137 return r; 138 } 139 } 140 141 if (createIfAbsent) 143 { 144 Region r = new RegionImpl(fqnToUse, this); 145 regionsRegistry.put(fqnToUse, r); 146 return r; 147 } 148 else 149 { 150 if (isUsingEvictions() && !regionsRegistry.containsKey(Fqn.ROOT)) 153 { 154 throw new RuntimeException ("No default eviction region defined!"); 155 } 156 } 157 158 Region nextBestThing = null; 160 Fqn nextFqn = fqnToUse; 161 162 while (nextBestThing == null) 163 { 164 nextFqn = nextFqn.getParent(); 165 if (regionsRegistry.containsKey(nextFqn)) 166 { 167 Region r = regionsRegistry.get(nextFqn); 168 169 if (type == Region.Type.ANY 170 || (type == Region.Type.MARSHALLING && r.getClassLoader() != null) 171 || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null)) 172 { 173 nextBestThing = r; 174 } 175 } 176 if (nextFqn.isRoot()) break; 177 } 178 179 return nextBestThing; 180 } 181 182 189 public Region getRegion(String fqn, boolean createIfAbsent) 190 { 191 return getRegion(Fqn.fromString(fqn), createIfAbsent); 192 } 193 194 public void registerClassLoader(Fqn fqn, ClassLoader cl) 195 { 196 Region existing = getRegion(fqn, false); 197 if (existing == null) 198 { 199 existing = getRegion(fqn, true); 200 } 201 existing.registerContextClassLoader(cl); 202 } 203 204 210 public void registerClassLoader(String fqn, ClassLoader cl) 211 { 212 registerClassLoader(Fqn.fromString(fqn), cl); 213 } 214 215 221 public void unregisterClassLoader(Fqn fqn) 222 { 223 Region region = getRegion(fqn, false); 224 if (region != null) region.unregisterContextClassLoader(); 225 } 226 227 228 public void unregisterClassLoader(String fqn) 229 { 230 unregisterClassLoader(Fqn.fromString(fqn)); 231 } 232 233 public void removeRegion(Fqn fqn) 234 { 235 Region r = regionsRegistry.remove(fqn); 236 if (isUsingEvictions() && r.getEvictionPolicy() != null) 237 { 238 evictionTimerTask.removeRegionToProcess(r); 239 } 240 } 241 242 245 protected EvictionTimerTask getEvictionTimerTask() 246 { 247 return evictionTimerTask; 248 } 249 250 251 257 public void removeRegion(String fqn) 258 { 259 removeRegion(Fqn.fromString(fqn)); 260 } 261 262 268 public void activate(Fqn fqn) 269 { 270 try 271 { 272 if (log.isTraceEnabled()) log.trace("Activating region " + fqn); 273 Region r = getRegion(fqn, false); 274 if (r != null) 275 { 276 if (!defaultInactive && r.getClassLoader() == null) 277 { 278 281 removeRegion(fqn); 284 } 285 else 286 { 287 r.setActive(true); 289 if (cache.getConfiguration().isFetchInMemoryState()) 291 { 292 activateRegion(r.getFqn().toString()); 293 } 294 } 295 } 296 else if (defaultInactive) 297 { 298 r = getRegion(fqn, true); 300 r.setActive(true); 301 if (cache.getConfiguration().isFetchInMemoryState()) 303 { 304 activateRegion(r.getFqn().toString()); 305 } 306 } 307 } 308 catch (Exception e) 309 { 310 throw new RuntimeException (e); 311 } 312 } 313 314 330 public void activateRegion(String subtreeFqn) throws CacheException 331 { 332 Fqn fqn = Fqn.fromString(subtreeFqn); 333 334 Node subtreeRoot = cache.findNode(fqn); 336 337 344 345 if (isActivatingDeactivating(fqn)) 346 { 347 throw new CacheException("Region " + subtreeRoot.getFqn() + " is already being activated/deactivated"); 348 } 349 350 if (log.isDebugEnabled()) 351 { 352 log.debug("activating " + fqn); 353 } 354 355 try 356 { 357 358 activationChangeNodes.add(fqn); 361 362 Region region = getRegion(fqn, true); 363 364 ClassLoader cl = region.getClassLoader(); 366 367 BuddyManager buddyManager = cache.getBuddyManager(); 368 if (buddyManager == null) 370 { 371 if (subtreeRoot == null) 374 { 375 subtreeRoot = cache.createSubtreeRootNode(fqn); 377 } 378 379 Address[] groupMembers = null; 380 Vector <Address> members = cache.getMembers(); 381 synchronized (members) 382 { 383 groupMembers = members.toArray(new Address[members.size()]); 384 } 385 if (groupMembers.length < 2) 386 { 387 if (log.isDebugEnabled()) 388 { 389 log.debug("No nodes able to give state"); 390 } 391 } 392 else 393 { 394 cache.fetchPartialState(groupMembers, subtreeRoot.getFqn()); 395 } 396 } 397 else 398 { 399 List buddies = buddyManager.getBuddyAddresses(); 402 for (Iterator it = buddies.iterator(); it.hasNext();) 403 { 404 Address buddy = (Address) it.next(); 405 Object sources[] = new Object []{buddy}; 406 Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, BuddyManager.getGroupNameFromAddress(buddy)); 407 Fqn buddyRoot = new Fqn(base, fqn); 408 subtreeRoot = cache.findNode(buddyRoot); 409 if (subtreeRoot == null) 410 { 411 subtreeRoot = cache.createSubtreeRootNode(buddyRoot); 413 } 414 cache.fetchPartialState(sources, subtreeRoot.getFqn()); 415 } 416 } 417 } 418 catch (Throwable t) 419 { 420 log.error("failed to activate " + subtreeFqn, t); 421 422 try 424 { 425 inactivateRegion(subtreeFqn); 426 } 427 catch (Exception e) 428 { 429 log.error("failed inactivating " + subtreeFqn, e); 430 } 432 433 if (t instanceof RegionNotEmptyException) 435 { 436 throw (RegionNotEmptyException) t; 437 } 438 else if (t instanceof CacheException) 439 { 440 throw (CacheException) t; 441 } 442 else 443 { 444 throw new CacheException(t.getClass().getName() + " " + 445 t.getLocalizedMessage(), t); 446 } 447 } 448 finally 449 { 450 activationChangeNodes.remove(fqn); 451 } 452 } 453 454 468 public void inactivateRegion(String subtreeFqn) throws CacheException 469 { 470 Fqn fqn = Fqn.fromString(subtreeFqn); 471 if (isActivatingDeactivating(fqn)) 472 { 473 throw new CacheException("Region " + subtreeFqn + " is already being activated/deactivated"); 474 } 475 476 NodeSPI parent = null; 477 NodeSPI subtreeRoot = null; 478 boolean parentLocked = false; 479 boolean subtreeLocked = false; 480 NodeLock parentLock = null; 481 NodeLock subtreeLock = null; 482 483 try 484 { 485 activationChangeNodes.add(fqn); 487 488 VersionAwareMarshaller marshaller = cache.getMarshaller(); 489 boolean inactive = marshaller.isInactive(subtreeFqn); 490 if (!inactive) 491 { 492 deactivate(subtreeFqn); 493 } 494 495 BuddyManager buddyManager = cache.getBuddyManager(); 497 ArrayList list = new ArrayList (); 498 list.add(fqn); 499 500 if (buddyManager != null) 501 { 502 Set buddies = cache.getChildrenNames(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN); 503 if (buddies != null) 504 { 505 for (Iterator it = buddies.iterator(); it.hasNext();) 506 { 507 Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, it.next()); 508 list.add(new Fqn(base, fqn)); 509 } 510 } 511 } 512 513 long stateFetchTimeout = cache.getConfiguration().getLockAcquisitionTimeout() + 5000; 514 for (Iterator it = list.iterator(); it.hasNext();) 516 { 517 Fqn subtree = (Fqn) it.next(); 518 subtreeRoot = cache.findNode(subtree); 519 if (subtreeRoot != null) 520 { 521 Object owner = cache.getOwnerForLock(); 523 subtreeLock = subtreeRoot.getLock(); 524 subtreeLock.acquireAll(owner, stateFetchTimeout, NodeLock.LockType.WRITE); 525 subtreeLocked = true; 526 527 parent = subtreeRoot.getParent(); 529 if (parent != null) 530 { 531 parentLock = parent.getLock(); 532 parentLock.acquire(owner, stateFetchTimeout, NodeLock.LockType.WRITE); 533 parentLocked = true; 534 } 535 536 cache._evictSubtree(subtree); 538 539 if (parent != null) 541 { 542 log.debug("forcing release of locks in parent"); 543 parentLock.releaseAll(); 544 } 545 546 parentLocked = false; 547 548 log.debug("forcing release of all locks in subtree"); 549 subtreeLock.releaseAll(); 550 subtreeLocked = false; 551 } 552 } 553 } 554 catch (InterruptedException ie) 555 { 556 throw new CacheException("Interrupted while acquiring lock", ie); 557 } 558 finally 559 { 560 565 if (parentLocked) 567 { 568 log.debug("forcing release of locks in parent"); 569 try 570 { 571 parentLock.releaseAll(); 572 } 573 catch (Throwable t) 574 { 575 log.error("failed releasing locks", t); 576 } 577 } 578 if (subtreeLocked) 579 { 580 log.debug("forcing release of all locks in subtree"); 581 try 582 { 583 subtreeLock.releaseAll(); 584 } 585 catch (Throwable t) 586 { 587 log.error("failed releasing locks", t); 588 } 589 } 590 591 activationChangeNodes.remove(fqn); 592 } 593 } 594 595 public boolean isActivatingDeactivating(Fqn fqn) 596 { 597 return activationChangeNodes.contains(fqn); 598 } 599 600 606 public void activate(String fqn) 607 { 608 activate(Fqn.fromString(fqn)); 609 } 610 611 612 public boolean hasRegion(Fqn fqn) 613 { 614 return regionsRegistry.containsKey(fqn); 615 } 616 617 623 public boolean hasRegion(String fqn) 624 { 625 return hasRegion(Fqn.fromString(fqn)); 626 } 627 628 634 public void deactivate(Fqn fqn) 635 { 636 try 637 { 638 Region region = getRegion(fqn, false); 639 640 if (region != null) 641 { 642 if (defaultInactive && region.getClassLoader() == null) 643 { 644 647 removeRegion(fqn); 650 } 651 else 652 { 653 region.setActive(false); 655 if (cache.getConfiguration().isFetchInMemoryState()) 658 { 659 inactivateRegion(fqn.toString()); 660 } 661 } 662 } 663 else if (!defaultInactive) 664 { 665 region = getRegion(fqn, true); 666 region.setActive(false); 667 if (cache.getConfiguration().isFetchInMemoryState()) 670 { 671 inactivateRegion(fqn.toString()); 672 } 673 } 674 } 675 catch (Exception e) 676 { 677 throw new RuntimeException (e); 678 } 679 } 680 681 687 public void deactivate(String fqn) 688 { 689 deactivate(Fqn.fromString(fqn)); 690 } 691 692 695 public void reset() 696 { 697 regionsRegistry.clear(); 698 } 699 700 705 public List <Region> getAllMarshallingRegions() 706 { 707 List <Region> regions = new ArrayList <Region>(); 708 709 for (Region r : regionsRegistry.values()) if (r.isActive() && r.getClassLoader() != null) regions.add(r); 710 711 Collections.sort(regions); 712 713 return regions; 714 } 715 716 721 public List <Region> getAllEvictionRegions() 722 { 723 List <Region> regions = new ArrayList <Region>(); 724 725 for (Region r : regionsRegistry.values()) 726 { 727 if (r.getEvictionPolicy() != null && evictionTimerTask.isRegionRegisteredForProcessing(r)) regions.add(r); 728 } 729 730 Collections.sort(regions); 731 732 return regions; 733 } 734 735 740 public List <Region> getAllRegions() 741 { 742 List <Region> regions = new ArrayList <Region>(regionsRegistry.values()); 743 744 Collections.sort(regions); 745 746 return regions; 747 } 748 749 public void setUsingEvictions(boolean usingEvictions) 750 { 751 this.usingEvictions = usingEvictions; 752 } 753 754 public void setEvictionConfig(EvictionConfig evictionConfig) 755 { 756 this.evictionConfig = evictionConfig; 757 boolean setDefault = false; 758 for (EvictionRegionConfig erc : evictionConfig.getEvictionRegionConfigs()) 760 { 761 Fqn fqn = erc.getRegionFqn(); 762 if (log.isTraceEnabled()) log.trace("Creating eviction region " + fqn); 763 764 if (fqn.equals(DEFAULT_REGION)) 765 { 766 if (setDefault) 767 { 768 throw new ConfigurationException("A default region for evictions has already been set for this cache"); 769 } 770 if (log.isTraceEnabled()) log.trace("Applying settings for " + DEFAULT_REGION + " to Fqn.ROOT"); 771 fqn = Fqn.ROOT; 772 setDefault = true; 773 } 774 Region r = getRegion(fqn, true); 775 r.setEvictionPolicy(erc.getEvictionPolicyConfig()); 776 } 777 } 778 779 public void startEvictionThread() 780 { 781 evictionTimerTask.init(evictionConfig.getWakeupIntervalSeconds(), cache.getNotifier()); 782 } 783 784 787 public String dumpRegions() 788 { 789 StringBuilder sb = new StringBuilder (); 790 for (Region r : regionsRegistry.values()) 791 { 792 sb.append("\tRegion " + r); 793 sb.append("\n"); 794 } 795 return sb.toString(); 796 } 797 798 public String toString() 799 { 800 return "RegionManager " + dumpRegions(); 801 } 802 } 803 | Popular Tags |