481373 Corner cases where session may remain in JDBCSessionManager memory

This commit is contained in:
Jan Bartel 2015-11-04 17:23:01 +11:00
parent b102bd507a
commit c63ef3e08b
2 changed files with 128 additions and 17 deletions

View File

@ -1250,6 +1250,8 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
*/
private void scavenge ()
{
Set<String> candidateIds = getAllCandidateExpiredSessionIds();
Connection connection = null;
try
{
@ -1283,7 +1285,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
}
}
}
scavengeSessions(expiredSessionIds, false);
scavengeSessions(candidateIds, expiredSessionIds, false);
//Pass 2: find sessions that have expired a while ago for which this node was their last manager
@ -1306,7 +1308,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
if (LOG.isDebugEnabled()) LOG.debug ("Found expired sessionId="+sessionId+" last managed by "+getWorkerName());
}
}
scavengeSessions(expiredSessionIds, false);
scavengeSessions(candidateIds, expiredSessionIds, false);
}
@ -1329,9 +1331,13 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
if (LOG.isDebugEnabled()) LOG.debug ("Found expired sessionId="+sessionId);
}
}
scavengeSessions(expiredSessionIds, true);
scavengeSessions(candidateIds, expiredSessionIds, true);
}
}
//Tell session managers to check remaining sessions in memory that may have expired
//but are no longer in the database
scavengeSessions(candidateIds);
}
}
catch (Exception e)
@ -1363,24 +1369,20 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
/**
* @param expiredSessionIds
*/
private void scavengeSessions (Set<String> expiredSessionIds, boolean forceDelete)
private void scavengeSessions (Set<String> candidateIds, Set<String> expiredSessionIds, boolean forceDelete)
{
Set<String> remainingIds = new HashSet<String>(expiredSessionIds);
Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
for (int i=0; contexts!=null && i<contexts.length; i++)
Set<SessionManager> managers = getAllSessionManagers();
for (SessionManager m:managers)
{
SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
if (sessionHandler != null)
Set<String> successfullyExpiredIds = ((JDBCSessionManager)m).expire(expiredSessionIds);
if (successfullyExpiredIds != null)
{
SessionManager manager = sessionHandler.getSessionManager();
if (manager != null && manager instanceof JDBCSessionManager)
{
Set<String> successfullyExpiredIds = ((JDBCSessionManager)manager).expire(expiredSessionIds);
if (successfullyExpiredIds != null)
remainingIds.removeAll(successfullyExpiredIds);
}
remainingIds.removeAll(successfullyExpiredIds);
candidateIds.removeAll(successfullyExpiredIds);
}
}
//Any remaining ids are of those sessions that no context removed
if (!remainingIds.isEmpty() && forceDelete)
@ -1402,6 +1404,63 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
}
}
}
/**
* These are the session ids that the session managers thought had
* expired, but were not expired in the database. This could be
* because the session is live on another node, or that the
* session no longer exists in the database because some other
* node removed it.
* @param candidateIds
*/
private void scavengeSessions (Set<String> candidateIds)
{
if (candidateIds.isEmpty())
return;
Set<SessionManager> managers = getAllSessionManagers();
for (SessionManager m:managers)
{
//tell the session managers to check the sessions that have expired in memory
//if they are no longer in the database, they should be removed
((JDBCSessionManager)m).expireCandidates(candidateIds);
}
}
private Set<String> getAllCandidateExpiredSessionIds()
{
HashSet<String> candidateIds = new HashSet<>();
Set<SessionManager> managers = getAllSessionManagers();
for (SessionManager m:managers)
{
candidateIds.addAll(((JDBCSessionManager)m).getCandidateExpiredIds());
}
return candidateIds;
}
private Set<SessionManager> getAllSessionManagers()
{
HashSet<SessionManager> managers = new HashSet<>();
Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
for (int i=0; contexts!=null && i<contexts.length; i++)
{
SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
if (sessionHandler != null)
{
SessionManager manager = sessionHandler.getSessionManager();
if (manager != null && manager instanceof JDBCSessionManager)
managers.add(manager);
}
}
return managers;
}
@ -1411,7 +1470,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
{
if (expiredIds == null || expiredIds.isEmpty())
return;
String[] ids = expiredIds.toArray(new String[expiredIds.size()]);
try (Connection con = getConnection())
{

View File

@ -569,6 +569,11 @@ public class JDBCSessionManager extends AbstractSessionManager
}
else
{
if (memSession != null)
{
//Session must have been removed from db by another node
removeSession(memSession, true);
}
//No session in db with matching id and context path.
LOG.debug("getSession({}): No session in database matching id={}",idInCluster,idInCluster);
}
@ -866,7 +871,54 @@ public class JDBCSessionManager extends AbstractSessionManager
}
}
protected void expireCandidates (Set<String> candidateIds)
{
Iterator<String> itor = candidateIds.iterator();
long now = System.currentTimeMillis();
while (itor.hasNext())
{
String id = itor.next();
//check if expired in db
try
{
Session memSession = _sessions.get(id);
if (memSession == null)
{
continue; //no longer in memory
}
Session s = loadSession(id, canonicalize(_context.getContextPath()), getVirtualHost(_context));
if (s == null)
{
//session no longer exists, can be safely expired
memSession.timeout();
}
}
catch (Exception e)
{
LOG.warn("Error checking db for expiry for session {}", id);
}
}
}
protected Set<String> getCandidateExpiredIds ()
{
HashSet<String> expiredIds = new HashSet<>();
Iterator<String> itor = _sessions.keySet().iterator();
while (itor.hasNext())
{
String id = itor.next();
//check to see if session should have expired
Session session = _sessions.get(id);
if (session._expiryTime > 0 && System.currentTimeMillis() > session._expiryTime)
expiredIds.add(id);
}
return expiredIds;
}
/**
* Load a session from the database
* @param id the id