diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java index 74454132f3a..836c357b99b 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java @@ -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 getExpired(Set candidates) + public Set doGetExpired(Set candidates, int expiryTimeoutSec) { - long now = System.currentTimeMillis(); - Set expired = new HashSet(); - - //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 pquery = pbuilder.build(); - QueryResults 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 tmp = new HashSet(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 kq = kbuilder.build(); - QueryResults 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 expired = new HashSet(); + + 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 pquery = pbuilder.build(); + QueryResults 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 tmp = new HashSet(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 kq = kbuilder.build(); + QueryResults 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; } diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java index e7611aab8d7..64c693a2084 100644 --- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java +++ b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java @@ -134,7 +134,7 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore * @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set) */ @Override - public Set getExpired(Set candidates) + public Set doGetExpired(Set candidates, int expiryTimeoutSec) { if (candidates == null || candidates.isEmpty()) return candidates; @@ -143,6 +143,9 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore Set expired = new HashSet(); + //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; diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java index 329c72c5162..b3cd1f793b7 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java @@ -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 getExpired(Set candidates) + public Set doGetExpired(Set candidates, int expiryTimeoutSec) { - long upperBound = System.currentTimeMillis(); + long now = System.currentTimeMillis(); + long upperBound = now; Set 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)); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java index ec9e90f3a59..d7bfee1f831 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java @@ -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 doGetExpired (Set 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 getExpired(Set 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; + } + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionStore.java index 4eece0bd65a..eaab680d220 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionStore.java @@ -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); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/CachingSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/CachingSessionDataStore.java index fe16f6aa966..d4ff31ee570 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/CachingSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/CachingSessionDataStore.java @@ -119,7 +119,7 @@ public class CachingSessionDataStore extends AbstractSessionDataStore * @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set) */ @Override - public Set getExpired(Set candidates) + public Set doGetExpired(Set candidates, int expiryTimeoutSec) { // TODO Auto-generated method stub return null; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/FileSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/FileSessionDataStore.java index 6c26b6fe640..9c7a3913b48 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/FileSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/FileSessionDataStore.java @@ -114,7 +114,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore * @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set) */ @Override - public Set getExpired(Set candidates) + public Set doGetExpired(Set 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 diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java index a60f74d2367..fc32eaf8458 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java @@ -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 getExpired(Set candidates) + public Set doGetExpired(Set candidates, int scavengeIntervalSec) { if (LOG.isDebugEnabled()) LOG.debug("Getting expired sessions "+System.currentTimeMillis()); long now = System.currentTimeMillis(); - Set 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 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 getUnloadableSessions () { return new HashSet(_unloadables.keySet()); } - - public void clearUnloadableSessions() - { - _unloadables.clear(); - } + + /** + * + */ + public void clearUnloadableSessions() + { + _unloadables.clear(); + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionDataStore.java index 78f4004102e..18730723459 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionDataStore.java @@ -72,7 +72,7 @@ public class NullSessionDataStore extends AbstractSessionDataStore * @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(java.util.Set) */ @Override - public Set getExpired(Set candidates) + public Set doGetExpired(Set candidates, int expiryTimeoutSec) { return candidates; //whatever is suggested we accept } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java index 3f05b08aca1..b96b4773a97 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java @@ -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(); + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionDataStore.java index 367d6f549d7..80ea9836553 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionDataStore.java @@ -95,7 +95,7 @@ public interface SessionDataStore extends LifeCycle * SessionDataStore * @return set of session ids */ - public Set getExpired (Set candidates); + public Set getExpired (Set candidates, int scavengePeriodSec); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java index 4e98e91f87e..b1c1d4286cc 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java @@ -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");