Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x

This commit is contained in:
Jan Bartel 2019-01-30 14:26:52 +11:00
commit e789cd6834
3 changed files with 109 additions and 69 deletions

View File

@ -616,12 +616,10 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
{ {
//get the session, if its not in memory, this will load it //get the session, if its not in memory, this will load it
Session session = get(id); Session session = get(id);
//Always delete it from the backing data store //Always delete it from the backing data store
if (_sessionDataStore != null) if (_sessionDataStore != null)
{ {
boolean dsdel = _sessionDataStore.delete(id); boolean dsdel = _sessionDataStore.delete(id);
if (LOG.isDebugEnabled()) LOG.debug("Session {} deleted in session data store {}",id, dsdel); if (LOG.isDebugEnabled()) LOG.debug("Session {} deleted in session data store {}",id, dsdel);
} }
@ -635,10 +633,6 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
return doDelete(id); return doDelete(id);
} }
/** /**
* @see org.eclipse.jetty.server.session.SessionCache#checkExpiration(Set) * @see org.eclipse.jetty.server.session.SessionCache#checkExpiration(Set)

View File

@ -116,7 +116,6 @@ public class Session implements SessionHandler.SessionIf
public class SessionInactivityTimer public class SessionInactivityTimer
{ {
protected final CyclicTimeout _timer; protected final CyclicTimeout _timer;
protected long _msec = -1;
public SessionInactivityTimer() public SessionInactivityTimer()
{ {
@ -127,31 +126,45 @@ public class Session implements SessionHandler.SessionIf
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Timer expired for session {}", getId()); LOG.debug("Timer expired for session {}", getId());
getSessionHandler().sessionInactivityTimerExpired(Session.this); long now = System.currentTimeMillis();
//handle what to do with the session after the timer expired
getSessionHandler().sessionInactivityTimerExpired(Session.this, now);
try (Lock lock = Session.this.lock())
{
//grab the lock and check what happened to the session: if it didn't get evicted and
//it hasn't expired, we need to reset the timer
if (Session.this.isResident() && Session.this.getRequests() <= 0 && Session.this.isValid() && !Session.this.isExpiredAt(now))
{
//session wasn't expired or evicted, we need to reset the timer
SessionInactivityTimer.this.schedule(Session.this.calculateInactivityTimeout(now));
}
}
} }
}; };
} }
/** /**
* @param ms the timeout to set; -1 means that the timer will not be * For backward api compatibility only.
* scheduled * @see #schedule(long)
*/ */
public void setTimeout(long ms) @Deprecated
public void schedule ()
{ {
_msec = ms; schedule(calculateInactivityTimeout(System.currentTimeMillis()));
if (LOG.isDebugEnabled())
LOG.debug("Session {} timer={}ms", getId(), ms);
} }
public void schedule() /**
* @param time the timeout to set; -1 means that the timer will not be
* scheduled
*/
public void schedule (long time)
{ {
if (_msec > 0) if (time >= 0)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("(Re)starting timer for session {} at {}ms", getId(), _msec); LOG.debug("(Re)starting timer for session {} at {}ms", getId(), time);
_timer.schedule(_msec, TimeUnit.MILLISECONDS); _timer.schedule(time, TimeUnit.MILLISECONDS);
} }
else else
{ {
@ -279,9 +292,15 @@ public class Session implements SessionHandler.SessionIf
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Session {} complete, active requests={}", getId(), _requests); LOG.debug("Session {} complete, active requests={}", getId(), _requests);
// start the inactivity timer // start the inactivity timer if necessary
if (_requests == 0) if (_requests == 0)
_sessionInactivityTimer.schedule(); {
//update the expiry time to take account of the time all requests spent inside of the
//session.
long now = System.currentTimeMillis();
_sessionData.calcAndSetExpiry(now);
_sessionInactivityTimer.schedule(calculateInactivityTimeout(now));
}
} }
} }
@ -513,7 +532,7 @@ public class Session implements SessionHandler.SessionIf
_sessionData.setMaxInactiveMs((long) secs * 1000L); _sessionData.setMaxInactiveMs((long) secs * 1000L);
_sessionData.calcAndSetExpiry(); _sessionData.calcAndSetExpiry();
_sessionData.setDirty(true); _sessionData.setDirty(true);
updateInactivityTimer();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
{ {
if (secs <= 0) if (secs <= 0)
@ -524,14 +543,29 @@ public class Session implements SessionHandler.SessionIf
} }
} }
/**
* Set the inactivity timer to the smaller of the session maxInactivity (ie @Deprecated
* session-timeout from web.xml), or the inactive eviction time. public void updateInactivityTimer()
*/
public void updateInactivityTimer()
{ {
//for backward api compatibility only
}
/**
* Calculate what the session timer setting should be based on:
* the time remaining before the session expires
* and any idle eviction time configured.
* The timer value will be the lesser of the above.
*
* @param now the time at which to calculate remaining expiry
* @return the time remaining before expiry or inactivity timeout
*/
public long calculateInactivityTimeout (long now)
{
long time = 0;
try (Lock lock = _lock.lock()) try (Lock lock = _lock.lock())
{ {
long remaining = _sessionData.getExpiry() - now;
long maxInactive = _sessionData.getMaxInactiveMs(); long maxInactive = _sessionData.getMaxInactiveMs();
int evictionPolicy = getSessionHandler().getSessionCache().getEvictionPolicy(); int evictionPolicy = getSessionHandler().getSessionCache().getEvictionPolicy();
@ -541,7 +575,7 @@ public class Session implements SessionHandler.SessionIf
if (evictionPolicy < SessionCache.EVICT_ON_INACTIVITY) if (evictionPolicy < SessionCache.EVICT_ON_INACTIVITY)
{ {
// we do not want to evict inactive sessions // we do not want to evict inactive sessions
_sessionInactivityTimer.setTimeout(-1); time = -1;
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Session {} is immortal && no inactivity eviction", getId()); LOG.debug("Session {} is immortal && no inactivity eviction", getId());
} }
@ -549,7 +583,7 @@ public class Session implements SessionHandler.SessionIf
{ {
// sessions are immortal but we want to evict after // sessions are immortal but we want to evict after
// inactivity // inactivity
_sessionInactivityTimer.setTimeout(TimeUnit.SECONDS.toMillis(evictionPolicy)); time = TimeUnit.SECONDS.toMillis(evictionPolicy);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Session {} is immortal; evict after {} sec inactivity", getId(), evictionPolicy); LOG.debug("Session {} is immortal; evict after {} sec inactivity", getId(), evictionPolicy);
} }
@ -559,31 +593,33 @@ public class Session implements SessionHandler.SessionIf
// sessions are not immortal // sessions are not immortal
if (evictionPolicy == SessionCache.NEVER_EVICT) if (evictionPolicy == SessionCache.NEVER_EVICT)
{ {
// timeout is just the maxInactive setting // timeout is the time remaining until its expiry
_sessionInactivityTimer.setTimeout(_sessionData.getMaxInactiveMs()); time = (remaining > 0 ? remaining : 0);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Session {} no eviction", getId()); LOG.debug("Session {} no eviction", getId());
} }
else if (evictionPolicy == SessionCache.EVICT_ON_SESSION_EXIT) else if (evictionPolicy == SessionCache.EVICT_ON_SESSION_EXIT)
{ {
// session will not remain in the cache, so no timeout // session will not remain in the cache, so no timeout
_sessionInactivityTimer.setTimeout(-1); time = -1;
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Session {} evict on exit", getId()); LOG.debug("Session {} evict on exit", getId());
} }
else else
{ {
// want to evict on idle: timer is lesser of the session's // want to evict on idle: timer is lesser of the session's
// maxInactive and eviction timeout // expiration remaining and the time to evict
_sessionInactivityTimer.setTimeout(Math.min(maxInactive, TimeUnit.SECONDS.toMillis(evictionPolicy))); time = (remaining > 0 ? (Math.min(maxInactive, TimeUnit.SECONDS.toMillis(evictionPolicy))) : 0);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Session {} timer set to lesser of maxInactive={} and inactivityEvict={}", getId(), maxInactive, evictionPolicy); LOG.debug("Session {} timer set to lesser of maxInactive={} and inactivityEvict={}", getId(), maxInactive, evictionPolicy);
} }
} }
} }
return time;
} }
/** /**
* @see javax.servlet.http.HttpSession#getMaxInactiveInterval() * @see javax.servlet.http.HttpSession#getMaxInactiveInterval()
*/ */
@ -963,16 +999,6 @@ public class Session implements SessionHandler.SessionIf
return _lock.lock(); return _lock.lock();
} }
/* ------------------------------------------------------------- */
/**
* Grab the lock on the session if it isn't locked already
*
* @return the lock
*/
public Lock lockIfNotHeld()
{
return _lock.lock();
}
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
/** /**
@ -1132,13 +1158,14 @@ public class Session implements SessionHandler.SessionIf
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
/**
* @param resident
*/
public void setResident(boolean resident) public void setResident(boolean resident)
{ {
_resident = resident; _resident = resident;
if (_resident) if (!_resident)
updateInactivityTimer();
else
_sessionInactivityTimer.destroy(); _sessionInactivityTimer.destroy();
} }

