422308 Change all session/sessionid managers to use shared Scheduler

This commit is contained in:
Jan Bartel 2013-11-22 19:22:44 +11:00
parent 3499c52019
commit 44416abb1f
5 changed files with 230 additions and 129 deletions

View File

@ -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<String> _sessionsIds = new HashSet<String>();
/**
* 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();
}

View File

@ -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<String,HashedSession> _sessions=new ConcurrentHashMap<String,HashedSession>();
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<HashedSession> i=_sessions.values().iterator(); i.hasNext();)
{
HashedSession session=i.next();

View File

@ -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();

View File

@ -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");

View File

@ -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;