[Jboss-cvs] JBossAS SVN: r56402 - branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Tue Aug 29 11:33:59 EDT 2006
Author: bstansberry at jboss.com
Date: 2006-08-29 11:33:58 -0400 (Tue, 29 Aug 2006)
New Revision: 56402
Modified:
branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/ClusteredSessionValve.java
branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/SessionReplicationContext.java
Log:
Optimize for non-cross-context sessions. Simplify to 1 ThreadLocal.
Modified: branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/ClusteredSessionValve.java
===================================================================
--- branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/ClusteredSessionValve.java 2006-08-29 15:32:57 UTC (rev 56401)
+++ branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/ClusteredSessionValve.java 2006-08-29 15:33:58 UTC (rev 56402)
@@ -80,8 +80,7 @@
{
// Initialize the context and store the request and response objects
// for any clustering code that has no direct access to these objects
- SessionReplicationContext.initContext(request, response);
-
+ SessionReplicationContext.enterWebapp(request, response, true);
try
{
// let the servlet invocation go through
@@ -90,17 +89,34 @@
finally // We replicate no matter what
{
// --> We are now after the servlet invocation
-
- Map sessions = SessionReplicationContext.clearContext();
-
- if (sessions.size() > 0)
+ try
{
- for (Iterator iter = sessions.entrySet().iterator(); iter.hasNext();)
+ SessionReplicationContext ctx = SessionReplicationContext.exitWebapp();
+
+ if (ctx.getSoleSnapshotManager() != null)
{
- Map.Entry entry = (Map.Entry) iter.next();
- ((SnapshotManager) entry.getValue()).snapshot((ClusteredSession) entry.getKey());
+ ctx.getSoleSnapshotManager().snapshot(ctx.getSoleSession());
}
+ else
+ {
+ // Cross-context request touched multiple sesssions;
+ // need to replicate them all
+ Map sessions = ctx.getCrossContextSessions();
+ if (sessions != null && sessions.size() > 0)
+ {
+ for (Iterator iter = sessions.entrySet().iterator(); iter.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ ((SnapshotManager) entry.getValue()).snapshot((ClusteredSession) entry.getKey());
+ }
+ }
+ }
}
+ finally
+ {
+ SessionReplicationContext.finishCacheActivity();
+ }
+
}
}
Modified: branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/SessionReplicationContext.java
===================================================================
--- branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/SessionReplicationContext.java 2006-08-29 15:32:57 UTC (rev 56401)
+++ branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/SessionReplicationContext.java 2006-08-29 15:33:58 UTC (rev 56402)
@@ -1,6 +1,5 @@
package org.jboss.web.tomcat.tc5.session;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -11,34 +10,30 @@
{
private static final ThreadLocal replicationContext = new ThreadLocal();
- private static final ThreadLocal localActivity = new ThreadLocal();
+ private static final SessionReplicationContext EMPTY = new SessionReplicationContext();
- private static final Map EMPTY;
-
- static
- {
- EMPTY = Collections.unmodifiableMap(new HashMap());
- }
-
- private int initCount;
- private final Map replicatableSessions;
+ private int webappCount;
+ private int activityCount;
+ private SnapshotManager soleManager;
+ private ClusteredSession soleSession;
+ private Map crossCtxSessions;
private Map expiredSessions;
private Request outerRequest;
private Response outerResponse;
/**
* Associate a SessionReplicationContext with the current thread, if
- * there isn't one already. If there isn't one, associated the
+ * there isn't one already. If there isn't one, associate the
* given request and response with the context.
* <p/>
- * <strong>NOTE:</strong> Nested calls to this method and {@link #clearContext()}
+ * <strong>NOTE:</strong> Nested calls to this method and {@link #exitWebapp()}
* are supported; once a context is established the number of calls to this
- * method and <code>clearContext()</code> are tracked.
+ * method and <code>exitWebapp()</code> are tracked.
*
* @param request
* @param response
*/
- public static void initContext(Request request, Response response)
+ public static void enterWebapp(Request request, Response response, boolean startCacheActivity)
{
SessionReplicationContext ctx = getCurrentContext();
if (ctx == null)
@@ -46,31 +41,43 @@
ctx = new SessionReplicationContext(request, response);
replicationContext.set(ctx);
}
- ctx.initCount++;
+
+ ctx.webappCount++;
+ if (startCacheActivity)
+ ctx.activityCount++;
}
/**
- * Remove the SessionReplicationContext from the current thread
- * and return a Map of all sessions possibly needing replication.
+ * Signals that the webapp is finished handling the request (and
+ * therefore replication can begin.)
*
- * @return a Map<ClusteredSession, SnapshotManager>
+ * @return a SessionReplicationContext, from which information
+ * about any sessions needing replication can be obtained.
+ * Will not return <code>null</code>.
*/
- public static Map clearContext()
+ public static SessionReplicationContext exitWebapp()
{
SessionReplicationContext ctx = getCurrentContext();
if (ctx != null)
{
- ctx.initCount--;
- if (ctx.initCount == 0 )
+ ctx.webappCount--;
+ if (ctx.webappCount < 1)
{
- // We've unwound any nested calls; clear the ThreadLocal
- // and return the sessions
- replicationContext.set(null);
- return ctx.replicatableSessions;
+ // We've unwound any nested webapp calls, so we'll clean up and
+ // return the context to allow replication. If all cache activity
+ // is done as well, clear the ThreadLocal
+
+ ctx.outerRequest = null;
+ ctx.outerResponse = null;
+
+ if (ctx.activityCount < 1)
+ replicationContext.set(null);
+
+ return ctx;
}
}
- // Just return an empty map
+ // A nested valve called us. Just return an empty context
return EMPTY;
}
@@ -78,25 +85,22 @@
public static void bindSession(ClusteredSession session, SnapshotManager manager)
{
SessionReplicationContext ctx = getCurrentContext();
- if (ctx != null)
+ if (ctx != null && ctx.webappCount > 0)
{
- ctx.replicatableSessions.put(session, manager);
+ ctx.addReplicatableSession(session, manager);
}
/*else {
- If there is no ctx, it means we are past the part of the request cycle
- where we track sessions for replication
+ We are past the part of the request cycle where we
+ track sessions for replication
}*/
}
public static void sessionExpired(ClusteredSession session, String realId, SnapshotManager manager)
{
SessionReplicationContext ctx = getCurrentContext();
- if (ctx != null)
+ if (ctx != null && ctx.webappCount > 0)
{
- Object obj = ctx.replicatableSessions.remove(session);
- if (obj != null)
- ctx.addExpiredSession(realId, manager);
- // else we weren't managing the session; just ignore
+ ctx.addExpiredSession(session, manager);
}
}
@@ -117,38 +121,38 @@
* so a subsequent call to finishLocalActivity does not remove
* the association (allowing nested calls).
*/
- public static void startLocalActivity()
+ public static void startCacheActivity()
{
- LocalSessionActivity ctx = getCurrentActivity();
+ SessionReplicationContext ctx = getCurrentContext();
if (ctx == null)
{
- ctx = new LocalSessionActivity();
- localActivity.set(ctx);
+ ctx = new SessionReplicationContext();
+ replicationContext.set(ctx);
}
- ctx.count++;
+ ctx.activityCount++;
}
/**
* Marks the completion of activity on a given session. Should be called
- * once for each invocation of {@link #startLocalActivity()}.
+ * once for each invocation of {@link #startCacheActivity()}.
*/
- public static void finishLocalActivity()
+ public static void finishCacheActivity()
{
- LocalSessionActivity ctx = getCurrentActivity();
+ SessionReplicationContext ctx = getCurrentContext();
if (ctx != null)
{
- ctx.count--;
- if (ctx.count == 0)
+ ctx.activityCount--;
+ if (ctx.activityCount < 1 && ctx.webappCount < 1)
{
- localActivity.set(null);
+ replicationContext.set(null);
}
}
}
public static boolean isLocallyActive()
{
- return getCurrentActivity() != null;
+ return getCurrentContext() != null;
}
public static Request getOriginalRequest()
@@ -168,27 +172,101 @@
return (SessionReplicationContext) replicationContext.get();
}
- private static LocalSessionActivity getCurrentActivity()
- {
- return (LocalSessionActivity) localActivity.get();
- }
-
private SessionReplicationContext(Request request, Response response)
{
this.outerRequest = request;
this.outerResponse = response;
- this.replicatableSessions = new HashMap();
}
- private void addExpiredSession(String realId, SnapshotManager manager)
+ private SessionReplicationContext() {}
+
+ /**
+ * Gets a Map<SnapshotManager, ClusteredSession> of sessions that were accessed
+ * during the course of a request. Will only be non-null if
+ * {@link #bindSession(ClusteredSession, SnapshotManager)} was called
+ * with more than one SnapshotManager (i.e the request crossed session
+ * contexts.)
+ */
+ public Map getCrossContextSessions()
{
- if (this.expiredSessions == null)
+ return crossCtxSessions;
+ }
+
+ /**
+ * Gets the SnapshotManager that was passed to
+ * {@link #bindSession(ClusteredSession, SnapshotManager)} if and only
+ * if only one such SnapshotManager was passed. Returns <code>null</code>
+ * otherwise, in which case a cross-context request is a possibility,
+ * and {@link #getCrossContextSessions()} should be checked.
+ */
+ public SnapshotManager getSoleSnapshotManager()
+ {
+ return soleManager;
+ }
+
+ /**
+ * Gets the ClusteredSession that was passed to
+ * {@link #bindSession(ClusteredSession, SnapshotManager)} if and only
+ * if only one SnapshotManager was passed. Returns <code>null</code>
+ * otherwise, in which case a cross-context request is a possibility,
+ * and {@link #getCrossContextSessions()} should be checked.
+ */
+ public ClusteredSession getSoleSession()
+ {
+ return soleSession;
+ }
+
+ private void addReplicatableSession(ClusteredSession session, SnapshotManager mgr)
+ {
+ if (crossCtxSessions != null)
{
- expiredSessions = new HashMap();
+ crossCtxSessions.put(session, mgr);
}
- expiredSessions.put(manager, realId);
+ else if (soleManager == null)
+ {
+ // First one bound
+ soleManager = mgr;
+ soleSession = session;
+ }
+ else if (!mgr.equals(soleManager))
+ {
+ // We have a cross-context call; need a Map for the sessions
+ crossCtxSessions = new HashMap();
+ crossCtxSessions.put(soleSession, soleManager);
+ crossCtxSessions.put(session, mgr);
+ soleManager = null;
+ soleSession = null;
+ }
+ else
+ {
+ soleSession = session;
+ }
}
+ private void addExpiredSession(ClusteredSession session, SnapshotManager manager)
+ {
+ boolean store = manager.equals(soleManager);
+ if (store)
+ {
+ soleManager = null;
+ soleSession = null;
+ }
+ else if (crossCtxSessions != null)
+ {
+ // Only store the session if it was previously in our map
+ store = (crossCtxSessions.remove(session) != null);
+ }
+
+ if (store)
+ {
+ if (this.expiredSessions == null)
+ {
+ expiredSessions = new HashMap();
+ }
+ expiredSessions.put(manager, session.getRealId());
+ }
+ }
+
private boolean isSessionExpired(String realId, SnapshotManager manager)
{
boolean result = false;
@@ -199,14 +277,4 @@
return result;
}
- // Static Member Classes
-
- /**
- * A mutable integer
- */
- private static class LocalSessionActivity
- {
- int count;
- }
-
}
More information about the jboss-cvs-commits
mailing list