View File

@ -1372,6 +1372,17 @@ public class SessionHandler extends ScopedHandler
} }
} }
/**
* @see #sessionInactivityTimerExpired(Session, long)
*/
@Deprecated
public void sessionInactivityTimerExpired (Session session)
{
//for backwards compilation compatibility only
sessionInactivityTimerExpired(session, System.currentTimeMillis());
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Each session has a timer that is configured to go off * Each session has a timer that is configured to go off
@ -1379,20 +1390,28 @@ public class SessionHandler extends ScopedHandler
* configurable amount of time, or the session itself * configurable amount of time, or the session itself
* has passed its expiry. * has passed its expiry.
* *
* If it has passed its expiry, then we will mark it for
* scavenging by next run of the HouseKeeper; if it has
* been idle longer than the configured eviction period,
* we evict from the cache.
*
* If none of the above are true, then the System timer
* is inconsistent and the caller of this method will
* need to reset the timer.
*
* @param session the session * @param session the session
* @param now the time at which to check for expiry
*/ */
public void sessionInactivityTimerExpired (Session session) public void sessionInactivityTimerExpired (Session session, long now)
{ {
if (session == null) if (session == null)
return; return;
//check if the session is: //check if the session is:
//1. valid //1. valid
//2. expired //2. expired
//3. idle //3. idle
boolean expired = false; try (Lock lock = session.lock())
try (Lock lock = session.lockIfNotHeld())
{ {
if (session.getRequests() > 0) if (session.getRequests() > 0)
return; //session can't expire or be idle if there is a request in it return; //session can't expire or be idle if there is a request in it
@ -1402,27 +1421,27 @@ public class SessionHandler extends ScopedHandler
if (!session.isValid()) if (!session.isValid())
return; //do nothing, session is no longer valid return; //do nothing, session is no longer valid
if (session.isExpiredAt(System.currentTimeMillis()) && session.getRequests() <=0)
expired = true;
}
if (expired) if (session.isExpiredAt(now))
{
//instead of expiring the session directly here, accumulate a list of
//session ids that need to be expired. This is an efficiency measure: as
//the expiration involves the SessionDataStore doing a delete, it is
//most efficient if it can be done as a bulk operation to eg reduce
//roundtrips to the persistent store. Only do this if the HouseKeeper that
//does the scavenging is configured to actually scavenge
if (_sessionIdManager.getSessionHouseKeeper() != null && _sessionIdManager.getSessionHouseKeeper().getIntervalSec() > 0)
{ {
_candidateSessionIdsForExpiry.add(session.getId()); //instead of expiring the session directly here, accumulate a list of
if (LOG.isDebugEnabled())LOG.debug("Session {} is candidate for expiry", session.getId()); //session ids that need to be expired. This is an efficiency measure: as
//the expiration involves the SessionDataStore doing a delete, it is
//most efficient if it can be done as a bulk operation to eg reduce
//roundtrips to the persistent store. Only do this if the HouseKeeper that
//does the scavenging is configured to actually scavenge
if (_sessionIdManager.getSessionHouseKeeper() != null && _sessionIdManager.getSessionHouseKeeper().getIntervalSec() > 0)
{
_candidateSessionIdsForExpiry.add(session.getId());
if (LOG.isDebugEnabled())LOG.debug("Session {} is candidate for expiry", session.getId());
}
}
else
{
//possibly evict the session
_sessionCache.checkInactiveSession(session);
} }
} }
else
_sessionCache.checkInactiveSession(session); //if inactivity eviction is enabled the session will be deleted from the cache
} }