Implement uniform expiry testing for all datastores, FileDataStore still todo.
This commit is contained in:
parent
5fa6bf4c10
commit
303aea96a3
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.server.session.AbstractSessionDataStore;
|
|||
import org.eclipse.jetty.server.session.SessionContext;
|
||||
import org.eclipse.jetty.server.session.SessionData;
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
@ -78,11 +79,6 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
private KeyFactory _keyFactory;
|
||||
private int _maxResults = DEFAULT_MAX_QUERY_RESULTS;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -189,57 +185,90 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getExpired(Set<String> candidates)
|
||||
public Set<String> doGetExpired(Set<String> candidates, int expiryTimeoutSec)
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
Set<String> expired = new HashSet<String>();
|
||||
|
||||
//get up to maxResult number of sessions that have expired
|
||||
ProjectionEntityQueryBuilder pbuilder = Query.projectionEntityQueryBuilder();
|
||||
pbuilder.addProjection(Projection.property(ID));
|
||||
pbuilder.filter(CompositeFilter.and(PropertyFilter.gt(EXPIRY, 0), PropertyFilter.le(EXPIRY, now)));
|
||||
pbuilder.limit(_maxResults);
|
||||
pbuilder.kind(KIND);
|
||||
StructuredQuery<ProjectionEntity> pquery = pbuilder.build();
|
||||
QueryResults<ProjectionEntity> presults = _datastore.run(pquery);
|
||||
|
||||
while (presults.hasNext())
|
||||
{
|
||||
ProjectionEntity pe = presults.next();
|
||||
String id = pe.getString(ID);
|
||||
expired.add(id);
|
||||
}
|
||||
|
||||
//reconcile against ids that the SessionStore thinks are expired
|
||||
Set<String> tmp = new HashSet<String>(candidates);
|
||||
tmp.removeAll(expired);
|
||||
if (!tmp.isEmpty())
|
||||
{
|
||||
//sessionstore thinks these are expired, but they are either no
|
||||
//longer in the db or not expired in the db, or we exceeded the
|
||||
//number of records retrieved by the expiry query, so check them
|
||||
//individually
|
||||
for (String s:tmp)
|
||||
{
|
||||
try
|
||||
{
|
||||
KeyQueryBuilder kbuilder = Query.keyQueryBuilder();
|
||||
kbuilder.filter(PropertyFilter.eq(ID, s));
|
||||
kbuilder.kind(KIND);
|
||||
StructuredQuery<Key> kq = kbuilder.build();
|
||||
QueryResults<Key> kresults = _datastore.run(kq);
|
||||
if (!kresults.hasNext())
|
||||
expired.add(s); //not in db, can be expired
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return expired;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
Set<String> expired = new HashSet<String>();
|
||||
|
||||
try
|
||||
{
|
||||
//get up to maxResult number of sessions that have expired
|
||||
ProjectionEntityQueryBuilder pbuilder = Query.projectionEntityQueryBuilder();
|
||||
pbuilder.addProjection(Projection.property(ID), Projection.property(LASTNODE), Projection.property(EXPIRY));
|
||||
pbuilder.filter(CompositeFilter.and(PropertyFilter.gt(EXPIRY, 0), PropertyFilter.le(EXPIRY, now)));
|
||||
pbuilder.limit(_maxResults);
|
||||
pbuilder.kind(KIND);
|
||||
StructuredQuery<ProjectionEntity> pquery = pbuilder.build();
|
||||
QueryResults<ProjectionEntity> presults = _datastore.run(pquery);
|
||||
|
||||
while (presults.hasNext())
|
||||
{
|
||||
ProjectionEntity pe = presults.next();
|
||||
String id = pe.getString(ID);
|
||||
String lastNode = pe.getString(LASTNODE);
|
||||
long expiry = pe.getLong(EXPIRY);
|
||||
|
||||
if (StringUtil.isBlank(lastNode))
|
||||
expired.add(id); //nobody managing it
|
||||
else
|
||||
{
|
||||
if (_context.getWorkerName().equals(lastNode))
|
||||
expired.add(id); //we're managing it, we can expire it
|
||||
else
|
||||
{
|
||||
if (_lastExpiryCheckTime <= 0)
|
||||
{
|
||||
//our first check, just look for sessions that we managed by another node that
|
||||
//expired at least 3 graceperiods ago
|
||||
if (expiry < (now - (1000L * (3 * _gracePeriodSec))))
|
||||
expired.add(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
//another node was last managing it, only expire it if it expired a graceperiod ago
|
||||
if (expiry < (now - (1000L * _gracePeriodSec)))
|
||||
expired.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//reconcile against ids that the SessionStore thinks are expired
|
||||
Set<String> tmp = new HashSet<String>(candidates);
|
||||
tmp.removeAll(expired);
|
||||
if (!tmp.isEmpty())
|
||||
{
|
||||
//sessionstore thinks these are expired, but they are either no
|
||||
//longer in the db or not expired in the db, or we exceeded the
|
||||
//number of records retrieved by the expiry query, so check them
|
||||
//individually
|
||||
for (String s:tmp)
|
||||
{
|
||||
try
|
||||
{
|
||||
KeyQueryBuilder kbuilder = Query.keyQueryBuilder();
|
||||
kbuilder.filter(PropertyFilter.eq(ID, s));
|
||||
kbuilder.kind(KIND);
|
||||
StructuredQuery<Key> kq = kbuilder.build();
|
||||
QueryResults<Key> kresults = _datastore.run(kq);
|
||||
if (!kresults.hasNext())
|
||||
expired.add(s); //not in db, can be expired
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return expired;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return expired; //return what we got
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -297,6 +326,8 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
oos.writeObject(session.getAllAttributes());
|
||||
oos.flush();
|
||||
|
||||
try
|
||||
{
|
||||
//turn a session into an entity
|
||||
entity = Entity.builder(key)
|
||||
.set(ID, session.getId())
|
||||
|
@ -310,6 +341,12 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
.set(EXPIRY, session.getExpiry())
|
||||
.set(MAXINACTIVE, session.getMaxInactiveMs())
|
||||
.set(ATTRIBUTES, Blob.copyFrom(baos.toByteArray())).build();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getExpired(Set<String> candidates)
|
||||
public Set<String> doGetExpired(Set<String> candidates, int expiryTimeoutSec)
|
||||
{
|
||||
if (candidates == null || candidates.isEmpty())
|
||||
return candidates;
|
||||
|
@ -143,6 +143,9 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
Set<String> expired = new HashSet<String>();
|
||||
|
||||
//TODO if there is NOT an idle timeout set, need to check other sessions that
|
||||
//might have expired
|
||||
|
||||
for (String candidate:candidates)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -151,12 +154,43 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
|
|||
{
|
||||
SessionData sd = load(candidate);
|
||||
|
||||
if (sd == null || sd.isExpiredAt(now))
|
||||
//if the session no longer exists
|
||||
if (sd == null)
|
||||
{
|
||||
expired.add(candidate);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Is null {} is expired {}", (sd==null), (sd !=null));
|
||||
}
|
||||
LOG.debug("Session {} does not exist in infinispan", candidate);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_context.getWorkerName().equals(sd.getLastNode()))
|
||||
{
|
||||
//we are its manager, add it to the expired set if it is expired now
|
||||
if ((sd.getExpiry() > 0 ) && sd.getExpiry() <= now)
|
||||
{
|
||||
expired.add(candidate);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Session {} managed by {} is expired", candidate, _context.getWorkerName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//if we are not the session's manager, only expire it iff:
|
||||
// this is our first expiryCheck and the session expired a long time ago
|
||||
//or
|
||||
//the session expired at least one graceperiod ago
|
||||
if (_lastExpiryCheckTime <=0)
|
||||
{
|
||||
if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * (3 * _gracePeriodSec))))
|
||||
expired.add(candidate);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * _gracePeriodSec)))
|
||||
expired.add(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -193,6 +227,11 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static String getCacheKey (String id, SessionContext context)
|
||||
{
|
||||
return context.getCanonicalContextPath()+"_"+context.getVhost()+"_"+id;
|
||||
|
@ -224,11 +263,17 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* @param sec the infinispan-specific idle timeout in sec or 0 if not set
|
||||
*/
|
||||
public void setInfinispanIdleTimeoutSec (int sec)
|
||||
{
|
||||
_infinispanIdleTimeoutSec = sec;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int getInfinispanIdleTimeoutSec ()
|
||||
{
|
||||
return _infinispanIdleTimeoutSec;
|
||||
|
|
|
@ -153,8 +153,6 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
private DBCollection _dbSessions;
|
||||
|
||||
|
||||
private long _gracePeriodMs = 1000L * 60 * 60; //default grace period is 1hr
|
||||
|
||||
public void setDBCollection (DBCollection collection)
|
||||
{
|
||||
_dbSessions = collection;
|
||||
|
@ -169,24 +167,7 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
return _dbSessions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int getGracePeriodSec ()
|
||||
{
|
||||
return (int)(_gracePeriodMs == 0L? 0 : _gracePeriodMs/1000L);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sec
|
||||
*/
|
||||
public void setGracePeriodSec (int sec)
|
||||
{
|
||||
if (sec < 0)
|
||||
_gracePeriodMs = 0;
|
||||
else
|
||||
_gracePeriodMs = sec * 1000L;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.SessionDataStore#load(org.eclipse.jetty.server.session.SessionKey)
|
||||
|
@ -342,12 +323,14 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getExpired(Set<String> candidates)
|
||||
public Set<String> doGetExpired(Set<String> candidates, int expiryTimeoutSec)
|
||||
{
|
||||
long upperBound = System.currentTimeMillis();
|
||||
long now = System.currentTimeMillis();
|
||||
long upperBound = now;
|
||||
Set<String> expiredSessions = new HashSet<>();
|
||||
|
||||
//firstly ask mongo to verify if these candidate ids have expired
|
||||
//firstly ask mongo to verify if these candidate ids have expired - all of
|
||||
//these candidates will be for our node
|
||||
BasicDBObject query = new BasicDBObject();
|
||||
query.put(__ID,new BasicDBObject("$in", candidates));
|
||||
query.put(__EXPIRY, new BasicDBObject("$gt", 0));
|
||||
|
@ -369,9 +352,13 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
if (verifiedExpiredSessions != null) verifiedExpiredSessions.close();
|
||||
}
|
||||
|
||||
|
||||
//now ask mongo to find sessions that expired a while ago
|
||||
upperBound = upperBound - (3 * _gracePeriodMs);
|
||||
//now ask mongo to find sessions last managed by other nodes that expired a while ago
|
||||
//if this is our first expiry check, make sure that we only grab really old sessions
|
||||
if (_lastExpiryCheckTime <= 0)
|
||||
upperBound = (now - (3*(1000L * _gracePeriodSec)));
|
||||
else
|
||||
upperBound = _lastExpiryCheckTime - (1000L * _gracePeriodSec);
|
||||
|
||||
query.clear();
|
||||
query.put(__EXPIRY, new BasicDBObject("$gt", 0));
|
||||
query.put(__EXPIRY, new BasicDBObject("$lt", upperBound));
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
package org.eclipse.jetty.server.session;
|
||||
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
|
||||
/**
|
||||
|
@ -30,6 +32,8 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
|||
public abstract class AbstractSessionDataStore extends AbstractLifeCycle implements SessionDataStore
|
||||
{
|
||||
protected SessionContext _context; //context associated with this session data store
|
||||
protected int _gracePeriodSec = 60 * 60; //default of 1hr
|
||||
protected long _lastExpiryCheckTime = 0; //last time in ms that getExpired was called
|
||||
|
||||
|
||||
/**
|
||||
|
@ -43,6 +47,16 @@ public abstract class AbstractSessionDataStore extends AbstractLifeCycle impleme
|
|||
public abstract void doStore(String id, SessionData data, long lastSaveTime) throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
* Implemented by subclasses to resolve which sessions this node
|
||||
* should attempt to expire.
|
||||
*
|
||||
* @param candidates the ids of sessions the SessionStore thinks has expired
|
||||
* @param scavengePeriodSec the period in sec of the scavenge cycle checks
|
||||
* @return the reconciled set of session ids that this node should attempt to expire
|
||||
* @throws Exception
|
||||
*/
|
||||
public abstract Set<String> doGetExpired (Set<String> candidates, int scavengePeriodSec);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -81,6 +95,25 @@ public abstract class AbstractSessionDataStore extends AbstractLifeCycle impleme
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set, int)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getExpired(Set<String> candidates, int scavengePeriodSec)
|
||||
{
|
||||
try
|
||||
{
|
||||
return doGetExpired (candidates, scavengePeriodSec);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lastExpiryCheckTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.SessionDataStore#newSessionData(java.lang.String, long, long, long, long)
|
||||
*/
|
||||
|
@ -110,7 +143,29 @@ public abstract class AbstractSessionDataStore extends AbstractLifeCycle impleme
|
|||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int getGracePeriodSec()
|
||||
{
|
||||
return _gracePeriodSec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param sec
|
||||
*/
|
||||
public void setGracePeriodSec(int sec)
|
||||
{
|
||||
_gracePeriodSec = sec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -565,7 +565,7 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
|
|||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("SessionStore checking expiration on {}", candidates);
|
||||
return _sessionDataStore.getExpired(candidates);
|
||||
return _sessionDataStore.getExpired(candidates, _expiryTimeoutSec);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ public class CachingSessionDataStore extends AbstractSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getExpired(Set<String> candidates)
|
||||
public Set<String> doGetExpired(Set<String> candidates, int expiryTimeoutSec)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
|
|
|
@ -114,7 +114,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getExpired(Set<String> candidates)
|
||||
public Set<String> doGetExpired(Set<String> candidates, int expiryTimeoutSec)
|
||||
{
|
||||
//we don't want to open up each file and check, so just leave it up to the SessionStore
|
||||
//TODO as the session manager is likely to be a lazy loader, if a session is never requested, its
|
||||
|
|
|
@ -58,8 +58,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
private int _attempts = -1; // <= 0 means unlimited attempts to load a session
|
||||
private boolean _deleteUnloadables = false; //true means if attempts exhausted delete the session
|
||||
private long _gracePeriodMs = 1000L * 60 * 60; //default grace period is 1hr
|
||||
|
||||
|
||||
/**
|
||||
* SessionTableSchema
|
||||
*
|
||||
|
@ -285,7 +284,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
|
||||
|
||||
public PreparedStatement getMyExpiredSessionsStatement (Connection connection, String canonicalContextPath, String vhost, long expiry)
|
||||
public PreparedStatement getExpiredSessionsStatement (Connection connection, String canonicalContextPath, String vhost, long expiry)
|
||||
throws SQLException
|
||||
{
|
||||
if (_dbAdaptor == null)
|
||||
|
@ -317,6 +316,42 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
return statement;
|
||||
}
|
||||
|
||||
|
||||
public PreparedStatement getMyExpiredSessionsStatement (Connection connection, SessionContext sessionContext, long expiry)
|
||||
throws SQLException
|
||||
{
|
||||
if (_dbAdaptor == null)
|
||||
throw new IllegalStateException("No DB adaptor");
|
||||
|
||||
if (sessionContext.getCanonicalContextPath() == null || "".equals(sessionContext.getCanonicalContextPath()))
|
||||
{
|
||||
if (_dbAdaptor.isEmptyStringNull())
|
||||
{
|
||||
PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getExpiryTimeColumn()+
|
||||
" from "+getTableName()+" where "+
|
||||
getLastNodeColumn() + " = ? and "+
|
||||
getContextPathColumn()+" is null and "+
|
||||
getVirtualHostColumn()+" = ? and "+getExpiryTimeColumn()+" >0 and "+getExpiryTimeColumn()+" <= ?");
|
||||
statement.setString(1, sessionContext.getWorkerName());
|
||||
statement.setString(2, sessionContext.getVhost());
|
||||
statement.setLong(3, expiry);
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
|
||||
PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getExpiryTimeColumn()+
|
||||
" from "+getTableName()+" where "+
|
||||
getLastNodeColumn()+" = ? and "+
|
||||
getContextPathColumn()+" = ? and "+
|
||||
getVirtualHostColumn()+" = ? and "+
|
||||
getExpiryTimeColumn()+" >0 and "+getExpiryTimeColumn()+" <= ?");
|
||||
|
||||
statement.setString(1, sessionContext.getWorkerName());
|
||||
statement.setString(2, sessionContext.getCanonicalContextPath());
|
||||
statement.setString(3, sessionContext.getVhost());
|
||||
statement.setLong(4, expiry);
|
||||
return statement;
|
||||
}
|
||||
|
||||
|
||||
public PreparedStatement getAllAncientExpiredSessionsStatement (Connection connection)
|
||||
|
@ -804,6 +839,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private void doUpdate (String id, SessionData data)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -854,27 +890,26 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getExpired(Set<String> candidates)
|
||||
public Set<String> doGetExpired(Set<String> candidates, int scavengeIntervalSec)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Getting expired sessions "+System.currentTimeMillis());
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
|
||||
Set<String> expiredSessionKeys = new HashSet<>();
|
||||
try (Connection connection = _dbAdaptor.getConnection())
|
||||
{
|
||||
connection.setAutoCommit(true);
|
||||
|
||||
/*
|
||||
* 1. Select sessions for our context that have expired
|
||||
* 1. Select sessions managed by this node for our context that have expired
|
||||
*/
|
||||
long upperBound = now;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug ("{}- Pass 1: Searching for sessions for context {} expired before {}", _context.getWorkerName(), _context.getCanonicalContextPath(), upperBound);
|
||||
LOG.debug ("{}- Pass 1: Searching for sessions for context {} managed by me {} and expired before {}", _context.getCanonicalContextPath(), _context.getWorkerName(), upperBound);
|
||||
|
||||
try (PreparedStatement statement = _sessionTableSchema.getMyExpiredSessionsStatement(connection, _context.getCanonicalContextPath(), _context.getVhost(), upperBound))
|
||||
try (PreparedStatement statement = _sessionTableSchema.getExpiredSessionsStatement(connection, _context.getCanonicalContextPath(), _context.getVhost(), upperBound))
|
||||
{
|
||||
try (ResultSet result = statement.executeQuery())
|
||||
{
|
||||
|
@ -889,30 +924,33 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
|
||||
/*
|
||||
* 2. Select sessions for any node or context that have expired a long time ago (ie at least 3 grace periods ago)
|
||||
* 2. Select sessions for any node or context that have expired
|
||||
* at least 1 graceperiod since the last expiry check. If we haven't done previous expiry checks, then check
|
||||
* those that have expired at least 3 graceperiod ago.
|
||||
*/
|
||||
try (PreparedStatement selectExpiredSessions = _sessionTableSchema.getAllAncientExpiredSessionsStatement(connection))
|
||||
{
|
||||
upperBound = now - (3 * _gracePeriodMs);
|
||||
if (upperBound > 0)
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("{}- Pass 2: Searching for sessions expired before {}",_context.getWorkerName(), upperBound);
|
||||
if (_lastExpiryCheckTime <= 0)
|
||||
upperBound = (now - (3*(1000L * _gracePeriodSec)));
|
||||
else
|
||||
upperBound = _lastExpiryCheckTime - (1000L * _gracePeriodSec);
|
||||
|
||||
selectExpiredSessions.setLong(1, upperBound);
|
||||
try (ResultSet result = selectExpiredSessions.executeQuery())
|
||||
if (LOG.isDebugEnabled()) LOG.debug("{}- Pass 2: Searching for sessions expired before {}",_context.getWorkerName(), upperBound);
|
||||
|
||||
selectExpiredSessions.setLong(1, upperBound);
|
||||
try (ResultSet result = selectExpiredSessions.executeQuery())
|
||||
{
|
||||
while (result.next())
|
||||
{
|
||||
while (result.next())
|
||||
{
|
||||
String sessionId = result.getString(_sessionTableSchema.getIdColumn());
|
||||
String ctxtpth = result.getString(_sessionTableSchema.getContextPathColumn());
|
||||
String vh = result.getString(_sessionTableSchema.getVirtualHostColumn());
|
||||
expiredSessionKeys.add(sessionId);
|
||||
if (LOG.isDebugEnabled()) LOG.debug ("{}- Found expired sessionId=",_context.getWorkerName(), sessionId);
|
||||
}
|
||||
String sessionId = result.getString(_sessionTableSchema.getIdColumn());
|
||||
String ctxtpth = result.getString(_sessionTableSchema.getContextPathColumn());
|
||||
String vh = result.getString(_sessionTableSchema.getVirtualHostColumn());
|
||||
expiredSessionKeys.add(sessionId);
|
||||
if (LOG.isDebugEnabled()) LOG.debug ("{}- Found expired sessionId=",_context.getWorkerName(), sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Set<String> notExpiredInDB = new HashSet<>();
|
||||
for (String k: candidates)
|
||||
|
@ -958,44 +996,48 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
LOG.warn(e);
|
||||
return expiredSessionKeys; //return whatever we got
|
||||
}
|
||||
|
||||
}
|
||||
public int getGracePeriodSec ()
|
||||
{
|
||||
return (int)(_gracePeriodMs == 0L? 0 : _gracePeriodMs/1000L);
|
||||
}
|
||||
|
||||
public void setGracePeriodSec (int sec)
|
||||
{
|
||||
if (sec < 0)
|
||||
_gracePeriodMs = 0;
|
||||
else
|
||||
_gracePeriodMs = sec * 1000L;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dbAdaptor
|
||||
*/
|
||||
public void setDatabaseAdaptor (DatabaseAdaptor dbAdaptor)
|
||||
{
|
||||
checkStarted();
|
||||
_dbAdaptor = dbAdaptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param schema
|
||||
*/
|
||||
public void setSessionTableSchema (SessionTableSchema schema)
|
||||
{
|
||||
checkStarted();
|
||||
_sessionTableSchema = schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attempts
|
||||
*/
|
||||
public void setLoadAttempts (int attempts)
|
||||
{
|
||||
checkStarted();
|
||||
_attempts = attempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int getLoadAttempts ()
|
||||
{
|
||||
return _attempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public boolean loadAttemptsExhausted (String id)
|
||||
{
|
||||
AtomicInteger i = _unloadables.get(id);
|
||||
|
@ -1004,18 +1046,27 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
return (i.get() >= _attempts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param delete
|
||||
*/
|
||||
public void setDeleteUnloadableSessions (boolean delete)
|
||||
{
|
||||
checkStarted();
|
||||
_deleteUnloadables = delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if we should delete data for sessions that we cant reconstitute
|
||||
*/
|
||||
public boolean isDeleteUnloadableSessions ()
|
||||
{
|
||||
return _deleteUnloadables;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param id
|
||||
*/
|
||||
protected void incLoadAttempt (String id)
|
||||
{
|
||||
AtomicInteger i = new AtomicInteger(0);
|
||||
|
@ -1027,6 +1078,10 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @return number of attempts to load the given id
|
||||
*/
|
||||
public int getLoadAttempts (String id)
|
||||
{
|
||||
AtomicInteger i = _unloadables.get(id);
|
||||
|
@ -1035,15 +1090,21 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
return i.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return how many sessions we've failed to load
|
||||
*/
|
||||
public Set<String> getUnloadableSessions ()
|
||||
{
|
||||
return new HashSet<String>(_unloadables.keySet());
|
||||
}
|
||||
|
||||
public void clearUnloadableSessions()
|
||||
{
|
||||
_unloadables.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void clearUnloadableSessions()
|
||||
{
|
||||
_unloadables.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ public class NullSessionDataStore extends AbstractSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getExpired(Set<String> candidates)
|
||||
public Set<String> doGetExpired(Set<String> candidates, int expiryTimeoutSec)
|
||||
{
|
||||
return candidates; //whatever is suggested we accept
|
||||
}
|
||||
|
|
|
@ -433,4 +433,23 @@ public class SessionData implements Serializable
|
|||
|
||||
return (getExpiry() < time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("id="+_id);
|
||||
builder.append(", contextpath="+_contextPath);
|
||||
builder.append(", vhost="+_vhost);
|
||||
builder.append(", accessed="+_accessed);
|
||||
builder.append(", lastaccessed="+_lastAccessed);
|
||||
builder.append(", created="+_created);
|
||||
builder.append(", cookieset="+_cookieSet);
|
||||
builder.append(", lastnode="+_lastNode);
|
||||
builder.append(", expiry="+_expiry);
|
||||
builder.append(", maxinactive="+_maxInactiveMs);
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ public interface SessionDataStore extends LifeCycle
|
|||
* SessionDataStore
|
||||
* @return set of session ids
|
||||
*/
|
||||
public Set<String> getExpired (Set<String> candidates);
|
||||
public Set<String> getExpired (Set<String> candidates, int scavengePeriodSec);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ public abstract class AbstractSessionInvalidateAndCreateTest
|
|||
assertTrue(listener.destroys.contains("session1"));
|
||||
assertTrue(listener.destroys.contains("session2"));
|
||||
//session2's HttpSessionBindingListener should have been called when it was scavenged
|
||||
assertTrue(servlet.unbound);
|
||||
assertTrue(servlet.listener.unbound);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -151,24 +151,33 @@ public abstract class AbstractSessionInvalidateAndCreateTest
|
|||
server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Foo implements Serializable
|
||||
{
|
||||
public boolean bar = false;
|
||||
|
||||
public boolean getBar() { return bar;};
|
||||
}
|
||||
|
||||
public static class TestServlet extends HttpServlet
|
||||
public static class MySessionBindingListener implements HttpSessionBindingListener, Serializable
|
||||
{
|
||||
private boolean unbound = false;
|
||||
|
||||
public class MySessionBindingListener implements HttpSessionBindingListener, Serializable
|
||||
public void valueUnbound(HttpSessionBindingEvent event)
|
||||
{
|
||||
unbound = true;
|
||||
}
|
||||
|
||||
public void valueBound(HttpSessionBindingEvent event)
|
||||
{
|
||||
|
||||
public void valueUnbound(HttpSessionBindingEvent event)
|
||||
{
|
||||
unbound = true;
|
||||
}
|
||||
|
||||
public void valueBound(HttpSessionBindingEvent event)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestServlet extends HttpServlet
|
||||
{
|
||||
public MySessionBindingListener listener = new MySessionBindingListener();
|
||||
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
|
||||
|
@ -190,7 +199,7 @@ public abstract class AbstractSessionInvalidateAndCreateTest
|
|||
//now make a new session
|
||||
session = request.getSession(true);
|
||||
session.setAttribute("identity", "session2");
|
||||
session.setAttribute("listener", new MySessionBindingListener());
|
||||
session.setAttribute("listener", listener);
|
||||
}
|
||||
else
|
||||
fail("Session already missing");
|
||||
|
|
Loading…
Reference in New Issue