[jboss-cvs] JBossAS SVN: r64678 - trunk/tomcat/src/main/org/jboss/web/tomcat/service/session.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Sat Aug 18 11:04:17 EDT 2007


Author: bstansberry at jboss.com
Date: 2007-08-18 11:04:16 -0400 (Sat, 18 Aug 2007)
New Revision: 64678

Added:
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListenerBase.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/PassivationListener.java
Modified:
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListener.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManager.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManagerMBean.java
Log:
[JBAS-4613] JBossCacheManager active session count should include backup sessions

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListener.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListener.java	2007-08-18 14:58:08 UTC (rev 64677)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListener.java	2007-08-18 15:04:16 UTC (rev 64678)
@@ -36,46 +36,21 @@
 import org.jboss.logging.Logger;
 
 @org.jboss.cache.notifications.annotation.CacheListener
-public class CacheListener
+public class CacheListener extends CacheListenerBase
 {
-   // Element within an FQN that is JSESSION
-   private static final int JSESSION_FQN_INDEX = 0;
-   // Element within an FQN that is the hostname
-   private static final int HOSTNAME_FQN_INDEX = 1;
-   // ELEMENT within an FQN this is the webapp name
-   private static final int WEBAPP_FQN_INDEX = 2;
-   // Element within an FQN that is the session id
-   private static final int SESSION_ID_FQN_INDEX = 3;
-   // Size of an Fqn that points to the root of a session
-   private static final int SESSION_FQN_SIZE = SESSION_ID_FQN_INDEX + 1;
    // Element within an FQN that is the root of a Pojo attribute map
    private static final int POJO_ATTRIBUTE_FQN_INDEX = SESSION_ID_FQN_INDEX + 1;
    // Element within an FQN that is the root of an individual Pojo attribute
    private static final int POJO_KEY_FQN_INDEX = POJO_ATTRIBUTE_FQN_INDEX + 1;
    // Size of an Fqn that points to the root of a session
    private static final int POJO_KEY_FQN_SIZE = POJO_KEY_FQN_INDEX + 1;
-   // The index of the root of a buddy backup subtree
-   private static final int BUDDY_BACKUP_ROOT_OWNER_INDEX = BuddyManager.BUDDY_BACKUP_SUBTREE_FQN.size();
-   // The size of the root of a buddy backup subtree (including owner)
-   private static final int BUDDY_BACKUP_ROOT_OWNER_SIZE = BUDDY_BACKUP_ROOT_OWNER_INDEX + 1;
-   
    private static Logger log_ = Logger.getLogger(CacheListener.class);
-   private JBossCacheManager manager_;
-   private String webapp_;
-   private String hostname_;
    private boolean fieldBased_;
-   // When trying to ignore unwanted notifications, do we check for local activity first?
-   private boolean disdainLocalActivity_;
 
    CacheListener(JBossCacheWrapper wrapper, JBossCacheManager manager, String hostname, String webapp)
-   {
-      manager_ = manager;
-      hostname_ = hostname;
-      webapp_ =  webapp;
-      ReplicationGranularity granularity = manager_.getReplicationGranularity();
-      fieldBased_ = (granularity == ReplicationGranularity.FIELD);
-      // TODO decide if disdaining local activity is always good for REPL_ASYNC
-      disdainLocalActivity_ = (granularity == ReplicationGranularity.SESSION);; // for now
+   {      
+      super(manager, hostname, webapp);
+      fieldBased_ = (manager_.getReplicationGranularity() == ReplicationGranularity.FIELD);
    }
 
    // --------------- TreeCacheListener methods ------------------------------------
@@ -123,34 +98,17 @@
       if (pre || isLocal)
          return;
       
-//      // If checking for local activity has a higher likelihood of
-//      // catching unwanted notifications than checking fqn size, 
-//      // do it first
-//      if (disdainLocalActivity_)
-//      {
-//         if (SessionReplicationContext.isLocallyActive())
-//            return;         
-//      }
-      
       boolean isBuddy = isBuddyFqn(fqn);      
       // We only care if there is a chance this is for a session root
       if (!isFqnSessionRootSized(fqn, isBuddy))
          return;
       
-//      if (!disdainLocalActivity_)
-//      {
-//         if (SessionReplicationContext.isLocallyActive())
-//            return;
-//      }
-      
       // We only care if this is for our webapp
       if (!isFqnForOurWebapp(fqn, isBuddy))
          return;
 
       // Query if we have version value in the distributed cache. 
       // If we have a version value, compare the version and invalidate if necessary.
-      // TODO get the key from the passed in data map!!
-//      Integer version = (Integer)cacheWrapper_.get(fqn, JBossCacheService.VERSION_KEY);
       Integer version = (Integer)data.get(JBossCacheService.VERSION_KEY);
       if(version != null)
       {
@@ -207,65 +165,13 @@
       // BES -- 2007/07/03 Not sure what this means
    }
    
-   private boolean isFqnForOurWebapp(Fqn fqn, boolean isBuddy)
-   {
-      try
-      {
-         if (webapp_.equals(fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + WEBAPP_FQN_INDEX : WEBAPP_FQN_INDEX))
-               && hostname_.equals(fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + HOSTNAME_FQN_INDEX : HOSTNAME_FQN_INDEX))
-               && JBossCacheService.SESSION.equals(fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + JSESSION_FQN_INDEX : JSESSION_FQN_INDEX)))
-            return true;
-      }
-      catch (IndexOutOfBoundsException e)
-      {
-         // can't be ours; too small; just fall through
-      }
-
-      return false;
-   }
-   
-   private static boolean isFqnSessionRootSized(Fqn fqn, boolean isBuddy)
-   {
-      return fqn.size() == (isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + SESSION_FQN_SIZE : SESSION_FQN_SIZE);
-   }
-   
    private static boolean isFqnPojoKeySized(Fqn fqn, boolean isBuddy)
    {
       return fqn.size() == (isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + POJO_KEY_FQN_SIZE : POJO_KEY_FQN_SIZE);
    }
    
-   private static String getIdFromFqn(Fqn fqn, boolean isBuddy)
-   {
-      return (String)fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + SESSION_ID_FQN_INDEX : SESSION_ID_FQN_INDEX);
-   }
-   
    private static String getPojoKeyFromFqn(Fqn fqn, boolean isBuddy)
    {
       return (String) fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + POJO_KEY_FQN_INDEX: POJO_KEY_FQN_INDEX);
    }
