1 package org.jboss.cache.interceptors; 2 3 import org.jboss.cache.CacheException; 4 import org.jboss.cache.CacheSPI; 5 import org.jboss.cache.Fqn; 6 import org.jboss.cache.GlobalTransaction; 7 import org.jboss.cache.InvocationContext; 8 import org.jboss.cache.NodeSPI; 9 import org.jboss.cache.TransactionEntry; 10 import org.jboss.cache.TransactionTable; 11 import org.jboss.cache.loader.AsyncCacheLoader; 12 import org.jboss.cache.loader.CacheLoader; 13 import org.jboss.cache.loader.ChainingCacheLoader; 14 import org.jboss.cache.lock.NodeLock; 15 import org.jboss.cache.marshall.MethodCall; 16 import org.jboss.cache.marshall.MethodCallFactory; 17 import org.jboss.cache.marshall.MethodDeclarations; 18 19 import java.util.Collections ; 20 import java.util.HashMap ; 21 import java.util.Iterator ; 22 import java.util.List ; 23 import java.util.ListIterator ; 24 import java.util.Map ; 25 import java.util.Set ; 26 27 33 public class CacheLoaderInterceptor extends BaseCacheLoaderInterceptor implements CacheLoaderInterceptorMBean 34 { 35 private boolean isCustomCacheLoader; 36 private long m_cacheLoads = 0; 37 private long m_cacheMisses = 0; 38 private TransactionTable txTable = null; 39 protected boolean isActivation = false; 40 41 46 protected boolean useCacheStore = true; 47 48 public void setCache(CacheSPI cache) 49 { 50 super.setCache(cache); 51 isCustomCacheLoader = isCustomCacheLoaderConfigured(loader); 52 txTable = cache.getTransactionTable(); 53 } 54 55 private boolean isCustomCacheLoaderConfigured(CacheLoader cl) 56 { 57 if (cl instanceof ChainingCacheLoader) 58 { 59 ChainingCacheLoader ccl = (ChainingCacheLoader) cl; 61 Iterator it = ccl.getCacheLoaders().iterator(); 62 boolean isCustom = false; 63 while (it.hasNext()) 64 { 65 CacheLoader nextCacheLoader = (CacheLoader) it.next(); 66 isCustom = isCustom || isCustomCacheLoaderConfigured(nextCacheLoader); 67 } 68 return isCustom; 69 } 70 else if (cl instanceof AsyncCacheLoader) 71 { 72 CacheLoader underlying = ((AsyncCacheLoader) cl).getCacheLoader(); 74 return isCustomCacheLoaderConfigured(underlying); 75 } 76 else 77 { 78 Package pkg = cl.getClass().getPackage(); return pkg == null || !pkg.getName().startsWith("org.jboss.cache"); 81 } 82 } 83 84 91 public Object invoke(MethodCall m) throws Throwable 92 { 93 Fqn fqn = null, fqn2 = null; 95 Object [] args = m.getArgs(); 96 boolean acquireLock = false; 98 boolean initNode = false; Object key = null; 100 InvocationContext ctx = cache.getInvocationContext(); 101 TransactionEntry entry = null; 102 GlobalTransaction gtx; 103 boolean recursive = false; 105 106 if ((gtx = ctx.getGlobalTransaction()) != null) 107 { 108 entry = txTable.get(gtx); 109 } 110 111 if (log.isTraceEnabled()) 112 { 113 log.trace("invoke " + m); 114 } 115 switch (m.getMethodId()) 116 { 117 case MethodDeclarations.putDataEraseMethodLocal_id: 118 case MethodDeclarations.putDataMethodLocal_id: 119 fqn = (Fqn) args[1]; 120 initNode = true; 121 break; 122 case MethodDeclarations.putKeyValMethodLocal_id: 123 fqn = (Fqn) args[1]; 124 if (useCacheStore) 125 { 126 initNode = true; 127 } 128 else 129 { 130 acquireLock = true; 131 } 132 break; 133 case MethodDeclarations.moveMethodLocal_id: 134 fqn = (Fqn) args[0]; 135 fqn2 = (Fqn) args[1]; 136 acquireLock = true; 137 recursive = true; 139 break; 140 case MethodDeclarations.addChildMethodLocal_id: 141 fqn = (Fqn) args[1]; 142 break; 143 case MethodDeclarations.getKeyValueMethodLocal_id: 144 fqn = (Fqn) args[0]; 145 key = args[1]; 146 acquireLock = true; 147 break; 148 case MethodDeclarations.getNodeMethodLocal_id: 149 case MethodDeclarations.getKeysMethodLocal_id: 150 case MethodDeclarations.getChildrenNamesMethodLocal_id: 151 case MethodDeclarations.releaseAllLocksMethodLocal_id: 152 case MethodDeclarations.printMethodLocal_id: 153 fqn = (Fqn) args[0]; 154 acquireLock = true; 155 break; 156 case MethodDeclarations.rollbackMethod_id: 157 cleanupNodesCreated(entry); 159 break; 160 default: 161 if (!useCacheStore) 162 { 163 if (m.getMethodId() == MethodDeclarations.removeKeyMethodLocal_id) 164 { 165 fqn = (Fqn) args[1]; 166 } 167 else if (m.getMethodId() == MethodDeclarations.removeDataMethodLocal_id) 168 { 169 fqn = (Fqn) args[1]; 170 initNode = true; 171 } 172 } 173 break; 174 } 175 176 178 179 if (fqn != null) 180 { 181 if (fqn2 != null) 182 { 183 loadIfNeeded(fqn2, key, initNode, acquireLock, m, entry, false, m.getMethodId() == MethodDeclarations.moveMethodLocal_id); 184 } 185 loadIfNeeded(fqn, key, initNode, acquireLock, m, entry, recursive, m.getMethodId() == MethodDeclarations.moveMethodLocal_id); 186 } 187 188 return super.invoke(m); 189 } 190 191 192 private void loadIfNeeded(Fqn fqn, Object key, boolean initNode, boolean acquireLock, MethodCall m, TransactionEntry entry, boolean recursive, boolean isMove) throws Throwable 193 { 194 obtainLoaderLock(fqn); 195 196 try 197 { 198 199 NodeSPI n = cache.peek(fqn); 200 201 boolean mustLoad = mustLoad(n, key); 202 if (log.isTraceEnabled()) 203 { 204 log.trace("load element " + fqn + " mustLoad=" + mustLoad); 205 } 206 if (mustLoad) 207 { 208 if (initNode) 209 { 210 n = createTempNode(fqn, entry); 211 } 212 else if (!wasRemovedInTx(fqn)) 213 { 214 n = loadNode(fqn, n, entry); 215 } 216 if (acquireLock) 229 { 230 lock(fqn, NodeLock.LockType.WRITE, false); } 232 } 233 234 if (recursive || m.getMethodId() == MethodDeclarations.getChildrenNamesMethodLocal_id) 236 { 237 loadChildren(fqn, n, recursive, isMove); 238 } 239 240 } 241 finally 242 { 243 releaseLoaderLock(fqn); 244 } 245 246 } 247 248 253 private void loadChildren(Fqn fqn, NodeSPI node, boolean recursive, boolean isMove) throws Throwable 254 { 255 256 if (node != null && node.getChildrenLoaded()) 257 { 258 return; 259 } 260 Set children_names = loader.getChildrenNames(fqn); 261 262 if (log.isTraceEnabled()) 263 { 264 log.trace("load children " + fqn + " children=" + children_names); 265 } 266 267 if (children_names == null) 269 { 270 if (node != null) 271 { 272 if (useCacheStore) 273 { 274 node.removeChildrenDirect(); } 276 node.setChildrenLoaded(true); 277 } 278 return; 279 } 280 281 if (node == null) 283 { 284 node = createNodes(fqn, null); } 286 287 for (Object name : children_names) 289 { 290 Fqn child_fqn = new Fqn(name); 292 NodeSPI child = node.addChildDirect(child_fqn); 294 if ((isMove || isActivation) && recursive) 295 { 296 child.putDirect(loader.get(child.getFqn())); 298 child.setDataLoaded(true); 299 } 300 else 301 { 302 child.setDataLoaded(false); 303 } 304 if (recursive) 305 { 306 loadChildren(child.getFqn(), child, true, isMove); 307 } 308 } 309 lock(fqn, recursive ? NodeLock.LockType.WRITE : NodeLock.LockType.READ, true); node.setChildrenLoaded(true); 311 } 312 313 private boolean mustLoad(NodeSPI n, Object key) 314 { 315 if (n == null) 316 { 317 log.trace("mustLoad, node null"); 318 return true; 319 } 320 if (!n.getDataLoaded()) 321 { 322 log.trace("must Load, uninitialized"); 323 return true; 324 } 325 331 return false; 332 } 333 334 public long getCacheLoaderLoads() 335 { 336 return m_cacheLoads; 337 } 338 339 public long getCacheLoaderMisses() 340 { 341 return m_cacheMisses; 342 } 343 344 public void resetStatistics() 345 { 346 m_cacheLoads = 0; 347 m_cacheMisses = 0; 348 } 349 350 public Map <String , Object > dumpStatistics() 351 { 352 Map <String , Object > retval = new HashMap <String , Object >(); 353 retval.put("CacheLoaderLoads", m_cacheLoads); 354 retval.put("CacheLoaderMisses", m_cacheMisses); 355 return retval; 356 } 357 358 protected void lock(Fqn fqn, NodeLock.LockType lock_type, boolean recursive) throws Throwable 359 { 360 361 if (configuration.isNodeLockingOptimistic()) return; 362 363 MethodCall m = MethodCallFactory.create(MethodDeclarations.lockMethodLocal, 364 fqn, lock_type, recursive); 365 super.invoke(m); 366 } 367 368 373 protected NodeSPI getNode(Fqn fqn) 374 { 375 return cache.peek(fqn); 376 } 391 392 397 private boolean wasRemovedInTx(Fqn fqn) 398 { 399 GlobalTransaction t = cache.getInvocationContext().getGlobalTransaction(); 400 if (t == null) 401 { 402 return false; 403 } 404 TransactionEntry entry = txTable.get(t); 405 Iterator i = entry.getCacheLoaderModifications().iterator(); 406 while (i.hasNext()) 407 { 408 MethodCall m = (MethodCall) i.next(); 409 if (m.getMethodId() == MethodDeclarations.removeNodeMethodLocal_id 410 && fqn.isChildOrEquals((Fqn) m.getArgs()[1])) 411 { 412 return true; 413 } 414 } 415 return false; 416 } 417 418 423 private NodeSPI loadNode(Fqn fqn, NodeSPI n, TransactionEntry entry) throws Exception 424 { 425 if (log.isTraceEnabled()) log.trace("loadNode " + fqn); 426 Map nodeData = loadData(fqn); 427 if (nodeData != null) 428 { 429 log.trace("Node data is not null, loading"); 430 n = createNodes(fqn, entry); 431 n.putDirect(nodeData); 433 } 434 435 if (n != null && !n.getDataLoaded()) 436 { 437 log.trace("Setting dataLoaded to true"); 438 n.setDataLoaded(true); 439 } 440 return n; 441 } 442 443 446 private NodeSPI createTempNode(Fqn fqn, TransactionEntry entry) throws Exception 447 { 448 NodeSPI n = createNodes(fqn, entry); 449 n.setDataLoaded(false); 450 if (log.isTraceEnabled()) 451 { 452 log.trace("createTempNode n " + n); 453 } 454 return n; 455 } 456 457 458 private NodeSPI createNodes(Fqn fqn, TransactionEntry entry) throws Exception 459 { 460 Fqn tmp_fqn = Fqn.ROOT; 461 462 int size = fqn.size(); 463 464 NodeSPI n = cache.getRoot(); 466 for (int i = 0; i < size; i++) 467 { 468 Object child_name = fqn.get(i); 469 tmp_fqn = new Fqn(tmp_fqn, child_name); 470 471 NodeSPI child_node = findChild(n, child_name); 472 boolean last = (i == size - 1); 473 474 if (child_node == null) 475 { 476 if (last) 477 { 478 child_node = n.addChildDirect(new Fqn(child_name)); 479 child_node.setDataLoaded(true); 480 } 481 else 482 { 483 child_node = n.addChildDirect(new Fqn(child_name)); 484 child_node.setDataLoaded(false); 485 } 486 487 if (entry != null) 488 { 489 entry.loadUninitialisedNode(tmp_fqn); 490 } 491 } 492 493 n = child_node; 494 } 495 496 return n; 497 } 498 499 private NodeSPI findChild(NodeSPI child, Object child_name) 500 { 501 return (NodeSPI) child.getChildrenMapDirect().get(child_name); 502 } 503 504 private void cleanupNodesCreated(TransactionEntry entry) 505 { 506 boolean traceEnabled = log.isTraceEnabled(); 507 log.trace("Removing temporarily created nodes from treecache"); 508 509 List list = entry.getDummyNodesCreatedByCacheLoader(); 511 if (list != null && list.size() > 0) 512 { 513 ListIterator i = list.listIterator(list.size()); 514 while (i.hasPrevious()) 515 { 516 Fqn fqn = (Fqn) i.previous(); 517 try 518 { 519 cache.evict(fqn, false); 520 } 521 catch (CacheException e) 522 { 523 if (traceEnabled) log.trace("Unable to evict node " + fqn, e); 524 } 525 } 526 } 527 } 528 529 530 private Map loadData(Fqn fqn) throws Exception 531 { 532 533 Map nodeData = loader.get(fqn); 534 boolean nodeExists = (nodeData != null); 535 if (log.isTraceEnabled()) log.trace("nodeExists " + nodeExists); 536 537 if (configuration.getExposeManagementStatistics() && getStatisticsEnabled()) 538 { 539 if (nodeExists) 540 { 541 m_cacheLoads++; 542 } 543 else 544 { 545 m_cacheMisses++; 546 } 547 } 548 549 556 if (nodeExists) 557 { 558 cache.getNotifier().notifyNodeLoaded(fqn, true, Collections.emptyMap(), true); 559 cache.getNotifier().notifyNodeLoaded(fqn, false, nodeData, true); 560 561 if (isActivation) 562 { 563 cache.getNotifier().notifyNodeActivated(fqn, true, true); 564 cache.getNotifier().notifyNodeActivated(fqn, false, true); 565 } 566 } 567 568 return nodeData; 569 } 570 571 private void warnCustom() 572 { 573 log.warn("CacheLoader.get(Fqn) returned a null; assuming the node nodes not exist."); 574 log.warn("The CacheLoader interface has changed since JBossCache 1.3.x"); 575 log.warn("Please see http://jira.jboss.com/jira/browse/JBCACHE-118"); 576 log.warn("CacheLoader.get() should return an empty Map if the node does exist but doesn't have any attributes."); 577 } 578 579 } | Popular Tags |