If only a few threads are waiting on a lock for an entity bean to free
up, the file size of server.log explodes with LOCKING-WAITING messages.
(server.log got up to 250 meg in only a 10 minute period with only a few
concurrent threads hitting JBoss). I fixed this so that only one
LOCKING-WAITING message is outputed per locking thread. When the thread
finally aquires the lock, it outputs a FINISHED-LOCKING-WAITING
message. Attached is the changes I made.
BTW, this message is EXTREMLY useful in finding deadlock I read on the
archive that you guys were thinking of removing the message.
in org.jboss.ejb.plugins.EntityInstanceInterceptor I changed the invoke
method.
public Object invoke(MethodInvocation mi)
throws Exception
{
// The id store is a CacheKey in the case of Entity
CacheKey key = (CacheKey)mi.getId();
// Get cache
AbstractInstanceCache cache =
(AbstractInstanceCache)container.getInstanceCache();
Sync mutex = (Sync)cache.getLock(key);
EnterpriseContext ctx = null;
try
{
boolean waitingOnTransaction = false; // So we don't output
LOCKING-WAITING all the time
boolean waitingOnContext = false; // So we don't output
LOCKING-WAITING all the time
do
{
if (mi.getTransaction() != null &&
mi.getTransaction().getStatus() == Status.STATUS_MARKED_ROLLBACK)
throw new RuntimeException("Transaction marked for
rollback, possibly a timeout");
try
{
mutex.acquire();
// Get context
ctx = cache.get(key);
// Do we have a running transaction with the context
Transaction tx = ctx.getTransaction();
if (tx != null &&
// And are we trying to enter with another
transaction
!tx.equals(mi.getTransaction()))
{
// Let's put the thread to sleep a lock release
will wake the thread
// Possible deadlock
if (!waitingOnTransaction)
{
Logger.debug("LOCKING-WAITING (TRANSACTION)
for id "+ctx.getId()+" ctx.hash "+ctx.hashCode()+" tx:"+((tx == null) ?
"null" : tx.toString()));
waitingOnTransaction = true;
}
// Try your luck again
ctx = null;
continue;
}
else
{
if (waitingOnTransaction)
{
Logger.debug("FINISHED-LOCKING-WAITING
(TRANSACTION) for id "+ctx.getId()+" ctx.hash "+ctx.hashCode()+"
tx:"+((tx == null) ? "null" : tx.toString()));
waitingOnTransaction = false;
}
// If we get here it's the right tx, or no tx
if (!ctx.isLocked())
{
//take it!
ctx.lock();
}
else
{
if (!isCallAllowed(mi)) {
// Go to sleep and wait for the lock to
be released
// This is not one of the "home calls" so
we need to wait for the lock
// Possible deadlock
if (!waitingOnContext) {
Logger.debug("LOCKING-WAITING (CTX)
for id "+ctx.getId()+" ctx.hash "+ctx.hashCode());
waitingOnContext = true;
}
// Try your luck again
ctx = null;
continue;
// Not allowed reentrant call
//throw new RemoteException("Reentrant
call");
}
else
{
if (waitingOnContext) {
Logger.debug("FINISHED-LOCKING-WAITING (CTX) for id "+ctx.getId()+"
ctx.hash "+ctx.hashCode());
waitingOnContext = false;
}
//We are in a home call so take the lock,
take it!
ctx.lock();
}
}
}
}
catch (InterruptedException ignored) {}
finally
{
mutex.release();
}
} while (ctx == null);
// Set context on the method invocation
mi.setEnterpriseContext(ctx);
// Go on, you won
return getNext().invoke(mi);
}
catch (RemoteException e)
{
// Discard instance
// EJB 1.1 spec 12.3.1
cache.remove(key);
throw e;
} catch (RuntimeException e)
{
// Discard instance
// EJB 1.1 spec 12.3.1
cache.remove(key);
throw e;
} catch (Error e)
{
// Discard instance
// EJB 1.1 spec 12.3.1
cache.remove(key);
throw e;
} finally
{
// Logger.debug("Release instance for "+id);
// ctx can be null if cache.get throws an Exception, for
// example when activating a bean.
if (ctx != null)
{
try
{
mutex.acquire();
// unlock the context
ctx.unlock();
if (ctx.getId() == null)
{
// Work only if no transaction was encapsulating
this remove()
if (ctx.getTransaction() == null)
{
// Here we arrive if the bean has been
removed and no
// transaction was associated with the
remove, or if
// the bean has been passivated
// Remove from cache
cache.remove(key);
// It has been removed -> send to the pool
container.getInstancePool().free(ctx);
}
else
{
// We want to remove the bean, but it has a
Tx associated with
// the remove() method. We remove it from the
cache, to avoid
// that a successive insertion with same pk
will break the
// cache. Anyway we don't free the context,
since the tx must
// finish. The EnterpriseContext instance
will be GC and not
// recycled.
cache.remove(key);
}
}
else
{
// Yeah, do nothing
}
}
catch (InterruptedException ignored) {}
finally
{
mutex.release();
}
}
}
}
_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/jboss-development