-   
-   private static boolean isBuddyFqn(Fqn fqn)
-   {
-      try
-      {
-         return BuddyManager.BUDDY_BACKUP_SUBTREE.equals(fqn.get(0));
-      }
-      catch (IndexOutOfBoundsException e)
-      {
-         // Can only happen if fqn is ROOT, and we shouldn't get
-         // notifications for ROOT.
-         // If it does, just means it's not a buddy
-         return false;
-      }      
-   }
-   
-   /**
-    * Extracts the owner portion of an buddy subtree Fqn.
-    * 
-    * @param fqn An Fqn that is a child of the buddy backup root node.
-    */
-   private static String getBuddyOwner(Fqn fqn)
-   {
-      return (String) fqn.get(BUDDY_BACKUP_ROOT_OWNER_INDEX);     
-   }
 }

Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListenerBase.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListenerBase.java	                        (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListenerBase.java	2007-08-18 15:04:16 UTC (rev 64678)
@@ -0,0 +1,78 @@
+package org.jboss.web.tomcat.service.session;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.buddyreplication.BuddyManager;
+
+public class CacheListenerBase
+{
+
+   private static final int JSESSION_FQN_INDEX = 0;
+   private static final int HOSTNAME_FQN_INDEX = 1;
+   private static final int WEBAPP_FQN_INDEX = 2;
+   protected static final int SESSION_ID_FQN_INDEX = 3;
+   private static final int SESSION_FQN_SIZE = SESSION_ID_FQN_INDEX + 1;
+   private static final int BUDDY_BACKUP_ROOT_OWNER_INDEX = BuddyManager.BUDDY_BACKUP_SUBTREE_FQN.size();
+   protected static final int BUDDY_BACKUP_ROOT_OWNER_SIZE = BUDDY_BACKUP_ROOT_OWNER_INDEX + 1;
+   protected JBossCacheManager manager_;
+   private String webapp_;
+   private String hostname_;
+
+   CacheListenerBase(JBossCacheManager manager, String hostname, String webapp)
+   {      
+      manager_ = manager;
+      hostname_ = hostname;
+      webapp_ =  webapp;
+   }
+
+   protected boolean isFqnForOurWebapp(Fqn fqn, boolean isBuddy)
+   {
+      try
+      {
+         if (webapp_.equals(fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + WEBAPP_FQN_INDEX : WEBAPP_FQN_INDEX))
+               && hostname_.equals(fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + HOSTNAME_FQN_INDEX : HOSTNAME_FQN_INDEX))
+               && JBossCacheService.SESSION.equals(fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + JSESSION_FQN_INDEX : JSESSION_FQN_INDEX)))
+            return true;
+      }
+      catch (IndexOutOfBoundsException e)
+      {
+         // can't be ours; too small; just fall through
+      }
+   
+      return false;
+   }
+
+   protected static boolean isFqnSessionRootSized(Fqn fqn, boolean isBuddy)
+   {
+      return fqn.size() == (isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + SESSION_FQN_SIZE : SESSION_FQN_SIZE);
+   }
+
+   protected static String getIdFromFqn(Fqn fqn, boolean isBuddy)
+   {
+      return (String)fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + SESSION_ID_FQN_INDEX : SESSION_ID_FQN_INDEX);
+   }
+
+   protected static boolean isBuddyFqn(Fqn fqn)
+   {
+      try
+      {
+         return BuddyManager.BUDDY_BACKUP_SUBTREE.equals(fqn.get(0));
+      }
+      catch (IndexOutOfBoundsException e)
+      {
+         // Can only happen if fqn is ROOT, and we shouldn't get
+         // notifications for ROOT.
+         // If it does, just means it's not a buddy
+         return false;
+      }      
+   }
+
+   /**
+    * Extracts the owner portion of an buddy subtree Fqn.
+    * 
+    * @param fqn An Fqn that is a child of the buddy backup root node.
+    */
+   protected static String getBuddyOwner(Fqn fqn)
+   {
+      return (String) fqn.get(BUDDY_BACKUP_ROOT_OWNER_INDEX);     
+   }
+}
\ No newline at end of file


Property changes on: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListenerBase.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + native

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2007-08-18 14:58:08 UTC (rev 64677)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2007-08-18 15:04:16 UTC (rev 64678)
@@ -28,8 +28,8 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
-import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.management.MBeanServer;
 import javax.management.MalformedObjectNameException;
@@ -45,6 +45,7 @@
 import org.apache.catalina.Valve;
 import org.apache.catalina.core.ContainerBase;
 import org.jboss.cache.CacheException;
+import org.jboss.cache.pojo.PojoCache;
 import org.jboss.metadata.WebMetaData;
 import org.jboss.mx.util.MBeanServerLocator;
 
@@ -82,8 +83,16 @@
    /**
     * Id/timestamp of sessions in cache that we haven't loaded
     */
-   private Map unloadedSessions_ = new ConcurrentHashMap();
-
+   private Map<String, OwnedSessionUpdate> unloadedSessions_ = 
+         new ConcurrentHashMap<String, OwnedSessionUpdate>();
+   
+   private AtomicInteger passivatedCount_ = new AtomicInteger();
+   private int maxPassivatedCount_;
+   
+   private int maxLocalActiveCounter_;
+   
+   private PojoCache pojoCache_;
+   
    /** Our TreeCache's ObjectName */
    private String cacheObjectNameString_ = "jboss.cache:service=TomcatClusteringCache";
 
@@ -131,6 +140,12 @@
    {
       super();
    }
