diff options
Diffstat (limited to 'jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java')
-rw-r--r-- | jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java | 605 |
1 files changed, 33 insertions, 572 deletions
diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java index e078b9a8d3..9cad23464f 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java @@ -20,93 +20,40 @@ package org.eclipse.jetty.nosql.mongodb; import java.net.UnknownHostException; -import java.util.HashSet; -import java.util.Iterator; import java.util.Random; import java.util.Set; -import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.SessionManager; -import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.session.AbstractSessionIdManager; -import org.eclipse.jetty.server.session.SessionHandler; +import org.eclipse.jetty.server.session.Session; import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; -import org.eclipse.jetty.util.thread.Scheduler; import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObjectBuilder; import com.mongodb.DBCollection; -import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.mongodb.Mongo; import com.mongodb.MongoException; /** - * Based partially on the JDBCSessionIdManager. - * <p> - * Theory is that we really only need the session id manager for the local - * instance so we have something to scavenge on, namely the list of known ids - * <p> - * This class has a timer that runs a periodic scavenger thread to query - * for all id's known to this node whose precalculated expiry time has passed. - * <p> - * These found sessions are then run through the invalidateAll(id) method that - * is a bit hinky but is supposed to notify all handlers this id is now DOA and - * ought to be cleaned up. this ought to result in a save operation on the session - * that will change the valid field to false (this conjecture is unvalidated atm) + * Manager of session ids based on sessions stored in Mongo. + * */ public class MongoSessionIdManager extends AbstractSessionIdManager { - private final static Logger __log = Log.getLogger("org.eclipse.jetty.server.session"); + private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); - final static DBObject __version_1 = new BasicDBObject(MongoSessionManager.__VERSION,1); - final static DBObject __valid_false = new BasicDBObject(MongoSessionManager.__VALID,false); - final static DBObject __valid_true = new BasicDBObject(MongoSessionManager.__VALID,true); + final static DBObject __version_1 = new BasicDBObject(MongoSessionDataStore.__VERSION,1); + final static DBObject __valid_false = new BasicDBObject(MongoSessionDataStore.__VALID,false); + final static DBObject __valid_true = new BasicDBObject(MongoSessionDataStore.__VALID,true); + final static DBObject __expiry = new BasicDBObject(MongoSessionDataStore.__EXPIRY, 1); - final static long __defaultScavengePeriod = 30 * 60 * 1000; // every 30 minutes - final DBCollection _sessions; - protected Server _server; - private Scheduler _scheduler; - private boolean _ownScheduler; - private Scheduler.Task _scavengerTask; - private Scheduler.Task _purgerTask; - - - - private long _scavengePeriod = __defaultScavengePeriod; - - - /** - * purge process is enabled by default - */ - private boolean _purge = true; - - /** - * purge process would run daily by default - */ - private long _purgeDelay = 24 * 60 * 60 * 1000; // every day - - /** - * how long do you want to persist sessions that are no longer - * valid before removing them completely - */ - private long _purgeInvalidAge = 24 * 60 * 60 * 1000; // default 1 day - - /** - * how long do you want to leave sessions that are still valid before - * assuming they are dead and removing them - */ - private long _purgeValidAge = 7 * 24 * 60 * 60 * 1000; // default 1 week /** @@ -114,57 +61,7 @@ public class MongoSessionIdManager extends AbstractSessionIdManager */ protected final Set<String> _sessionsIds = new ConcurrentHashSet<>(); - /** - * The maximum number of items to return from a purge query. - */ - private int _purgeLimit = 0; - - private int _scavengeBlockSize; - - - /** - * Scavenger - * - */ - protected class Scavenger implements Runnable - { - @Override - public void run() - { - try - { - scavenge(); - } - finally - { - if (_scheduler != null && _scheduler.isRunning()) - _scavengerTask = _scheduler.schedule(this, _scavengePeriod, TimeUnit.MILLISECONDS); - } - } - } - - - /** - * Purger - * - */ - protected class Purger implements Runnable - { - @Override - public void run() - { - try - { - purge(); - } - finally - { - if (_scheduler != null && _scheduler.isRunning()) - _purgerTask = _scheduler.schedule(this, _purgeDelay, TimeUnit.MILLISECONDS); - } - } - } - + @@ -177,9 +74,8 @@ public class MongoSessionIdManager extends AbstractSessionIdManager /* ------------------------------------------------------------ */ public MongoSessionIdManager(Server server, DBCollection sessions) { - super(new Random()); + super(server, new Random()); - _server = server; _sessions = sessions; _sessions.ensureIndex( @@ -193,187 +89,10 @@ public class MongoSessionIdManager extends AbstractSessionIdManager // so that we can take advantage of index prefixes // http://docs.mongodb.org/manual/core/index-compound/#compound-index-prefix _sessions.ensureIndex( - BasicDBObjectBuilder.start().add(MongoSessionManager.__VALID, 1).add(MongoSessionManager.__ACCESSED, 1).get(), + BasicDBObjectBuilder.start().add(MongoSessionDataStore.__VALID, 1).add(MongoSessionDataStore.__ACCESSED, 1).get(), BasicDBObjectBuilder.start().add("sparse", false).add("background", true).get()); } - /* ------------------------------------------------------------ */ - /** - * Scavenge is a process that periodically checks the tracked session - * ids of this given instance of the session id manager to see if they - * are past the point of expiration. - */ - protected void scavenge() - { - long now = System.currentTimeMillis(); - __log.debug("SessionIdManager:scavenge:at {}", now); - /* - * run a query returning results that: - * - are in the known list of sessionIds - * - the expiry time has passed - * - * we limit the query to return just the __ID so we are not sucking back full sessions - * - * break scavenge query into blocks for faster mongo queries - */ - Set<String> block = new HashSet<String>(); - - Iterator<String> itor = _sessionsIds.iterator(); - while (itor.hasNext()) - { - block.add(itor.next()); - if ((_scavengeBlockSize > 0) && (block.size() == _scavengeBlockSize)) - { - //got a block - scavengeBlock (now, block); - //reset for next run - block.clear(); - } - } - - //non evenly divisble block size, or doing it all at once - if (!block.isEmpty()) - scavengeBlock(now, block); - } - - - /* ------------------------------------------------------------ */ - /** - * Check a block of session ids for expiry and thus scavenge. - * - * @param atTime purge at time - * @param ids set of session ids - */ - protected void scavengeBlock (long atTime, Set<String> ids) - { - if (ids == null) - return; - - BasicDBObject query = new BasicDBObject(); - query.put(MongoSessionManager.__ID,new BasicDBObject("$in", ids )); - query.put(MongoSessionManager.__EXPIRY, new BasicDBObject("$gt", 0)); - query.put(MongoSessionManager.__EXPIRY, new BasicDBObject("$lt", atTime)); - - DBCursor checkSessions = _sessions.find(query, new BasicDBObject(MongoSessionManager.__ID, 1)); - - for ( DBObject session : checkSessions ) - { - __log.debug("SessionIdManager:scavenge: expiring session {}", (String)session.get(MongoSessionManager.__ID)); - expireAll((String)session.get(MongoSessionManager.__ID)); - } - } - - /* ------------------------------------------------------------ */ - /** - * ScavengeFully will expire all sessions. In most circumstances - * you should never need to call this method. - * - * <b>USE WITH CAUTION</b> - */ - protected void scavengeFully() - { - __log.debug("SessionIdManager:scavengeFully"); - - DBCursor checkSessions = _sessions.find(); - - for (DBObject session : checkSessions) - { - expireAll((String)session.get(MongoSessionManager.__ID)); - } - - } - - /* ------------------------------------------------------------ */ - /** - * Purge is a process that cleans the mongodb cluster of old sessions that are no - * longer valid. - * - * There are two checks being done here: - * - * - if the accessed time is older than the current time minus the purge invalid age - * and it is no longer valid then remove that session - * - if the accessed time is older then the current time minus the purge valid age - * then we consider this a lost record and remove it - * - * NOTE: if your system supports long lived sessions then the purge valid age should be - * set to zero so the check is skipped. - * - * The second check was added to catch sessions that were being managed on machines - * that might have crashed without marking their sessions as 'valid=false' - */ - protected void purge() - { - __log.debug("PURGING"); - BasicDBObject invalidQuery = new BasicDBObject(); - - invalidQuery.put(MongoSessionManager.__VALID, false); - invalidQuery.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _purgeInvalidAge)); - - DBCursor oldSessions = _sessions.find(invalidQuery, new BasicDBObject(MongoSessionManager.__ID, 1)); - - if (_purgeLimit > 0) - { - oldSessions.limit(_purgeLimit); - } - - for (DBObject session : oldSessions) - { - String id = (String)session.get("id"); - - __log.debug("MongoSessionIdManager:purging invalid session {}", id); - - _sessions.remove(session); - } - - if (_purgeValidAge != 0) - { - BasicDBObject validQuery = new BasicDBObject(); - - validQuery.put(MongoSessionManager.__VALID, true); - validQuery.put(MongoSessionManager.__ACCESSED,new BasicDBObject("$lt",System.currentTimeMillis() - _purgeValidAge)); - - oldSessions = _sessions.find(validQuery,new BasicDBObject(MongoSessionManager.__ID,1)); - - if (_purgeLimit > 0) - { - oldSessions.limit(_purgeLimit); - } - - for (DBObject session : oldSessions) - { - String id = (String)session.get(MongoSessionManager.__ID); - - __log.debug("MongoSessionIdManager:purging valid session {}", id); - - _sessions.remove(session); - } - } - - } - - /* ------------------------------------------------------------ */ - /** - * Purge is a process that cleans the mongodb cluster of old sessions that are no - * longer valid. - * - */ - protected void purgeFully() - { - BasicDBObject invalidQuery = new BasicDBObject(); - invalidQuery.put(MongoSessionManager.__VALID, false); - - DBCursor oldSessions = _sessions.find(invalidQuery, new BasicDBObject(MongoSessionManager.__ID, 1)); - - for (DBObject session : oldSessions) - { - String id = (String)session.get(MongoSessionManager.__ID); - - __log.debug("MongoSessionIdManager:purging invalid session {}", id); - - _sessions.remove(session); - } - - } /* ------------------------------------------------------------ */ @@ -382,192 +101,20 @@ public class MongoSessionIdManager extends AbstractSessionIdManager return _sessions; } - - /* ------------------------------------------------------------ */ - public boolean isPurgeEnabled() - { - return _purge; - } - - /* ------------------------------------------------------------ */ - public void setPurge(boolean purge) - { - this._purge = purge; - } - - - /* ------------------------------------------------------------ */ - /** - * The period in seconds between scavenge checks. - * - * @param scavengePeriod the scavenge period in seconds - */ - public void setScavengePeriod(long scavengePeriod) - { - if (scavengePeriod <= 0) - _scavengePeriod = __defaultScavengePeriod; - else - _scavengePeriod = TimeUnit.SECONDS.toMillis(scavengePeriod); - } - - /* ------------------------------------------------------------ */ - /** When scavenging, the max number of session ids in the query. - * - * @param size the scavenge block size - */ - public void setScavengeBlockSize (int size) - { - _scavengeBlockSize = size; - } - - /* ------------------------------------------------------------ */ - public int getScavengeBlockSize () - { - return _scavengeBlockSize; - } - - - /* ------------------------------------------------------------ */ - /** - * The maximum number of items to return from a purge query. If <= 0 there is no limit. Defaults to 0 - * - * @param purgeLimit the purge limit - */ - public void setPurgeLimit(int purgeLimit) - { - _purgeLimit = purgeLimit; - } - - /* ------------------------------------------------------------ */ - public int getPurgeLimit() - { - return _purgeLimit; - } - - - - /* ------------------------------------------------------------ */ - public void setPurgeDelay(long purgeDelay) - { - if ( isRunning() ) - { - throw new IllegalStateException(); - } - - this._purgeDelay = purgeDelay; - } - - /* ------------------------------------------------------------ */ - public long getPurgeInvalidAge() - { - return _purgeInvalidAge; - } - - /* ------------------------------------------------------------ */ - /** - * sets how old a session is to be persisted past the point it is - * no longer valid - * @param purgeValidAge the purge valid age - */ - public void setPurgeInvalidAge(long purgeValidAge) - { - this._purgeInvalidAge = purgeValidAge; - } - - /* ------------------------------------------------------------ */ - public long getPurgeValidAge() - { - return _purgeValidAge; - } - - /* ------------------------------------------------------------ */ - /** - * sets how old a session is to be persist past the point it is - * considered no longer viable and should be removed - * - * NOTE: set this value to 0 to disable purging of valid sessions - * @param purgeValidAge the purge valid age - */ - public void setPurgeValidAge(long purgeValidAge) - { - this._purgeValidAge = purgeValidAge; - } /* ------------------------------------------------------------ */ @Override protected void doStart() throws Exception { - __log.debug("MongoSessionIdManager:starting"); - - - synchronized (this) - { - //try and use a common scheduler, fallback to own - _scheduler =_server.getBean(Scheduler.class); - if (_scheduler == null) - { - _scheduler = new ScheduledExecutorScheduler(); - _ownScheduler = true; - _scheduler.start(); - } - else if (!_scheduler.isStarted()) - throw new IllegalStateException("Shared scheduler not started"); - - - //setup the scavenger thread - if (_scavengePeriod > 0) - { - if (_scavengerTask != null) - { - _scavengerTask.cancel(); - _scavengerTask = null; - } - - _scavengerTask = _scheduler.schedule(new Scavenger(), _scavengePeriod, TimeUnit.MILLISECONDS); - } - else if (__log.isDebugEnabled()) - __log.debug("Scavenger disabled"); - - - //if purging is enabled, setup the purge thread - if ( _purge ) - { - if (_purgerTask != null) - { - _purgerTask.cancel(); - _purgerTask = null; - } - _purgerTask = _scheduler.schedule(new Purger(), _purgeDelay, TimeUnit.MILLISECONDS); - } - else if (__log.isDebugEnabled()) - __log.debug("Purger disabled"); - } + if (LOG.isDebugEnabled()) LOG.debug("MongoSessionIdManager:starting"); + super.doStart(); } /* ------------------------------------------------------------ */ @Override protected void doStop() throws Exception { - synchronized (this) - { - if (_scavengerTask != null) - { - _scavengerTask.cancel(); - _scavengerTask = null; - } - - if (_purgerTask != null) - { - _purgerTask.cancel(); - _purgerTask = null; - } - - if (_ownScheduler && _scheduler != null) - { - _scheduler.stop(); - _scheduler = null; - } - } + if (LOG.isDebugEnabled()) LOG.debug("MongoSessionIdManager:stopping"); super.doStop(); } @@ -576,20 +123,26 @@ public class MongoSessionIdManager extends AbstractSessionIdManager * Searches database to find if the session id known to mongo, and is it valid */ @Override - public boolean idInUse(String sessionId) + public boolean isIdInUse(String sessionId) { /* - * optimize this query to only return the valid variable + * optimize this query to only return the valid and expiry */ - DBObject o = _sessions.findOne(new BasicDBObject("id",sessionId), __valid_true); + DBObject fields = new BasicDBObject(); + fields.put(MongoSessionDataStore.__VALID, new Long(1)); + fields.put(MongoSessionDataStore.__EXPIRY, new Long(1)); + + DBObject o = _sessions.findOne(new BasicDBObject(MongoSessionDataStore.__ID,sessionId), fields); if ( o != null ) { - Boolean valid = (Boolean)o.get(MongoSessionManager.__VALID); + Boolean valid = (Boolean)o.get(MongoSessionDataStore.__VALID); if ( valid == null ) - { + return false; + + Long expiry = (Long)o.get(MongoSessionDataStore.__EXPIRY); + if (expiry < System.currentTimeMillis()) return false; - } return valid; } @@ -599,119 +152,27 @@ public class MongoSessionIdManager extends AbstractSessionIdManager /* ------------------------------------------------------------ */ @Override - public void addSession(HttpSession session) + public void useId(Session session) { if (session == null) - { return; - } /* * already a part of the index in mongo... */ - __log.debug("MongoSessionIdManager:addSession {}", session.getId()); - - _sessionsIds.add(session.getId()); - + LOG.debug("MongoSessionIdManager:addSession {}", session.getId()); } - - /* ------------------------------------------------------------ */ - @Override - public void removeSession(HttpSession session) - { - if (session == null) - { - return; - } - - _sessionsIds.remove(session.getId()); - } - - /* ------------------------------------------------------------ */ - /** Remove the session id from the list of in-use sessions. - * Inform all other known contexts that sessions with the same id should be - * invalidated. - * @see org.eclipse.jetty.server.SessionIdManager#invalidateAll(java.lang.String) - */ - @Override - public void invalidateAll(String sessionId) - { - _sessionsIds.remove(sessionId); - - //tell all contexts that may have a session object with this id to - //get rid of them - 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 MongoSessionManager) - { - ((MongoSessionManager)manager).invalidateSession(sessionId); - } - } - } - } /* ------------------------------------------------------------ */ - /** - * Expire this session for all contexts that are sharing the session - * id. - * @param sessionId the session id - */ - public void expireAll (String sessionId) - { - _sessionsIds.remove(sessionId); - - - //tell all contexts that may have a session object with this id to - //get rid of them - 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 MongoSessionManager) - { - ((MongoSessionManager)manager).expire(sessionId); - } - } - } - } - - /* ------------------------------------------------------------ */ @Override - public void renewSessionId(String oldClusterId, String oldNodeId, HttpServletRequest request) + public boolean removeId(String id) { - //generate a new id - String newClusterId = newSessionId(request.hashCode()); - - _sessionsIds.remove(oldClusterId);//remove the old one from the list - _sessionsIds.add(newClusterId); //add in the new session id to the list - - //tell all contexts to update the id - 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 MongoSessionManager) - { - ((MongoSessionManager)manager).renewSessionId(oldClusterId, oldNodeId, newClusterId, getNodeId(newClusterId, request)); - } - } - } + //The corresponding session document will be marked as expired or invalid? + return true; //can't distinguish first remove vs subsequent removes } + + } |