345290 Weak references from SessionIdManager. HashSessionManager cleanup.

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@3123 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Greg Wilkins 2011-05-12 02:16:19 +00:00
parent 70d0d0d1f2
commit 50ebfdd13b
4 changed files with 158 additions and 145 deletions

View File

@ -18,6 +18,7 @@ jetty-7.4.1-SNAPSHOT
+ 344513 Attempting to set ConfigurationClasses in jetty-web.xml causes NPE
+ 344529 Ability to customize the error handling of the OSGi HttpService
+ 345047 Readded deprecated ScanningAppDeployer#setMonitoredDir
+ 345290 Weak references from SessionIdManager. HashSessionManager cleanup.
+ JETTY-954 WebAppContext eats any start exceptions instead of stopping the server load
+ JETTY-1314 Handle bad URI encodings
+ JETTY-1324 Tested not using CESU-8 instead of UTF-8

View File

@ -626,7 +626,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement
*/
public abstract Session getSession(String idInCluster);
protected abstract void invalidateSessions();
protected abstract void invalidateSessions() throws Exception;
/* ------------------------------------------------------------ */

View File

@ -13,7 +13,19 @@
package org.eclipse.jetty.server.session;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@ -28,7 +40,7 @@ import org.eclipse.jetty.util.MultiMap;
*/
public class HashSessionIdManager extends AbstractSessionIdManager
{
MultiMap<String> _sessions;
private final Map<String, Set<WeakReference<HttpSession>>> _sessions = new HashMap<String, Set<WeakReference<HttpSession>>>();
/* ------------------------------------------------------------ */
public HashSessionIdManager()
@ -77,7 +89,6 @@ public class HashSessionIdManager extends AbstractSessionIdManager
@Override
protected void doStart() throws Exception
{
_sessions=new MultiMap<String>(true);
super.doStart();
}
@ -85,9 +96,7 @@ public class HashSessionIdManager extends AbstractSessionIdManager
@Override
protected void doStop() throws Exception
{
if (_sessions!=null)
_sessions.clear(); // Maybe invalidate?
_sessions=null;
_sessions.clear();
super.doStop();
}
@ -97,7 +106,10 @@ public class HashSessionIdManager extends AbstractSessionIdManager
*/
public boolean idInUse(String id)
{
return _sessions.containsKey(id);
synchronized (this)
{
return _sessions.containsKey(id);
}
}
/* ------------------------------------------------------------ */
@ -106,7 +118,19 @@ public class HashSessionIdManager extends AbstractSessionIdManager
*/
public void addSession(HttpSession session)
{
_sessions.add(getClusterId(session.getId()),session);
String id = getClusterId(session.getId());
WeakReference<HttpSession> ref = new WeakReference<HttpSession>(session);
synchronized (this)
{
Set<WeakReference<HttpSession>> sessions = _sessions.get(id);
if (sessions==null)
{
sessions=new HashSet<WeakReference<HttpSession>>();
_sessions.put(id,sessions);
}
sessions.add(ref);
}
}
/* ------------------------------------------------------------ */
@ -115,7 +139,32 @@ public class HashSessionIdManager extends AbstractSessionIdManager
*/
public void removeSession(HttpSession session)
{
_sessions.removeValue(getClusterId(session.getId()),session);
String id = getClusterId(session.getId());
synchronized (this)
{
Collection<WeakReference<HttpSession>> sessions = _sessions.get(id);
if (sessions!=null)
{
for (Iterator<WeakReference<HttpSession>> iter = sessions.iterator(); iter.hasNext();)
{
WeakReference<HttpSession> ref = iter.next();
HttpSession s=ref.get();
if (s==null)
{
iter.remove();
continue;
}
if (s==session)
{
iter.remove();
break;
}
}
if (sessions.isEmpty())
_sessions.remove(id);
}
}
}
/* ------------------------------------------------------------ */
@ -124,19 +173,22 @@ public class HashSessionIdManager extends AbstractSessionIdManager
*/
public void invalidateAll(String id)
{
// Do not use iterators as this method tends to be called recursively
// by the invalidate calls.
while (_sessions.containsKey(id))
{
Session session=(Session)_sessions.getValue(id,0);
if (session.isValid())
{
session.invalidate();
}
_sessions.removeValue(id,session);
}
Collection<WeakReference<HttpSession>> sessions;
synchronized (this)
{
sessions = _sessions.remove(id);
}
if (sessions!=null)
{
for (WeakReference<HttpSession> ref: sessions)
{
Session session=(Session)ref.get();
if (session!=null && session.isValid())
session.invalidate();
}
sessions.clear();
}
}
}