+   
+   public JBossCacheManager(PojoCache cache)
+   {
+      super();
+      this.pojoCache_ = cache;
+   }
 
    /**
     * Initializes this Manager when running in embedded mode.
@@ -148,7 +163,15 @@
       this.replicationFieldBatchMode_ =
          webMetaData.getReplicationFieldBatchMode() ? Boolean.TRUE : Boolean.FALSE;
       
-      proxy_ = new JBossCacheService(cacheObjectNameString_);
+      PojoCache pc = getPojoCache();
+      if (pc == null)
+      {
+         proxy_ = new JBossCacheService(cacheObjectNameString_);
+      }
+      else
+      {
+         proxy_ = new JBossCacheService(pc);
+      }
 
       // Confirm our replication granularity is compatible with the cache
       // Throws ISE if not
@@ -419,6 +442,49 @@
       return sb.toString();
    }
 
+   public long getLocalActiveSessionCount()
+   {
+      return activeCounter_;
+   }
+
+   public long getMaxLocalActiveSessionCount()
+   {
+      return super.getMaxActiveSessionCount();
+   }
+
+   public long getMaxPassivatedSessionCount()
+   {
+      return 0;
+   }
+
+   public long getPassivatedSessionCount()
+   {
+      return passivatedCount_.get();
+//      return passivatedSessions_.size();
+   }
+   
+   @Override
+   public int getActiveSessions()
+   {
+      return calcActiveSessions();
+   }
+
+   @Override
+   public long getActiveSessionCount()
+   {
+      return calcActiveSessions();
+   }
+
+   public long getPassivationMaxIdleTime()
+   {
+      return passivationMaxIdleTime_;
+   }
+
+   public long getPassivationMinIdleTime()
+   {
+      return passivationMinIdleTime_;
+   }
+
    // Manager-methods -------------------------------------
 
    /**
@@ -437,6 +503,8 @@
       {
          startUnembedded();
       }
+      
+      log_.debug("JBossCacheManager for " + getContainer().getName() + " started");
    }
 
    public void stop() throws LifecycleException
@@ -463,6 +531,12 @@
       
       snapshotManager_.stop();
       
+      // Clean up maps
+      sessions_.clear();
+      unloadedSessions_.clear();
+      
+      passivatedCount_.set(0);
+      
       started_ = false;
       
       // Notify our interested LifecycleListeners
@@ -483,6 +557,7 @@
     */
    protected void clearSessions()
    {
+      boolean passivation = isPassivationEnabled();
       // First, the sessions we have actively loaded
       ClusteredSession[] sessions = findLocalSessions();
       for(int i=0; i < sessions.length; i++)
@@ -500,10 +575,9 @@
          boolean localOnly = true;
          try
          {
-            if(isPassivationEnabled() && ses.isValid())
-            {
-               
-               processSessionPassivation(ses.getRealId(), this.getContainer().getParent().getName());
+            if(passivation && ses.isValid())
+            {               
+               processSessionPassivation(ses.getRealId());
             }
             else
             {
@@ -522,19 +596,28 @@
             // ref to the session by clearing its internal state
             ses.recycle();
          }
-      }
-
-      if(!isPassivationEnabled())
+      }      
+      
+      Set<Map.Entry<String, OwnedSessionUpdate>> unloaded = 
+               unloadedSessions_.entrySet();
+      for (Iterator<Map.Entry<String, OwnedSessionUpdate>> it = unloaded.iterator(); it.hasNext();)
       {
-//       Next, the local copy of the distributed cache
-         Map unloaded = new HashMap(unloadedSessions_);
-         Set keys = unloaded.keySet();
-         for (Iterator it = keys.iterator(); it.hasNext(); )
+         Map.Entry<String, OwnedSessionUpdate> entry = it.next();
+         String realId = entry.getKey();
+         if (passivation)
          {
-            String realId = (String) it.next();
-            proxy_.removeSessionLocal(realId);
-            unloadedSessions_.remove(realId);
+            OwnedSessionUpdate osu = entry.getValue();
+            // Ignore the marker entries for our passivated sessions
+            if (!osu.passivated)
+            {
+               proxy_.evictSession(realId, osu.owner);
+            }
          }
+         else
+         {
+            proxy_.removeSessionLocal(realId);           
+         }
+         it.remove(); 
       }
    }
 
@@ -558,36 +641,35 @@
     *         exceeds the maximum number allowed
     */
    public Session createSession(String sessionId)
-   {
-      if (log_.isTraceEnabled())
-      {
-         log_.trace("createSession: active sessions = " + activeCounter_ +
-                    " , session map size = " + sessions_.size() +
-                    " and max allowed sessions = " + maxActive_);
-      }
+   {      
+      // First check if we've reached the max allowed sessions, 
+      // then try to expire/passivate sessions to free memory
+      // maxActive_ -1 is unlimited
       // We check here for maxActive instead of in add().  add() gets called
       // when we load an already existing session from the distributed cache
       // (e.g. in a failover) and we don't want to fail in that situation.
 
-      // JBCLUSTER-15
-      // first check if passivation is enabled and reached the max allowed sessions, 
-      /// then try to expire/passivate sessions to free memory 
-      if(maxActive_ != -1 && sessions_.size() >= maxActive_ && isPassivationEnabled())
+      if(maxActive_ != -1 && calcActiveSessions() >= maxActive_)
       {
+         if (log_.isTraceEnabled())
+         {
+            log_.trace("createSession(): active sessions = " + calcActiveSessions() +
+                       " and max allowed sessions = " + maxActive_);
+         }
          processExpires();
+         
+         if (calcActiveSessions() >= maxActive_)
+         {
+            // Exceeds limit. We need to reject it.
+            rejectedCounter_++;
+            // Catalina api does not specify what happens
+            // but we will throw a runtime exception for now.
+            String msgEnd = (sessionId == null) ? "" : " id " + sessionId;
+            throw new IllegalStateException("createSession(): number of " +
+                   "active sessions exceeds the maximum limit: " +
+                   maxActive_ + " when trying to create session" + msgEnd);
+         }
       }
-      // maxActive_ -1 is unlimited
-      if (maxActive_ != -1 && sessions_.size() >= maxActive_)
-      {
-         // Exceeds limit. We need to reject it.
-         rejectedCounter_++;
-         // Catalina api does not specify what happens
-         // but we will throw a runtime exception for now.
-         String msgEnd = (sessionId == null) ? "" : " id " + sessionId;
-         throw new IllegalStateException("JBossCacheManager.createSession(): number of " +
-                "active sessions exceeds the maximum limit: " +
-                maxActive_ + " when trying to create session" + msgEnd);
-      }
 
       ClusteredSession session = createEmptyClusteredSession();
 
@@ -618,10 +700,7 @@
          log_.trace("Created a ClusteredSession with id: " + sessionId);
       }
 
-      createdCounter_++;
-      // JBCLUSTER-15 - if we have created a session it must be handled by this manager
-      // therefore we must increment the active counter
-      activeCounter_++;
+      createdCounter_++; // the call to add() handles the other counters 
       
       // Add this session to the set of those potentially needing replication
       SessionReplicationContext.bindSession(session, snapshotManager_);
@@ -718,9 +797,7 @@
             storeSession(session);
          }
 
-         activeCounter_++;
-         if (activeCounter_ > maxActiveCounter_)
-            maxActiveCounter_++;
+         calcActiveSessions();
          
          if (log_.isTraceEnabled())
          {
@@ -918,7 +995,7 @@
             
             sessions_.remove(realId);
             stats_.removeStats(realId);
-            activeCounter_--;
+//            activeCounter_--;
          }
       }
    }
@@ -962,7 +1039,7 @@
             // It's a bit ad-hoc to do it here. But since we currently call
             // this when session expires ...
             expiredCounter_++;
-            activeCounter_--;
+//            activeCounter_--;
          }
       }
    }
