* @return
* @throws Throwable
*/
public Object invoke(MethodCall call) throws Throwable
{
JBCMethodCall m = (JBCMethodCall) call;
Fqn fqn = null; // if set, load the data
Method meth = m.getMethod();
Object[] args = m.getArgs();
boolean acquireLock = false; // do we need to acquire a lock if we load this node from cloader?
Map nodeData = null;
boolean initNode = false; // keep uninitialized
Object key = null;
InvocationContext ctx = getInvocationContext();
TransactionEntry entry = null;
GlobalTransaction gtx = null;
if ((gtx = ctx.getGlobalTransaction()) != null)
{
entry = txTable.get(gtx);
}
if (log.isTraceEnabled())
log.trace("invoke " + m);
switch (m.getMethodId())
{
case MethodDeclarations.putDataEraseMethodLocal_id:
case MethodDeclarations.putDataMethodLocal_id:
fqn = (Fqn) args[1];
initNode = true;
break;
case MethodDeclarations.putKeyValMethodLocal_id:
fqn = (Fqn) args[1];
if (useCacheStore)
initNode = true;
else
acquireLock = true;
break;
case MethodDeclarations.addChildMethodLocal_id:
fqn = (Fqn) args[1];
break;
case MethodDeclarations.getKeyValueMethodLocal_id:
fqn = (Fqn) args[0];
key = args[1];
acquireLock = true;
break;
case MethodDeclarations.getNodeMethodLocal_id:
case MethodDeclarations.getKeysMethodLocal_id:
case MethodDeclarations.getChildrenNamesMethodLocal_id:
case MethodDeclarations.releaseAllLocksMethodLocal_id:
case MethodDeclarations.printMethodLocal_id:
fqn = (Fqn) args[0];
acquireLock = true;
break;
case MethodDeclarations.rollbackMethod_id:
// clean up nodesCreated map
cleanupNodesCreated(entry);
break;
default:
if (!useCacheStore)
{
if (m.getMethodId() == MethodDeclarations.removeKeyMethodLocal_id)
{
fqn = (Fqn) args[1];
}
else if (m.getMethodId() == MethodDeclarations.removeDataMethodLocal_id)
{
fqn = (Fqn) args[1];
initNode = true;
}
}
break;
}
/* On the way in: load elements into cache from the CacheLoader if not yet in the cache. We need to synchronize
this so only 1 thread attempts to load a given element */
if (fqn != null)
{
DataNode n = cache.peek(fqn);
if (log.isTraceEnabled())
log.trace("load element " + fqn + " mustLoad=" + mustLoad(n, key));
if (mustLoad(n, key))
{
if (initNode)
{
n = createTempNode(fqn, entry);
}
// 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, DataNode.LOCK_TYPE_WRITE, false); // not recursive
if (!initNode && !wasRemovedInTx(fqn))
{
n = loadNode(fqn, n, entry);
}
}
// The complete list of children aren't known without loading them
if (m.getMethodId() == MethodDeclarations.getChildrenNamesMethodLocal_id)
{
loadChildren(fqn, n);
}
}