/** * Tries to passivate the instance. If the instance is in use and passivateAfterCommit parameter * is true then the instance will passivated after the transaction commits. Otherwise, the * instance will be passivated later according to the container's commit option and max age. */ protected void tryToPassivate(EnterpriseContext ctx, boolean passivateAfterCommit) { Object id = ctx.getId(); if (id == null) return; BeanLock lock = getContainer().getLockManager().getLock(id); boolean lockedBean = false; try { /* If this is a BeanLockExt only attempt the lock as the call to remove is going to have to acquire the cache lock, but this may already be held since this method is called by passivation policies without the cache lock. This can lead to a deadlock as in the case of a size based eviction during a cache get attempts to lock the bean that has been locked by an age based background thread as seen in bug 987389 on sourceforge. */ if (lock instanceof BeanLockExt) { BeanLockExt lock2 = (BeanLockExt) lock; lockedBean = lock2.attemptSync(); if (lockedBean == false) { unableToPassivateDueToCtxLock(ctx, passivateAfterCommit); return; } } else { // Use the blocking sync lock.sync(); lockedBean = true; } if (canPassivate(ctx)) { try { remove(id); passivate(ctx); freeContext(ctx); } catch (Exception ignored) { log.warn("failed to passivate, id=" + id, ignored); } } else { // Touch the entry to make it MRU synchronized (getCacheLock()) { getCache().get(id); } unableToPassivateDueToCtxLock(ctx, passivateAfterCommit); } } finally { if (lockedBean) lock.releaseSync(); getContainer().getLockManager().removeLockRef(id); } }
protected void unableToPassivateDueToCtxLock( EnterpriseContext ctx, boolean passivateAfterCommit) { log.warn("Unable to passivate due to ctx lock, id=" + ctx.getId()); }