Details
Description
Looks pretty textbook deadlook to me. I think the _sessionIdManager should be the outermost lock through which threads arrive to do their stuff. In this case however the removeSession releases _sessionIdManager too early.
Found one Java-level deadlock:
=============================
"17758642@qtp-24109300-249":
waiting to lock monitor 0x096d883c (object 0x5c17ce90, a org.mortbay.jetty.servlet.HashSessionIdManager),
which is held by "Timer-3"
"Timer-3":
waiting to lock monitor 0x0b997a1c (object 0x60d4c980, a java.util.HashMap),
which is held by "Timer-6"
"Timer-6":
waiting to lock monitor 0x096d883c (object 0x5c17ce90, a org.mortbay.jetty.servlet.HashSessionIdManager),
which is held by "Timer-3"
Java stack information for the threads listed above:
===================================================
"17758642@qtp-24109300-249":
at org.mortbay.jetty.servlet.HashSessionIdManager.newSessionId(HashSessionIdManager.java:219)
- waiting to lock <0x5c17ce90> (a org.mortbay.jetty.servlet.HashSessionIdManager)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.<init>(AbstractSessionManager.java:753)
at org.mortbay.jetty.servlet.HashSessionManager$Session.<init>(HashSessionManager.java:511)
at org.mortbay.jetty.servlet.HashSessionManager.newSession(HashSessionManager.java:345)
at org.mortbay.jetty.servlet.AbstractSessionManager.newHttpSession(AbstractSessionManager.java:413)
at org.mortbay.jetty.Request.getSession(Request.java:1158)
at org.mortbay.jetty.Request.getSession(Request.java:1130)
at com.liferay.portal.servlet.filters.virtualhost.VirtualHostFilter.doFilter(VirtualHostFilter.java:118)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1148)
at com.liferay.portal.kernel.servlet.BaseFilter.processFilter(BaseFilter.java:154)
at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:94)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1148)
at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:738)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1148)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:387)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:534)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:864)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:390)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:520)
"Timer-3":
at com.liferay.portal.kernel.servlet.PortletSessionTracker._invalidate(PortletSessionTracker.java:90) - waiting to lock <0x60d4c980> (a java.util.HashMap)
at com.liferay.portal.kernel.servlet.PortletSessionTracker.invalidate(PortletSessionTracker.java:59)
at com.liferay.portal.kernel.servlet.PortletSessionTracker.valueUnbound(PortletSessionTracker.java:66)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.unbindValue(AbstractSessionManager.java:1129)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.removeAttribute(AbstractSessionManager.java:1023) - locked <0x6dfb98a8> (a org.mortbay.jetty.servlet.HashSessionManager$Session)
at com.liferay.portal.servlet.PortalSessionListener.sessionDestroyed(PortalSessionListener.java:124)
at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:665)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.invalidate(AbstractSessionManager.java:938)
at org.mortbay.jetty.servlet.HashSessionManager$Session.invalidate(HashSessionManager.java:536)
at org.mortbay.jetty.servlet.HashSessionIdManager.invalidateAll(HashSessionIdManager.java:198) - locked <0x5c17ce90> (a org.mortbay.jetty.servlet.HashSessionIdManager)
at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:657) - locked <0x5c17ce90> (a org.mortbay.jetty.servlet.HashSessionIdManager)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.timeout(AbstractSessionManager.java:922)
at org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:283)
at org.mortbay.jetty.servlet.HashSessionManager.access$000(HashSessionManager.java:44)
at org.mortbay.jetty.servlet.HashSessionManager$2.run(HashSessionManager.java:217)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
"Timer-6":
at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:638) - waiting to lock <0x5c17ce90> (a org.mortbay.jetty.servlet.HashSessionIdManager)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.invalidate(AbstractSessionManager.java:938)
at org.mortbay.jetty.servlet.HashSessionManager$Session.invalidate(HashSessionManager.java:536)
at com.liferay.util.servlet.SharedSessionWrapper.invalidate(SharedSessionWrapper.java:138)
at com.liferay.portal.kernel.servlet.PortletSessionTracker._invalidate(PortletSessionTracker.java:100) - locked <0x60d4c980> (a java.util.HashMap)
at com.liferay.portal.kernel.servlet.PortletSessionTracker.invalidate(PortletSessionTracker.java:59)
at com.liferay.portal.kernel.servlet.PortletSessionTracker.valueUnbound(PortletSessionTracker.java:66)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.unbindValue(AbstractSessionManager.java:1129)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.removeAttribute(AbstractSessionManager.java:1023) - locked <0x6ca72ad0> (a org.mortbay.jetty.servlet.HashSessionManager$Session)
at com.liferay.portal.servlet.PortalSessionListener.sessionDestroyed(PortalSessionListener.java:124)
at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:665)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.timeout(AbstractSessionManager.java:922)
at org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:283)
at org.mortbay.jetty.servlet.HashSessionManager.access$000(HashSessionManager.java:44)
at org.mortbay.jetty.servlet.HashSessionManager$2.run(HashSessionManager.java:217)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
Found 1 deadlock.
I've fixed this by extending the synchronized (_sessionIdManager) block to cover a bit more of the removeSession method.
/* ------------------------------------------------------------ */
/** Remove session from manager
- @param session The session to remove
- @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
- {@link SessionIdManager#invalidateAll(String)} should be called.
*/
public void removeSession(Session session, boolean invalidate)
{
// Remove session from context and global maps
synchronized (_sessionIdManager)
{
boolean removed = false;
synchronized (this)
{
//take this session out of the map of sessions for this context
if (getSession(session.getClusterId()) != null)
}
if (removed)
{ // Remove session from all context and global id maps _sessionIdManager.removeSession(session); if (invalidate) _sessionIdManager.invalidateAll(session.getClusterId()); }if (invalidate && _sessionListeners!=null)
{ HttpSessionEvent event=new HttpSessionEvent(session); for (int i=LazyList.size(_sessionListeners); i-->0;) ((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionDestroyed(event); } }
if (!invalidate)
}
Extends the syncronization block in AbstractSessionManager removeSession to cover some more stuff.