@@ -994,31 +1071,34 @@
       {
          // JBCLUSTER-15
          // We need to check for maxActive first before attempting to create a new session
-         if (log_.isTraceEnabled())
-         {
-            log_.trace("createSession: active sessions = " + activeCounter_ +
-                       " , session map size = " + sessions_.size() +
-                       " and max allowed sessions = " + maxActive_);
-         }
-         // first check if passivation is enabled and reached the max allowed sessions, 
-         /// then try to expire/passivate sessions to free memory 
-         if(maxActive_ != -1 && sessions_.size() >= maxActive_ && isPassivationEnabled())
-         {
-            processExpires();
-         }
-         // maxActive_ -1 is unlimited
-         if (maxActive_ != -1 && sessions_.size() >= maxActive_)
-         {
-            // Exceeds limit. We need to reject it.
-            rejectedCounter_++;
-            // Catalina api does not specify what happens
-            // but we will throw a runtime exception for now.
-            String msgEnd = (realId == null) ? "" : " id " + realId;
-            throw new IllegalStateException("JBossCacheManager.createSession(): number of " +
-                   "active sessions exceeds the maximum limit: " +
-                   maxActive_ + " when trying to load session" + msgEnd);
-         }
+//         if(maxActive_ != -1 
+//               && isPassivationEnabled()
+//               && calcActiveSessions() >= maxActive_)
+//         {
+//            if (log_.isTraceEnabled())
+//            {
+//               log_.trace("loadSession(): active sessions = " + calcActiveSessions() +
+//                          " and max allowed sessions = " + maxActive_);
+//            }
+//            
+//            processExpires();
+//         }
          
+         // BES 2007/08/01 DO NOT REJECT A SESSION HERE -- FAILOVER MUST WORK
+         
+//         // maxActive_ -1 is unlimited
+//         if (maxActive_ != -1 && sessions_.size() >= maxActive_)
+//         {
+//            // Exceeds limit. We need to reject it.
+//            rejectedCounter_++;
+//            // Catalina api does not specify what happens
+//            // but we will throw a runtime exception for now.
+//            String msgEnd = (realId == null) ? "" : " id " + realId;
+//            throw new IllegalStateException("JBossCacheManager.createSession(): number of " +
+//                   "active sessions exceeds the maximum limit: " +
+//                   maxActive_ + " when trying to load session" + msgEnd);
+//         }
+         
          // This is either the first time we've seen this session on this
          // server, or we previously expired it and have since gotten
          // a replication message from another server
@@ -1215,17 +1295,29 @@
     */
    protected void processExpires()
    {
-      if (maxInactiveInterval_ < 0)
+      boolean expire = maxInactiveInterval_ >= 0;
+      boolean passivate = isPassivationEnabled();
+      if (!expire && !passivate)
       {
          return;
       }
+      
+      long expirationInterval = maxInactiveInterval_ * 1000L;
+      long passivationMax = passivationMaxIdleTime_ * 1000L;
+      long passivationMin = passivationMinIdleTime_ * 1000L;
 
-      if (log_.isTraceEnabled())
-      {
-         log_.trace("processExpires():max active sessions = " + maxActive_);
-         log_.trace("processExpires(): passivation mode = " + isPassivationEnabled()); 
+      boolean trace = log_.isTraceEnabled();
+      if (trace)
+      { 
          log_.trace("processExpires(): Looking for sessions that have expired ...");
+         log_.trace("processExpires(): active sessions = " + calcActiveSessions());
+         log_.trace("processExpires(): expired sessions = " + expiredCounter_);
+         if (passivate)
+         {
+            log_.trace("processExpires(): passivated count = " + getPassivatedSessionCount());
+         }
       }
+      
       try
       {
          // First, handle the sessions we are actively managing
@@ -1241,60 +1333,51 @@
                   continue;
                }
 
-               // JBAS-2403. Check for outdated sessions where we think
-               // the local copy has timed out.  If found, refresh the
-               // session from the cache in case that might change the timeout
-               if (session.isOutdated() && !(session.isValid(false)))
+               if (expire)
                {
-                  // JBAS-2792 don't assign the result of loadSession to session
-                  // just update the object from the cache or fall through if
-                  // the session has been removed from the cache
-                  loadSession(session.getRealId());
+                  // JBAS-2403. Check for outdated sessions where we think
+                  // the local copy has timed out.  If found, refresh the
+                  // session from the cache in case that might change the timeout
+                  if (session.isOutdated() && !(session.isValid(false)))
+                  {
+                     // JBAS-2792 don't assign the result of loadSession to session
+                     // just update the object from the cache or fall through if
+                     // the session has been removed from the cache
+                     loadSession(session.getRealId());
+                  }
+   
+                  // Do a normal invalidation check that will expire the
+                  // session if it has timed out
+                  // DON'T SYNCHRONIZE on session here -- isValid() and
+                  // expire() are meant to be multi-threaded and synchronize
+                  // properly internally; synchronizing externally can lead
+                  // to deadlocks!!
+                  if (!session.isValid()) continue;
                }
-
-               // Do a normal invalidation check that will expire any
-               // sessions that have timed out
-               // DON'T SYNCHRONIZE on session here -- isValid() and
-               // expire() are meant to be multi-threaded and synchronize
-               // properly internally; synchronizing externally can lead
-               // to deadlocks!!
-               if (!session.isValid()) continue;
-               
                // JBCLUSTER-15
-               if (log_.isTraceEnabled())
+                
+               // we now have a valid session; see if we need to passivate it
+               if (passivate)
                {
-                  log_.trace("processExpires(): Checking passivation for session " + session.getId());
-               } 
-               // now that we have valid session, see if we need to 
-               // passivate it based on the configurable passivation min and max Idle time
-               if (isPassivationEnabled())
-               {
                   long timeNow = System.currentTimeMillis();
-                  int timeIdle = (int) ((timeNow - session.getLastAccessedTimeInternal()) / 1000L);
+                  long timeIdle = timeNow - session.getLastAccessedTimeInternal();
                   // if maxIdle time configured, means that we need to passivate sessions that have
                   // exceeded the max allowed idle time
-                  if (passivationMaxIdleTime_ >= 0 && timeIdle > passivationMaxIdleTime_)
+                  if (passivationMax >= 0 
+                        && timeIdle > passivationMax)
                   {
-                     if(log_.isTraceEnabled())
-                     {
-                        log_.trace("JBossCacheManager.processExpires() passivating session " + session.getRealId());
-                     }
-                     processSessionPassivation(session.getRealId(), this.getContainer().getParent().getName());
+                     processSessionPassivation(session.getRealId());
                   }
-                  // If the session didn't exceed the passivationMaxIdleTime_, See   
+                  // If the session didn't exceed the passivationMaxIdleTime_, see   
                   // if the number of sessions managed by this manager greater than the max allowed 
                   // active sessions, passivate the session if it exceed passivationMinIdleTime_ 
-                  else if (maxActive_ > 0 && passivationMinIdleTime_ > 0 && sessions_.size()> maxActive_)
+                  else if (maxActive_ > 0 
+                              && passivationMin > 0 
+                              && calcActiveSessions() >= maxActive_ 
+                              && timeIdle > passivationMin)
                   {
-                     if(timeIdle > passivationMinIdleTime_)
-                     {
-                        if(log_.isTraceEnabled())
-                        {
-                           log_.trace("JBossCacheManager.processExpires() passivating session " + session.getRealId());
-                        }
-                        processSessionPassivation(session.getRealId(), this.getContainer().getParent().getName());
-                     }
-                  }
+                     processSessionPassivation(session.getRealId());
+                  }                  
                }
                
             }
@@ -1314,28 +1397,49 @@
          for (Iterator it = entries.iterator(); it.hasNext(); )
          {
             Map.Entry entry = (Map.Entry) it.next();
+            String realId = (String) entry.getKey();
             OwnedSessionUpdate osu = (OwnedSessionUpdate) entry.getValue();
-            int elapsed = (int) ((now - osu.updateTime) / 1000L);
-            if (elapsed >= maxInactiveInterval_)
+            // Ignore marker entries for our own passivated sessions
+            if (osu.passivated)
+               continue;
+            long elapsed = (now - osu.updateTime);
+            try
             {
-               String realId = (String) entry.getKey();               
-               try
+               if (expire && elapsed >= expirationInterval)
                {
                   proxy_.removeSessionLocal(realId, osu.owner);
                   unloadedSessions_.remove(realId);
                }
-                              
-               // JBClUSTER-15
-               // we don't need to worry about session passivation here, since the 
-               // method processSessionPassivation() takes care of unloadedSessions_ map
-               // when it receives a notification of passivation event happened in the 
-               // distributed store from the CacheListener
-               catch (Exception ex)
+               else if (passivate)
                {
-                  log_.error("processExpire(): failed removing unloaded session " + 
-                          realId + " with exception: " + 
-                          ex, ex);
+                  // if maxIdle time configured, means that we need to passivate sessions that have
+                  // exceeded the max allowed idle time
+                  if (passivationMax >= 0 
+                        && elapsed > passivationMax)
+                  {
+                     processUnloadedSessionPassivation(realId, osu);
+                  }
+                  // If the session didn't exceed the passivationMaxIdleTime_, See   
+                  // if the number of sessions managed by this manager greater than the max allowed 
+                  // active sessions, passivate the session if it exceed passivationMinIdleTime_ 
+                  else if (maxActive_ > 0 
+                              && passivationMin >= 0 
+                              && calcActiveSessions() >= maxActive_ 
+                              && elapsed >= passivationMin)
+                  {
+                     processUnloadedSessionPassivation(realId, osu);
+                  }               
                }
+            }               
+            // JBClUSTER-15
+            // we don't need to worry about session passivation here, since the 
+            // method processSessionPassivation() takes care of unloadedSessions_ map
+            // when it receives a notification of passivation event happened in the 
+            // distributed store from the CacheListener
+            catch (Exception ex)
+            {
+               log_.error("processExpires(): failed removing unloaded session " + 
+                       realId, ex);
             }
          }
       }
