[Jboss-cvs] JBossAS SVN: r56304 - 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
Sat Aug 26 16:40:12 EDT 2006
Author: bstansberry at jboss.com
Date: 2006-08-26 16:40:10 -0400 (Sat, 26 Aug 2006)
New Revision: 56304
Removed:
branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/LocalSessionActivity.java
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/JBossCacheManager.java
branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/JBossCacheService.java
branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/SessionReplicationContext.java
Log:
Simplify and tighten use of ThreadLocals
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-26 20:37:55 UTC (rev 56303)
+++ branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/ClusteredSessionValve.java 2006-08-26 20:40:10 UTC (rev 56304)
@@ -22,6 +22,9 @@
package org.jboss.web.tomcat.tc5.session;
import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+
import javax.servlet.ServletException;
import org.apache.catalina.*;
@@ -29,6 +32,7 @@
import org.apache.catalina.connector.Response;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.valves.ValveBase;
+import org.jboss.web.tomcat.tc5.session.SessionReplicationContext.ReplicatableSession;
/**
* This Valve detects all sessions that were used in a request. All sessions are given to a snapshot
@@ -75,30 +79,31 @@
*/
public void invoke(Request request, Response response) throws IOException, ServletException
{
- // Store the request and response object for the clustering code that has no direct access to
- // this objects
+ // 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);
try
{
-
-
// let the servlet invocation go through
getNext().invoke(request, response);
-
+ }
+ finally // We replicate no matter what
+ {
// --> We are now after the servlet invocation
- SessionReplicationContext[] sessions = SessionReplicationContext.getActiveSessions();
+ Set sessions = SessionReplicationContext.clearContext();
- for (int i = 0; i < sessions.length; i++)
+ if (sessions.size() > 0)
{
- sessions[i].getSnapshot().snapshot(sessions[i].getSessionId());
+ ReplicatableSession sess;
+ for (Iterator iter = sessions.iterator(); iter.hasNext();)
+ {
+ sess = (ReplicatableSession) iter.next();
+ sess.getSnapshot().snapshot(sess.getSessionId());
+ }
}
}
- finally
- {
- SessionReplicationContext.clearContext();
- }
}
// Lifecylce-interface
Modified: branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/JBossCacheManager.java
===================================================================
--- branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/JBossCacheManager.java 2006-08-26 20:37:55 UTC (rev 56303)
+++ branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/JBossCacheManager.java 2006-08-26 20:40:10 UTC (rev 56304)
@@ -615,7 +615,7 @@
// Add this session to the set of those potentially needing replication
// We use the realId here
String realId = getRealId(sessionId);
- SessionReplicationContext.addActiveSession(realId, snapshotManager_);
+ SessionReplicationContext.bindSession(realId, snapshotManager_);
return session;
}
@@ -776,7 +776,7 @@
// session from the other nodes to be gravitated, thus resuscitating
// the session.
if (session == null
- && !SessionReplicationContext.isSessionActive(realId, snapshotManager_))
+ && !SessionReplicationContext.isSessionBound(realId, snapshotManager_))
{
session = loadSession(realId);
if (session != null)
@@ -795,7 +795,7 @@
if (session != null)
{
// Add this session to the set of those potentially needing replication
- SessionReplicationContext.addActiveSession(realId, snapshotManager_);
+ SessionReplicationContext.bindSession(realId, snapshotManager_);
}
return session;
@@ -865,8 +865,7 @@
*/
public ClusteredSession findLocalSession(String realId)
{
- ClusteredSession session = (ClusteredSession) sessions_.get(realId);
- return session;
+ return (ClusteredSession) sessions_.get(realId);
}
/**
@@ -890,11 +889,11 @@
try {
// Ignore any cache notifications that our own work generates
- LocalSessionActivity.startLocalActivity(realId);
+ SessionReplicationContext.startLocalActivity(realId);
clusterSess.removeMyself();
}
finally {
- LocalSessionActivity.finishLocalActivity();
+ SessionReplicationContext.finishLocalActivity();
}
sessions_.remove(realId);
@@ -981,7 +980,7 @@
// Ignore cache notifications we may generate for this
// session if data gravitation occurs.
- LocalSessionActivity.startLocalActivity(realId);
+ SessionReplicationContext.startLocalActivity(realId);
session = proxy_.loadSession(realId, session);
}
@@ -1012,7 +1011,7 @@
endTransaction(realId);
}
finally {
- LocalSessionActivity.finishLocalActivity();
+ SessionReplicationContext.finishLocalActivity();
}
}
@@ -1069,7 +1068,7 @@
// at this level because we don't want to resume handling
// notifications until any compensating changes resulting
// from a tx rollback are done.
- LocalSessionActivity.startLocalActivity(realId);
+ SessionReplicationContext.startLocalActivity(realId);
session.processSessionRepl();
}
@@ -1102,7 +1101,7 @@
endTransaction(session.getId());
}
finally {
- LocalSessionActivity.finishLocalActivity();
+ SessionReplicationContext.finishLocalActivity();
}
}
}
Modified: branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/JBossCacheService.java
===================================================================
--- branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/JBossCacheService.java 2006-08-26 20:37:55 UTC (rev 56303)
+++ branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/JBossCacheService.java 2006-08-26 20:40:10 UTC (rev 56304)
@@ -555,13 +555,13 @@
Fqn fqn = getFieldFqn(realId, key);
try {
// Ignore any cache notifications that our own work generates
- LocalSessionActivity.startLocalActivity(realId);
+ SessionReplicationContext.startLocalActivity(realId);
return proxy_.putObject(fqn, pojo);
} catch (CacheException e) {
throw new RuntimeException("JBossCacheService: exception occurred in cache setPojo ... ", e);
}
finally {
- LocalSessionActivity.finishLocalActivity();
+ SessionReplicationContext.finishLocalActivity();
}
}
@@ -581,13 +581,13 @@
Fqn fqn = getFieldFqn(realId, key);
try {
// Ignore any cache notifications that our own work generates
- LocalSessionActivity.startLocalActivity(realId);
+ SessionReplicationContext.startLocalActivity(realId);
return proxy_.removeObject(fqn);
} catch (CacheException e) {
throw new RuntimeException("JBossCacheService: exception occurred in cache removePojo ... ", e);
}
finally {
- LocalSessionActivity.finishLocalActivity();
+ SessionReplicationContext.finishLocalActivity();
}
}
@@ -607,11 +607,11 @@
Fqn fqn = getAttributeFqn(realId);
try {
// Ignore any cache notifications that our own work generates
- LocalSessionActivity.startLocalActivity(realId);
+ SessionReplicationContext.startLocalActivity(realId);
cacheWrapper_.evictSubtree(fqn);
}
finally {
- LocalSessionActivity.finishLocalActivity();
+ SessionReplicationContext.finishLocalActivity();
}
}
@@ -631,11 +631,11 @@
Fqn fqn = getFieldFqn(realId, key);
try {
// Ignore any cache notifications that our own work generates
- LocalSessionActivity.startLocalActivity(realId);
+ SessionReplicationContext.startLocalActivity(realId);
cacheWrapper_.evictSubtree(fqn);
}
finally {
- LocalSessionActivity.finishLocalActivity();
+ SessionReplicationContext.finishLocalActivity();
}
}
Deleted: branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/LocalSessionActivity.java
===================================================================
--- branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/LocalSessionActivity.java 2006-08-26 20:37:55 UTC (rev 56303)
+++ branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/LocalSessionActivity.java 2006-08-26 20:40:10 UTC (rev 56304)
@@ -1,87 +0,0 @@
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2005, JBoss Inc., and individual contributors as indicated
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* This is free software; you can redistribute it and/or modify it
-* under the terms of the GNU Lesser General Public License as
-* published by the Free Software Foundation; either version 2.1 of
-* the License, or (at your option) any later version.
-*
-* This software is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this software; if not, write to the Free
-* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-*/
-package org.jboss.web.tomcat.tc5.session;
-
-/**
- * Binds the session id of a session that is currently being manipulated
- * locally to a ThreadLocal so CacheListener can ignore events generated by the
- * activity.
- *
- * @author Brian Stansberry
- * @version $Id$
- */
-class LocalSessionActivity
-{
- private static ThreadLocal activeSessions = new ThreadLocal();
-
- private String sessionId;
- private int level = 0;
-
- /**
- * Marks the current thread as actively processing the given session.
- * If the thread has already been so marked, increases a counter
- * so a subsequent call to finishLocalActivity does not remove
- * the association (allowing nested calls).
- *
- * @param sessionId. Can be <code>null</code>.
- */
- public static void startLocalActivity(String sessionId)
- {
- LocalSessionActivity current = (LocalSessionActivity) activeSessions.get();
- if (current == null || !(current.sessionId.equals(sessionId)))
- {
- current = new LocalSessionActivity(sessionId);
- activeSessions.set(current);
- }
- current.level++;
- }
-
- /**
- * Marks the completion of activity on a given session. Should be called
- * once for each invocation of {@link #startLocalActivity(String)}.
- *
- */
- public static void finishLocalActivity()
- {
- LocalSessionActivity current = (LocalSessionActivity) activeSessions.get();
- if (current != null)
- {
- if (--current.level == 0)
- activeSessions.set(null);
- }
- }
-
- public static boolean isLocallyActive(String sessionId)
- {
- boolean result = false;
- LocalSessionActivity active = (LocalSessionActivity) activeSessions.get();
- if (active != null)
- result = active.sessionId.equals(sessionId);
-
- return result;
- }
-
- private LocalSessionActivity(String sessionId)
- {
- this.sessionId = sessionId;
- }
-}
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-26 20:37:55 UTC (rev 56303)
+++ branches/Branch_4_0/tomcat/src/main/org/jboss/web/tomcat/tc5/session/SessionReplicationContext.java 2006-08-26 20:40:10 UTC (rev 56304)
@@ -1,151 +1,241 @@
package org.jboss.web.tomcat.tc5.session;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
-import java.util.Stack;
-import javax.servlet.http.HttpServletRequest;
-
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
public final class SessionReplicationContext
{
- private String sessionId;
- private SnapshotManager snapshot;
+ private static final ThreadLocal replicationContext = new ThreadLocal();
- private static final ThreadLocal contextStack = new ThreadLocal();
- private static final ThreadLocal requestThreadLocal = new ThreadLocal();
- private static final ThreadLocal responseThreadLocal = new ThreadLocal();
+ private static final ThreadLocal localActivity = new ThreadLocal();
+ private static final Set EMPTY;
+
+ static
+ {
+ EMPTY = Collections.unmodifiableSet(new HashSet());
+ }
+
+ private int initCount;
+ private final Set replicatableSessions;
+ private Request outerRequest;
+ private Response outerResponse;
+
public static void initContext(Request request, Response response)
{
- Stack stack = (Stack) contextStack.get();
- if (stack == null)
+ SessionReplicationContext ctx = getCurrentContext();
+ if (ctx == null)
{
- stack = new Stack();
- contextStack.set(stack);
+ ctx = new SessionReplicationContext(request, response);
+ replicationContext.set(ctx);
}
- stack.push(new LinkedHashSet());
+ ctx.initCount++;
+ }
+
+ public static Set clearContext()
+ {
+ Set replicatable = EMPTY;
+ SessionReplicationContext ctx = getCurrentContext();
+ if (ctx != null)
+ {
+ ctx.initCount--;
+ if (ctx.initCount == 0 )
+ {
+ replicatable = ctx.replicatableSessions;
+ replicationContext.set(null);
+ }
+ }
+ return replicatable;
- // We only store the outermost request if there are nested calls
- // to this method in the same request
- if (stack.size() == 1)
+ }
+
+ public static void bindSession(String realId, SnapshotManager manager)
+ {
+ SessionReplicationContext ctx = getCurrentContext();
+ if (ctx != null)
{
- requestThreadLocal.set(request);
- responseThreadLocal.set(response);
+ ctx.replicatableSessions.add(new ReplicatableSession(realId, manager));
}
+ /*else {
+ If there is no ctx, it means we are past the part of the request cycle
+ where the session will be invalidated by the app, so no further need
+ to track binding
+ }*/
}
- public static SessionReplicationContext[] getActiveSessions()
+ public static boolean isSessionBound(String realId, SnapshotManager manager)
{
- Stack stack = (Stack) contextStack.get();
- Set set = (Set) stack.peek();
-
- SessionReplicationContext[] result = new SessionReplicationContext[set.size()];
- return (SessionReplicationContext[]) set.toArray(result);
+ boolean result = false;
+ SessionReplicationContext ctx = getCurrentContext();
+ if (ctx != null)
+ {
+ result = ctx.replicatableSessions.contains(new ReplicatableSession(realId, manager));
+ }
+ return result;
}
- public static void clearContext()
+ /**
+ * Marks the current thread as actively processing the given session.
+ * If the thread has already been so marked, increases a counter
+ * so a subsequent call to finishLocalActivity does not remove
+ * the association (allowing nested calls).
+ *
+ * @param sessionId. Can be <code>null</code>.
+ */
+ public static void startLocalActivity(String sessionId)
{
- Stack stack = (Stack) contextStack.get();
- stack.pop();
-
- // If this is the last in the stack, clear the request and response
- if (stack.size() == 0)
+ LocalSessionActivity ctx = getCurrentActivity();
+ if (ctx == null)
{
- requestThreadLocal.set(null);
- responseThreadLocal.set(null);
- // TODO consider leaving the stack around
- contextStack.set(null);
+ ctx = new LocalSessionActivity(sessionId);
+ localActivity.set(ctx);
}
+ else if (!sessionId.equals(ctx.sessionId))
+ {
+ throw new IllegalStateException("Conflicting active sessions " +
+ ctx.sessionId + " and " + sessionId);
+ }
+
+ ctx.count++;
}
- public static void addActiveSession(String realId, SnapshotManager manager)
+ /**
+ * Marks the completion of activity on a given session. Should be called
+ * once for each invocation of {@link #startLocalActivity(String)}.
+ */
+ public static void finishLocalActivity()
{
- Stack stack = (Stack) contextStack.get();
- if (stack != null)
+ LocalSessionActivity ctx = getCurrentActivity();
+ if (ctx != null)
{
- Set set = (Set) stack.peek();
- if (set != null)
- set.add(new SessionReplicationContext(realId, manager));
+ ctx.count--;
+ if (ctx.count == 0)
+ {
+ localActivity.set(null);
+ }
}
}
- public static boolean isSessionActive(String realId, SnapshotManager manager)
+ public static boolean isLocallyActive(String sessionId)
{
boolean result = false;
- Stack stack = (Stack) contextStack.get();
- if (stack != null)
+ LocalSessionActivity ctx = getCurrentActivity();
+ if (ctx != null)
{
- Set set = (Set) stack.peek();
- result = set.contains(new SessionReplicationContext(realId, manager));
+ result = sessionId.equals(ctx.sessionId);
}
return result;
}
public static Request getOriginalRequest()
{
- return (Request) requestThreadLocal.get();
+ SessionReplicationContext ctx = getCurrentContext();
+ return (ctx == null ? null : ctx.outerRequest);
}
public static Response getOriginalResponse()
{
- return (Response) responseThreadLocal.get();
+ SessionReplicationContext ctx = getCurrentContext();
+ return (ctx == null ? null : ctx.outerResponse);
}
- // Prevent external instantiation
- private SessionReplicationContext(String sessionId, SnapshotManager manager)
+ private static SessionReplicationContext getCurrentContext()
{
- this.sessionId = sessionId;
- this.snapshot = manager;
+ return (SessionReplicationContext) replicationContext.get();
}
-
- public SnapshotManager getSnapshot()
+
+ private static LocalSessionActivity getCurrentActivity()
{
- return snapshot;
+ return (LocalSessionActivity) localActivity.get();
}
-
- public String getSessionId()
+
+ private SessionReplicationContext(Request request, Response response)
{
- return sessionId;
+ this.outerRequest = request;
+ this.outerResponse = response;
+ this.replicatableSessions = new LinkedHashSet();
}
-
- public boolean equals(Object obj)
+
+ private static class LocalSessionActivity
{
- if (this == obj)
- return true;
+ int count;
+ final String sessionId;
- if (obj instanceof SessionReplicationContext)
+ private LocalSessionActivity(String sessionId)
{
- SessionReplicationContext other = (SessionReplicationContext) obj;
- // Test the snapshot first as it is more likely to be unique
- return (this.snapshot.equals(other.snapshot)
- && this.sessionId.equals(other.sessionId));
+ if (sessionId == null)
+ throw new IllegalArgumentException("sessionId cannot be null");
+
+ this.sessionId = sessionId;
}
-
- return false;
}
-
- /**
- * Returns the {@link #getSnapshot snapshot}'s hashcode, as it should be sufficient
- * to minimize bucket collisions; for the same request there shouldn't be more
- * than one session per snapshot.
- */
- public int hashCode()
+
+
+ public static class ReplicatableSession
{
- return snapshot.hashCode();
- }
+ private String sessionId;
+ private SnapshotManager snapshot;
+
+ // Prevent external instantiation
+ private ReplicatableSession(String sessionId, SnapshotManager manager)
+ {
+ this.sessionId = sessionId;
+ this.snapshot = manager;
+ }
- public String toString()
- {
- StringBuffer sb = new StringBuffer(getClass().getName());
- sb.append("{sessionid=");
- sb.append(sessionId);
- sb.append("snapshot=");
- sb.append(snapshot);
- sb.append("}");
- return sb.toString();
+ public SnapshotManager getSnapshot()
+ {
+ return snapshot;
+ }
+
+ public String getSessionId()
+ {
+ return sessionId;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+
+ if (obj instanceof ReplicatableSession)
+ {
+ ReplicatableSession other = (ReplicatableSession) obj;
+ // Test the snapshot first as it is more likely to be unique
+ // and it's a simple object identity test
+ return (this.snapshot.equals(other.snapshot)
+ && this.sessionId.equals(other.sessionId));
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the {@link #getSnapshot snapshot}'s hashcode, as it should be sufficient
+ * to minimize bucket collisions; for the same request there shouldn't be more
+ * than one session per snapshot.
+ */
+ public int hashCode()
+ {
+ return snapshot.hashCode();
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer(getClass().getName());
+ sb.append("{sessionid=");
+ sb.append(sessionId);
+ sb.append("snapshot=");
+ sb.append(snapshot);
+ sb.append("}");
+ return sb.toString();
+ }
+
}
More information about the jboss-cvs-commits
mailing list