[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