@@ -1343,6 +1447,17 @@
       {
          log_.error("processExpires: failed with exception: " + ex, ex);
       }
+      
+      if (trace)
+      { 
+         log_.trace("processExpires(): Completed ...");
+         log_.trace("processExpires(): active sessions = " + calcActiveSessions());
+         log_.trace("processExpires(): expired sessions = " + expiredCounter_);
+         if (passivate)
+         {
+            log_.trace("processExpires(): passivated count = " + getPassivatedSessionCount());
+         }
+      }
    }
    
    public void processRemoteAttributeRemoval(String realId, String attrKey)
@@ -1420,19 +1535,63 @@
 
          // Remove any stats for this session
          stats_.removeStats(realId);
-         
-         // Update counter.
-         activeCounter_--;
       }
    }
    
-   public void processSessionPassivation(String realId, String dataOwner)
+   private void sessionPassivated()
    {
+      int pc = passivatedCount_.incrementAndGet();
+      if (pc > maxPassivatedCount_)
+         maxPassivatedCount_ = pc;
+   }
+   
+   public void sessionActivated()
+   {
+      int pc = passivatedCount_.decrementAndGet();
+      // Correct for drift since we don't know the true passivation
+      // count when we started.  We can get activations of sessions
+      // we didn't know were passivated.
+      if (pc < 0) 
+      {
+         // Just reverse our decrement.
+         passivatedCount_.incrementAndGet();
+      }
+   }
+   
+   /** 
+    * Calculates the number of active sessions, and updates
+    * the max # of local active sessions and max # of sessions.
+    * <p>
+    * Call this method when a new session is added or when an
+    * accurate count of active sessions is needed.
+    * </p>
+    * 
+    * @return the size of the sessions map + the size of the unloaded sessions 
+    *         map - the count of passivated sessions
+    */
+   private int calcActiveSessions()
+   {
+      activeCounter_ = sessions_.size();
+      if (activeCounter_ > maxLocalActiveCounter_)
+         maxLocalActiveCounter_ = activeCounter_;
+      
+      int count = activeCounter_ + unloadedSessions_.size() - passivatedCount_.get();
+      if (count > maxActiveCounter_)
+         maxActiveCounter_ = count;
+      return count;
+   }
+   
+   /**
+    * Session passivation logic for an actively managed session.
+    * 
+    * @param realId the session id, minus any jvmRoute
+    */
+   private void processSessionPassivation(String realId)
+   {
       // get the session from the local map
       ClusteredSession session = findLocalSession(realId);
-      // only remove actively managed session and add to the unloaded sessions
+      // Remove actively managed session and add to the unloaded sessions
       // if it's already unloaded session (session == null) don't do anything, 
-      // the evict notification will tell the server that has the session to remove it. 
       if (session != null)
       {
          synchronized (session)
@@ -1448,13 +1607,16 @@
                SessionReplicationContext.startCacheActivity();
                session.passivate();
                proxy_.evictSession(realId);
+               sessionPassivated();
             }
             finally {
                SessionReplicationContext.finishCacheActivity();
             }
-
+            
+            // Put the session in the unloadedSessions map. This will
+            // expose the session to regular invalidation.
             Object obj = unloadedSessions_.put(realId, 
-                  new OwnedSessionUpdate(dataOwner, session.getLastAccessedTime()));
+                  new OwnedSessionUpdate(null, session.getLastAccessedTime(), true));
             if (log_.isTraceEnabled())
             {
                if (obj == null)
@@ -1467,12 +1629,42 @@
                }
             }
             sessions_.remove(realId);
-            stats_.removeStats(realId);
+//            stats_.removeStats(realId);
          }
-         activeCounter_--;
+//         activeCounter_--;
       }
+      else if (log_.isTraceEnabled())
+      {
+         log_.trace("processSessionPassivation():  could not find session " + realId);
+      }
    }
