Make setting of last saved time less fragile.

This commit is contained in:
Jan Bartel 2015-11-12 11:17:20 +11:00
parent b0748c5865
commit b18769c1f9
7 changed files with 99 additions and 104 deletions

View File

@ -44,7 +44,7 @@ public abstract class AbstractSessionDataStore extends AbstractLifeCycle impleme
} }
public abstract void doStore(SessionKey key, SessionData data) throws Exception; public abstract void doStore(SessionKey key, SessionData data, boolean isNew) throws Exception;
public Context getContext() public Context getContext()
@ -65,9 +65,17 @@ public abstract class AbstractSessionDataStore extends AbstractLifeCycle impleme
@Override @Override
public void store(SessionKey key, SessionData data) throws Exception public void store(SessionKey key, SessionData data) throws Exception
{ {
long lastSave = data.getLastSaved();
data.setLastSaved(System.currentTimeMillis());
try try
{ {
doStore(key, data); doStore(key, data, (lastSave<=0));
}
catch (Exception e)
{
//reset last save time
data.setLastSaved(lastSave);
} }
finally finally
{ {

View File

@ -374,6 +374,8 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
removeId(oldClusterId);//remove the old one from the list (and database) removeId(oldClusterId);//remove the old one from the list (and database)
useId(newClusterId); //add the new id to list
//tell all contexts to update the id //tell all contexts to update the id
Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class); Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
for (int i=0; contexts!=null && i<contexts.length; i++) for (int i=0; contexts!=null && i<contexts.length; i++)

View File

@ -231,28 +231,19 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
session.setSessionManager(_manager); session.setSessionManager(_manager);
//if the session data has changed, or the cache is considered stale, write it to any backing store
if ((session.isNew() || session.getSessionData().isDirty() || isStale(session)) && _sessionDataStore != null)
{
session.willPassivate();
_sessionDataStore.store(key, session.getSessionData());
session.didActivate();
}
Session existing = doPutIfAbsent(key,session); Session existing = doPutIfAbsent(key,session);
if (existing == null) if (existing == null)
{ {
//session not already in cache write through
if (_sessionDataStore != null)
{
session.willPassivate();
_sessionDataStore.store(SessionKey.getKey(session.getSessionData()), session.getSessionData());
session.didActivate();
}
_sessionStats.increment(); _sessionStats.increment();
} }
else
{
//if the session data has changed, or the cache is considered stale, write it to any backing store
if ((session.getSessionData().isDirty() || isStale(session)) && _sessionDataStore != null)
{
session.willPassivate();
_sessionDataStore.store(key, session.getSessionData());
session.didActivate();
}
}
} }
/** /**

View File

@ -228,7 +228,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore
* @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(org.eclipse.jetty.server.session.SessionKey, org.eclipse.jetty.server.session.SessionData) * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(org.eclipse.jetty.server.session.SessionKey, org.eclipse.jetty.server.session.SessionData)
*/ */
@Override @Override
public void doStore(SessionKey key, SessionData data) throws Exception public void doStore(SessionKey key, SessionData data, boolean isNew) throws Exception
{ {
File file = null; File file = null;
if (_storeDir != null) if (_storeDir != null)

View File

@ -308,7 +308,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
} }
} }
PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+", "+getExpiryTimeColumn()+ PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getExpiryTimeColumn()+
" from "+getTableName()+" where "+getContextPathColumn()+" = ? and "+ " from "+getTableName()+" where "+getContextPathColumn()+" = ? and "+
getVirtualHostColumn()+" = ? and "+ getVirtualHostColumn()+" = ? and "+
getExpiryTimeColumn()+" >0 and "+getExpiryTimeColumn()+" <= ?"); getExpiryTimeColumn()+" >0 and "+getExpiryTimeColumn()+" <= ?");
@ -636,7 +636,6 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
_sessionTableSchema.setDatabaseAdaptor(_dbAdaptor); _sessionTableSchema.setDatabaseAdaptor(_dbAdaptor);
_sessionTableSchema.prepareTables(); _sessionTableSchema.prepareTables();
} }
} }
@ -741,108 +740,101 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
* @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore() * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore()
*/ */
@Override @Override
public void doStore(SessionKey key, SessionData data) throws Exception public void doStore(SessionKey key, SessionData data, boolean isNew) throws Exception
{ {
if (data==null || key==null) if (data==null || key==null)
return; return;
try (Connection connection = _dbAdaptor.getConnection()) if (isNew)
{ {
connection.setAutoCommit(true); doInsert(key, data);
}
//If last saved field not set, then this is a fresh session that has never been persisted else
if (data.getLastSaved() <= 0) {
{ doUpdate(key, data);
doInsert(connection, key, data);
}
else
{
doUpdate(connection, key, data);
}
} }
} }
private void doInsert (Connection connection, SessionKey key, SessionData data) private void doInsert (SessionKey key, SessionData data)
throws Exception throws Exception
{ {
String s = _sessionTableSchema.getInsertSessionStatementAsString(); String s = _sessionTableSchema.getInsertSessionStatementAsString();
try (PreparedStatement statement = connection.prepareStatement(s))
try (Connection connection = _dbAdaptor.getConnection())
{ {
connection.setAutoCommit(true);
try (PreparedStatement statement = connection.prepareStatement(s))
{
statement.setString(1, key.getId()); //session id
statement.setString(2, key.getCanonicalContextPath()); //context path
statement.setString(3, key.getVhost()); //first vhost
statement.setString(4, data.getLastNode());//my node id
statement.setLong(5, data.getAccessed());//accessTime
statement.setLong(6, data.getLastAccessed()); //lastAccessTime
statement.setLong(7, data.getCreated()); //time created
statement.setLong(8, data.getCookieSet());//time cookie was set
statement.setLong(9, data.getLastSaved()); //last saved time
statement.setLong(10, data.getExpiry());
statement.setLong(11, data.getMaxInactiveMs());
long now = System.currentTimeMillis(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(data.getAllAttributes());
oos.flush();
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
statement.setString(1, key.getId()); //session id statement.setBinaryStream(12, bais, bytes.length);//attribute map as blob
statement.setString(2, key.getCanonicalContextPath()); //context path statement.executeUpdate();
statement.setString(3, key.getVhost()); //first vhost if (LOG.isDebugEnabled())
statement.setString(4, data.getLastNode());//my node id LOG.debug("Inserted session "+data);
statement.setLong(5, data.getAccessed());//accessTime }
statement.setLong(6, data.getLastAccessed()); //lastAccessTime
statement.setLong(7, data.getCreated()); //time created
statement.setLong(8, data.getCookieSet());//time cookie was set
statement.setLong(9, now); //last saved time
statement.setLong(10, data.getExpiry());
statement.setLong(11, data.getMaxInactiveMs());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(data.getAllAttributes());
oos.flush();
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
statement.setBinaryStream(12, bais, bytes.length);//attribute map as blob
statement.executeUpdate();
data.setLastSaved(now);
if (LOG.isDebugEnabled())
LOG.debug("Inserted session "+data);
} }
} }
private void doUpdate (Connection connection, SessionKey key, SessionData data) private void doUpdate (SessionKey key, SessionData data)
throws Exception throws Exception
{ {
try (PreparedStatement statement = _sessionTableSchema.getUpdateSessionStatement(connection, key.getCanonicalContextPath())) try (Connection connection = _dbAdaptor.getConnection())
{ {
long now = System.currentTimeMillis(); connection.setAutoCommit(true);
try (PreparedStatement statement = _sessionTableSchema.getUpdateSessionStatement(connection, key.getCanonicalContextPath()))
{
statement.setString(1, data.getLastNode());//should be my node id
statement.setLong(2, data.getAccessed());//accessTime
statement.setLong(3, data.getLastAccessed()); //lastAccessTime
statement.setLong(4, data.getLastSaved()); //last saved time
statement.setLong(5, data.getExpiry());
statement.setLong(6, data.getMaxInactiveMs());
statement.setString(1, data.getLastNode());//should be my node id ByteArrayOutputStream baos = new ByteArrayOutputStream();
statement.setLong(2, data.getAccessed());//accessTime ObjectOutputStream oos = new ObjectOutputStream(baos);
statement.setLong(3, data.getLastAccessed()); //lastAccessTime oos.writeObject(data.getAllAttributes());
statement.setLong(4, now); //last saved time oos.flush();
statement.setLong(5, data.getExpiry()); byte[] bytes = baos.toByteArray();
statement.setLong(6, data.getMaxInactiveMs()); ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
statement.setBinaryStream(7, bais, bytes.length);//attribute map as blob
ByteArrayOutputStream baos = new ByteArrayOutputStream(); if ((key.getCanonicalContextPath() == null || "".equals(key.getCanonicalContextPath())) && _dbAdaptor.isEmptyStringNull())
ObjectOutputStream oos = new ObjectOutputStream(baos); {
oos.writeObject(data.getAllAttributes()); statement.setString(8, key.getId());
oos.flush(); statement.setString(9, key.getVhost());
byte[] bytes = baos.toByteArray(); }
ByteArrayInputStream bais = new ByteArrayInputStream(bytes); else
statement.setBinaryStream(7, bais, bytes.length);//attribute map as blob {
statement.setString(8, key.getId());
statement.setString(9, key.getCanonicalContextPath());
statement.setString(10, key.getVhost());
}
if ((key.getCanonicalContextPath() == null || "".equals(key.getCanonicalContextPath())) && _dbAdaptor.isEmptyStringNull()) statement.executeUpdate();
{
statement.setString(8, key.getId());
statement.setString(9, key.getVhost());
}
else
{
statement.setString(8, key.getId());
statement.setString(9, key.getCanonicalContextPath());
statement.setString(10, key.getVhost());
}
statement.executeUpdate(); if (LOG.isDebugEnabled())
LOG.debug("Updated session "+data);
data.setLastSaved(now); }
if (LOG.isDebugEnabled()) }
LOG.debug("Updated session "+data);
}
} }

View File

@ -61,7 +61,7 @@ public class NullSessionDataStore extends AbstractSessionDataStore
* @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore() * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore()
*/ */
@Override @Override
public void doStore(SessionKey key, SessionData data) throws Exception public void doStore(SessionKey key, SessionData data, boolean isNew) throws Exception
{ {
//noop //noop
} }

View File

@ -126,6 +126,7 @@ public abstract class AbstractForwardedSessionTest
HttpSession sess = request.getSession(false); HttpSession sess = request.getSession(false);
assertNotNull(sess); assertNotNull(sess);
assertNotNull(sess.getAttribute("servlet3"));
sess.setAttribute("servlet1", "servlet1"); sess.setAttribute("servlet1", "servlet1");
} }
} }
@ -144,6 +145,7 @@ public abstract class AbstractForwardedSessionTest
//the session should exist after the forward //the session should exist after the forward
HttpSession sess = request.getSession(false); HttpSession sess = request.getSession(false);
assertNotNull(sess); assertNotNull(sess);
assertNotNull(sess.getAttribute("servlet3"));
} }
} }