View File

@ -53,6 +53,7 @@ import org.eclipse.jetty.util.log.Log;
*/
public class HashSessionManager extends AbstractSessionManager
{
protected final ConcurrentMap<String,HashedSession> _sessions=new ConcurrentHashMap<String,HashedSession>();
private static int __id;
private Timer _timer;
private boolean _timerStop=false;
@ -61,7 +62,6 @@ public class HashSessionManager extends AbstractSessionManager
private int _savePeriodMs=0; //don't do period saves by default
private int _idleSavePeriodMs = 0; // don't idle save sessions by default.
private TimerTask _saveTask;
protected ConcurrentMap<String,HashedSession> _sessions;
private File _storeDir;
private boolean _lazyLoad=false;
private volatile boolean _sessionsLoaded=false;
@ -79,7 +79,6 @@ public class HashSessionManager extends AbstractSessionManager
@Override
public void doStart() throws Exception
{
_sessions=new ConcurrentHashMap<String,HashedSession>();
super.doStart();
_timerStop=false;
@ -113,15 +112,7 @@ public class HashSessionManager extends AbstractSessionManager
@Override
public void doStop() throws Exception
{
if (_storeDir != null)
saveSessions();
super.doStop();
_sessions.clear();
_sessions=null;
// stop the scavenger
// stop the scavengers
synchronized(this)
{
if (_saveTask!=null)
@ -134,6 +125,12 @@ public class HashSessionManager extends AbstractSessionManager
_timer.cancel();
_timer=null;
}
// This will callback invalidate sessions - where we decide if we will save
super.doStop();
_sessions.clear();
}
/* ------------------------------------------------------------ */
@ -228,7 +225,7 @@ public class HashSessionManager extends AbstractSessionManager
{
try
{
saveSessions();
saveSessions(true);
}
catch (Exception e)
{
@ -381,16 +378,32 @@ public class HashSessionManager extends AbstractSessionManager
/* ------------------------------------------------------------ */
@Override
protected void invalidateSessions()
protected void invalidateSessions() throws Exception
{
// Invalidate all sessions to cause unbind events
ArrayList<HashedSession> sessions=new ArrayList<HashedSession>(_sessions.values());
for (Iterator<HashedSession> i=sessions.iterator(); i.hasNext();)
int loop=100;
while (sessions.size()>0 && loop-->0)
{
HashedSession session=i.next();
session.invalidate();
// If we are called from doStop
if (isStopping() && _storeDir != null && _storeDir.exists() && _storeDir.canWrite())
{
// Then we only save and remove the session - it is not invalidated.
for (HashedSession session : sessions)
{
session.save(false);
removeSession(session,false);
}
}
else
{
for (HashedSession session : sessions)
session.invalidate();
}
// check that no new sessions were created while we were iterating
sessions=new ArrayList<HashedSession>(_sessions.values());
}
_sessions.clear();
}
/* ------------------------------------------------------------ */
@ -412,7 +425,6 @@ public class HashSessionManager extends AbstractSessionManager
{
return _sessions.remove(clusterId)!=null;
}
/* ------------------------------------------------------------ */
public void setStoreDirectory (File dir)
@ -485,10 +497,8 @@ public class HashSessionManager extends AbstractSessionManager
return null;
}
/* ------------------------------------------------------------ */
public void saveSessions() throws Exception
public void saveSessions(boolean reactivate) throws Exception
{
if (_storeDir==null || !_storeDir.exists())
{
@ -501,48 +511,8 @@ public class HashSessionManager extends AbstractSessionManager
return;
}
Iterator<Map.Entry<String, HashedSession>> itor = _sessions.entrySet().iterator();
while (itor.hasNext())
{
Map.Entry<String,HashedSession> entry = itor.next();
String id = entry.getKey();
HashedSession session = entry.getValue();
synchronized(session)
{
// No point saving a session that has been idled or has had a previous save failure
if (!session.isIdled() && !session.isSaveFailed())
{
File file = null;
FileOutputStream fos = null;
try
{
file = new File (_storeDir, id);
if (file.exists())
file.delete();
file.createNewFile();
fos = new FileOutputStream (file);
session.willPassivate();
session.save(fos);
session.didActivate();
fos.close();
}
catch (Exception e)
{
session.saveFailed();
Log.warn("Problem persisting session "+id, e);
if (fos != null)
{
// Must not leave files open if the saving failed
IO.close(fos);
// No point keeping the file if we didn't save the whole session
file.delete();
}
}
}
}
}
for (HashedSession session : _sessions.values())
session.save(true);
}
/* ------------------------------------------------------------ */
@ -640,37 +610,64 @@ public class HashSessionManager extends AbstractSessionManager
/* ------------------------------------------------------------ */
@Override
public void invalidate ()
protected void doInvalidate()
throws IllegalStateException
{
if (isRunning())
super.doInvalidate();
// Remove from the disk
if (_storeDir!=null && getId()!=null)
{
super.invalidate();
remove();
String id=getId();
File f = new File(_storeDir, id);
f.delete();
}
}
/* ------------------------------------------------------------ */
public void remove()
private synchronized void save(boolean reactivate)
{
String id=getId();
if (id==null)
return;
//all sessions are invalidated when jetty is stopped, make sure we don't
//remove all the sessions in this case
if (isStopping() || isStopped())
return;
if (_storeDir==null || !_storeDir.exists())
// Only idle the session if not already idled and no previous save/idle has failed
if (!isIdled() && !_saveFailed)
{
return;
}
File f = new File(_storeDir, id);
f.delete();
}
if (Log.isDebugEnabled())
Log.debug("Saving {} {}",super.getId(),reactivate);
File file = null;
FileOutputStream fos = null;
try
{
file = new File(_storeDir, super.getId());
if (file.exists())
file.delete();
file.createNewFile();
fos = new FileOutputStream(file);
willPassivate();
save(fos);
if (reactivate)
didActivate();
else
clearAttributes();
}
catch (Exception e)
{
saveFailed(); // We won't try again for this session
Log.warn("Problem saving session " + super.getId(), e);
if (fos != null)
{
// Must not leave the file open if the saving failed
IO.close(fos);
// No point keeping the file if we didn't save the whole session
file.delete();
_idled=false; // assume problem was before _values.clear();
}
}
}
}
/* ------------------------------------------------------------ */
public synchronized void save(OutputStream os) throws IOException
{
@ -751,6 +748,7 @@ public class HashSessionManager extends AbstractSessionManager
}
}
/* ------------------------------------------------------------ */
/**
* Idle the session to reduce session memory footprint.
@ -760,45 +758,7 @@ public class HashSessionManager extends AbstractSessionManager
*/
public synchronized void idle()
{
// Only idle the session if not already idled and no previous save/idle has failed
if (!isIdled() && !_saveFailed)
{
if (Log.isDebugEnabled())
Log.debug("Idling " + super.getId());
File file = null;
FileOutputStream fos = null;
try
{
file = new File(_storeDir, super.getId());
if (file.exists())
file.delete();
file.createNewFile();
fos = new FileOutputStream(file);
willPassivate();
save(fos);
clearAttributes();
_idled = true;
}
catch (Exception e)
{
saveFailed(); // We won't try again for this session
Log.warn("Problem idling session " + super.getId(), e);
if (fos != null)
{
// Must not leave the file open if the saving failed
IO.close(fos);
// No point keeping the file if we didn't save the whole session
file.delete();
_idled=false; // assume problem was before _values.clear();
}
}
}
save(false);
}
/* ------------------------------------------------------------ */