+   
+   /**
+    * Session passivation logic for sessions only in the distributed store.
+    * 
+    * @param realId the session id, minus any jvmRoute
+    */
+   private void processUnloadedSessionPassivation(String realId, OwnedSessionUpdate osu)
+   {
+      if (log_.isTraceEnabled())
+      {
+         log_.trace("Passivating session with id: " + realId);
+      }
 
+      try {
+         // Tell the proxy to ignore cache notifications we are about
+         // to generate for this session.
+         SessionReplicationContext.startCacheActivity();
+         proxy_.evictSession(realId, osu.owner);
+         osu.passivated = true;
+         sessionPassivated();
+      }
+      finally {
+         SessionReplicationContext.finishCacheActivity();
+      }
+      
+   }
+
    /**
     * Gets the session id with any jvmRoute removed.
     * 
@@ -1495,12 +1687,13 @@
    protected void unloadedSessionChanged(String realId, String dataOwner)
    {
       Object obj = unloadedSessions_.put(realId, 
-            new OwnedSessionUpdate(dataOwner, System.currentTimeMillis()));
+            new OwnedSessionUpdate(dataOwner, System.currentTimeMillis(), false));
       if (log_.isTraceEnabled())
       {
          if (obj == null)
          {
             log_.trace("New session " + realId + " added to unloaded session map");
+            calcActiveSessions();
          }
          else
          {
@@ -1510,15 +1703,16 @@
    }
    
    /**
-    * Returns true if the passivation mode is set to true in JBoss-web.xml and JBoss Cache passivation
+    * Returns true if the passivation mode is set to true in jboss-web.xml and JBoss Cache passivation
     * has been enabled with proper configured cache loader. Otherwise, it returns false
     * 
     * @return
     */
-   protected boolean isPassivationEnabled()
+   public boolean isPassivationEnabled()
    {
       return (passivationMode_ && proxy_.isCachePassivationEnabled());
    }
+   
    // ----------------------------------------------------  Lifecyle Unembedded
    
    /**
@@ -1626,7 +1820,15 @@
       // Create the JBossCacheService
       try
       {
-         proxy_ = new JBossCacheService(cacheObjectNameString_);
+         PojoCache pc = getPojoCache();
+         if (pc == null)
+         {
+            proxy_ = new JBossCacheService(cacheObjectNameString_);
+         }
+         else
+         {
+            proxy_ = new JBossCacheService(pc);
+         }
          
          // Confirm our replication granularity is compatible with the cache
          // Throws ISE if not
@@ -1763,15 +1965,23 @@
     */
    private void initializeUnloadedSessions() throws CacheException
    {      
-      Map sessions = proxy_.getSessionIds();
+      Map<String, String> sessions = proxy_.getSessionIds();
       if (sessions != null)
       {
+         boolean passivateExcess = isPassivationEnabled() 
+                                       && maxActive_ > 0
+                                       && passivationMinIdleTime_ >= 0;
          long now = System.currentTimeMillis();
-         for (Iterator it = sessions.entrySet().iterator(); it.hasNext(); )
+         for (Iterator<Map.Entry<String, String>> it = sessions.entrySet().iterator(); it.hasNext(); )
          {
-            Map.Entry entry = (Entry) it.next();
-            unloadedSessions_.put(entry.getKey(), 
-                  new OwnedSessionUpdate((String) entry.getValue(), now));
+            Map.Entry<String, String> entry = it.next();
+            String realId = entry.getKey();
+            OwnedSessionUpdate osu = new OwnedSessionUpdate(entry.getValue(), now, false);
+            unloadedSessions_.put(realId, osu);
+            if (passivateExcess && calcActiveSessions() > maxActive_)
+            {
+               processUnloadedSessionPassivation(realId, osu);
+            }
          }
       }
    }
@@ -1909,17 +2119,24 @@
          return null;
       }
    }
+   
+   public PojoCache getPojoCache()
+   {
+      return pojoCache_;
+   }
 
    
    private class OwnedSessionUpdate
    {
       String owner;
       long updateTime;
+      boolean passivated;
       
-      OwnedSessionUpdate(String owner, long updateTime)
+      OwnedSessionUpdate(String owner, long updateTime, boolean passivated)
       {
          this.owner = owner;
          this.updateTime = updateTime;
+         this.passivated = passivated;
       }
    }
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java	2007-08-18 14:58:08 UTC (rev 64677)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java	2007-08-18 15:04:16 UTC (rev 64678)
@@ -125,4 +125,57 @@
     * @return a comma-separated list of session ids
     */
    String listLocalSessionIds();
+   
+   /**
+    * Gets the count of sessions known to this manager, excluding those
+    * in the distributed stored that have not been accessed on this node.
+    */
+   long getLocalActiveSessionCount();
+   
+   /**
+    * Gets the highest value seen for {@link #getLocalSessionCount()}
+    */
+   long getMaxLocalActiveSessionCount();
+   
+   /**
+    * Gets whether passivation was enabled in jboss-web.xml and in the
+    * underlying cache.
+    * 
+    * @return <code>true</code> if passivation is enabled in both
+    *         jboss-web.xml and in the cache; <code>false</code> otherwise
+    */
+   boolean isPassivationEnabled();
+   
+   /**
+    * Gets the number of passivated sessions
+    * 
+    * @return
+    */
+   long getPassivatedSessionCount();
+   
+   /**
+    * Gets the highest number of passivated sessions seen.
+    * 
+    * @return
+    */
+   long getMaxPassivatedSessionCount();
+   
+   /**
+    * Elapsed time after which an inactive session will be passivated 
+    * to persistent storage if {@link #isPassivationEnabled() passivation is
+    * enabled}.
+    * 
+    * @return
+    */
+   long getPassivationMaxIdleTime();
+   
+   /**
+    * Elapsed time after which an inactive session will be passivated 
+    * to persistent storage if {@link #isPassivationEnabled() passivation is
+    * enabled} and the manager needs to passivate sessions early in order to
+    * comply with a {@link JBossManagerMBean#getMaxActiveAllowed()} setting.
+    * 
+    * @return
+    */
+   long getPassivationMinIdleTime();
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java	2007-08-18 14:58:08 UTC (rev 64677)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java	2007-08-18 15:04:16 UTC (rev 64678)
@@ -40,7 +40,7 @@
 import javax.management.ObjectName;
 import javax.transaction.TransactionManager;
 
-import org.apache.catalina.Context;
+import org.apache.catalina.Container;
 import org.jboss.aspects.patterns.observable.Observer;
 import org.jboss.aspects.patterns.observable.Subject;
 import org.jboss.cache.Cache;
@@ -99,8 +99,22 @@
    // the TreeCache do it?
    private boolean useTreeCacheMarshalling_ = false;
    
+   // Are we configured for passivation?
+   private boolean usePassivation_ = false;
    private WeakHashMap typeMap = new WeakHashMap();
    
+   public JBossCacheService(PojoCache cache)
+   {
+      if (cache == null)
+      {
+         throw new IllegalArgumentException("cache cannot be null");
+      }
+      
+      pojoCache_ = cache;
+      
+      init();
+   }
+   
    public JBossCacheService(String treeCacheObjectName) throws ClusteringNotSupportedException
    {
       // Find JBossCacheService
@@ -134,17 +148,27 @@
          throw new ClusteringNotSupportedException(str);
       }
       
+      init();
+   }
+   
+   private void init()
+   {
       plainCache_ = pojoCache_.getCache();
       cacheWrapper_ = new JBossCacheWrapper(pojoCache_);
-      
+   
       useTreeCacheMarshalling_ = plainCache_.getConfiguration().isUseRegionBasedMarshalling();
+      CacheLoaderConfig clc = plainCache_.getConfiguration().getCacheLoaderConfig();
+      if(clc != null)
+      {
+         usePassivation_ = (clc.isPassivation() && !clc.isShared());
+      }
    }
 
    public void start(ClassLoader tcl, JBossCacheManager manager)
    {
       manager_ = manager;
       
-      Context webapp = (Context) manager_.getContainer();
+      Container webapp = manager_.getContainer();
       String path = webapp.getName();
       if( path.length() == 0 || path.equals("/")) {
          // If this is root.
@@ -172,23 +196,25 @@
       // Listen for cache changes
       cacheListener_ = new CacheListener(cacheWrapper_, manager_, hostName_, webAppPath_);
       plainCache_.addCacheListener(cacheListener_);
-
-      // register the tcl and bring over the state for the webapp
-      Object[] objs = new Object[]{SESSION, hostName_, webAppPath_};
-      Fqn pathFqn = new Fqn( objs );
-      try {
-         if(useTreeCacheMarshalling_)
+      
+      if(useTreeCacheMarshalling_)
+      {
+         // register the tcl and bring over the state for the webapp
+         try
          {
+            Object[] objs = new Object[]{SESSION, hostName_, webAppPath_};
+            Fqn pathFqn = new Fqn( objs );
             log_.debug("UseMarshalling is true. We will register the fqn: " +
                         pathFqn + " with class loader" +tcl +
                         " and activate the webapp's Region");
             Region region = plainCache_.getRegion(pathFqn, true);
             region.registerContextClassLoader(tcl);
-            region.activate();
+            region.activate(); 
          }
-      } catch (Exception ex)
-      {
-         throw new RuntimeException("Can't register class loader", ex);
+         catch (Exception ex)
+         {
+            throw new RuntimeException("Can't register class loader", ex);
+         }
       }
 
       // We require the cache tm to be BatchModeTransactionManager now.
@@ -199,13 +225,15 @@
                  " Please check the jboss-web-cluster-service.xml TransactionManagerClassLookup field.");
       }
       
-      if(isCachePassivationEnabled())
+      if(manager_.isPassivationEnabled())
       {
-         log_.debug("JBossCache passivation is enabled");
+         log_.debug("Passivation is enabled");
+         PassivationListener pl = new PassivationListener(manager_, hostName_, webAppPath_);
+         plainCache_.addCacheListener(pl);
       }
       else
       {
-         log_.debug("JBossCache passivation is disabled");
+         log_.debug("Passivation is disabled");
       }
    }
 
@@ -238,7 +266,11 @@
       }
 
       // remove session data
-      cacheWrapper_.removeLocalSubtree(pathFqn);
+      // BES 2207/08/18 Can't do this as it will 
+      // 1) blow away passivated sessions
+      // 2) leave the cache in an inconsistent state if the war
+      //    is restarted
+//      cacheWrapper_.removeLocalSubtree(pathFqn);
    }
 
    /**
@@ -383,18 +415,21 @@
          }
          cacheWrapper_.removeLocalSubtree(fqn);
       }
-   }
-   
+   }   
       
    public void evictSession(String realId)
    {
-      Fqn fqn = getSessionFqn(realId);
+      evictSession(realId, null);      
+   }   
+      
+   public void evictSession(String realId, String dataOwner)
+   {
+      Fqn fqn = dataOwner == null ? getSessionFqn(realId) : getSessionFqn(realId, dataOwner);
       if(log_.isTraceEnabled())
       {
          log_.trace("evictSession(): evicting session from my distributed store. Fqn: " + fqn);
       }
-      cacheWrapper_.evictSubtree(fqn);
-      
+      cacheWrapper_.evictSubtree(fqn);      
    }
 
    public boolean exists(String realId)
@@ -513,9 +548,9 @@
     *         the session as value (or a <code>null</code>  value if buddy
     *         replication is not enabled.) Will not return <code>null</code>.
     */
