[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