[jbosscache-commits] JBoss Cache SVN: r6215 - in core/trunk/src: main/java/org/jboss/cache/factories and 9 other directories.
jbosscache-commits at lists.jboss.org
jbosscache-commits at lists.jboss.org
Tue Jul 8 12:27:16 EDT 2008
Author: manik.surtani at jboss.com
Date: 2008-07-08 12:27:15 -0400 (Tue, 08 Jul 2008)
New Revision: 6215
Added:
core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java
Modified:
core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java
core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java
core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java
core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java
core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java
core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java
core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
core/trunk/src/test/java/org/jboss/cache/api/NodeReplicatedMoveTest.java
core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/CacheLoaderTest.java
core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java
core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/CacheLoaderTest.java
core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/PassivationTest.java
core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java
core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java
Log:
MVCC + CacheLoading and Passivation - preliminary work
Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -118,7 +118,7 @@
else
{
if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn + ")");
- NodeSPI parentNode = lookupForEviction(ctx, fqn.getParent());
+ NodeSPI parentNode = lookupInAllScopes(ctx, fqn.getParent());
if (parentNode != null)
{
@@ -136,6 +136,16 @@
}
}
+ private NodeSPI lookupInAllScopes(InvocationContext ctx, Fqn fqn)
+ {
+ NodeSPI nodeSPI = lookupForEviction(ctx, fqn);
+ if (nodeSPI == null)
+ {
+ nodeSPI = dataContainer.peek(fqn);
+ }
+ return nodeSPI;
+ }
+
protected NodeSPI lookupForEviction(InvocationContext ctx, Fqn fqn)
{
return ctx.lookUpNode(fqn);
Modified: core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -87,6 +87,18 @@
if (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
{
+ // if MVCC, then the CLI or AI must come before the MVCCLI.
+ if (configuration.isUsingCacheLoaders())
+ {
+ if (configuration.getCacheLoaderConfig().isPassivation())
+ {
+ interceptorChain.appendIntereceptor(createInterceptor(ActivationInterceptor.class));
+ }
+ else
+ {
+ interceptorChain.appendIntereceptor(createInterceptor(CacheLoaderInterceptor.class));
+ }
+ }
interceptorChain.appendIntereceptor(createInterceptor(MVCCLockingInterceptor.class));
}
else if (configuration.getNodeLockingScheme() == NodeLockingScheme.PESSIMISTIC)
@@ -98,12 +110,14 @@
{
if (configuration.getCacheLoaderConfig().isPassivation())
{
- interceptorChain.appendIntereceptor(createInterceptor(ActivationInterceptor.class));
+ if (configuration.getNodeLockingScheme() != NodeLockingScheme.MVCC)
+ interceptorChain.appendIntereceptor(createInterceptor(LegacyActivationInterceptor.class));
interceptorChain.appendIntereceptor(createInterceptor(PassivationInterceptor.class));
}
else
{
- interceptorChain.appendIntereceptor(createInterceptor(CacheLoaderInterceptor.class));
+ if (configuration.getNodeLockingScheme() != NodeLockingScheme.MVCC)
+ interceptorChain.appendIntereceptor(createInterceptor(LegacyCacheLoaderInterceptor.class));
interceptorChain.appendIntereceptor(createInterceptor(CacheStoreInterceptor.class));
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -4,7 +4,6 @@
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
import org.jboss.cache.NodeSPI;
-import org.jboss.cache.commands.WriteCommand;
import org.jboss.cache.commands.read.GetChildrenNamesCommand;
import org.jboss.cache.commands.read.GetDataMapCommand;
import org.jboss.cache.commands.read.GetKeyValueCommand;
@@ -27,11 +26,9 @@
import org.jboss.cache.invocation.InvocationContext;
import org.jboss.cache.loader.CacheLoader;
import org.jboss.cache.loader.CacheLoaderManager;
-import org.jboss.cache.lock.LockManager;
-import org.jboss.cache.lock.LockType;
-import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.mvcc.MVCCNodeHelper;
+import org.jboss.cache.mvcc.NullMarkerNode;
import org.jboss.cache.notifications.Notifier;
-import org.jboss.cache.transaction.TransactionContext;
import org.jboss.cache.transaction.TransactionTable;
import java.util.Collections;
@@ -52,7 +49,6 @@
private long cacheLoads = 0;
private long cacheMisses = 0;
private CacheLoaderManager clm;
- private LockManager lockManager;
protected TransactionTable txTable = null;
protected CacheLoader loader;
@@ -62,7 +58,9 @@
protected boolean isActivation = false;
protected boolean usingVersionedInvalidation = false;
+ protected MVCCNodeHelper helper;
+
/**
* True if CacheStoreInterceptor is in place.
* This allows us to skip loading keys for remove(Fqn, key) and put(Fqn, key).
@@ -72,15 +70,15 @@
@Inject
protected void injectDependencies(TransactionTable txTable, CacheLoaderManager clm, Configuration configuration,
- DataContainer dataContainer, LockManager lockManager, Notifier notifier)
+ DataContainer dataContainer, Notifier notifier, MVCCNodeHelper helper)
{
this.txTable = txTable;
this.clm = clm;
CacheMode mode = configuration.getCacheMode();
usingVersionedInvalidation = configuration.getNodeLockingScheme().isVersionedScheme() && mode.isInvalidation();
this.dataContainer = dataContainer;
- this.lockManager = lockManager;
this.notifier = notifier;
+ this.helper = helper;
}
@Start
@@ -94,7 +92,7 @@
{
if (command.getFqn() != null)
{
- loadIfNeeded(ctx, command.getFqn(), null, false, true, false, ctx.getTransactionContext(), false, false, false);
+ loadIfNeeded(ctx, command.getFqn(), null, false, true, false, false, false, false);
}
return invokeNextInterceptor(ctx, command);
}
@@ -104,7 +102,7 @@
{
if (command.getFqn() != null)
{
- loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, useCacheStore, !useCacheStore, ctx.getTransactionContext(), false, false, false);
+ loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, useCacheStore, !useCacheStore, false, false, false);
}
return invokeNextInterceptor(ctx, command);
}
@@ -122,9 +120,9 @@
{
if (command.getTo() != null)
{
- loadIfNeeded(ctx, command.getTo(), null, false, false, true, ctx.getTransactionContext(), false, true, false);
+ loadIfNeeded(ctx, command.getTo(), null, false, false, true, false, true, false);
}
- loadIfNeeded(ctx, command.getFqn(), null, false, false, true, ctx.getTransactionContext(), true, true, false);
+ loadIfNeeded(ctx, command.getFqn(), null, false, false, true, true, true, false);
}
return invokeNextInterceptor(ctx, command);
}
@@ -134,7 +132,7 @@
{
if (command.getFqn() != null)
{
- loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, true, ctx.getTransactionContext(), false, false, false);
+ loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, true, false, false, false);
}
return invokeNextInterceptor(ctx, command);
}
@@ -145,7 +143,7 @@
{
if (command.getFqn() != null)
{
- loadIfNeeded(ctx, command.getFqn(), null, false, false, true, ctx.getTransactionContext(), false, false, !usingVersionedInvalidation);
+ loadIfNeeded(ctx, command.getFqn(), null, false, false, true, false, false, !usingVersionedInvalidation);
}
return invokeNextInterceptor(ctx, command);
}
@@ -156,7 +154,7 @@
Fqn fqn = command.getFqn();
if (fqn != null)
{
- loadIfNeeded(ctx, fqn, null, false, false, false, ctx.getTransactionContext(), false, false, true);
+ loadIfNeeded(ctx, fqn, null, false, false, false, false, false, true);
NodeSPI n = dataContainer.peek(fqn, true, true);
loadChildren(fqn, n, false, false, ctx);
}
@@ -169,7 +167,7 @@
{
if (command.getFqn() != null)
{
- loadIfNeeded(ctx, command.getFqn(), null, true, false, true, ctx.getTransactionContext(), false, false, false);
+ loadIfNeeded(ctx, command.getFqn(), null, true, false, true, false, false, false);
}
return invokeNextInterceptor(ctx, command);
}
@@ -179,7 +177,7 @@
{
if (command.getFqn() != null)
{
- loadIfNeeded(ctx, command.getFqn(), null, true, false, true, ctx.getTransactionContext(), false, false, false);
+ loadIfNeeded(ctx, command.getFqn(), null, true, false, true, false, false, false);
}
return invokeNextInterceptor(ctx, command);
}
@@ -216,7 +214,7 @@
{
if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC && command.getFqn() != null)
{
- loadIfNeeded(ctx, command.getFqn(), null, false, false, false, ctx.getTransactionContext(), false, false, false);
+ loadIfNeeded(ctx, command.getFqn(), null, false, false, false, false, false, false);
}
return invokeNextInterceptor(ctx, command);
}
@@ -226,7 +224,7 @@
{
if (command.getFqn() != null && !useCacheStore)
{
- loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, false, ctx.getTransactionContext(), false, false, false);
+ loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, false, false, false, false);
}
return invokeNextInterceptor(ctx, command);
}
@@ -237,73 +235,42 @@
Fqn fqn = command.getFqn();
if (fqn != null && !useCacheStore)
{
- loadIfNeeded(ctx, fqn, null, false, true, false, ctx.getTransactionContext(), false, false, false);
+ loadIfNeeded(ctx, fqn, null, false, true, false, false, false, false);
}
return invokeNextInterceptor(ctx, command);
}
- private void loadIfNeeded(InvocationContext ctx, Fqn fqn, Object key, boolean allKeys, boolean initNode, boolean acquireLock, TransactionContext transactionContext, boolean recursive, boolean isMove, boolean bypassLoadingData) throws Throwable
+ private void loadIfNeeded(InvocationContext ctx, Fqn fqn, Object key, boolean allKeys, boolean initNode, boolean acquireWriteLock, boolean recursive, boolean isMove, boolean bypassLoadingData) throws Throwable
{
- NodeSPI n = dataContainer.peek(fqn, true, true);
- Object lockOwner = lockManager.getLockOwner(ctx);
- boolean needLock = n != null && !lockManager.ownsLock(fqn, lockOwner);
- boolean mustLoad = false;
- try
+ NodeSPI n = helper.wrapNodeForReading(ctx, fqn);
+ if (n instanceof NullMarkerNode)
{
- if (needLock)
- {
- if (!lockManager.lock(n, LockType.READ, lockOwner))
- throw new TimeoutException("Unable to acquire lock on " + fqn + ". Lock info: " + lockManager.printLockInfo(n));
- }
- mustLoad = mustLoad(n, key, allKeys || isMove);
+ ctx.getLookedUpNodes().remove(fqn);
+ n = null;
}
- finally
- {
- if (needLock) lockManager.unlock(n, lockOwner);
- }
+ boolean mustLoad = mustLoad(n, key, allKeys || isMove);
- if (trace)
- {
- log.trace("load element " + fqn + " mustLoad=" + mustLoad);
- }
+ if (trace) log.trace("load element " + fqn + " mustLoad=" + mustLoad);
+
if (mustLoad)
{
- if (initNode)
+ if (acquireWriteLock || initNode)
{
- n = createTempNode(fqn, transactionContext);
+ boolean isNew = n == null;
+ n = helper.wrapNodeForWriting(ctx, fqn, true, false, true, false, true); // won't create any nodes but will acquire locks.
+ if (isNew && n != null) n.setDataLoaded(false);
}
- // Only attempt to acquire this lock if we need to - i.e., if
- // the lock hasn't already been acquired by the Lock
- // interceptor. CRUD methods (put, remove) would have acquired
- // this lock - even if the node is not in memory and needs to be
- // loaded. Non-CRUD methods (put) would NOT have acquired this
- // lock so if we are to load the node from cache loader, we need
- // to acquire a write lock here. as a 'catch-all', DO NOT
- // attempt to acquire a lock here *anyway*, even for CRUD
- // methods - this leads to a deadlock when you have threads
- // simultaneously trying to create a node. See
- // org.jboss.cache.loader.deadlock.ConcurrentCreationDeadlockTest
- // - Manik Surtani (21 March 2006)
- if (acquireLock)
+ if (n == null || !n.isDeleted())
{
- lock(fqn, LockType.WRITE, false, ctx);// non-recursive for now
- }
-
-// if (!initNode && !wasRemovedInTx(fqn, ctx.getGlobalTransaction()))
- if (!wasRemovedInTx(fqn, ctx))
- {
- if (bypassLoadingData)
+ if (n == null && loader.exists(fqn))
{
- if (n == null && loader.exists(fqn))
- {
- // just create a dummy node in memory
- n = createTempNode(fqn, transactionContext);
- }
+ // just create a dummy node in memory
+ n = helper.wrapNodeForWriting(ctx, fqn, true, true, true, false, false); // won't create any nodes but will acquire locks.
}
- else
+ if (!bypassLoadingData)
{
- n = loadNode(ctx, fqn, n, transactionContext);
+ n = loadNode(ctx, fqn, n);
}
}
}
@@ -363,16 +330,16 @@
// Create if node had not been created already
if (node == null)
{
- node = createNodes(fqn, null);// dont care about local transactions
+ node = helper.wrapNodeForWriting(ctxt, fqn, true, true, true, false, false);
}
// Create one DataNode per child, mark as UNINITIALIZED
for (Object name : childrenNames)
{
- Fqn childFqn = Fqn.fromElements(name);// this is a RELATIVE Fqn!!
+ Fqn childFqn = Fqn.fromRelativeElements(fqn, name);
// create child if it didn't exist
- NodeSPI child = node.addChildDirect(childFqn);
+ NodeSPI child = helper.wrapNodeForWriting(ctxt, childFqn, true, true, true, false, false);
if ((isMove || isActivation) && recursive)
{
// load data for children as well!
@@ -385,7 +352,6 @@
loadChildren(child.getFqn(), child, true, isMove, ctxt);
}
}
- lock(fqn, recursive ? LockType.WRITE : LockType.READ, true, ctxt);// recursive=true: lock entire subtree
node.setChildrenLoaded(true);
}
@@ -454,41 +420,14 @@
return retval;
}
- protected void lock(Fqn fqn, LockType lockType, boolean recursive, InvocationContext ctx) throws Throwable
- {
- if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC) return;
-
- if (recursive)
- lockManager.lockAllAndRecord(fqn, lockType, ctx);
- else
- lockManager.lockAndRecord(fqn, lockType, ctx);
- }
-
/**
- * Returns true if the FQN or parent was removed during the current
- * transaction.
- * This is O(N) WRT to the number of modifications so far.
- */
- private boolean wasRemovedInTx(Fqn fqn, InvocationContext ctx)
- {
- TransactionContext transactionContext = ctx.getTransactionContext();
- if (transactionContext == null) return false;
-
- for (WriteCommand txCacheCommand : transactionContext.getModifications())
- {
- if (txCacheCommand instanceof RemoveNodeCommand && fqn.isChildOrEquals(txCacheCommand.getFqn())) return true;
- }
- return false;
- }
-
- /**
* Loads a node from disk; if it exists creates parent TreeNodes.
* If it doesn't exist on disk but in memory, clears the
* uninitialized flag, otherwise returns null.
*/
- private NodeSPI loadNode(InvocationContext ctx, Fqn fqn, NodeSPI n, TransactionContext transactionContext) throws Exception
+ private NodeSPI loadNode(InvocationContext ctx, Fqn fqn, NodeSPI n) throws Exception
{
- if (trace) log.trace("loadNode " + fqn);
+ if (trace) log.trace("loadNode " + fqn + " node is " + n);
Map nodeData = loadData(fqn);
if (nodeData != null)
{
@@ -500,8 +439,6 @@
notifier.notifyNodeActivated(fqn, true, Collections.emptyMap(), ctx);
}
- n = createNodes(fqn, transactionContext);
-// n.clearDataDirect();
n.setInternalState(nodeData);
// set this node as valid?
@@ -521,44 +458,6 @@
return n;
}
- /**
- * Creates a new memory node in preparation for storage.
- */
- private NodeSPI createTempNode(Fqn fqn, TransactionContext transactionContext) throws Exception
- {
- NodeSPI n = createNodes(fqn, transactionContext);
- n.setDataLoaded(false);
- if (trace)
- {
- log.trace("createTempNode n " + n);
- }
- return n;
- }
-
- @SuppressWarnings("unchecked")
- private NodeSPI createNodes(Fqn fqn, TransactionContext transactionContext) throws Exception
- {
- Object[] results = dataContainer.createNodes(fqn);
- List<NodeSPI> createdNodes = (List<NodeSPI>) results[0];
-
- NodeSPI lastCreated = null;
- for (NodeSPI node : createdNodes)
- {
- node.setDataLoaded(false);
- if (transactionContext != null)
- {
- transactionContext.addDummyNodeCreatedByCacheLoader(node.getFqn());
- }
- lastCreated = node;
- }
-
- // mark the leaf node as data loaded since that is what we are doing in this interceptor.
- if (lastCreated != null) lastCreated.setDataLoaded(true);
-
- // regardless of whether the last node was created, return it.
- return (NodeSPI) results[1];
- }
-
private Map loadData(Fqn fqn) throws Exception
{
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,7 +1,6 @@
package org.jboss.cache.interceptors;
import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
import org.jboss.cache.Modification;
import org.jboss.cache.NodeSPI;
@@ -54,7 +53,6 @@
private Map<GlobalTransaction, Set<Fqn>> preparingTxs = new ConcurrentHashMap<GlobalTransaction, Set<Fqn>>();
private long cacheStores = 0;
private CacheLoader loader;
- private DataContainer dataContainer;
private CacheLoaderManager loaderManager;
public CacheStoreInterceptor()
@@ -64,13 +62,12 @@
}
@Inject
- protected void init(DataContainer dataContainer, CacheLoaderManager loaderManager, TransactionManager txManager, CacheLoaderConfig clConfig)
+ protected void init(CacheLoaderManager loaderManager, TransactionManager txManager, CacheLoaderConfig clConfig)
{
// never inject a CacheLoader at this stage - only a CacheLoaderManager, since the CacheLoaderManager only creates a CacheLoader instance when it @Starts.
this.loaderManager = loaderManager;
this.loaderConfig = clConfig;
txMgr = txManager;
- this.dataContainer = dataContainer;
}
@Start
@@ -89,9 +86,7 @@
if (!ctx.isOriginLocal() && loaderConfig.isShared())
{
if (trace)
- {
log.trace("Passing up method call and bypassing this interceptor since the cache loader is shared and this call originated remotely.");
- }
return true;
}
return false;
@@ -131,9 +126,9 @@
Object returnValue = invokeNextInterceptor(ctx, command);
// persist additional internal state, if any, and then clean up internal resources
Set<Fqn> affectedFqns = preparingTxs.remove(gtx);
- if (affectedFqns != null)
+ if (affectedFqns != null && !affectedFqns.isEmpty())
{
- storeInternalState(affectedFqns);
+ storeInternalState(affectedFqns, ctx);
}
return returnValue;
}
@@ -220,7 +215,7 @@
{
loader.removeData(command.getFqn());
// we need to mark this node as data loaded
- NodeSPI n = dataContainer.peek(command.getFqn(), false, false);
+ NodeSPI n = ctx.lookUpNode(command.getFqn());
if (n != null)
{
n.setDataLoaded(true);
@@ -283,15 +278,15 @@
return txMgr != null && txMgr.getTransaction() != null;
}
- private void storeInternalState(Set<Fqn> affectedFqns) throws Exception
+ private void storeInternalState(Set<Fqn> affectedFqns, InvocationContext ctx) throws Exception
{
if (configuration.getNodeLockingScheme().isVersionedScheme())
{
for (Fqn f : affectedFqns)
{
// NOT going to store tombstones!!
- NodeSPI n = dataContainer.peek(f, false, false);
- if (n != null)
+ NodeSPI n = ctx.lookUpNode(f);
+ if (n != null && !n.isDeleted())
{
Map internalState = n.getInternalState(true);
loader.put(f, internalState);
Copied: core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java (from rev 6207, core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -0,0 +1,391 @@
+package org.jboss.cache.interceptors;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Modification;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.commands.AbstractVisitor;
+import org.jboss.cache.commands.read.GetChildrenNamesCommand;
+import org.jboss.cache.commands.read.GetKeyValueCommand;
+import org.jboss.cache.commands.read.GetKeysCommand;
+import org.jboss.cache.commands.read.GetNodeCommand;
+import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
+import org.jboss.cache.commands.tx.PrepareCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
+import org.jboss.cache.commands.write.MoveCommand;
+import org.jboss.cache.commands.write.PutDataMapCommand;
+import org.jboss.cache.commands.write.PutForExternalReadCommand;
+import org.jboss.cache.commands.write.PutKeyValueCommand;
+import org.jboss.cache.commands.write.RemoveKeyCommand;
+import org.jboss.cache.commands.write.RemoveNodeCommand;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.transaction.TransactionContext;
+
+import javax.transaction.SystemException;
+import javax.transaction.TransactionManager;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Loads nodes that don't exist at the time of the call into memory from the CacheLoader.
+ * If the nodes were evicted earlier then we remove them from the cache loader after
+ * their attributes have been initialized and their children have been loaded in memory.
+ *
+ * @author <a href="mailto:{hmesha at novell.com}">{Hany Mesha}</a>
+ * @version $Id$
+ */
+public class LegacyActivationInterceptor extends LegacyCacheLoaderInterceptor implements ActivationInterceptorMBean
+{
+
+ protected TransactionManager txMgr = null;
+ private long activations = 0;
+ ActivationModificationsBuilder builder;
+
+ /**
+ * List<Transaction> that we have registered for
+ */
+ protected ConcurrentHashMap transactions = new ConcurrentHashMap(16);
+ protected static final Object NULL = new Object();
+
+ public LegacyActivationInterceptor()
+ {
+ isActivation = true;
+ useCacheStore = false;
+ }
+
+ @Inject
+ public void injectTransactionManager(TransactionManager txMgr)
+ {
+ this.txMgr = txMgr;
+ }
+
+ @Start
+ public void createModificationsBuilder()
+ {
+ builder = new ActivationModificationsBuilder();
+ }
+
+ @Override
+ public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
+ {
+ Object returnValue = super.visitClearDataCommand(ctx, command);
+ if (trace)
+ log.trace("This is a remove data operation; removing the data from the loader, no activation processing needed.");
+ loader.removeData(command.getFqn());
+ return returnValue;
+ }
+
+ @Override
+ public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable
+ {
+ Object returnValue = super.visitRemoveNodeCommand(ctx, command);
+ if (trace)
+ log.trace("This is a remove operation; removing the node from the loader, no activation processing needed.");
+ loader.remove(command.getFqn());
+ return returnValue;
+ }
+
+ @Override
+ public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
+ {
+ Object returnValue = super.visitGetChildrenNamesCommand(ctx, command);
+ removeNodeFromCacheLoader(ctx, command.getFqn());
+ return returnValue;
+ }
+
+ @Override
+ public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
+ {
+ Object returnValue = super.visitGetKeysCommand(ctx, command);
+ removeNodeFromCacheLoader(ctx, command.getFqn());
+ return returnValue;
+ }
+
+ @Override
+ public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
+ {
+ Object returnValue = super.visitGetNodeCommand(ctx, command);
+ removeNodeFromCacheLoader(ctx, command.getFqn());
+ return returnValue;
+ }
+
+ @Override
+ public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
+ {
+ Object returnValue = super.visitGetKeyValueCommand(ctx, command);
+ removeNodeFromCacheLoader(ctx, command.getFqn());
+ return returnValue;
+ }
+
+ @Override
+ public Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable
+ {
+ return visitPutKeyValueCommand(ctx, command);
+ }
+
+ @Override
+ public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+ {
+ Object returnValue = super.visitPutKeyValueCommand(ctx, command);
+ removeNodeFromCacheLoader(ctx, command.getFqn());
+ return returnValue;
+ }
+
+ @Override
+ public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+ {
+ Object returnValue = super.visitPutDataMapCommand(ctx, command);
+ removeNodeFromCacheLoader(ctx, command.getFqn());
+ return returnValue;
+ }
+
+ @Override
+ public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
+ {
+ Object returnValue = super.visitRemoveKeyCommand(ctx, command);
+ removeNodeFromCacheLoader(ctx, command.getFqn());
+ return returnValue;
+ }
+
+ @Override
+ public Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable
+ {
+ Object returnValue = super.visitMoveCommand(ctx, command);
+ if (trace)
+ log.trace("This is a move operation; removing the FROM node from the loader, no activation processing needed.");
+ loader.remove(command.getFqn());
+ removeNodeFromCacheLoader(ctx, command.getFqn().getParent());
+ removeNodeFromCacheLoader(ctx, command.getTo());
+ return returnValue;
+ }
+
+
+ /**
+ * Remove the node from the cache loader if it exists in memory,
+ * its attributes have been initialized, its children have been loaded,
+ * AND it was found in the cache loader (nodeLoaded = true).
+ * Then notify the listeners that the node has been activated.
+ */
+ private void removeNodeFromCacheLoader(InvocationContext ctx, Fqn fqn) throws Throwable
+ {
+ NodeSPI n;
+ if (((n = dataContainer.peek(fqn, true, false)) != null) && n.isDataLoaded() && loader.exists(fqn))
+ {
+ // node not null and attributes have been loaded?
+ if (!n.getChildrenDirect().isEmpty())
+ {
+ boolean result = childrenLoaded(n);
+ if (result)
+ {
+ log.debug("children all initialized");
+ remove(fqn);
+ }
+ }
+ else if (loaderNoChildren(fqn))
+ {
+ if (log.isDebugEnabled()) log.debug("no children " + n);
+ remove(fqn);
+ }
+ }
+ }
+
+ private static boolean childrenLoaded(NodeSPI<?, ?> node)
+ {
+ if (!node.isChildrenLoaded())
+ {
+ return false;
+ }
+ for (NodeSPI child : node.getChildrenDirect())
+ {
+ if (!child.isDataLoaded())
+ {
+ return false;
+ }
+ }
+ return true;
+
+ }
+
+ @Override
+ public Object visitOptimisticPrepareCommand(InvocationContext ctx, OptimisticPrepareCommand command) throws Throwable
+ {
+ Object retval = invokeNextInterceptor(ctx, command);
+ if (inTransaction())
+ {
+ prepareCacheLoader(ctx);
+ }
+ return retval;
+ }
+
+ private boolean inTransaction() throws SystemException
+ {
+ return txMgr != null && txMgr.getTransaction() != null;
+ }
+
+ @Override
+ public Object visitPrepareCommand(InvocationContext ctx, PrepareCommand command) throws Throwable
+ {
+ Object retval = invokeNextInterceptor(ctx, command);
+ if (inTransaction())
+ {
+ prepareCacheLoader(ctx);
+ }
+ return retval;
+ }
+
+ private void remove(Fqn fqn) throws Exception
+ {
+ loader.remove(fqn);
+ if (getStatisticsEnabled()) activations++;
+ }
+
+ /**
+ * Returns true if the loader indicates no children for this node.
+ * Return false on error.
+ */
+ private boolean loaderNoChildren(Fqn fqn)
+ {
+ try
+ {
+ Set childrenNames = loader.getChildrenNames(fqn);
+ return (childrenNames == null);
+ }
+ catch (Exception e)
+ {
+ log.error("failed getting the children names for " + fqn + " from the cache loader", e);
+ return false;
+ }
+ }
+
+ public long getActivations()
+ {
+ return activations;
+ }
+
+ @Override
+ public void resetStatistics()
+ {
+ super.resetStatistics();
+ activations = 0;
+ }
+
+ @Override
+ public Map<String, Object> dumpStatistics()
+ {
+ Map<String, Object> retval = super.dumpStatistics();
+ if (retval == null)
+ {
+ retval = new HashMap<String, Object>();
+ }
+ retval.put("Activations", activations);
+ return retval;
+ }
+
+ private void prepareCacheLoader(InvocationContext ctx) throws Throwable
+ {
+ GlobalTransaction gtx = ctx.getGlobalTransaction();
+ TransactionContext tCtx = ctx.getTransactionContext();
+ if (tCtx == null)
+ {
+ throw new Exception("tCtx for transaction " + gtx + " not found in transaction table");
+ }
+ List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
+
+ builder.visitCollection(ctx, tCtx.getModifications());
+ if (cacheLoaderModifications.size() > 0)
+ {
+ loader.prepare(gtx, cacheLoaderModifications, false);
+ }
+ }
+
+ public class ActivationModificationsBuilder extends AbstractVisitor
+ {
+
+ private List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
+ private int txActs = 0;
+
+ @Override
+ public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand removeNodeCommand) throws Throwable
+ {
+ Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, removeNodeCommand.getFqn());
+ cacheLoaderModifications.add(mod);
+ return null;
+ }
+
+ @Override
+ public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+ {
+ Fqn fqn = command.getFqn();
+ handlePutCommand(ctx, fqn);
+ return null;
+ }
+
+ @Override
+ public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+ {
+ Fqn fqn = command.getFqn();
+ handlePutCommand(ctx, fqn);
+ return null;
+ }
+
+ // On the way out, remove the node from the cache loader.
+ // Only remove the node if it exists in memory, its attributes have
+ // been initialized, its children have been loaded
+ // AND it was found in the cache loader (nodeLoaded = true).
+ // Then notify the listeners that the node has been activated.
+ private void handlePutCommand(InvocationContext ctx, Fqn fqn)
+ throws Exception
+ {
+ if (fqn != null && dataContainer.peek(fqn, false, false) != null && loader.exists(fqn))
+ {
+ NodeSPI n = dataContainer.peek(fqn, true, false);// don't load
+ // node not null and attributes have been loaded?
+ if (n != null && n.isDataLoaded())
+ {
+ // has children?
+ boolean result = childrenLoaded(n);
+ if (!n.getChildrenDirect().isEmpty() && result)
+ {
+ // children have been loaded, remove the node
+ addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+ txActs++;
+ }
+ // doesn't have children, check the cache loader
+ else if (loaderNoChildren(fqn))
+ {
+ addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+ txActs++;
+ }
+ }
+ }
+ }
+
+ private boolean loaderNoChildren(Fqn fqn) throws Exception
+ {
+ return loader.getChildrenNames(fqn) != null;
+ }
+
+ private void addRemoveMod(InvocationContext ctx, List<Modification> l, Fqn fqn, Map data)
+ {
+ Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, fqn);
+ l.add(mod);
+ notifier.notifyNodeActivated(fqn, false, data, ctx);
+ }
+
+ public List<Modification> getCacheLoaderModifications()
+ {
+ return cacheLoaderModifications;
+ }
+
+ public int getTxActs()
+ {
+ return txActs;
+ }
+ }
+}
\ No newline at end of file
Copied: core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java (from rev 6207, core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -0,0 +1,583 @@
+package org.jboss.cache.interceptors;
+
+import org.jboss.cache.CacheException;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.commands.WriteCommand;
+import org.jboss.cache.commands.read.GetChildrenNamesCommand;
+import org.jboss.cache.commands.read.GetDataMapCommand;
+import org.jboss.cache.commands.read.GetKeyValueCommand;
+import org.jboss.cache.commands.read.GetKeysCommand;
+import org.jboss.cache.commands.read.GetNodeCommand;
+import org.jboss.cache.commands.tx.RollbackCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
+import org.jboss.cache.commands.write.MoveCommand;
+import org.jboss.cache.commands.write.PutDataMapCommand;
+import org.jboss.cache.commands.write.PutForExternalReadCommand;
+import org.jboss.cache.commands.write.PutKeyValueCommand;
+import org.jboss.cache.commands.write.RemoveKeyCommand;
+import org.jboss.cache.commands.write.RemoveNodeCommand;
+import org.jboss.cache.config.Configuration;
+import static org.jboss.cache.config.Configuration.CacheMode;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.interceptors.base.CommandInterceptor;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.loader.CacheLoaderManager;
+import org.jboss.cache.lock.LockManager;
+import org.jboss.cache.lock.LockType;
+import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.transaction.TransactionContext;
+import org.jboss.cache.transaction.TransactionTable;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Loads nodes that don't exist at the time of the call into memory from the CacheLoader
+ *
+ * @author Bela Ban
+ * @version $Id$
+ */
+public class LegacyCacheLoaderInterceptor extends CommandInterceptor implements CacheLoaderInterceptorMBean
+{
+ private long cacheLoads = 0;
+ private long cacheMisses = 0;
+ private CacheLoaderManager clm;
+ private LockManager lockManager;
+
+ protected TransactionTable txTable = null;
+ protected CacheLoader loader;
+ protected DataContainer dataContainer;
+ protected Notifier notifier;
+
+ protected boolean isActivation = false;
+ protected boolean usingVersionedInvalidation = false;
+
+
+ /**
+ * True if CacheStoreInterceptor is in place.
+ * This allows us to skip loading keys for remove(Fqn, key) and put(Fqn, key).
+ * It also affects removal of node data and listing children.
+ */
+ protected boolean useCacheStore = true;
+
+ @Inject
+ protected void injectDependencies(TransactionTable txTable, CacheLoaderManager clm, Configuration configuration,
+ DataContainer dataContainer, LockManager lockManager, Notifier notifier)
+ {
+ this.txTable = txTable;
+ this.clm = clm;
+ CacheMode mode = configuration.getCacheMode();
+ usingVersionedInvalidation = configuration.getNodeLockingScheme().isVersionedScheme() && mode.isInvalidation();
+ this.dataContainer = dataContainer;
+ this.lockManager = lockManager;
+ this.notifier = notifier;
+ }
+
+ @Start
+ protected void startInterceptor()
+ {
+ loader = clm.getCacheLoader();
+ }
+
+ @Override
+ public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+ {
+ if (command.getFqn() != null)
+ {
+ loadIfNeeded(ctx, command.getFqn(), null, false, true, false, ctx.getTransactionContext(), false, false, false);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ @Override
+ public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+ {
+ if (command.getFqn() != null)
+ {
+ loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, useCacheStore, !useCacheStore, ctx.getTransactionContext(), false, false, false);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ @Override
+ public Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable
+ {
+ return visitPutKeyValueCommand(ctx, command);
+ }
+
+ @Override
+ public Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable
+ {
+ if (command.getFqn() != null)
+ {
+ if (command.getTo() != null)
+ {
+ loadIfNeeded(ctx, command.getTo(), null, false, false, true, ctx.getTransactionContext(), false, true, false);
+ }
+ loadIfNeeded(ctx, command.getFqn(), null, false, false, true, ctx.getTransactionContext(), true, true, false);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ @Override
+ public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
+ {
+ if (command.getFqn() != null)
+ {
+ loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, true, ctx.getTransactionContext(), false, false, false);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+
+ @Override
+ public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
+ {
+ if (command.getFqn() != null)
+ {
+ loadIfNeeded(ctx, command.getFqn(), null, false, false, true, ctx.getTransactionContext(), false, false, !usingVersionedInvalidation);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ @Override
+ public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
+ {
+ Fqn fqn = command.getFqn();
+ if (fqn != null)
+ {
+ loadIfNeeded(ctx, fqn, null, false, false, false, ctx.getTransactionContext(), false, false, true);
+ NodeSPI n = dataContainer.peek(fqn, true, true);
+ loadChildren(fqn, n, false, false, ctx);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+
+ @Override
+ public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
+ {
+ if (command.getFqn() != null)
+ {
+ loadIfNeeded(ctx, command.getFqn(), null, true, false, true, ctx.getTransactionContext(), false, false, false);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ @Override
+ public Object visitGetDataMapCommand(InvocationContext ctx, GetDataMapCommand command) throws Throwable
+ {
+ if (command.getFqn() != null)
+ {
+ loadIfNeeded(ctx, command.getFqn(), null, true, false, true, ctx.getTransactionContext(), false, false, false);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ @Override
+ public Object visitRollbackCommand(InvocationContext ctx, RollbackCommand command) throws Throwable
+ {
+ // clean up nodesCreated map
+ if (trace) log.trace("Removing temporarily created nodes from treecache");
+
+ // this needs to be done in reverse order.
+ List list = ctx.getTransactionContext().getDummyNodesCreatedByCacheLoader();
+ if (list != null && list.size() > 0)
+ {
+ ListIterator i = list.listIterator(list.size());
+ while (i.hasPrevious())
+ {
+ Fqn fqn = (Fqn) i.previous();
+ try
+ {
+ dataContainer.evict(fqn, false);
+ }
+ catch (CacheException e)
+ {
+ if (trace) log.trace("Unable to evict node " + fqn, e);
+ }
+ }
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ @Override
+ public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable
+ {
+ if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC && command.getFqn() != null)
+ {
+ loadIfNeeded(ctx, command.getFqn(), null, false, false, false, ctx.getTransactionContext(), false, false, false);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ @Override
+ public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
+ {
+ if (command.getFqn() != null && !useCacheStore)
+ {
+ loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, false, ctx.getTransactionContext(), false, false, false);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ @Override
+ public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
+ {
+ Fqn fqn = command.getFqn();
+ if (fqn != null && !useCacheStore)
+ {
+ loadIfNeeded(ctx, fqn, null, false, true, false, ctx.getTransactionContext(), false, false, false);
+ }
+ return invokeNextInterceptor(ctx, command);
+ }
+
+ private void loadIfNeeded(InvocationContext ctx, Fqn fqn, Object key, boolean allKeys, boolean initNode, boolean acquireLock, TransactionContext transactionContext, boolean recursive, boolean isMove, boolean bypassLoadingData) throws Throwable
+ {
+ NodeSPI n = dataContainer.peek(fqn, true, true);
+ Object lockOwner = lockManager.getLockOwner(ctx);
+ boolean needLock = n != null && !lockManager.ownsLock(fqn, lockOwner);
+ boolean mustLoad = false;
+ try
+ {
+ if (needLock)
+ {
+ if (!lockManager.lock(n, LockType.READ, lockOwner))
+ throw new TimeoutException("Unable to acquire lock on " + fqn + ". Lock info: " + lockManager.printLockInfo(n));
+ }
+ mustLoad = mustLoad(n, key, allKeys || isMove);
+ }
+ finally
+ {
+ if (needLock) lockManager.unlock(n, lockOwner);
+ }
+
+ if (trace)
+ {
+ log.trace("load element " + fqn + " mustLoad=" + mustLoad);
+ }
+ if (mustLoad)
+ {
+ if (initNode)
+ {
+ n = createTempNode(fqn, transactionContext);
+ }
+
+ // Only attempt to acquire this lock if we need to - i.e., if
+ // the lock hasn't already been acquired by the Lock
+ // interceptor. CRUD methods (put, remove) would have acquired
+ // this lock - even if the node is not in memory and needs to be
+ // loaded. Non-CRUD methods (put) would NOT have acquired this
+ // lock so if we are to load the node from cache loader, we need
+ // to acquire a write lock here. as a 'catch-all', DO NOT
+ // attempt to acquire a lock here *anyway*, even for CRUD
+ // methods - this leads to a deadlock when you have threads
+ // simultaneously trying to create a node. See
+ // org.jboss.cache.loader.deadlock.ConcurrentCreationDeadlockTest
+ // - Manik Surtani (21 March 2006)
+ if (acquireLock)
+ {
+ lock(fqn, LockType.WRITE, false, ctx);// non-recursive for now
+ }
+
+// if (!initNode && !wasRemovedInTx(fqn, ctx.getGlobalTransaction()))
+ if (!wasRemovedInTx(fqn, ctx))
+ {
+ if (bypassLoadingData)
+ {
+ if (n == null && loader.exists(fqn))
+ {
+ // just create a dummy node in memory
+ n = createTempNode(fqn, transactionContext);
+ }
+ }
+ else
+ {
+ n = loadNode(ctx, fqn, n, transactionContext);
+ }
+ }
+ }
+
+ // The complete list of children aren't known without loading them
+ if (recursive)
+ {
+ loadChildren(fqn, n, recursive, isMove, ctx);
+ }
+ }
+
+ /**
+ * Load the children.
+ *
+ * @param node may be null if the node was not found.
+ * @param ctxt
+ */
+ private void loadChildren(Fqn fqn, NodeSPI node, boolean recursive, boolean isMove, InvocationContext ctxt) throws Throwable
+ {
+
+ if (node != null && node.isChildrenLoaded())
+ {
+ if (trace) log.trace("Children already loaded!");
+ return;
+ }
+ Set childrenNames;
+ try
+ {
+ childrenNames = loader.getChildrenNames(fqn);
+ }
+ catch (Exception e)
+ {
+ if (log.isInfoEnabled()) log.info("Cache loader was unable to load state", e);
+ // return!
+ return;
+ }
+
+ if (trace)
+ {
+ log.trace("load children " + fqn + " children=" + childrenNames);
+ }
+
+ // For getChildrenNames null means no children
+ if (childrenNames == null)
+ {
+ if (node != null)
+ {
+ if (useCacheStore)
+ {
+ node.removeChildrenDirect();//getChildrenMapDirect().clear();
+ }
+ node.setChildrenLoaded(true);
+ }
+ return;
+ }
+
+ // Create if node had not been created already
+ if (node == null)
+ {
+ node = createNodes(fqn, null);// dont care about local transactions
+ }
+
+ // Create one DataNode per child, mark as UNINITIALIZED
+ for (Object name : childrenNames)
+ {
+ Fqn childFqn = Fqn.fromElements(name);// this is a RELATIVE Fqn!!
+
+ // create child if it didn't exist
+ NodeSPI child = node.addChildDirect(childFqn);
+ if ((isMove || isActivation) && recursive)
+ {
+ // load data for children as well!
+ child.setInternalState(loader.get(child.getFqn()));
+ child.setDataLoaded(true);
+ }
+
+ if (recursive)
+ {
+ loadChildren(child.getFqn(), child, true, isMove, ctxt);
+ }
+ }
+ lock(fqn, recursive ? LockType.WRITE : LockType.READ, true, ctxt);// recursive=true: lock entire subtree
+ node.setChildrenLoaded(true);
+ }
+
+ private boolean mustLoad(NodeSPI n, Object key, boolean allKeys)
+ {
+ if (n == null)
+ {
+ if (trace) log.trace("must load, node null");
+ return true;
+ }
+
+ // check this first!!!
+ if (!n.isValid() && configuration.getNodeLockingScheme().isVersionedScheme())
+ {
+ // attempt to load again; this only happens if we have tombstones lying around, or we are using invalidation.
+ if (trace) log.trace("loading again from cache loader since in-memory node is marked as invalid");
+ return true;
+ }
+
+ // JBCACHE-1172 Skip single-key optimization if request needs all keys
+ if (!allKeys)
+ {
+ // if we are not looking for a specific key don't bother loading!
+ if (key == null)
+ {
+ if (trace) log.trace("don't load, key requested is null");
+ return false;
+ }
+ if (n.getKeysDirect().contains(key))
+ {
+ if (trace) log.trace("don't load, already have necessary key in memory");
+ return false;
+ }
+ }
+ if (!n.isDataLoaded())
+ {
+ if (trace) log.trace("must Load, uninitialized");
+ return true;
+ }
+ return false;
+ }
+
+ public long getCacheLoaderLoads()
+ {
+ return cacheLoads;
+ }
+
+ public long getCacheLoaderMisses()
+ {
+ return cacheMisses;
+ }
+
+ @Override
+ public void resetStatistics()
+ {
+ cacheLoads = 0;
+ cacheMisses = 0;
+ }
+
+ @Override
+ public Map<String, Object> dumpStatistics()
+ {
+ Map<String, Object> retval = new HashMap<String, Object>();
+ retval.put("CacheLoaderLoads", cacheLoads);
+ retval.put("CacheLoaderMisses", cacheMisses);
+ return retval;
+ }
+
+ protected void lock(Fqn fqn, LockType lockType, boolean recursive, InvocationContext ctx) throws Throwable
+ {
+ if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC) return;
+
+ if (recursive)
+ lockManager.lockAllAndRecord(fqn, lockType, ctx);
+ else
+ lockManager.lockAndRecord(fqn, lockType, ctx);
+ }
+
+ /**
+ * Returns true if the FQN or parent was removed during the current
+ * transaction.
+ * This is O(N) WRT to the number of modifications so far.
+ */
+ private boolean wasRemovedInTx(Fqn fqn, InvocationContext ctx)
+ {
+ TransactionContext transactionContext = ctx.getTransactionContext();
+ if (transactionContext == null) return false;
+
+ for (WriteCommand txCacheCommand : transactionContext.getModifications())
+ {
+ if (txCacheCommand instanceof RemoveNodeCommand && fqn.isChildOrEquals(txCacheCommand.getFqn())) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Loads a node from disk; if it exists creates parent TreeNodes.
+ * If it doesn't exist on disk but in memory, clears the
+ * uninitialized flag, otherwise returns null.
+ */
+ private NodeSPI loadNode(InvocationContext ctx, Fqn fqn, NodeSPI n, TransactionContext transactionContext) throws Exception
+ {
+ if (trace) log.trace("loadNode " + fqn);
+ Map nodeData = loadData(fqn);
+ if (nodeData != null)
+ {
+ if (trace) log.trace("Node data is not null, loading");
+
+ notifier.notifyNodeLoaded(fqn, true, Collections.emptyMap(), ctx);
+ if (isActivation)
+ {
+ notifier.notifyNodeActivated(fqn, true, Collections.emptyMap(), ctx);
+ }
+
+ n = createNodes(fqn, transactionContext);
+// n.clearDataDirect();
+ n.setInternalState(nodeData);
+
+ // set this node as valid?
+ if (usingVersionedInvalidation) n.setValid(true, false);
+
+ notifier.notifyNodeLoaded(fqn, false, nodeData, ctx);
+ if (isActivation)
+ {
+ notifier.notifyNodeActivated(fqn, false, nodeData, ctx);
+ }
+ }
+ if (n != null && !n.isDataLoaded())
+ {
+ if (trace) log.trace("Setting dataLoaded to true");
+ n.setDataLoaded(true);
+ }
+ return n;
+ }
+
+ /**
+ * Creates a new memory node in preparation for storage.
+ */
+ private NodeSPI createTempNode(Fqn fqn, TransactionContext transactionContext) throws Exception
+ {
+ NodeSPI n = createNodes(fqn, transactionContext);
+ n.setDataLoaded(false);
+ if (trace)
+ {
+ log.trace("createTempNode n " + n);
+ }
+ return n;
+ }
+
+ @SuppressWarnings("unchecked")
+ private NodeSPI createNodes(Fqn fqn, TransactionContext transactionContext) throws Exception
+ {
+ Object[] results = dataContainer.createNodes(fqn);
+ List<NodeSPI> createdNodes = (List<NodeSPI>) results[0];
+
+ NodeSPI lastCreated = null;
+ for (NodeSPI node : createdNodes)
+ {
+ node.setDataLoaded(false);
+ if (transactionContext != null)
+ {
+ transactionContext.addDummyNodeCreatedByCacheLoader(node.getFqn());
+ }
+ lastCreated = node;
+ }
+
+ // mark the leaf node as data loaded since that is what we are doing in this interceptor.
+ if (lastCreated != null) lastCreated.setDataLoaded(true);
+
+ // regardless of whether the last node was created, return it.
+ return (NodeSPI) results[1];
+ }
+
+ private Map loadData(Fqn fqn) throws Exception
+ {
+
+ Map nodeData = loader.get(fqn);
+ boolean nodeExists = (nodeData != null);
+ if (trace) log.trace("nodeExists " + nodeExists);
+
+ if (getStatisticsEnabled())
+ {
+ if (nodeExists)
+ {
+ cacheLoads++;
+ }
+ else
+ {
+ cacheMisses++;
+ }
+ }
+ return nodeData;
+ }
+
+}
\ No newline at end of file
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -3,6 +3,7 @@
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
import org.jboss.cache.NodeFactory;
+import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.VisitableCommand;
import org.jboss.cache.commands.read.ExistsCommand;
import org.jboss.cache.commands.read.GetChildrenNamesCommand;
@@ -31,7 +32,10 @@
import org.jboss.cache.mvcc.MVCCNodeHelper;
import org.jboss.cache.mvcc.ReadCommittedNode;
+import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
/**
* Interceptor to implement <a href="http://wiki.jboss.org/wiki/JBossCacheMVCC">MVCC</a> functionality.
@@ -115,12 +119,44 @@
ctx.getOptionOverrides().setLockAcquisitionTimeout(0);
if (command.isRecursive())
{
- List<Fqn> fqnsToEvict = helper.wrapNodesForWriting(ctx, command.getFqn());
+ List<Fqn> fqnsToEvict;
+ if (command.getFqn().isRoot())
+ {
+ // special treatment - deal with all of root's kids instead.
+ Map<Object, NodeSPI> children = dataContainer.peek(Fqn.ROOT).getChildrenMapDirect();
+ if (children != null && !children.isEmpty())
+ {
+ fqnsToEvict = new LinkedList<Fqn>();
+ for (NodeSPI child : children.values())
+ fqnsToEvict.addAll(helper.wrapNodesForWriting(ctx, child.getFqn()));
+ }
+ else
+ {
+ fqnsToEvict = Collections.emptyList();
+ }
+ }
+ else
+ {
+ fqnsToEvict = helper.wrapNodesForWriting(ctx, command.getFqn());
+ }
+
command.setNodesToEvict(fqnsToEvict);
}
else
{
- helper.wrapNodeForWriting(ctx, command.getFqn(), true, false, false, true, true);
+ if (command.getFqn().isRoot())
+ {
+ Map<Object, NodeSPI> children = dataContainer.peek(Fqn.ROOT).getChildrenMapDirect();
+ if (children != null && !children.isEmpty())
+ {
+ for (NodeSPI child : children.values())
+ helper.wrapNodeForWriting(ctx, child.getFqn(), true, false, false, true, true);
+ }
+ }
+ else
+ {
+ helper.wrapNodeForWriting(ctx, command.getFqn(), true, false, false, true, true);
+ }
}
return invokeNextInterceptor(ctx, command);
@@ -131,7 +167,7 @@
{
// this should be handled the same as a recursive evict command.
ctx.getOptionOverrides().setLockAcquisitionTimeout(0);
- helper.wrapNodesForWriting(ctx, command.getFqn());
+ if (!command.getFqn().isRoot()) helper.wrapNodesForWriting(ctx, command.getFqn());
return invokeNextInterceptor(ctx, command);
}
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,6 +1,5 @@
package org.jboss.cache.interceptors;
-import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.write.EvictCommand;
@@ -31,13 +30,11 @@
protected CacheLoader loader;
private Notifier notifier;
- private DataContainer dataContainer;
@Inject
- public void setDependencies(Notifier notifier, DataContainer dataContainer, CacheLoaderManager loaderManager)
+ public void setDependencies(Notifier notifier, CacheLoaderManager loaderManager)
{
this.notifier = notifier;
- this.dataContainer = dataContainer;
this.loader = loaderManager.getCacheLoader();
}
@@ -51,7 +48,7 @@
{
if (command.isRecursive())
{
- List<Fqn> fqnsToEvict = dataContainer.getNodesForEviction(command.getFqn(), true);
+ List<Fqn> fqnsToEvict = command.getNodesToEvict();
if (fqnsToEvict != null)
{
for (Fqn f : fqnsToEvict)
@@ -74,7 +71,7 @@
{
// evict method local doesn't hold attributes therefore we have
// to get them manually
- Map attributes = getNodeAttributes(fqn);
+ Map attributes = getNodeAttributes(ctx, fqn);
// notify listeners that this node is about to be passivated
notifier.notifyNodePassivated(fqn, true, attributes, ctx);
if (trace) log.trace("Passivating " + fqn);
@@ -113,13 +110,13 @@
/**
* Returns attributes for a node.
*/
- private Map getNodeAttributes(Fqn fqn) throws NodeNotLoadedException
+ private Map getNodeAttributes(InvocationContext ctx, Fqn fqn) throws NodeNotLoadedException
{
if (fqn == null)
{
throw new NodeNotLoadedException();
}
- NodeSPI n = dataContainer.peek(fqn, true, false);
+ NodeSPI n = ctx.lookUpNode(fqn);
if (n != null)
{
Modified: core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -308,7 +308,7 @@
_move(m.getFqn(), m.getFqn2());
break;
default:
- throw new CacheException("Unknown modificatiobn " + m.getType());
+ throw new CacheException("Unknown modification " + m.getType());
}
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -91,31 +91,35 @@
*
* @param ctx current invocation context
* @param fqn fqn to fetch and wrap
+ * @return read committed node, or null if one is not found.
* @throws InterruptedException if write locks are forced and the lock manager is interrupted.
*/
- public void wrapNodeForReading(InvocationContext ctx, Fqn fqn) throws InterruptedException
+ public ReadCommittedNode wrapNodeForReading(InvocationContext ctx, Fqn fqn) throws InterruptedException
{
- wrapNodeForReading(ctx, fqn, ctx.getOptionOverrides().isForceWriteLock());
+ return wrapNodeForReading(ctx, fqn, ctx.getOptionOverrides().isForceWriteLock());
}
- private void wrapNodeForReading(InvocationContext ctx, Fqn f, boolean writeLockForced) throws InterruptedException
+ private ReadCommittedNode wrapNodeForReading(InvocationContext ctx, Fqn f, boolean writeLockForced) throws InterruptedException
{
+ NodeSPI n;
if (writeLockForced)
{
if (trace) log.trace("Forcing lock on reading node " + f);
- wrapNodeForWriting(ctx, f, true, false, false, false, false);
+ return wrapNodeForWriting(ctx, f, true, false, false, false, false);
}
- else if (ctx.lookUpNode(f) == null)
+ else if ((n = ctx.lookUpNode(f)) == null)
{
if (trace) log.trace("Node " + f + " is not in context, fetching from container.");
// simple implementation. Peek the node, wrap it, put wrapped node in the context.
InternalNode node = dataContainer.peekInternalNode(f, false);
ReadCommittedNode wrapped = nodeFactory.createMvccNode(node);
if (wrapped != null) ctx.putLookedUpNode(f, wrapped);
+ return wrapped;
}
else
{
if (trace) log.trace("Node " + f + " is already in context.");
+ return (ReadCommittedNode) n;
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -37,6 +37,8 @@
public void copyNodeForUpdate(DataContainer container, boolean allowWriteSkew, InvocationContext ctx, NodeFactory nodeFactory)
{
+ if (changed) return; // already copied
+
changed = true;
backup = node;
node = backup.copy();
@@ -51,7 +53,7 @@
{
Fqn fqn = getFqn();
if (trace)
- log.trace("Updating node [" + fqn + "]. deleted=" + isDeleted() + " valid=" + isValid() + " changed" + isChanged() + " created=" + created);
+ log.trace("Updating node [" + fqn + "]. deleted=" + isDeleted() + " valid=" + isValid() + " changed=" + isChanged() + " created=" + created);
// check if node has been deleted.
if (deleted)
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -26,6 +26,8 @@
@Override
public void copyNodeForUpdate(DataContainer container, boolean allowWriteSkew, InvocationContext ctx, NodeFactory nodeFactory)
{
+ if (changed) return; // already copied
+
Fqn fqn = getFqn();
// mark node as changed.
Modified: core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -42,7 +42,6 @@
{
private static final Log log = LogFactory.getLog(PessimisticTransactionContext.class);
- private static final boolean trace = log.isTraceEnabled();
/**
* Local transaction
Modified: core/trunk/src/test/java/org/jboss/cache/api/NodeReplicatedMoveTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/NodeReplicatedMoveTest.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/NodeReplicatedMoveTest.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -11,7 +11,6 @@
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
-import org.jboss.cache.NodeNotExistsException;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.Configuration.CacheMode;
@@ -142,7 +141,7 @@
cache1.move(B, A);// should throw an NPE
if (!isOptimistic()) assert false : "Should throw an exception!";
}
- catch (NodeNotExistsException expected)
+ catch (Exception expected)
{
if (isOptimistic()) assert false : "Should not have thrown an exception!";
}
Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/CacheLoaderTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/CacheLoaderTest.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/CacheLoaderTest.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,8 +1,14 @@
package org.jboss.cache.api.mvcc.read_committed;
+import org.jboss.cache.api.mvcc.LockAssert;
import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.ComponentRegistry;
+import org.jboss.cache.invocation.InvocationContextContainer;
import org.jboss.cache.loader.DummyInMemoryCacheLoaderTest;
import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockManager;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
@Test(groups = {"functional", "mvcc"})
@@ -15,4 +21,12 @@
cache.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
cache.getConfiguration().setIsolationLevel(IsolationLevel.READ_COMMITTED);
}
+
+ @AfterMethod
+ public void postTest()
+ {
+ ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+
+ LockAssert.assertNoLocks(cr.getComponent(LockManager.class), cr.getComponent(InvocationContextContainer.class));
+ }
}
Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,10 +1,16 @@
package org.jboss.cache.api.mvcc.read_committed;
+import org.jboss.cache.api.mvcc.LockAssert;
import org.jboss.cache.config.CacheLoaderConfig;
import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.ComponentRegistry;
+import org.jboss.cache.invocation.InvocationContextContainer;
import org.jboss.cache.loader.DummySharedInMemoryCacheLoader;
import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockManager;
import org.jboss.cache.passivation.PassivationTestsBase;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
@Test(groups = {"functional", "mvcc"})
@@ -19,4 +25,12 @@
clc.setPassivation(true);
cache.getConfiguration().setCacheLoaderConfig(clc);
}
+
+ @AfterMethod
+ public void postTest()
+ {
+ ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+
+ LockAssert.assertNoLocks(cr.getComponent(LockManager.class), cr.getComponent(InvocationContextContainer.class));
+ }
}
Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/CacheLoaderTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/CacheLoaderTest.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/CacheLoaderTest.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,8 +1,14 @@
package org.jboss.cache.api.mvcc.repeatable_read;
+import org.jboss.cache.api.mvcc.LockAssert;
import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.ComponentRegistry;
+import org.jboss.cache.invocation.InvocationContextContainer;
import org.jboss.cache.loader.DummyInMemoryCacheLoaderTest;
import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockManager;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
@Test(groups = {"functional", "mvcc"})
@@ -15,4 +21,12 @@
cache.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
cache.getConfiguration().setIsolationLevel(IsolationLevel.REPEATABLE_READ);
}
+
+ @AfterMethod
+ public void postTest()
+ {
+ ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+
+ LockAssert.assertNoLocks(cr.getComponent(LockManager.class), cr.getComponent(InvocationContextContainer.class));
+ }
}
Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/PassivationTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/PassivationTest.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/PassivationTest.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,10 +1,16 @@
package org.jboss.cache.api.mvcc.repeatable_read;
+import org.jboss.cache.api.mvcc.LockAssert;
import org.jboss.cache.config.CacheLoaderConfig;
import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.ComponentRegistry;
+import org.jboss.cache.invocation.InvocationContextContainer;
import org.jboss.cache.loader.DummySharedInMemoryCacheLoader;
import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockManager;
import org.jboss.cache.passivation.PassivationTestsBase;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
@Test(groups = {"functional", "mvcc"})
@@ -19,4 +25,12 @@
clc.setPassivation(true);
cache.getConfiguration().setCacheLoaderConfig(clc);
}
+
+ @AfterMethod
+ public void postTest()
+ {
+ ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+
+ LockAssert.assertNoLocks(cr.getComponent(LockManager.class), cr.getComponent(InvocationContextContainer.class));
+ }
}
\ No newline at end of file
Modified: core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -728,39 +728,32 @@
public void testGetChildren12()
{
Set children;
- try
- {
- cache.put("/a/b", "key", "val");
- cache.put("/a/b/1", "key", "val");
- cache.put("/a/b/2", "key", "val");
- cache.put("/a/b/3", "key", "val");
- children = cache.getNode("/a/b").getChildrenNames();
- assertEquals(3, children.size());
+ cache.put("/a/b", "key", "val");
+ cache.put("/a/b/1", "key", "val");
+ cache.put("/a/b/2", "key", "val");
+ cache.put("/a/b/3", "key", "val");
+ children = cache.getNode("/a/b").getChildrenNames();
+ assertEquals(3, children.size());
- cache.evict(Fqn.fromString("/a/b/3"));
- cache.evict(Fqn.fromString("/a/b/2"));
- // cache.evict(Fqn.fromString("/a/b/1"));
- cache.evict(Fqn.fromString("/a/b"));
- cache.evict(Fqn.fromString("/a"));
+ cache.evict(Fqn.fromString("/a/b/3"));
+ cache.evict(Fqn.fromString("/a/b/2"));
+ // cache.evict(Fqn.fromString("/a/b/1"));
+ cache.evict(Fqn.fromString("/a/b"));
+ cache.evict(Fqn.fromString("/a"));
- NodeSPI n = (NodeSPI) cache.getNode("/a/b");
- assert !n.isChildrenLoaded();
+ NodeSPI n = cache.getNode("/a/b");
+ assert !n.isChildrenLoaded();
- children = cache.getNode("/a/b").getChildrenNames();
- assertEquals(3, children.size());
+ children = cache.getNode("/a/b").getChildrenNames();
+ assertEquals(3, children.size());
- cache.evict(Fqn.fromString("/a/b/3"));
- cache.evict(Fqn.fromString("/a/b/2"));
- // cache.evict(Fqn.fromString("/a/b/1"));
- cache.evict(Fqn.fromString("/a/b"));
- cache.evict(Fqn.fromString("/a"));
- children = cache.getNode("/a/b").getChildrenNames();
- assertEquals(3, children.size());
- }
- catch (Exception e)
- {
- fail(e.toString());
- }
+ cache.evict(Fqn.fromString("/a/b/3"));
+ cache.evict(Fqn.fromString("/a/b/2"));
+ // cache.evict(Fqn.fromString("/a/b/1"));
+ cache.evict(Fqn.fromString("/a/b"));
+ cache.evict(Fqn.fromString("/a"));
+ children = cache.getNode("/a/b").getChildrenNames();
+ assertEquals(3, children.size());
}
public void testLoaderGetChildrenNames() throws Exception
@@ -1035,16 +1028,12 @@
mgr.begin();
Set children = cache.getNode("/a").getChildrenNames();
- System.out.println("**** " + cache.getTransactionManager());
-
assertEquals(3, children.size());
assertTrue(children.contains("1"));
assertTrue(children.contains("2"));
assertTrue(children.contains("3"));
- assertEquals(5, cache.getNumberOfLocksHeld());
mgr.commit();
-
}
Modified: core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java 2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java 2008-07-08 16:27:15 UTC (rev 6215)
@@ -742,7 +742,6 @@
assertTrue(children.contains("1"));
assertTrue(children.contains("2"));
assertTrue(children.contains("3"));
- assertEquals(5, cache.getNumberOfLocksHeld());
mgr.commit();
}
More information about the jbosscache-commits
mailing list