-   public Map getSessionIds() throws CacheException
+   public Map<String, String> getSessionIds() throws CacheException
    {
-      Map result = new HashMap();
+      Map<String, String> result = new HashMap<String, String>();
       
       Node bbRoot = plainCache_.getRoot().getChild(BUDDY_BACKUP_FQN);
       if (bbRoot != null)
@@ -945,15 +980,7 @@
  
    public boolean isCachePassivationEnabled()
    {
-      CacheLoaderConfig clc = plainCache_.getConfiguration().getCacheLoaderConfig();
-      if(clc != null)
-      {
-         return (clc.isPassivation() && !clc.isShared());
-      }
-      else
-      {
-         return false;
-      }
+      return usePassivation_;      
    }
    
    private Fqn getFieldFqn(String id, String key)

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManager.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManager.java	2007-08-18 14:58:08 UTC (rev 64677)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManager.java	2007-08-18 15:04:16 UTC (rev 64678)
@@ -92,15 +92,16 @@
    protected boolean passivationMode_ = false;
    
    /**
-    * Min time (seconds) the session must be idle since lastAccesstime before it's eligable for passivation
-    * This overrides maxActive_, to prevent thrashing if the there are lots of active sessions.
-    * Setting to -1 means it's ignored
+    * Min time (milliseconds) the session must be idle since lastAccesstime before 
+    * it's eligible for passivation if passivation is enabled and more
+    * than maxActive_ sessions are in memory.
+    * Setting to -1 means it's ignored.
     */
    protected int passivationMinIdleTime_ = -1;
    
    /**
-    * Max time (seconds) the session must be idle since lastAccesstime before it's eligable for passivation
-    * This overrides maxActive_, to prevent thrashing if the there are lots of active sessions.
+    * Max time (milliseconds) the session must be idle since lastAccesstime before 
+    * it will be passivated if passivation is enabled.
     * Setting to -1 means session should not be forced out.
     */
    protected int passivationMaxIdleTime_ = -1;
@@ -142,14 +143,14 @@
     */
    protected int sessionIdLength_ = 16;
 
-   // Maximum of ative sessions allowed. -1 is unlimited.
+   // Maximum of active sessions allowed. -1 is unlimited.
    protected int maxActive_ = -1;
 
    // Number of sessions created by this manager
    protected int createdCounter_ = 0;
 
    // number of rejected sessions because the number active sessions exceeds maxActive
-   protected int rejectedCounter_ = 0;
+   protected volatile int rejectedCounter_ = 0;
 
    // Number of active sessions
    protected int activeCounter_ = 0;
@@ -158,7 +159,7 @@
    protected int maxActiveCounter_ = 0;
 
    // number of expired session ids. Not sure what exactly does it mean in our clustered case.
-   protected int expiredCounter_ = 0;
+   protected volatile int expiredCounter_ = 0;
 
    protected long timeSinceLastReset_ = 0;
 
@@ -687,7 +688,6 @@
 
    public void setContainer(Container container)
    {
-
       // De-register from the old Container (if any)
       if ((this.container_ != null) && (this.container_ instanceof Context))
          this.container_.removePropertyChangeListener(this);
@@ -858,7 +858,6 @@
       throw new RuntimeException("JBossManager.load(): Method not implemented.");
    }
 
-
    public void backgroundProcess()
    {
       // Called from Catalina StandardEngine for every 60 seconds.
@@ -875,60 +874,8 @@
    /**
     * Go through all sessions and look if they have expired
     */
-   protected void processExpires()
-   {
-      // What's the time?
-//      long timeNow = System.currentTimeMillis();
+   protected abstract void processExpires();
 
-      // Get all sessions
-      Session sessions[] = findSessions();
-      if (log_.isTraceEnabled())
-      {
-         log_.trace("Looking for sessions that have expired ...");
-      }
-
-      for (int i = 0; i < sessions.length; ++i)
-      {
-         ClusteredSession session = (ClusteredSession) sessions[i];
-
-         // We only look at valid sessions. This will remove session if not valid already.
-         if (!session.isValid())
-         {
-            continue;
-         }
-
-         /* I don't think it is right to check idle time based on lastAccessedTime since it may
-         // remove some request that is currently in progress!!!
-         // How long are they allowed to be idle?
-         int maxInactiveInterval = session.getMaxInactiveInterval();
-
-         // Negative values = never expire
-         if( maxInactiveInterval < 0 )
-         {
-            continue;
-         }
-
-         // How long has this session been idle?
-         int timeIdle =
-            (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
-
-         // Too long?
-         if( timeIdle >= maxInactiveInterval )
-         {
-            try
-            {
-               log_.debug("Session with id = " + session.getId() + " has expired on local node");
-               remove(session);
-            }
-            catch(Throwable t)
-            {
-               log_.error("Problems while expiring session with id = " + session.getId(), t);
-            }
-         }
-         */
-      }
-   }
-
    public void propertyChange(PropertyChangeEvent evt)
    {
       // TODO Need to handle it here.

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManagerMBean.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManagerMBean.java	2007-08-18 14:58:08 UTC (rev 64677)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManagerMBean.java	2007-08-18 15:04:16 UTC (rev 64678)
@@ -53,7 +53,7 @@
    long timeInSecondsSinceLastReset();
 
    /**
-    * Gets the number of sessions active on this node.  Does not include
+    * Gets the number of sessions active on this node.  This includes
     * replicated sessions that have not been accessed on this node.
     */
    long getActiveSessionCount();
@@ -79,28 +79,26 @@
    
    /**
     * Gets the highest number of sessions concurrently active on this node.   
-    * Does not include replicated sessions that have not been accessed on 
+    * This includes replicated sessions that have not been accessed on 
     * this node.
     */
    long getMaxActiveSessionCount();
    
    /**
-    * Gets the maximum number of active sessions that will concurrently be
-    * allowed on this node.  Does not include replicated sessions that have 
-    * not been accessed on this node.
+    * Gets the maximum number of {@link #getActiveSessionCount() active sessions}
+    * that will concurrently be allowed on this node.  This includes replicated 
+    * sessions that have not been accessed on this node.
     */
    int getMaxActiveAllowed();
    
    /**
     * Sets the maximum number of active sessions that will concurrently be
-    * allowed on this node.  Does not include replicated sessions that have 
-    * not been accessed on this node.
+    * allowed on this node, excluding any sessions that have been passivated.  
+    * This includes replicated sessions that have not been accessed on this 
+    * node. If the {@link #getActiveSessionCount() active session count} 
+    * exceeds this value and an attempt to create a new session is made, 
+    * session creation will fail with an {@link IllegalStateException}.
     * 
-    * <p>
-    * Note that if sessions fail over to this node from other nodes, the max
-    * number of active sessions may exceed this value.
-    * </p>
-    * 
     * @param max the max number of sessions, or <code>-1</code> if there is
     *            no limit.
     */

Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/PassivationListener.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/PassivationListener.java	                        (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/PassivationListener.java	2007-08-18 15:04:16 UTC (rev 64678)
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.service.session;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.notifications.annotation.NodeActivated;
+import org.jboss.cache.notifications.event.NodeActivatedEvent;
+
+/**
+ * Listener for JBoss Cache activation events.  Triggers updates of
+ * the passivation counter.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision$
+ */
+ at org.jboss.cache.notifications.annotation.CacheListener
+public class PassivationListener extends CacheListenerBase
+{
+
+   PassivationListener(JBossCacheManager manager, String hostname, String webapp)
+   {      
+      super(manager, hostname, webapp);
+   }
+   
+   // NOTE: Don't track passivation from here -- we know in JBossCacheManager
+   // when we trigger a passivation. Avoid spurious listener callbacks to
+   // webapps that aren't interested.
+   
+//   @NodePassivated
+//   public void nodePassivated(NodePassivatedEvent event)
+//   {
+//      Fqn fqn = event.getFqn();
+//      if (isFqnForOurWebapp(fqn, isBuddyFqn(fqn)))
+//      {
+//         manager_.sessionPassivated();
+//      }
+//   }
+   
+   // We do want activation callbacks, as JBossCacheManager can't readily
+   // track whether a cache read is going to result in an activation
+   
+   @NodeActivated
+   public void nodeActivated(NodeActivatedEvent event)
+   {
+      Fqn fqn = event.getFqn();
+      boolean isBuddy = isBuddyFqn(fqn);      
+      if (isFqnSessionRootSized(fqn, isBuddy) 
+            && isFqnForOurWebapp(fqn, isBuddy))
+      {
+         manager_.sessionActivated();
+      }
+      
+   }
+
+}


Property changes on: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/PassivationListener.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + native




More information about the jboss-cvs-commits mailing list