Jetty 9.4.x 2038 slow filesessiondatastore (#2102)
* Issue #2038 Speed up FileSessionDataStore Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
parent
356bf2e06f
commit
a0b8321ef4
|
@ -24,22 +24,27 @@ import java.io.DataOutputStream;
|
|||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
@ -54,11 +59,21 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
@ManagedObject
|
||||
public class FileSessionDataStore extends AbstractSessionDataStore
|
||||
{
|
||||
|
||||
|
||||
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
|
||||
private File _storeDir;
|
||||
private boolean _deleteUnrestorableFiles = false;
|
||||
private Map<String,String> _sessionFileMap = new ConcurrentHashMap<>();
|
||||
private String _contextString;
|
||||
protected long _lastSweepTime = 0L;
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize(SessionContext context) throws Exception
|
||||
{
|
||||
super.initialize(context);
|
||||
_contextString = _context.getCanonicalContextPath()+"_"+_context.getVhost();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
|
@ -70,6 +85,8 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
_sessionFileMap.clear();
|
||||
_lastSweepTime = 0;
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
|
@ -99,27 +116,53 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.SessionDataStore#delete(java.lang.String)
|
||||
* Delete a session
|
||||
*
|
||||
* @param id session id
|
||||
*/
|
||||
@Override
|
||||
public boolean delete(String id) throws Exception
|
||||
{
|
||||
File file = null;
|
||||
if (_storeDir != null)
|
||||
{
|
||||
file = getFile(_storeDir, id);
|
||||
if (file != null && file.exists() && file.getParentFile().equals(_storeDir))
|
||||
{
|
||||
return file.delete();
|
||||
}
|
||||
//remove from our map
|
||||
String filename = _sessionFileMap.remove(getIdWithContext(id));
|
||||
if (filename == null)
|
||||
return false;
|
||||
|
||||
//remove the file
|
||||
return deleteFile(filename);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(Set)
|
||||
* Delete the file associated with a session
|
||||
*
|
||||
* @param filename name of the file containing the session's information
|
||||
*
|
||||
* @return true if file was deleted, false otherwise
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean deleteFile (String filename) throws Exception
|
||||
{
|
||||
if (filename == null)
|
||||
return false;
|
||||
File file = new File(_storeDir, filename);
|
||||
return Files.deleteIfExists(file.toPath());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see which sessions have expired.
|
||||
*
|
||||
* @param candidates the set of session ids that the SessionCache believes
|
||||
* have expired
|
||||
* @return the complete set of sessions that have expired, including those
|
||||
* that are not currently loaded into the SessionCache
|
||||
*/
|
||||
@Override
|
||||
public Set<String> doGetExpired(final Set<String> candidates)
|
||||
|
@ -127,89 +170,108 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
final long now = System.currentTimeMillis();
|
||||
HashSet<String> expired = new HashSet<String>();
|
||||
|
||||
HashSet<String> idsWithContext = new HashSet<>();
|
||||
|
||||
|
||||
//one pass to get all idWithContext
|
||||
File [] files = _storeDir.listFiles(new FilenameFilter()
|
||||
//iterate over the files and work out which have expired
|
||||
for (String filename:_sessionFileMap.values())
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
if (dir != _storeDir)
|
||||
return false;
|
||||
|
||||
//dir may contain files that don't match our naming pattern
|
||||
if (!match(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
String idWithContext = getIdWithContextFromString(name);
|
||||
if (!StringUtil.isBlank(idWithContext))
|
||||
idsWithContext.add(idWithContext);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//got the list of all sessionids with their contexts, remove all old files for each one
|
||||
for (String idWithContext:idsWithContext)
|
||||
{
|
||||
deleteOldFiles(_storeDir, idWithContext);
|
||||
}
|
||||
|
||||
|
||||
//now find sessions that have expired in any context
|
||||
files = _storeDir.listFiles(new FilenameFilter()
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
if (dir != _storeDir)
|
||||
return false;
|
||||
|
||||
//dir may contain files that don't match our naming pattern
|
||||
if (!match(name))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
long expiry = getExpiryFromString(name);
|
||||
return expiry > 0 && expiry < now;
|
||||
long expiry = getExpiryFromFilename(filename);
|
||||
if (expiry > 0 && expiry < now)
|
||||
expired.add(getIdFromFilename(filename));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (files != null)
|
||||
{
|
||||
for (File f:files)
|
||||
{
|
||||
expired.add(getIdFromFile(f));
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
//check candidates that were not found to be expired, perhaps they no
|
||||
//longer exist and they should be expired
|
||||
//check candidates that were not found to be expired, perhaps
|
||||
//because they no longer exist and they should be expired
|
||||
for (String c:candidates)
|
||||
{
|
||||
if (!expired.contains(c))
|
||||
{
|
||||
//check if the file exists
|
||||
File f = getFile(_storeDir, c);
|
||||
if (f == null || !f.exists())
|
||||
//if it doesn't have a file then the session doesn't exist
|
||||
String filename = _sessionFileMap.get(getIdWithContext(c));
|
||||
if (filename == null)
|
||||
expired.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
//Infrequently iterate over all files in the store, and delete those
|
||||
//that expired a long time ago, even if they belong to
|
||||
//another context. This ensures that files that
|
||||
//belong to defunct contexts are cleaned up.
|
||||
//If the graceperiod is disabled, don't do the sweep!
|
||||
if ((_gracePeriodSec > 0) && ((_lastSweepTime == 0) || ((now - _lastSweepTime) >= (5*TimeUnit.SECONDS.toMillis(_gracePeriodSec)))))
|
||||
{
|
||||
_lastSweepTime = now;
|
||||
sweepDisk();
|
||||
}
|
||||
return expired;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check all session files that do not belong to this context and
|
||||
* remove any that expired long ago (ie at least 5 gracePeriods ago).
|
||||
*/
|
||||
public void sweepDisk()
|
||||
{
|
||||
//iterate over the files in the store dir and check expiry times
|
||||
long now = System.currentTimeMillis();
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Sweeping {} for old session files", _storeDir);
|
||||
try
|
||||
{
|
||||
Files.walk(_storeDir.toPath(), 1, FileVisitOption.FOLLOW_LINKS)
|
||||
.filter(p->!Files.isDirectory(p)).filter(p->!isOurContextSessionFilename(p.getFileName().toString()))
|
||||
.filter(p->isSessionFilename(p.getFileName().toString()))
|
||||
.forEach(p->{
|
||||
|
||||
try
|
||||
{
|
||||
sweepFile(now, p);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if the expiry on the file is very old, and
|
||||
* delete the file if so. "Old" means that it expired at least
|
||||
* 5 gracePeriods ago. The session can belong to any context.
|
||||
*
|
||||
* @param now the time now in msec
|
||||
* @param p the file to check
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void sweepFile (long now, Path p)
|
||||
throws Exception
|
||||
{
|
||||
if (p == null)
|
||||
return;
|
||||
|
||||
long expiry = getExpiryFromFilename(p.getFileName().toString());
|
||||
//files with 0 expiry never expire
|
||||
if (expiry >0 && ((now - expiry) >= (5*TimeUnit.SECONDS.toMillis(_gracePeriodSec))))
|
||||
{
|
||||
Files.deleteIfExists(p);
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Sweep deleted {}", p.getFileName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.SessionDataStore#load(java.lang.String)
|
||||
|
@ -223,13 +285,20 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
{
|
||||
public void run ()
|
||||
{
|
||||
//get rid of all but the newest file for a session
|
||||
File file = deleteOldFiles(_storeDir, getIdWithContext(id));
|
||||
|
||||
if (file == null || !file.exists())
|
||||
//load session info from its file
|
||||
String idWithContext = getIdWithContext(id);
|
||||
String filename = _sessionFileMap.get(idWithContext);
|
||||
if (filename == null)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("No file: {}",file);
|
||||
LOG.debug("Unknown file {}",filename);
|
||||
return;
|
||||
}
|
||||
File file = new File (_storeDir, filename);
|
||||
if (!file.exists())
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("No such file {}",filename);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -243,9 +312,16 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
{
|
||||
if (isDeleteUnrestorableFiles() && file.exists() && file.getParentFile().equals(_storeDir))
|
||||
{
|
||||
file.delete();
|
||||
try
|
||||
{
|
||||
delete(id);
|
||||
LOG.warn("Deleted unrestorable file for session {}", id);
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.warn("Unable to delete unrestorable file {} for session {}", filename, id, x);
|
||||
}
|
||||
}
|
||||
|
||||
exception.set(e);
|
||||
}
|
||||
|
@ -255,6 +331,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
//ensure this runs with the context classloader set
|
||||
_context.run(r);
|
||||
|
||||
|
@ -275,19 +352,20 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
File file = null;
|
||||
if (_storeDir != null)
|
||||
{
|
||||
//remove any existing files for the session
|
||||
deleteAllFiles(_storeDir, getIdWithContext(id));
|
||||
delete(id);
|
||||
|
||||
//make a fresh file using the latest session expiry
|
||||
file = new File(_storeDir, getIdWithContextAndExpiry(data));
|
||||
String filename = getIdWithContextAndExpiry(data);
|
||||
String idWithContext = getIdWithContext(id);
|
||||
file = new File(_storeDir, filename);
|
||||
|
||||
try(FileOutputStream fos = new FileOutputStream(file,false))
|
||||
{
|
||||
save(fos, id, data);
|
||||
_sessionFileMap.put(idWithContext, filename);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
if (file != null)
|
||||
file.delete(); // No point keeping the file if we didn't save the whole session
|
||||
throw new UnwriteableSessionDataException(id, _context,e);
|
||||
|
@ -296,16 +374,100 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
|
||||
/**
|
||||
* Read the names of the existing session files and build a map of
|
||||
* fully qualified session ids (ie with context) to filename. If there
|
||||
* is more than one file for the same session, only the most recently modified will
|
||||
* be kept and the rest deleted. At the same time, any files - for any context -
|
||||
* that expired a long time ago will be cleaned up.
|
||||
*
|
||||
* @throws IllegalStateException if storeDir doesn't exist, isn't readable/writeable
|
||||
* or contains 2 files with the same lastmodify time for the same session. Throws IOException
|
||||
* if the lastmodifytimes can't be read.
|
||||
*/
|
||||
public void initializeStore ()
|
||||
throws Exception
|
||||
{
|
||||
if (_storeDir == null)
|
||||
throw new IllegalStateException("No file store specified");
|
||||
|
||||
if (!_storeDir.exists())
|
||||
_storeDir.mkdirs();
|
||||
else
|
||||
{
|
||||
if (!(_storeDir.isDirectory() &&_storeDir.canWrite() && _storeDir.canRead()))
|
||||
throw new IllegalStateException(_storeDir.getAbsolutePath()+" must be readable/writeable dir");
|
||||
|
||||
//iterate over files in _storeDir and build map of session id to filename.
|
||||
//if we come across files for sessions in other contexts, check if they're
|
||||
//ancient and remove if necessary.
|
||||
MultiException me = new MultiException();
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
Files.walk(_storeDir.toPath(), 1, FileVisitOption.FOLLOW_LINKS)
|
||||
.filter(p->!Files.isDirectory(p)).filter(p->isSessionFilename(p.getFileName().toString()))
|
||||
.forEach(p->{
|
||||
//first get rid of all ancient files, regardless of which
|
||||
//context they are for
|
||||
try
|
||||
{
|
||||
sweepFile(now, p);
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
me.add(x);
|
||||
}
|
||||
|
||||
String filename = p.getFileName().toString();
|
||||
String context = getContextFromFilename(filename);
|
||||
//now process it if it wasn't deleted, and it is for our context
|
||||
if (Files.exists(p) && _contextString.equals(context))
|
||||
{
|
||||
//the session is for our context, populate the map with it
|
||||
String sessionIdWithContext = getIdWithContextFromFilename(filename);
|
||||
if (sessionIdWithContext != null)
|
||||
{
|
||||
//handle multiple session files existing for the same session: remove all
|
||||
//but the file with the most recent expiry time
|
||||
String existing = _sessionFileMap.putIfAbsent(sessionIdWithContext, filename);
|
||||
if (existing != null)
|
||||
{
|
||||
//if there was a prior filename, work out which has the most
|
||||
//recent modify time
|
||||
try
|
||||
{
|
||||
long existingExpiry = getExpiryFromFilename(existing);
|
||||
long thisExpiry = getExpiryFromFilename(filename);
|
||||
|
||||
if (thisExpiry > existingExpiry)
|
||||
{
|
||||
//replace with more recent file
|
||||
Path existingPath = _storeDir.toPath().resolve(existing);
|
||||
//update the file we're keeping
|
||||
_sessionFileMap.put(sessionIdWithContext, filename);
|
||||
//delete the old file
|
||||
Files.delete(existingPath);
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Replaced {} with {}", existing, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
//we found an older file, delete it
|
||||
Files.delete(p);
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Deleted expired session file {}", filename);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
me.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
me.ifExceptionThrow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.SessionDataStore#isPassivating()
|
||||
|
@ -326,12 +488,14 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
@Override
|
||||
public boolean exists(String id) throws Exception
|
||||
{
|
||||
File sessionFile = deleteOldFiles(_storeDir, getIdWithContext(id));
|
||||
if (sessionFile == null || !sessionFile.exists())
|
||||
String idWithContext = getIdWithContext(id);
|
||||
String filename = _sessionFileMap.get(idWithContext);
|
||||
|
||||
if (filename == null)
|
||||
return false;
|
||||
|
||||
//check the expiry
|
||||
long expiry = getExpiryFromFile(sessionFile);
|
||||
long expiry = getExpiryFromFilename(filename);
|
||||
if (expiry <= 0)
|
||||
return true; //never expires
|
||||
else
|
||||
|
@ -369,6 +533,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the session id with its context.
|
||||
*
|
||||
|
@ -377,7 +542,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
*/
|
||||
private String getIdWithContext (String id)
|
||||
{
|
||||
return _context.getCanonicalContextPath()+"_"+_context.getVhost()+"_"+id;
|
||||
return _contextString+"_"+id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -391,35 +556,16 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Work out which session id the file relates to.
|
||||
* @param file the file to check
|
||||
* @return the session id the file relates to.
|
||||
*/
|
||||
private String getIdFromFile (File file)
|
||||
private String getIdFromFilename (String filename)
|
||||
{
|
||||
if (file == null)
|
||||
if (filename == null)
|
||||
return null;
|
||||
String name = file.getName();
|
||||
|
||||
return name.substring(name.lastIndexOf('_')+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expiry time of the session stored in the file.
|
||||
* @param file the file from which to extract the expiry time
|
||||
* @return the expiry time
|
||||
*/
|
||||
private long getExpiryFromFile (File file)
|
||||
{
|
||||
if (file == null)
|
||||
return 0;
|
||||
|
||||
return getExpiryFromString(file.getName());
|
||||
return filename.substring(filename.lastIndexOf('_')+1);
|
||||
}
|
||||
|
||||
|
||||
private long getExpiryFromString (String filename)
|
||||
|
||||
private long getExpiryFromFilename (String filename)
|
||||
{
|
||||
if (StringUtil.isBlank(filename) || filename.indexOf("_") < 0)
|
||||
throw new IllegalStateException ("Invalid or missing filename");
|
||||
|
@ -428,26 +574,24 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
return (s==null?0:Long.parseLong(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the session id and context from the filename.
|
||||
* @param file the file whose name to use
|
||||
* @return the session id plus context
|
||||
*/
|
||||
private String getIdWithContextFromFile (File file)
|
||||
|
||||
private String getContextFromFilename (String filename)
|
||||
{
|
||||
if (file == null)
|
||||
if (StringUtil.isBlank(filename))
|
||||
return null;
|
||||
|
||||
String s = getIdWithContextFromString(file.getName());
|
||||
return s;
|
||||
int start = filename.indexOf('_');
|
||||
int end = filename.lastIndexOf('_');
|
||||
return filename.substring(start+1, end);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the session id and context from the filename
|
||||
* @param filename the name of the file to use
|
||||
* @return the session id plus context
|
||||
*/
|
||||
private String getIdWithContextFromString (String filename)
|
||||
private String getIdWithContextFromFilename (String filename)
|
||||
{
|
||||
if (StringUtil.isBlank(filename) || filename.indexOf('_') < 0)
|
||||
return null;
|
||||
|
@ -456,11 +600,31 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if the filename matches our session pattern
|
||||
* @param filename
|
||||
* @return
|
||||
* Check if the filename is a session filename.
|
||||
*
|
||||
* @param filename the filename to check
|
||||
* @return true if the filename has the correct filename format
|
||||
*/
|
||||
private boolean match (String filename)
|
||||
private boolean isSessionFilename (String filename)
|
||||
{
|
||||
if (StringUtil.isBlank(filename))
|
||||
return false;
|
||||
String[] parts = filename.split("_");
|
||||
|
||||
//Need at least 4 parts for a valid filename
|
||||
if (parts.length < 4)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the filename matches our session pattern
|
||||
* and is a session for our context.
|
||||
*
|
||||
* @param filename the filename to check
|
||||
* @return true if the filename has the correct filename format and is for this context
|
||||
*/
|
||||
private boolean isOurContextSessionFilename (String filename)
|
||||
{
|
||||
if (StringUtil.isBlank(filename))
|
||||
return false;
|
||||
|
@ -470,166 +634,11 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
|||
if (parts.length < 4)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a File for the session id for the current context.
|
||||
*
|
||||
* @param storeDir the session storage directory
|
||||
* @param id the session id
|
||||
* @return the file
|
||||
*/
|
||||
private File getFile (final File storeDir, final String id)
|
||||
{
|
||||
File[] files = storeDir.listFiles (new FilenameFilter() {
|
||||
|
||||
/**
|
||||
* @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
if (dir != storeDir)
|
||||
//Also needs to be for our context
|
||||
String context = getContextFromFilename(filename);
|
||||
if (context == null)
|
||||
return false;
|
||||
return (name.contains(getIdWithContext(id)));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (files == null || files.length < 1)
|
||||
return null;
|
||||
return files[0];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all existing session files for the session in the context
|
||||
* @param storeDir where the session files are stored
|
||||
* @param idInContext the session id within a particular context
|
||||
*/
|
||||
private void deleteAllFiles(final File storeDir, final String idInContext)
|
||||
{
|
||||
File[] files = storeDir.listFiles (new FilenameFilter() {
|
||||
|
||||
/**
|
||||
* @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
if (dir != storeDir)
|
||||
return false;
|
||||
return (name.contains(idInContext));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//no files for that id
|
||||
if (files == null || files.length < 1)
|
||||
return;
|
||||
|
||||
//delete all files
|
||||
for (File f:files)
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.deleteIfExists(f.toPath());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to delete session file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Delete all but the most recent file for a given session id in a context.
|
||||
*
|
||||
* @param storeDir the directory in which sessions are stored
|
||||
* @param idWithContext the id of the session
|
||||
* @return the most recent remaining file for the session, can be null
|
||||
*/
|
||||
private File deleteOldFiles (final File storeDir, final String idWithContext)
|
||||
{
|
||||
File[] files = storeDir.listFiles (new FilenameFilter() {
|
||||
|
||||
/**
|
||||
* @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
if (dir != storeDir)
|
||||
return false;
|
||||
|
||||
if (!match(name))
|
||||
return false;
|
||||
|
||||
return (name.contains(idWithContext));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//no file for that session
|
||||
if (files == null || files.length == 0)
|
||||
return null;
|
||||
|
||||
|
||||
//delete all but the most recent file
|
||||
File newest = null;
|
||||
|
||||
for (File f:files)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (newest == null)
|
||||
{
|
||||
//haven't looked at any files yet
|
||||
newest = f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f.lastModified() > newest.lastModified())
|
||||
{
|
||||
//this file is more recent
|
||||
Files.deleteIfExists(newest.toPath());
|
||||
newest = f;
|
||||
}
|
||||
else if (f.lastModified() < newest.lastModified())
|
||||
{
|
||||
//this file is older
|
||||
Files.deleteIfExists(f.toPath());
|
||||
}
|
||||
else
|
||||
{
|
||||
//files have same last modified times, decide based on latest expiry time
|
||||
long exp1 = getExpiryFromFile(newest);
|
||||
long exp2 = getExpiryFromFile(f);
|
||||
if (exp2 >= exp1)
|
||||
{
|
||||
//this file has a later expiry date
|
||||
Files.deleteIfExists(newest.toPath());
|
||||
newest = f;
|
||||
}
|
||||
else
|
||||
{
|
||||
//this file has an earlier expiry date
|
||||
Files.deleteIfExists(f.toPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to delete old session file", e);
|
||||
}
|
||||
}
|
||||
|
||||
return newest;
|
||||
return (_contextString.equals(context));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
package org.eclipse.jetty.server.session;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.Collections;
|
||||
|
@ -37,6 +40,7 @@ import org.junit.Test;
|
|||
|
||||
public class FileSessionManagerTest
|
||||
{
|
||||
public static final long ONE_DAY = (1000L*60L*60L*24L);
|
||||
private static StdErrLog _log;
|
||||
private static boolean _stacks;
|
||||
|
||||
|
@ -110,6 +114,12 @@ public class FileSessionManagerTest
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* When starting the filestore, check that really old expired
|
||||
* files are deleted irrespective of context session belongs to.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteOfOlderFiles() throws Exception
|
||||
{
|
||||
|
@ -129,42 +139,139 @@ public class FileSessionManagerTest
|
|||
File testDir = MavenTestingUtils.getTargetTestingDir("hashes");
|
||||
FS.ensureEmpty(testDir);
|
||||
ds.setStoreDir(testDir);
|
||||
handler.setSessionIdManager(idmgr);
|
||||
handler.start();
|
||||
|
||||
//create a bunch of older files for same session abc
|
||||
//create a really old file for session abc
|
||||
String name1 = "100__0.0.0.0_abc";
|
||||
File f1 = new File(testDir, name1);
|
||||
if (f1.exists())
|
||||
Assert.assertTrue(f1.delete());
|
||||
f1.createNewFile();
|
||||
|
||||
//create another really old file for session abc
|
||||
Thread.sleep(1100);
|
||||
|
||||
String name2 = "101__0.0.0.0_abc";
|
||||
File f2 = new File(testDir, name2);
|
||||
if (f2.exists())
|
||||
Assert.assertTrue(f2.delete());
|
||||
f2.createNewFile();
|
||||
|
||||
//make one file for session abc that should not have expired
|
||||
Thread.sleep(1100);
|
||||
|
||||
String name3 = "102__0.0.0.0_abc";
|
||||
long exp = System.currentTimeMillis() + ONE_DAY;
|
||||
String name3 = Long.toString(exp)+"__0.0.0.0_abc";
|
||||
File f3 = new File(testDir, name3);
|
||||
if (f3.exists())
|
||||
Assert.assertTrue(f3.delete());
|
||||
f3.createNewFile();
|
||||
|
||||
//make a file that is for a different context
|
||||
//that expired a long time ago - should be
|
||||
//removed by sweep on startup
|
||||
Thread.sleep(1100);
|
||||
String name4 = "1099_foo_0.0.0.0_abc";
|
||||
File f4 = new File(testDir, name4);
|
||||
if (f4.exists())
|
||||
Assert.assertTrue(f4.delete());
|
||||
f4.createNewFile();
|
||||
|
||||
//make a file that is for a different context
|
||||
//that should not have expired - ensure it is
|
||||
//not removed
|
||||
exp = System.currentTimeMillis() + ONE_DAY;
|
||||
String name5 = Long.toString(exp)+"_foo_0.0.0.0_abcdefg";
|
||||
File f5 = new File(testDir, name5);
|
||||
if (f5.exists())
|
||||
Assert.assertTrue(f5.delete());
|
||||
f5.createNewFile();
|
||||
|
||||
//make a file that is for a different context
|
||||
//that expired, but only recently - it should
|
||||
//not be removed by the startup process
|
||||
exp = System.currentTimeMillis() - 1000L;
|
||||
String name6 = Long.toString(exp)+"_foo_0.0.0.0_abcdefg";
|
||||
File f6 = new File(testDir, name5);
|
||||
if (f6.exists())
|
||||
Assert.assertTrue(f6.delete());
|
||||
f6.createNewFile();
|
||||
|
||||
handler.setSessionIdManager(idmgr);
|
||||
handler.start();
|
||||
|
||||
Session session = handler.getSession("abc");
|
||||
Assert.assertTrue(!f1.exists());
|
||||
Assert.assertTrue(!f2.exists());
|
||||
Assert.assertTrue(f3.exists());
|
||||
Assert.assertTrue(!f4.exists());
|
||||
Assert.assertTrue(f5.exists());
|
||||
Assert.assertTrue(f6.exists());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests that only the most recent file will be
|
||||
* loaded into the cache, even if it is already
|
||||
* expired. Other recently expired files for
|
||||
* same session should be deleted.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testLoadOnlyMostRecent() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
SessionHandler handler = new SessionHandler();
|
||||
handler.setServer(server);
|
||||
final DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server);
|
||||
idmgr.setServer(server);
|
||||
server.setSessionIdManager(idmgr);
|
||||
|
||||
FileSessionDataStore ds = new FileSessionDataStore();
|
||||
ds.setGracePeriodSec(100); //set graceperiod to 100sec to control what we consider as very old
|
||||
ds.setDeleteUnrestorableFiles(false); //turn off deletion of unreadable session files
|
||||
DefaultSessionCache ss = new DefaultSessionCache(handler);
|
||||
handler.setSessionCache(ss);
|
||||
ss.setSessionDataStore(ds);
|
||||
|
||||
File testDir = MavenTestingUtils.getTargetTestingDir("hashes");
|
||||
FS.ensureEmpty(testDir);
|
||||
ds.setStoreDir(testDir);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
//create a file for session abc that expired 5sec ago
|
||||
long exp = now -5000L;
|
||||
String name1 = Long.toString(exp)+"__0.0.0.0_abc";
|
||||
File f1 = new File(testDir, name1);
|
||||
if (f1.exists())
|
||||
Assert.assertTrue(f1.delete());
|
||||
f1.createNewFile();
|
||||
|
||||
//create a file for same session that expired 4 sec ago
|
||||
exp = now - 4000L;
|
||||
String name2 = Long.toString(exp)+"__0.0.0.0_abc";
|
||||
File f2 = new File(testDir, name2);
|
||||
if (f2.exists())
|
||||
Assert.assertTrue(f2.delete());
|
||||
f2.createNewFile();
|
||||
|
||||
|
||||
//make a file for same session that expired 3 sec ago
|
||||
exp = now - 3000L;
|
||||
String name3 = Long.toString(exp)+"__0.0.0.0_abc";
|
||||
File f3 = new File(testDir, name3);
|
||||
if (f3.exists())
|
||||
Assert.assertTrue(f3.delete());
|
||||
f3.createNewFile();
|
||||
|
||||
handler.setSessionIdManager(idmgr);
|
||||
handler.start();
|
||||
|
||||
Assert.assertFalse(f1.exists());
|
||||
Assert.assertFalse(f2.exists());
|
||||
Assert.assertTrue(f3.exists());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testUnrestorableFileRemoval() throws Exception
|
||||
|
@ -176,25 +283,22 @@ public class FileSessionManagerTest
|
|||
idmgr.setServer(server);
|
||||
server.setSessionIdManager(idmgr);
|
||||
|
||||
File testDir = MavenTestingUtils.getTargetTestingDir("hashes");
|
||||
FS.ensureEmpty(testDir);
|
||||
String expectedFilename = (System.currentTimeMillis()+ 10000)+"__0.0.0.0_validFile123";
|
||||
|
||||
Assert.assertTrue(new File(testDir, expectedFilename).createNewFile());
|
||||
Assert.assertTrue("File should exist!", new File(testDir, expectedFilename).exists());
|
||||
|
||||
DefaultSessionCache ss = new DefaultSessionCache(handler);
|
||||
FileSessionDataStore ds = new FileSessionDataStore();
|
||||
ss.setSessionDataStore(ds);
|
||||
handler.setSessionCache(ss);
|
||||
ds.setDeleteUnrestorableFiles(true); //invalid file will be removed
|
||||
handler.setSessionIdManager(idmgr);
|
||||
|
||||
File testDir = MavenTestingUtils.getTargetTestingDir("hashes");
|
||||
FS.ensureEmpty(testDir);
|
||||
|
||||
ds.setStoreDir(testDir);
|
||||
handler.start();
|
||||
|
||||
String expectedFilename = (System.currentTimeMillis()+ 10000)+"__0.0.0.0_validFile123";
|
||||
|
||||
Assert.assertTrue(new File(testDir, expectedFilename).createNewFile());
|
||||
|
||||
Assert.assertTrue("File should exist!", new File(testDir, expectedFilename).exists());
|
||||
|
||||
Session session = handler.getSession("validFile123");
|
||||
|
||||
Assert.assertTrue("File shouldn't exist!", !new File(testDir,expectedFilename).exists());
|
||||
|
@ -315,6 +419,6 @@ public class FileSessionManagerTest
|
|||
{
|
||||
nonNumber.delete();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import static org.junit.Assert.assertNotNull;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
|
||||
|
@ -87,12 +89,13 @@ public class FileTestHelper
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fname != null)
|
||||
return new File (_tmpDir, fname);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void assertFileExists (String sessionId, boolean exists)
|
||||
public static void assertSessionExists (String sessionId, boolean exists)
|
||||
{
|
||||
assertNotNull(_tmpDir);
|
||||
assertTrue(_tmpDir.exists());
|
||||
|
@ -115,6 +118,29 @@ public class FileTestHelper
|
|||
assertFalse(found);
|
||||
}
|
||||
|
||||
public static void assertFileExists (String filename, boolean exists)
|
||||
{
|
||||
assertNotNull(_tmpDir);
|
||||
assertTrue(_tmpDir.exists());
|
||||
File file = new File (_tmpDir, filename);
|
||||
if (exists)
|
||||
assertTrue(file.exists());
|
||||
else
|
||||
assertFalse(file.exists());
|
||||
}
|
||||
|
||||
|
||||
public static void createFile (String filename)
|
||||
throws IOException
|
||||
{
|
||||
assertNotNull(_tmpDir);
|
||||
assertTrue(_tmpDir.exists());
|
||||
|
||||
File file = new File (_tmpDir, filename);
|
||||
Files.deleteIfExists(file.toPath());
|
||||
file.createNewFile();
|
||||
}
|
||||
|
||||
|
||||
public static void deleteFile (String sessionId)
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ public class NonClusteredSessionScavengingTest extends AbstractNonClusteredSessi
|
|||
@Override
|
||||
public void assertSession(String id, boolean exists)
|
||||
{
|
||||
FileTestHelper.assertFileExists(id, exists);
|
||||
FileTestHelper.assertSessionExists(id, exists);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
package org.eclipse.jetty.server.session;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
@ -67,10 +69,90 @@ public class TestFileSessions extends AbstractTestBase
|
|||
return FileTestHelper.newSessionDataStoreFactory();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testSweep () throws Exception
|
||||
{
|
||||
int scavengePeriod = 2;
|
||||
String contextPath = "/test";
|
||||
String servletMapping = "/server";
|
||||
int inactivePeriod = 5;
|
||||
int gracePeriod = 10;
|
||||
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
|
||||
cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
|
||||
FileSessionDataStoreFactory storeFactory = (FileSessionDataStoreFactory)createSessionDataStoreFactory();
|
||||
storeFactory.setGracePeriodSec(gracePeriod);
|
||||
TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory);
|
||||
server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
|
||||
|
||||
try
|
||||
{
|
||||
server1.start();
|
||||
|
||||
//create file not for our context that expired long ago and should be removed by sweep
|
||||
FileTestHelper.createFile("101_foobar_0.0.0.0_sessiona");
|
||||
FileTestHelper.assertSessionExists("sessiona", true);
|
||||
|
||||
//create a file not for our context that is not expired and should be ignored
|
||||
String nonExpiredForeign = (System.currentTimeMillis()+TimeUnit.DAYS.toMillis(1))+"_foobar_0.0.0.0_sessionb";
|
||||
FileTestHelper.createFile(nonExpiredForeign);
|
||||
FileTestHelper.assertFileExists(nonExpiredForeign, true);
|
||||
|
||||
//create a file not for our context that is recently expired, a thus ignored by sweep
|
||||
String expiredForeign = (System.currentTimeMillis()-TimeUnit.SECONDS.toMillis(1))+"_foobar_0.0.0.0_sessionc";
|
||||
FileTestHelper.createFile(expiredForeign);
|
||||
FileTestHelper.assertFileExists(expiredForeign, true);
|
||||
|
||||
//create a file that is not a session file, it should be ignored
|
||||
FileTestHelper.createFile("whatever.txt");
|
||||
FileTestHelper.assertFileExists("whatever.txt", true);
|
||||
|
||||
//create a file that is a non-expired session file for our context that should be ignored
|
||||
String nonExpired = (System.currentTimeMillis()+TimeUnit.DAYS.toMillis(1))+"_test_0.0.0.0_sessionb";
|
||||
FileTestHelper.createFile(nonExpired);
|
||||
FileTestHelper.assertFileExists(nonExpired, true);
|
||||
|
||||
//create a file that is a never-expire session file for our context that should be ignored
|
||||
String neverExpired = "0_test_0.0.0.0_sessionc";
|
||||
FileTestHelper.createFile(neverExpired);
|
||||
FileTestHelper.assertFileExists(neverExpired, true);
|
||||
|
||||
//create a file that is a never-expire session file for another context that should be ignored
|
||||
String foreignNeverExpired = "0_test_0.0.0.0_sessionc";
|
||||
FileTestHelper.createFile(foreignNeverExpired);
|
||||
FileTestHelper.assertFileExists(foreignNeverExpired, true);
|
||||
|
||||
|
||||
//need to wait to ensure scavenge runs so sweeper runs
|
||||
Thread.currentThread().sleep(2000L*scavengePeriod);
|
||||
FileTestHelper.assertSessionExists("sessiona", false);
|
||||
FileTestHelper.assertFileExists("whatever.txt", true);
|
||||
FileTestHelper.assertFileExists(nonExpired, true);
|
||||
FileTestHelper.assertFileExists(nonExpiredForeign, true);
|
||||
FileTestHelper.assertFileExists(expiredForeign, true);
|
||||
FileTestHelper.assertFileExists(neverExpired, true);
|
||||
FileTestHelper.assertFileExists(foreignNeverExpired, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
server1.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void test () throws Exception
|
||||
{
|
||||
String contextPath = "";
|
||||
String contextPath = "/test";
|
||||
String servletMapping = "/server";
|
||||
int inactivePeriod = 5;
|
||||
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
|
||||
|
@ -97,26 +179,37 @@ public class TestFileSessions extends AbstractTestBase
|
|||
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
|
||||
|
||||
//check that the file for the session exists after creating the session
|
||||
FileTestHelper.assertFileExists(TestServer.extractSessionId(sessionCookie), true);
|
||||
FileTestHelper.assertSessionExists(TestServer.extractSessionId(sessionCookie), true);
|
||||
File file1 = FileTestHelper.getFile(TestServer.extractSessionId(sessionCookie));
|
||||
|
||||
|
||||
//request the session and check that the file for the session exists with an updated lastmodify
|
||||
//request the session and check that the file for the session was changed
|
||||
Request request = client.newRequest("http://localhost:" + port1 + contextPath + servletMapping + "?action=check");
|
||||
request.header("Cookie", sessionCookie);
|
||||
ContentResponse response2 = request.send();
|
||||
assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
|
||||
FileTestHelper.assertFileExists(TestServer.extractSessionId(sessionCookie), true);
|
||||
FileTestHelper.assertSessionExists(TestServer.extractSessionId(sessionCookie), true);
|
||||
File file2 = FileTestHelper.getFile(TestServer.extractSessionId(sessionCookie));
|
||||
assertTrue (!file1.equals(file2));
|
||||
assertTrue (file2.lastModified() > file1.lastModified());
|
||||
|
||||
assertFalse (file1.exists());
|
||||
assertTrue(file2.exists());
|
||||
|
||||
//check expiry time in filename changed
|
||||
String tmp = file1.getName();
|
||||
tmp = tmp.substring(0, tmp.indexOf("_"));
|
||||
|
||||
long f1 = Long.valueOf(tmp);
|
||||
tmp = file2.getName();
|
||||
tmp = tmp.substring(0, tmp.indexOf("_"));
|
||||
long f2 = Long.valueOf(tmp);
|
||||
assertTrue (f2>f1);
|
||||
|
||||
//invalidate the session and verify that the session file is deleted
|
||||
request = client.newRequest("http://localhost:" + port1 + contextPath + servletMapping + "?action=remove");
|
||||
request.header("Cookie", sessionCookie);
|
||||
response2 = request.send();
|
||||
assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
|
||||
FileTestHelper.assertFileExists(TestServer.extractSessionId(sessionCookie), false);
|
||||
FileTestHelper.assertSessionExists(TestServer.extractSessionId(sessionCookie), false);
|
||||
|
||||
//make another session
|
||||
response1 = client.GET("http://localhost:" + port1 + contextPath + servletMapping + "?action=init");
|
||||
|
@ -124,11 +217,11 @@ public class TestFileSessions extends AbstractTestBase
|
|||
sessionCookie = response1.getHeaders().get("Set-Cookie");
|
||||
assertTrue(sessionCookie != null);
|
||||
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
|
||||
FileTestHelper.assertFileExists(TestServer.extractSessionId(sessionCookie), true);
|
||||
FileTestHelper.assertSessionExists(TestServer.extractSessionId(sessionCookie), true);
|
||||
|
||||
//wait for it to be scavenged
|
||||
Thread.currentThread().sleep((inactivePeriod + 2)*1000);
|
||||
FileTestHelper.assertFileExists(TestServer.extractSessionId(sessionCookie), false);
|
||||
FileTestHelper.assertSessionExists(TestServer.extractSessionId(sessionCookie), false);
|
||||
|
||||
}
|
||||
finally
|
||||
|
@ -157,11 +250,12 @@ public class TestFileSessions extends AbstractTestBase
|
|||
{
|
||||
HttpSession session = request.getSession(false);
|
||||
session.invalidate();
|
||||
//assertTrue(session == null);
|
||||
}
|
||||
else if ("check".equals(action))
|
||||
{
|
||||
HttpSession session = request.getSession(false);
|
||||
assertTrue(session != null);
|
||||
try {Thread.currentThread().sleep(1);}catch (Exception e) {e.printStackTrace();}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue