From 44416abb1f94806bb2896bc1a71afc68623f9c76 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Fri, 22 Nov 2013 19:22:44 +1100 Subject: [PATCH] 422308 Change all session/sessionid managers to use shared Scheduler --- .../nosql/mongodb/MongoSessionIdManager.java | 175 ++++++++++-------- .../server/session/HashSessionManager.java | 112 +++++++---- .../server/session/JDBCSessionIdManager.java | 65 +++++-- .../session/HashSessionManagerTest.java | 6 + .../jetty/nosql/mongodb/MongoTestServer.java | 1 - 5 files changed, 230 insertions(+), 129 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 f8e7418b915..1771d3d085c 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 @@ -38,6 +38,8 @@ import org.eclipse.jetty.server.session.AbstractSessionIdManager; import org.eclipse.jetty.server.session.SessionHandler; 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; @@ -69,20 +71,18 @@ public class MongoSessionIdManager extends AbstractSessionIdManager final static DBObject __valid_false = new BasicDBObject(MongoSessionManager.__VALID,false); final static DBObject __valid_true = new BasicDBObject(MongoSessionManager.__VALID,true); - final static long __defaultScavengeDelay = 10 * 6 * 1000; // wait at least 10 minutes final static long __defaultScavengePeriod = 30 * 60 * 1000; // every 30 minutes final DBCollection _sessions; protected Server _server; - private Timer _scavengeTimer; - private Timer _purgeTimer; - private TimerTask _scavengerTask; - private TimerTask _purgeTask; + private Scheduler _scheduler; + private boolean _ownScheduler; + private Scheduler.Task _scavengerTask; + private Scheduler.Task _purgerTask; + - - private long _scavengeDelay = __defaultScavengeDelay; private long _scavengePeriod = __defaultScavengePeriod; @@ -116,6 +116,52 @@ public class MongoSessionIdManager extends AbstractSessionIdManager */ protected final Set _sessionsIds = new HashSet(); + + /** + * 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); + } + } + } + + + /* ------------------------------------------------------------ */ public MongoSessionIdManager(Server server) throws UnknownHostException, MongoException @@ -172,8 +218,7 @@ public class MongoSessionIdManager extends AbstractSessionIdManager __log.debug("SessionIdManager:scavenge: expiring session {}", (String)session.get(MongoSessionManager.__ID)); expireAll((String)session.get(MongoSessionManager.__ID)); } - } - + } } /* ------------------------------------------------------------ */ @@ -297,20 +342,6 @@ public class MongoSessionIdManager extends AbstractSessionIdManager this._purge = purge; } - /* ------------------------------------------------------------ */ - /** - * The delay before the first scavenge operation is performed. - * - * sets the scavengeDelay - */ - public void setScavengeDelay(long scavengeDelay) - { - if (scavengeDelay <= 0) - this._scavengeDelay = __defaultScavengeDelay; - else - this._scavengeDelay = TimeUnit.SECONDS.toMillis(scavengeDelay); - } - /* ------------------------------------------------------------ */ /** @@ -376,77 +407,69 @@ public class MongoSessionIdManager extends AbstractSessionIdManager protected void doStart() throws Exception { __log.debug("MongoSessionIdManager:starting"); - - /* - * setup the scavenger thread - */ - if (_scavengeDelay > 0) - { - _scavengeTimer = new Timer("MongoSessionIdScavenger",true); - synchronized (this) + + 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(); + } + + //setup the scavenger thread + if (_scavengePeriod > 0) { if (_scavengerTask != null) { _scavengerTask.cancel(); + _scavengerTask = null; } - - _scavengerTask = new TimerTask() - { - @Override - public void run() - { - scavenge(); - } - }; - - _scavengeTimer.schedule(_scavengerTask,_scavengeDelay,_scavengePeriod); + + _scavengerTask = _scheduler.schedule(new Scavenger(), _scavengePeriod, TimeUnit.MILLISECONDS); } - } - - /* - * if purging is enabled, setup the purge thread - */ - if ( _purge ) - { - _purgeTimer = new Timer("MongoSessionPurger", true); - - synchronized (this) - { - if (_purgeTask != null) + + + //if purging is enabled, setup the purge thread + if ( _purge ) + { + if (_purgerTask != null) { - _purgeTask.cancel(); + _purgerTask.cancel(); + _purgerTask = null; } - _purgeTask = new TimerTask() - { - @Override - public void run() - { - purge(); - } - }; - - _purgeTimer.schedule(_purgeTask,0,_purgeDelay); + _purgerTask = _scheduler.schedule(new Purger(), _purgeDelay, TimeUnit.MILLISECONDS); } } } - + /* ------------------------------------------------------------ */ @Override protected void doStop() throws Exception { - if (_scavengeTimer != null) + synchronized (this) { - _scavengeTimer.cancel(); - _scavengeTimer = null; + if (_scavengerTask != null) + { + _scavengerTask.cancel(); + _scavengerTask = null; + } + + if (_purgerTask != null) + { + _purgerTask.cancel(); + _purgerTask = null; + } + + if (_ownScheduler && _scheduler != null) + { + _scheduler.stop(); + _scheduler = null; + } } - - if (_purgeTimer != null) - { - _purgeTimer.cancel(); - _purgeTimer = null; - } - super.doStop(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java index eb831795b50..0038e111853 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java @@ -31,6 +31,7 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -39,6 +40,8 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.ClassLoadingObjectInputStream; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; +import org.eclipse.jetty.util.thread.Scheduler; /* ------------------------------------------------------------ */ @@ -60,19 +63,64 @@ public class HashSessionManager extends AbstractSessionManager protected final ConcurrentMap _sessions=new ConcurrentHashMap(); private static int __id; - private Timer _timer; + private Scheduler _timer; private boolean _timerStop=false; - private TimerTask _task; + private Scheduler.Task _task; long _scavengePeriodMs=30000; long _savePeriodMs=0; //don't do period saves by default long _idleSavePeriodMs = 0; // don't idle save sessions by default. - private TimerTask _saveTask; + private Scheduler.Task _saveTask; File _storeDir; private boolean _lazyLoad=false; private volatile boolean _sessionsLoaded=false; private boolean _deleteUnrestorableSessions=false; + /** + * Scavenger + * + */ + protected class Scavenger implements Runnable + { + @Override + public void run() + { + try + { + scavenge(); + } + finally + { + if (_timer != null && _timer.isRunning()) + _timer.schedule(this, _scavengePeriodMs, TimeUnit.MILLISECONDS); + } + } + } + + /** + * Saver + * + */ + protected class Saver implements Runnable + { + @Override + public void run() + { + try + { + saveSessions(true); + } + catch (Exception e) + { + LOG.warn(e); + } + finally + { + if (_timer != null && _timer.isRunning()) + _timer.schedule(this, _savePeriodMs, TimeUnit.MILLISECONDS); + } + } + } /* ------------------------------------------------------------ */ @@ -91,14 +139,24 @@ public class HashSessionManager extends AbstractSessionManager super.doStart(); _timerStop=false; - ServletContext context = ContextHandler.getCurrentContext(); - if (context!=null) - _timer=(Timer)context.getAttribute("org.eclipse.jetty.server.session.timer"); - if (_timer==null) + //try shared scheduler from Server first + _timer = getSessionHandler().getServer().getBean(Scheduler.class); + if (_timer == null) { + //try one passwed into the context + ServletContext context = ContextHandler.getCurrentContext(); + if (context!=null) + _timer = (Scheduler)context.getAttribute("org.eclipse.jetty.server.session.timer"); + } + + if (_timer == null) + { + //make a scheduler if none useable _timerStop=true; - _timer=new Timer("HashSessionScavenger-"+__id++, true); + _timer=new ScheduledExecutorScheduler(); + _timer.start(); } + setScavengePeriod(getScavengePeriod()); @@ -131,7 +189,7 @@ public class HashSessionManager extends AbstractSessionManager _task.cancel(); _task=null; if (_timer!=null && _timerStop) - _timer.cancel(); + _timer.stop(); _timer=null; } @@ -217,24 +275,10 @@ public class HashSessionManager extends AbstractSessionManager { if (_saveTask!=null) _saveTask.cancel(); + _saveTask = null; if (_savePeriodMs > 0 && _storeDir!=null) //only save if we have a directory configured { - _saveTask = new TimerTask() - { - @Override - public void run() - { - try - { - saveSessions(true); - } - catch (Exception e) - { - LOG.warn(e); - } - } - }; - _timer.schedule(_saveTask,_savePeriodMs,_savePeriodMs); + _saveTask = _timer.schedule(new Saver(),_savePeriodMs,TimeUnit.MILLISECONDS); } } } @@ -275,16 +319,11 @@ public class HashSessionManager extends AbstractSessionManager synchronized (this) { if (_task!=null) - _task.cancel(); - _task = new TimerTask() { - @Override - public void run() - { - scavenge(); - } - }; - _timer.schedule(_task,_scavengePeriodMs,_scavengePeriodMs); + _task.cancel(); + _task = null; + } + _task = _timer.schedule(new Scavenger(),_scavengePeriodMs, TimeUnit.MILLISECONDS); } } } @@ -303,13 +342,14 @@ public class HashSessionManager extends AbstractSessionManager Thread thread=Thread.currentThread(); ClassLoader old_loader=thread.getContextClassLoader(); try - { + { if (_loader!=null) thread.setContextClassLoader(_loader); // For each session long now=System.currentTimeMillis(); - + __log.debug("Scavenging sessions at {}", now); + for (Iterator i=_sessions.values().iterator(); i.hasNext();) { HashedSession session=i.next(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java index c57188d5d64..6eced568361 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java @@ -35,6 +35,7 @@ import java.util.Random; import java.util.Set; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.TimeUnit; import javax.naming.InitialContext; import javax.servlet.http.HttpServletRequest; @@ -46,6 +47,8 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.SessionManager; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; +import org.eclipse.jetty.util.thread.Scheduler; @@ -73,8 +76,10 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager protected String _sessionTableRowId = "rowId"; protected int _deleteBlockSize = 10; //number of ids to include in where 'in' clause - protected Timer _timer; //scavenge timer - protected TimerTask _task; //scavenge task + protected Scheduler.Task _task; //scavenge task + protected Scheduler _scheduler; + protected Scavenger _scavenger; + protected boolean _ownScheduler; protected long _lastScavengeTime; protected long _scavengeIntervalMs = 1000L * 60 * 10; //10mins protected String _blobType; //if not set, is deduced from the type of the database at runtime @@ -98,6 +103,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager protected DatabaseAdaptor _dbAdaptor; private String _selectExpiredSessions; + /** @@ -232,6 +238,28 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager } } + + /** + * Scavenger + * + */ + protected class Scavenger implements Runnable + { + + @Override + public void run() + { + try + { + scavenge(); + } + finally + { + if (_scheduler != null && _scheduler.isRunning()) + _scheduler.schedule(this, _scavengeIntervalMs, TimeUnit.MILLISECONDS); + } + } + } public JDBCSessionIdManager(Server server) @@ -351,21 +379,17 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager if (LOG.isDebugEnabled()) LOG.debug("Scavenging every "+_scavengeIntervalMs+" ms"); - if (_timer!=null && (period!=old_period || _task==null)) + + //if (_timer!=null && (period!=old_period || _task==null)) + if (_scheduler != null && (period!=old_period || _task==null)) { synchronized (this) { if (_task!=null) _task.cancel(); - _task = new TimerTask() - { - @Override - public void run() - { - scavenge(); - } - }; - _timer.schedule(_task,_scavengeIntervalMs,_scavengeIntervalMs); + if (_scavenger == null) + _scavenger = new Scavenger(); + _task = _scheduler.schedule(_scavenger,_scavengeIntervalMs,TimeUnit.MILLISECONDS); } } } @@ -561,7 +585,16 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager super.doStart(); if (LOG.isDebugEnabled()) LOG.debug("Scavenging interval = "+getScavengeInterval()+" sec"); - _timer=new Timer("JDBCSessionScavenger", true); + + //try and use a common scheduler, fallback to own + _scheduler =_server.getBean(Scheduler.class); + if (_scheduler == null) + { + _scheduler = new ScheduledExecutorScheduler(); + _ownScheduler = true; + _scheduler.start(); + } + setScavengeInterval(getScavengeInterval()); } @@ -577,9 +610,9 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager if (_task!=null) _task.cancel(); _task=null; - if (_timer!=null) - _timer.cancel(); - _timer=null; + if (_ownScheduler && _scheduler !=null) + _scheduler.stop(); + _scheduler=null; } _sessionIds.clear(); super.doStop(); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java index 960fa62f5ed..fa9a8b1bbed 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java @@ -23,6 +23,7 @@ import java.io.File; import junit.framework.Assert; import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.StdErrLog; @@ -96,11 +97,16 @@ public class HashSessionManagerTest { File testDir = MavenTestingUtils.getTargetTestingDir("saved"); testDir.mkdirs(); + + Server server = new Server(); + SessionHandler handler = new SessionHandler(); + handler.setServer(server); HashSessionManager manager = new HashSessionManager(); manager.setStoreDirectory(testDir); manager.setMaxInactiveInterval(5); Assert.assertTrue(testDir.exists()); Assert.assertTrue(testDir.canWrite()); + handler.setSessionManager(manager); AbstractSessionIdManager idManager = new HashSessionIdManager(); idManager.setWorkerName("foo"); diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java index d118c4ba0a7..988f8a382bf 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java @@ -61,7 +61,6 @@ public class MongoTestServer extends AbstractTestServer System.err.println("MongoTestServer:SessionIdManager scavenge: delay:"+ _scavengePeriod + " period:"+_scavengePeriod); MongoSessionIdManager idManager = new MongoSessionIdManager(_server); idManager.setWorkerName("w"+(__workers++)); - idManager.setScavengeDelay((_scavengePeriod)); idManager.setScavengePeriod(_scavengePeriod); return idManager;