From ef6d0194b9d3af44176b6d1488be158d5f9efc3f Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Mon, 22 Feb 2016 15:08:29 +0100 Subject: [PATCH] Issue #352 Integrate session idling for MongoSessionManager --- .../org/eclipse/jetty/nosql/NoSqlSession.java | 134 +++++++++- .../jetty/nosql/NoSqlSessionManager.java | 28 ++- .../nosql/mongodb/MongoSessionIdManager.java | 29 ++- .../nosql/mongodb/MongoSessionManager.java | 74 ++++-- .../jetty/nosql/mongodb/IdleSessionTest.java | 236 ++++++++++++++++++ .../jetty/nosql/mongodb/MongoTestServer.java | 8 +- 6 files changed, 478 insertions(+), 31 deletions(-) create mode 100644 tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/IdleSessionTest.java diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSession.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSession.java index afdd9ed31a9..943b3c32d0c 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSession.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSession.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.nosql; + import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @@ -32,7 +33,9 @@ import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------ */ public class NoSqlSession extends MemSession { - private final static Logger __log = Log.getLogger("org.eclipse.jetty.server.session"); + private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); + + private enum IdleState {NOT_IDLE, IDLE, IDLING, DEIDLING}; private final NoSqlSessionManager _manager; private Set _dirty; @@ -40,6 +43,10 @@ public class NoSqlSession extends MemSession private Object _version; private long _lastSync; + private IdleState _idle = IdleState.NOT_IDLE; + + private boolean _deIdleFailed; + /* ------------------------------------------------------------ */ public NoSqlSession(NoSqlSessionManager manager, HttpServletRequest request) { @@ -73,7 +80,7 @@ public class NoSqlSession extends MemSession } - + /* ------------------------------------------------------------ */ @Override public void setAttribute(String name, Object value) { @@ -93,7 +100,7 @@ public class NoSqlSession extends MemSession } - + /* ------------------------------------------------------------ */ @Override protected void timeout() throws IllegalStateException { @@ -106,6 +113,10 @@ public class NoSqlSession extends MemSession @Override protected void checkValid() throws IllegalStateException { + //whenever a method is called on the session, check that it was not idled and + //reinflate it if necessary + if (!isDeIdleFailed() && _manager.getIdlePeriod() > 0 && isIdle()) + deIdle(); super.checkValid(); } @@ -113,7 +124,8 @@ public class NoSqlSession extends MemSession @Override protected boolean access(long time) { - __log.debug("NoSqlSession:access:active {} time {}", _active, time); + if (LOG.isDebugEnabled()) + LOG.debug("NoSqlSession:access:active {} time {}", _active, time); if (_active.incrementAndGet()==1) { long period=_manager.getStalePeriod()*1000L; @@ -122,7 +134,8 @@ public class NoSqlSession extends MemSession else if (period>0) { long stale=time-_lastSync; - __log.debug("NoSqlSession:access:stale "+stale); + if (LOG.isDebugEnabled()) + LOG.debug("NoSqlSession:access:stale "+stale); if (stale>period) refresh(); } @@ -170,7 +183,112 @@ public class NoSqlSession extends MemSession _lastSync=getAccessed(); } } + + + /* ------------------------------------------------------------ */ + public void idle () + { + synchronized (this) + { + if (!isIdle() && !isIdling()) //don't re-idle an idle session as the attribute map will be empty + { + if (LOG.isDebugEnabled()) + LOG.debug("Idling {}", super.getId()); + setIdling(); + save(false); + willPassivate(); + clearAttributes(); + setIdle(true); + } + } + } + + + /* ------------------------------------------------------------ */ + public synchronized void deIdle() + { + if (LOG.isDebugEnabled()) + LOG.debug("Checking before de-idling {}, isidle:{}, isDeidleFailed:", super.getId(), isIdle(), isDeIdleFailed()); + + if (isIdle() && !isDeIdleFailed()) + { + setDeIdling(); + if (LOG.isDebugEnabled()) + LOG.debug("De-idling " + super.getId()); + + // Update access time to prevent race with idling period + super.access(System.currentTimeMillis()); + + //access may have expired and invalidated the session, so only deidle if it is still valid + if (isValid()) + { + try + { + setIdle(false); + _version=_manager.refresh(this, new Long(0)); //ensure version should not match to force refresh + if (_version == null) + setDeIdleFailed(true); + } + catch (Exception e) + { + setDeIdleFailed(true); + LOG.warn("Problem de-idling session " + super.getId(), e); + invalidate(); + } + } + } + } + + /* ------------------------------------------------------------ */ + public synchronized boolean isIdle () + { + return _idle == IdleState.IDLE; + } + + + /* ------------------------------------------------------------ */ + public synchronized boolean isIdling () + { + return _idle == IdleState.IDLING; + } + + /* ------------------------------------------------------------ */ + public synchronized boolean isDeIdling() + { + return _idle == IdleState.DEIDLING; + } + + + public synchronized void setIdling () + { + _idle = IdleState.IDLING; + } + + public synchronized void setDeIdling () + { + _idle = IdleState.DEIDLING; + } + + /* ------------------------------------------------------------ */ + public synchronized void setIdle (boolean idle) + { + if (idle) + _idle = IdleState.IDLE; + else + _idle = IdleState.NOT_IDLE; + } + + + public boolean isDeIdleFailed() + { + return _deIdleFailed; + } + + public void setDeIdleFailed(boolean _deIdleFailed) + { + this._deIdleFailed = _deIdleFailed; + } /* ------------------------------------------------------------ */ protected void refresh() @@ -209,13 +327,17 @@ public class NoSqlSession extends MemSession { return _version; } - + + + /* ------------------------------------------------------------ */ @Override public void setClusterId(String clusterId) { super.setClusterId(clusterId); } + + /* ------------------------------------------------------------ */ @Override public void setNodeId(String nodeId) { diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java index 137d2385411..288a0d1f453 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java @@ -45,6 +45,7 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme private int _stalePeriod=0; private int _savePeriod=0; private int _idlePeriod=-1; + private boolean _deidleBeforeExpiry = true; private boolean _invalidateOnStop; private boolean _preserveOnStop = true; private boolean _saveAllAttributes; @@ -82,6 +83,8 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme if (session==null) { + __log.debug("Session {} is not in memory", idInCluster); + //session not in this node's memory, load it session=loadSession(idInCluster); @@ -109,6 +112,8 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme else __log.debug("session does not exist {}", idInCluster); } + else + session.deIdle(); return session; } @@ -206,8 +211,15 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme //we need to expire the session with its listeners, so load it session = loadSession(idInCluster); } + else + { + //deidle if the session was idled + if (isDeidleBeforeExpiry()) + session.deIdle(); + } - if (session != null) + //check that session is still valid after potential de-idle + if (session != null && session.isValid()) session.timeout(); } catch (Exception e) @@ -304,7 +316,6 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme * The Idle Period is the time in seconds before an in memory session is passivated. * When this period is exceeded, the session will be passivated and removed from memory. If the session was dirty, it will be written to the DB. * If the idle period is set to a value < 0, then the session is never idled. - * If the save period is set to 0, then the session is idled whenever the active request count goes from 1 to 0. * @return the idlePeriod */ public int getIdlePeriod() @@ -317,7 +328,6 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme * The Idle Period is the time in seconds before an in memory session is passivated. * When this period is exceeded, the session will be passivated and removed from memory. If the session was dirty, it will be written to the DB. * If the idle period is set to a value < 0, then the session is never idled. - * If the save period is set to 0, then the session is idled whenever the active request count goes from 1 to 0. * @param idlePeriod the idlePeriod in seconds */ public void setIdlePeriod(int idlePeriod) @@ -385,6 +395,18 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme _saveAllAttributes = saveAllAttributes; } + /* ------------------------------------------------------------ */ + public boolean isDeidleBeforeExpiry() + { + return _deidleBeforeExpiry; + } + + /* ------------------------------------------------------------ */ + public void setDeidleBeforeExpiry(boolean deidleBeforeExpiry) + { + _deidleBeforeExpiry = deidleBeforeExpiry; + } + /* ------------------------------------------------------------ */ @Override public void renewSessionId(String oldClusterId, String oldNodeId, String newClusterId, String newNodeId) 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 e078b9a8d35..a6a78835f62 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 @@ -76,10 +76,10 @@ public class MongoSessionIdManager extends AbstractSessionIdManager final DBCollection _sessions; protected Server _server; - private Scheduler _scheduler; - private boolean _ownScheduler; - private Scheduler.Task _scavengerTask; - private Scheduler.Task _purgerTask; + protected Scheduler _scheduler; + protected boolean _ownScheduler; + protected Scheduler.Task _scavengerTask; + protected Scheduler.Task _purgerTask; @@ -134,6 +134,7 @@ public class MongoSessionIdManager extends AbstractSessionIdManager try { scavenge(); + idle(); } finally { @@ -687,6 +688,26 @@ public class MongoSessionIdManager extends AbstractSessionIdManager } } + + public void idle () + { + //tell all contexts to passivate out idle sessions + Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class); + for (int i=0; contexts!=null && i