[jboss-cvs] JBossAS SVN: r75571 - in branches/JBPAPP_4_2_0_GA-JBPAPP-947: testsuite and 5 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Jul 9 21:53:54 EDT 2008


Author: bstansberry at jboss.com
Date: 2008-07-09 21:53:54 -0400 (Wed, 09 Jul 2008)
New Revision: 75571

Modified:
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/server/src/main/org/jboss/metadata/WebMetaData.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/build.xml
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/imports/sections/cluster.xml
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/src/main/org/jboss/test/cluster/test/SimpleTestCase.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/DeployerConfig.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/JBossWeb.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/JBossWebMBean.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/TomcatDeployer.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/BatchReplicationClusteredSessionValve.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSessionValve.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java
   branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/resources/webserver-xmbean.xml
Log:
[JBPAPP-947] Default maxUnreplicatedInterval to 60 secs; make configurable

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/server/src/main/org/jboss/metadata/WebMetaData.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/server/src/main/org/jboss/metadata/WebMetaData.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/server/src/main/org/jboss/metadata/WebMetaData.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -153,6 +153,10 @@
     * for pojo replication or not.
     */
    private boolean replicationFieldBatchMode = true;
+   
+   /** By default replicate clustered session metadata at least every 60 seconds */
+   public static final int DEFAULT_MAX_UNREPLICATED_INTERVAL = 60;   
+   private Integer maxUnreplicatedInterval = null;
 
    /** Should the context use session cookies or use default */
    private int sessionCookies = SESSION_COOKIES_DEFAULT;
@@ -758,6 +762,21 @@
       return replicationFieldBatchMode;
    }
 
+   public void setReplicationFieldBatchMode(boolean batchMode)
+   {
+      this.replicationFieldBatchMode = batchMode;
+   }
+
+   public Integer getMaxUnreplicatedInterval()
+   {
+      return maxUnreplicatedInterval;
+   }
+
+   public void setMaxUnreplicatedInterval(Integer maxUnreplicatedInterval)
+   {
+      this.maxUnreplicatedInterval = maxUnreplicatedInterval;
+   }
+
    public void importXml(Element element) throws DeploymentException
    {
       String rootTag = element.getOwnerDocument().getDocumentElement().getTagName();
@@ -1220,7 +1239,7 @@
                        + "' (should be ['SYNC', 'ASYNC']) in jboss-web.xml");
          }
 
-         // ... then manage "replication-type".
+         // ... then manage "replication-granularity".
          //
          Element replicationGranularityElement = MetaData.getOptionalChild(sessionReplicationRootElement, "replication-granularity");
          if (replicationGranularityElement != null)
@@ -1243,6 +1262,21 @@
             Boolean flag = Boolean.valueOf(MetaData.getElementContent(batchModeElement));
             replicationFieldBatchMode = flag.booleanValue();
          }
+
+         Element maxUnreplicatedIntervalElement = MetaData.getOptionalChild(sessionReplicationRootElement, "max-unreplicated-interval");
+         if (maxUnreplicatedIntervalElement != null)
+         {
+            String maxUnrep =  MetaData.getElementContent(maxUnreplicatedIntervalElement);
+            try
+            {
+               maxUnreplicatedInterval = Integer.valueOf(maxUnrep);
+            }
+            catch (NumberFormatException e)
+            {
+               throw new DeploymentException("max-unreplicated-interval value set to a non-integer value: '" + maxUnrep
+                     + " in jboss-web.xml");
+            }
+         }
       }
 
       // Check for a war level class loading config

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/build.xml
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/build.xml	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/build.xml	2008-07-10 01:53:54 UTC (rev 75571)
@@ -1125,6 +1125,7 @@
     <antcall target="tests-clustering-unit">
       <param name="cluster.includes.refid" value="cluster.http.includes"/>
       <param name="jboss-junit-configuration" value="BuddyReplEnabled-${jboss-junit-configuration}"/>
+      <param name="jbosstest.cluster.web.cache.br" value="true"/>
       <param name="jbosstest.cluster.node0.config" value="cluster-${jboss-junit-configuration}-BR-0"/>
       <param name="jbosstest.cluster.node1.config" value="cluster-${jboss-junit-configuration}-BR-1"/>
     </antcall>
@@ -2851,7 +2852,21 @@
     <property name="jboss-junit-configuration" value="TCP"/>
     <antcall target="one-cluster-test" inheritRefs="true"/>
   </target>
+	 
+  <target name="one-cluster-test-nostart" if="test">
 
+    <property name="jboss-junit-configuration" value="UDP"/>
+
+    <echo message="Going to call target tests-clustering-unit for ${test}"/>
+
+    <antcall target="tests-clustering-unit">
+      <param name="cluster.includes.refid" value="one.test.includes"/>
+      <param name="jboss-junit-configuration" value="Default-${jboss-junit-configuration}"/>
+      <param name="jbosstest.cluster.node0.config" value="cluster-${jboss-junit-configuration}-0"/>
+      <param name="jbosstest.cluster.node1.config" value="cluster-${jboss-junit-configuration}-1"/>
+    </antcall>	  	
+  </target>
+
   <!-- Misc tests of the testing framework itself
   -->
   <target name="tests-apache" description="Test that apache can be started/stopped from ant">

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/imports/sections/cluster.xml
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/imports/sections/cluster.xml	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/imports/sections/cluster.xml	2008-07-10 01:53:54 UTC (rev 75571)
@@ -43,7 +43,10 @@
 
       <!-- build httpsessionreplication.jar -->
       <war warfile="${build.lib}/http-sr.war"
-         webxml="${build.resources}/cluster/http/web.xml">
+         webxml="${build.resources}/cluster/http/http-sr/WEB-INF/web.xml">
+         <webinf dir="${build.resources}/cluster/http/http-sr/WEB-INF">
+            <include name="jboss-web.xml"/>
+         </webinf>
          <fileset dir="${build.resources}/cluster/http">
             <include name="*.jsp"/>
          </fileset>

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/src/main/org/jboss/test/cluster/test/SimpleTestCase.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/src/main/org/jboss/test/cluster/test/SimpleTestCase.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/testsuite/src/main/org/jboss/test/cluster/test/SimpleTestCase.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -22,8 +22,8 @@
 package org.jboss.test.cluster.test;
 
 import junit.framework.Test;
+
 import org.apache.commons.httpclient.HttpClient;
-import org.jboss.jmx.adaptor.rmi.RMIAdaptor;
 import org.jboss.test.JBossClusteredTestCase;
 
 /**
@@ -107,16 +107,6 @@
       HttpClient client = new HttpClient();
       makeGet(client, baseURL0_ +setURLName);
 
-      // Create a session on server 1.
-      HttpClient client1 = new HttpClient();
-      makeGet(client1, baseURL1_ +setURLName);
-      
-      // Find out the session id and use it to build an FQN
-      String sessionID = getSessionID(client1, servers_[1]);
-      // Strip off the jvmRoute, if there is one
-      sessionID = stripJvmRoute(sessionID);
-      String sessionFqn = "/JSESSION/localhost/http-sr/" + sessionID;
-
       sleepThread(6000);
       
       // Set the server0 session to ensure replication occurs
@@ -125,7 +115,7 @@
       attr = makeGetWithState(client, baseURL0_ +getURLName);
       assertNotNull("Http session get", attr);
       
-      // Sleep 15 secs.  This plus the previous 18 secs is enough to expire
+      // Sleep 15 secs.  This plus the previous 6 secs is enough to expire
       // session0 on server1 if replication failed to keep it alive
       sleepThread(15000);
       
@@ -146,32 +136,20 @@
       attr = makeGetWithState(client, baseURL0_ +getURLName);
       assertFalse("Original session not present", attr2.equals(attr));
       
-      // sleep 45 more seconds so session 1 will expire on server0.
-      // need a total of 70 secs -- 60 to expire and 10 to ensure the 
-      // bg thread runs. 20 secs to expire is not enough as the reduced
-      // life of this session is not available to the manager w/o 
-      // deserializing the session
-      sleepThread(45000);
-      
-      // Confirm 2nd session is gone from the distributed cache on node 0
-      RMIAdaptor[] adaptors = getAdaptors();
-      assertEquals("Session gone from distributed cache for " + sessionFqn, 
-            null,
-            SessionTestUtil.getSessionVersion(adaptors[0], sessionFqn));
-      assertEquals("Session gone from distributed cache for " + sessionFqn,
-            null,
-            SessionTestUtil.getBuddySessionVersion(adaptors[0], sessionFqn));
-      
       getLog().debug("Exit testSessionTimeout");
    }
    
+   /**
+    * Tests that a request before maxUnreplicatedInterval has passed doesn't
+    * trigger replication.
+    */
    public void testMaxUnreplicatedInterval()
    {
       getLog().debug("Enter testMaxUnreplicatedInterval");
 
       String setURLName = "/http-sr/testsessionreplication.jsp";
       String getURLName = "/http-sr/getattribute.jsp";
-      String accessURLName = "/http-sr/access.jsp";
+      String versionURLName = "/http-sr/version.jsp";
 
       // Create an instance of HttpClient.
       HttpClient client = new HttpClient();
@@ -181,18 +159,23 @@
       // Get the Attribute set by testsessionreplication.jsp
       String attr = makeGetWithState(client, baseURL0_ +getURLName);
       
-      // Sleep 90% of the maxInactiveInterval
-      sleepThread(18000);
+      // Sleep a bit, but less than the 16 sec maxUnreplicatedInterval
+      sleepThread(500);
       
       // Access the session without touching any attribute
-      makeGet(client, baseURL0_ +accessURLName);
+      String ver = makeGetWithState(client, baseURL0_ +versionURLName);
       
-      // Sleep some more, long enough for the session to expire
-      // if access didn't cause replication and for the bg thread to run
-      sleepThread(17000);
+      // Sleep some more, long enough for the session to replicate
+      // if the last request incorrectly caused replication 
+      sleepThread(2000);
       
       // Switch servers
       setCookieDomainToThisServer(client, servers_[1]);
+      
+      String ver1 = makeGetWithState(client, baseURL1_ +versionURLName);
+      
+      assertEquals("Session version count unchanged", ver, ver1);
+      
       // Get the Attribute set by testsessionreplication.jsp
       String attr1 = makeGetWithState(client, baseURL1_ +getURLName);
       

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/DeployerConfig.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/DeployerConfig.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/DeployerConfig.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -108,6 +108,12 @@
     * if it detects a failover.
     */
    private boolean useJK = false;
+   
+   /**
+    * Maximum interval a clustered session should allow request to not
+    * replicate the session timestamp. 
+    */
+   private int maxUnreplicatedInterval;
 
    /**
     * Get the request attribute name under which the JAAS Subject is store
@@ -287,6 +293,16 @@
       this.useJK = useJK;
    }
 
+   public int getMaxUnreplicatedInterval()
+   {
+      return maxUnreplicatedInterval;
+   }
+
+   public void setMaxUnreplicatedInterval(int maxUnreplicatedInterval)
+   {
+      this.maxUnreplicatedInterval = maxUnreplicatedInterval;
+   }
+
    public String getSubjectAttributeName()
    {
       return subjectAttributeName;

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/JBossWeb.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/JBossWeb.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/JBossWeb.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -41,6 +41,7 @@
 import org.apache.tomcat.util.modeler.Registry;
 import org.jboss.deployment.DeploymentInfo;
 import org.jboss.deployment.SubDeployerExt;
+import org.jboss.metadata.WebMetaData;
 import org.jboss.mx.util.MBeanProxyExt;
 import org.jboss.security.plugins.JaasSecurityManagerServiceMBean;
 import org.jboss.system.ServiceControllerMBean;
@@ -130,6 +131,12 @@
     * Whether we are using Apache MOD_JK(2) module or not
     */
    private boolean useJK = false;
+   
+   /**
+    * Maximum interval a clustered session should allow request to not
+    * replicate the session timestamp. 
+    */
+   private int maxUnreplicatedInterval = WebMetaData.DEFAULT_MAX_UNREPLICATED_INTERVAL;
 
    /**
     * A flag indicating if the JBoss Loader should be used
@@ -301,8 +308,18 @@
    public void setUseJK(boolean useJK)
    {
       this.useJK = useJK;
-   } 
+   }
 
+   public int getMaxUnreplicatedInterval()
+   {
+      return maxUnreplicatedInterval;
+   }
+
+   public void setMaxUnreplicatedInterval(int maxUnreplicatedInterval)
+   {
+      this.maxUnreplicatedInterval = maxUnreplicatedInterval;
+   }
+
    public boolean getDeleteWorkDirOnContextDestroy()
    {
       return deleteWorkDirOnContextDestroy;
@@ -647,6 +664,7 @@
       config.setSnapshotMode(this.snapshotMode);
       config.setUseLocalCache(this.useLocalCache);
       config.setUseJK(this.useJK);
+      config.setMaxUnreplicatedInterval(this.maxUnreplicatedInterval);
       config.setSubjectAttributeName(this.subjectAttributeName);
       config.setUseJBossWebLoader(this.useJBossWebLoader);
       config.setAllowSelfPrivilegedWebApps(this.allowSelfPrivilegedWebApps);

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/JBossWebMBean.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/JBossWebMBean.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/JBossWebMBean.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -124,6 +124,45 @@
    public void setCacheName(String cacheName);
 
    /**
+    * Get the maximum interval between requests, in seconds, after which a
+    * request will trigger replication of the session's metadata regardless
+    * of whether the request has otherwise made the session dirty. Such 
+    * replication ensures that other nodes in the cluster are aware of a 
+    * relatively recent value for the session's timestamp and won't incorrectly
+    * expire an unreplicated session upon failover.
+    * <p/>
+    * Default value is {@link #DEFAULT_MAX_UNREPLICATED_INTERVAL}.
+    * <p/>
+    * The cost of the metadata replication depends on the configured
+    * {@link #setReplicationGranularityString(String) replication granularity}.
+    * With <code>SESSION</code>, the sesssion's attribute map is replicated 
+    * along with the metadata, so it can be fairly costly.  With other 
+    * granularities, the metadata object is replicated separately from the
+    * attributes and only contains a String, and a few longs, ints and booleans.
+    * 
+    * @return the maximum interval since last replication after which a request
+    *         will trigger session metadata replication. A value of 
+    *         <code>0</code> means replicate metadata on every request; a value 
+    *         of <code>-1</code> means never replicate metadata unless the 
+    *         session is otherwise dirty.
+    */
+   public int getMaxUnreplicatedInterval();
+
+   /**
+    * Sets the maximum interval between requests, in seconds, after which a
+    * request will trigger replication of the session's metadata regardless
+    * of whether the request has otherwise made the session dirty.
+    * 
+    * @param  maxUnreplicatedInterval  
+    *         the maximum interval since last replication after which a request
+    *         will trigger session metadata replication. A value of 
+    *         <code>0</code> means replicate metadata on every request; a value 
+    *         of <code>-1</code> means never replicate metadata unless the 
+    *         session is otherwise dirty.
+    */
+   public void setMaxUnreplicatedInterval(int maxUnreplicatedInterval);
+
+   /**
     * Get the JBoss UCL use flag
     */
    public boolean getUseJBossWebLoader();

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/TomcatDeployer.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/TomcatDeployer.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/TomcatDeployer.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -332,6 +332,13 @@
                jbcm.setSnapshotInterval(snapshotInterval);
             }
             
+            // JBAS-5706 -- use the DeployerConfig value as a default for
+            // WebMetaData.maxUnreplicatedInterval
+            if (metaData.getMaxUnreplicatedInterval() == null)
+            {
+               metaData.setMaxUnreplicatedInterval(new Integer(config.getMaxUnreplicatedInterval()));
+            }
+            
             String name = "//" + ((hostName == null) ? "localhost" : hostName) + ctxPath;
             manager.init(name, metaData, config.isUseJK(), config.isUseLocalCache());
             

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/BatchReplicationClusteredSessionValve.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/BatchReplicationClusteredSessionValve.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/BatchReplicationClusteredSessionValve.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -91,7 +91,13 @@
       // situation, this will cause data gravitation, which will occur 
       // thus outside of the scope of the tx we are about to start.  
       // JBossCacheManager will ensure the gravitation is in its own tx
-      request.getSession(false);
+      String requestedId = request.getRequestedSessionId();
+      if (requestedId != null)
+      {
+         // Use the manager directly so we don't invoke access() on a session
+         // that the request otherwise doesn't use
+         manager_.findSession(requestedId);
+      }
       
       // Start a new transaction, we need transaction so all the replication are sent in batch.
       try

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -151,10 +151,7 @@
    protected transient long lastReplicated;
 
    /**
-    * Maximum percentage of the inactive interval this session
-    * should be allowed to go unreplicated if access to the
-    * session doesn't mark it as dirty. Drives the calculation
-    * of maxUnreplicatedInterval.
+    * @deprecated Not used
     */
    protected transient int maxUnreplicatedFactor = 80;
    
@@ -163,8 +160,11 @@
     * should be allowed to go unreplicated if access to the
     * session doesn't mark it as dirty. 
     */
-   protected transient long maxUnreplicatedInterval;
+   protected transient long maxUnreplicatedInterval = 0;
    
+   /** True if maxUnreplicatedInterval is 0 or less than maxInactiveInterval */
+   protected transient boolean alwaysReplicateMetadata = true;
+   
    /**
     * Whether any of this session's attributes implement
     * HttpSessionActivationListener.
@@ -200,7 +200,7 @@
       invalidationPolicy = manager.getInvalidateSessionPolicy();
       this.useJK = useJK;
       this.firstAccess = true;
-      calcMaxUnreplicatedInterval();
+      checkAlwaysReplicateMetadata();
    }
 
    /**
@@ -342,40 +342,18 @@
    }
 
    /**
-    * Gets the maximum percentage of the <code>maxInactiveInterval</code>
-    * beyond which a session should be replicated upon access even if it 
-    * isn't dirty.  Used to ensure that even a read-only session gets 
-    * replicated before it expires, so that it isn't removed from other
-    * nodes.
-    * 
-    * @return  an int between 1 and 100, or -1 if replicating on access is
-    *          disabled
+    * @deprecated Returns a meaningless value; use {@link #setMaxUnreplicatedInterval(int)}
     */
    public int getMaxUnreplicatedFactor()
    {
-      return maxUnreplicatedFactor;
+      return 80;
    }
 
    /**
-    * Sets the maximum percentage of the <code>maxInactiveInterval</code>
-    * beyond which a session should be replicated upon access even if it 
-    * isn't dirty.  Used to ensure that even a read-only session gets 
-    * replicated before it expires, so that it isn't removed from other
-    * nodes.
-    * 
-    * @param maxUnreplicatedFactor  an int between 1 and 100, or -1 to
-    *                               disable replicating on access
-    * 
-    * @throws IllegalArgumentException if the factor isn't -1 or between
-    *                                  1 and 100
+    * @deprecated Ignored; use {@link #setMaxUnreplicatedInterval(int)}
     */
    public void setMaxUnreplicatedFactor(int factor)
-   {
-      if ((factor != -1 && factor < 1) || factor > 100)
-         throw new IllegalArgumentException("Invalid factor " + factor +
-                                   " -- must be between 1 and 100 or -1");
-      this.maxUnreplicatedFactor = factor;
-      calcMaxUnreplicatedInterval();
+   {      
    }
    
 
@@ -386,7 +364,7 @@
    public void setMaxInactiveInterval(int interval)
    {
       super.setMaxInactiveInterval(interval);
-      calcMaxUnreplicatedInterval();
+      checkAlwaysReplicateMetadata();
       sessionMetadataDirty();
    }
 
@@ -408,32 +386,74 @@
       lastReplicated = System.currentTimeMillis();
    }
 
+   /**
+    * Get the maximum interval between requests, in <strong>milliseconds</strong>, 
+    * after which a request will trigger replication of the session's metadata 
+    * regardless of whether the request has otherwise made the session dirty. 
+    * <p/>
+    * <strong>NOTE:</strong> This value is in milliseconds while the equivalent
+    * property in JBossCacheManager is in seconds.
+    * 
+    * @return the maximum interval since last replication after which a request
+    *         will trigger session metadata replication. A value of 
+    *         <code>0</code> means replicate metadata on every request; a value 
+    *         of <code>-1</code> means never replicate metadata unless the 
+    *         session is otherwise dirty.
+    */
    public long getMaxUnreplicatedInterval()
    {
       return maxUnreplicatedInterval;
    }
+
+   /**
+    * Sets the maximum interval between requests, in <strong>milliseconds</strong>, 
+    * after which a request will trigger replication of the session's metadata 
+    * regardless of whether the request has otherwise made the session dirty. 
+    * <p/>
+    * <strong>NOTE:</strong> This value is in milliseconds while the equivalent
+    * property in JBossCacheManager is in seconds.
+    * 
+    * @param  maxUnreplicatedInterval  
+    *         the maximum interval since last replication after which a request
+    *         will trigger session metadata replication. A value of 
+    *         <code>0</code> means replicate metadata on every request; a value 
+    *         of <code>-1</code> means never replicate metadata unless the 
+    *         session is otherwise dirty. A value less than <code>-1</code> is
+    *         treated as <code>-1</code>.
+    */
+   public void setMaxUnreplicatedInterval(long interval)
+   {
+      this.maxUnreplicatedInterval = Math.max(interval, -1);
+      checkAlwaysReplicateMetadata();
+   }
    
    public boolean getExceedsMaxUnreplicatedInterval()
    {
-      boolean result = false;
+      boolean exceeds = alwaysReplicateMetadata;
       
-      if (maxUnreplicatedInterval > 0) // -1 means ignore; 0 means expire now
+      if (!exceeds && maxUnreplicatedInterval > 0) // -1 means ignore
       {
-         result = ((System.currentTimeMillis() - lastReplicated) >= maxUnreplicatedInterval);
+         long unrepl = System.currentTimeMillis() - lastReplicated;
+         exceeds = (unrepl >= maxUnreplicatedInterval);
       }      
       
-      return result;
+      return exceeds;
    }
    
-   private void calcMaxUnreplicatedInterval()
+   private void checkAlwaysReplicateMetadata()
    {
-      if (maxInactiveInterval < 0 || maxUnreplicatedFactor < 0)
-         maxUnreplicatedInterval = -1;
-      else
+      boolean was = this.alwaysReplicateMetadata;
+      this.alwaysReplicateMetadata = 
+         (maxUnreplicatedInterval == 0 
+            || (maxUnreplicatedInterval > 0 && maxInactiveInterval >= 0 
+                  && maxUnreplicatedInterval > (maxInactiveInterval * 1000)));
+      
+      if (this.alwaysReplicateMetadata && !was && log.isTraceEnabled())
       {
-         // Ignoring casting would be (mII * 1000) * (mUF / 100)
-         maxUnreplicatedInterval = maxInactiveInterval * maxUnreplicatedFactor * 10;
-      }
+         log.trace(id + " will always replicate metadata; maxUnreplicatedInterval=" 
+                   + maxUnreplicatedInterval
+                   + ", maxInactiveInterval=" + maxInactiveInterval);
+      }  
    }
 
    /**
@@ -1012,8 +1032,8 @@
       version = 0;
       hasActivationListener = null;
       lastReplicated = 0;
-      maxUnreplicatedFactor = 80;
-      calcMaxUnreplicatedInterval();
+      maxUnreplicatedInterval = 0;
+      this.alwaysReplicateMetadata = true;
    }
    
    /**
@@ -1132,6 +1152,12 @@
          // access cannot be the first.
          this.firstAccess = false;
          
+         // Assume deserialization means replication and use thisAccessedTime
+         // as a proxy for when replication occurred
+         this.lastReplicated = this.thisAccessedTime;
+         
+         checkAlwaysReplicateMetadata();
+         
          // TODO uncomment when work on JBAS-1900 is completed      
 //         // Session notes -- for FORM auth apps, allow replicated session 
 //         // to be used without requiring a new login
@@ -1426,7 +1452,8 @@
    
    public boolean getReplicateSessionBody()
    {
-      return sessionMetadataDirty || getExceedsMaxUnreplicatedInterval();
+      return sessionMetadataDirty || getExceedsMaxUnreplicatedInterval()
+                || (maxUnreplicatedInterval == -1 && sessionAttributesDirty);
    }
 
    protected boolean isGetDirty(Object attribute)

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSessionValve.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSessionValve.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSessionValve.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -51,13 +51,15 @@
 
    // Valve-lifecycle_ helper object
    protected LifecycleSupport support = new LifecycleSupport(this);
+   
+   protected Manager manager;
 
    /**
     * Create a new Valve.
     */
-   public ClusteredSessionValve()
+   public ClusteredSessionValve(Manager manager)
    {
-      super();
+      this.manager = manager;
    }
 
    /**
@@ -83,6 +85,14 @@
       SessionReplicationContext.enterWebapp(request, response, true);
       try
       {  
+         // Workaround to JBAS-5735. Ensure we get the session from the manager
+         // rather than a cached ref from the Request.
+         String requestedId = request.getRequestedSessionId();
+         if (requestedId != null)
+         {
+            manager.findSession(requestedId);
+         }
+         
          // let the servlet invocation go through
          getNext().invoke(request, response);
       }

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -45,6 +45,8 @@
    public JBossCacheClusteredSession(JBossCacheManager manager)
    {
       super(manager, manager.getUseJK());
+      int maxUnrep = manager.getMaxUnreplicatedInterval() * 1000;
+      setMaxUnreplicatedInterval(maxUnrep);
       establishProxy();
    }
 

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -45,6 +45,7 @@
 import org.apache.catalina.Valve;
 import org.apache.catalina.core.ContainerBase;
 import org.jboss.cache.CacheException;
+import org.jboss.cache.aop.PojoCacheMBean;
 import org.jboss.metadata.WebMetaData;
 import org.jboss.mx.util.MBeanServerLocator;
 import org.jboss.web.tomcat.service.JBossWeb;
@@ -130,6 +131,8 @@
     * Whether we are doing trace level logging
     */
    private boolean trace;
+   
+   private int maxUnreplicatedInterval_ = WebMetaData.DEFAULT_MAX_UNREPLICATED_INTERVAL;
 
    //  ----------------------------------------------------------  Constructors
 
@@ -137,6 +140,17 @@
    {
       super();
    }
+   
+   /** 
+    * Create a new JBossCacheManager using the given cache. For use in unit testing.
+    * 
+    * @param pojoCache
+    */
+   public JBossCacheManager(PojoCacheMBean pojoCache)
+   {
+      super();
+      this.proxy_ = new JBossCacheService(pojoCache);
+   }
 
    /**
     * Initializes this Manager when running in embedded mode.
@@ -154,7 +168,14 @@
       this.replicationFieldBatchMode_ =
          webMetaData.getReplicationFieldBatchMode() ? Boolean.TRUE : Boolean.FALSE;
       
-      proxy_ = new JBossCacheService(cacheObjectNameString_);
+      Integer maxUnrep = webMetaData.getMaxUnreplicatedInterval();
+      if (maxUnrep != null)
+      {
+         this.maxUnreplicatedInterval_ = maxUnrep.intValue();
+      }
+      
+      if (proxy_ == null)
+         proxy_ = new JBossCacheService(cacheObjectNameString_);
 
       // Confirm our replication granularity is compatible with the cache
       // Throws ISE if not
@@ -377,6 +398,16 @@
    {
       this.useLocalCache_ = useLocalCache;
    }
+   
+   public int getMaxUnreplicatedInterval()
+   {
+      return maxUnreplicatedInterval_;
+   }
+   
+   public void setMaxUnreplicatedInterval(int maxUnreplicatedInterval)
+   {
+      this.maxUnreplicatedInterval_ = maxUnreplicatedInterval;
+   }
 
    // JBossCacheManagerMBean-methods -------------------------------------
 
@@ -1019,7 +1050,7 @@
             }
             catch (Exception exn)
             {
-               exn.printStackTrace();
+               log_.error("Problem rolling back session mgmt transaction", exn);
             }
             
             // We will need to alert Tomcat of this exception.
@@ -1248,12 +1279,18 @@
          long now = System.currentTimeMillis();
          Map unloaded = new HashMap(unloadedSessions_);
          Set entries = unloaded.entrySet();
+         // We may have not gotten replication of a timestamp for requests 
+         // that occurred w/in maxUnreplicatedInterval_ of the previous
+         // request. So we add a grace period to avoid flushing a session early
+         // and permanently losing part of its node structure in JBoss Cache.
+         long maxUnrep = maxUnreplicatedInterval_ < 0 ? 60 : maxUnreplicatedInterval_;
+         long maxUnused = maxInactiveInterval_ + maxUnrep;
          for (Iterator it = entries.iterator(); it.hasNext(); )
          {
             Map.Entry entry = (Map.Entry) it.next();
             OwnedSessionUpdate osu = (OwnedSessionUpdate) entry.getValue();
             int elapsed = (int) ((now - osu.updateTime) / 1000L);
-            if (elapsed >= maxInactiveInterval_)
+            if (elapsed >= maxUnused)
             {
                String realId = (String) entry.getKey();
                try
@@ -1699,7 +1736,7 @@
       }
 
       // Add clustered session valve
-      ClusteredSessionValve valve = new ClusteredSessionValve();
+      ClusteredSessionValve valve = new ClusteredSessionValve(this);
       installContextValve(valve);
    }
 

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -109,6 +109,45 @@
     * is used.
     */
    int getSnapshotInterval();
+
+   /**
+    * Get the maximum interval between requests, in seconds, after which a
+    * request will trigger replication of the session's metadata regardless
+    * of whether the request has otherwise made the session dirty. Such 
+    * replication ensures that other nodes in the cluster are aware of a 
+    * relatively recent value for the session's timestamp and won't incorrectly
+    * expire an unreplicated session upon failover.
+    * <p/>
+    * Default value is {@link #DEFAULT_MAX_UNREPLICATED_INTERVAL}.
+    * <p/>
+    * The cost of the metadata replication depends on the configured
+    * {@link #setReplicationGranularityString(String) replication granularity}.
+    * With <code>SESSION</code>, the sesssion's attribute map is replicated 
+    * along with the metadata, so it can be fairly costly.  With other 
+    * granularities, the metadata object is replicated separately from the
+    * attributes and only contains a String, and a few longs, ints and booleans.
+    * 
+    * @return the maximum interval since last replication after which a request
+    *         will trigger session metadata replication. A value of 
+    *         <code>0</code> means replicate metadata on every request; a value 
+    *         of <code>-1</code> means never replicate metadata unless the 
+    *         session is otherwise dirty.
+    */
+   public int getMaxUnreplicatedInterval();
+
+   /**
+    * Sets the maximum interval between requests, in seconds, after which a
+    * request will trigger replication of the session's metadata regardless
+    * of whether the request has otherwise made the session dirty.
+    * 
+    * @param  maxUnreplicatedInterval  
+    *         the maximum interval since last replication after which a request
+    *         will trigger session metadata replication. A value of 
+    *         <code>0</code> means replicate metadata on every request; a value 
+    *         of <code>-1</code> means never replicate metadata unless the 
+    *         session is otherwise dirty.
+    */
+   public void setMaxUnreplicatedInterval(int maxUnreplicatedInterval);
    
    /**
     * Lists all session ids known to this manager, including those in the 

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java	2008-07-10 01:53:54 UTC (rev 75571)
@@ -71,11 +71,10 @@
    public static final String SESSION = "JSESSION";
    public static final String ATTRIBUTE = "ATTRIBUTE";
    // Needed for cache invalidation
-   static final String VERSION_KEY = "VERSION";
+   public static final String VERSION_KEY = "VERSION";
    static final String FQN_DELIMITER = "/";
    
    private PojoCacheMBean proxy_;
-   private ObjectName cacheServiceName_;
    
    // name of webapp's virtual host(JBAS-2194). 
    // Idea is host_name + web_app_path + session id is a unique combo.
@@ -95,39 +94,46 @@
    
    private WeakHashMap typeMap = new WeakHashMap();
    
-   public JBossCacheService(String treeCacheObjectName) throws ClusteringNotSupportedException
+   /**
+    * Creates a JMX proxy PojoCacheMBean for the given object name.
+    * 
+    * @param objectName the object name
+    * @return the proxy
+    * @throws ClusteringNotSupportedException if there is a problem
+    */
+   private static PojoCacheMBean getPojoCacheMBean(String objectName)
+      throws ClusteringNotSupportedException
    {
-      // Find JBossCacheService
       try
       {
-         cacheServiceName_ = new ObjectName(treeCacheObjectName);
+         ObjectName cacheServiceName = new ObjectName(objectName);
          // Create Proxy-Object for this service
-         proxy_ = (PojoCacheMBean) MBeanProxyExt.create(PojoCacheMBean.class,
-                                                        cacheServiceName_);
+         return (PojoCacheMBean) MBeanProxyExt.create(PojoCacheMBean.class,
+                                                        cacheServiceName);
       }
       catch (Throwable t)
       {
-
          String str = "Could not access TreeCache service " + 
-                     (cacheServiceName_ == null ? "<null>" : cacheServiceName_.toString()) + 
+                     (objectName == null ? "<null>" : objectName) + 
                      " for Tomcat clustering";
          log_.debug(str);
          throw new ClusteringNotSupportedException(str, t);
-      }
-      
-      if (proxy_ == null)
-      {
-         String str = "Could not access TreeCache service " + 
-                     (cacheServiceName_ == null ? "<null>" : cacheServiceName_.toString()) + 
-                     " for Tomcat clustering";
-         log_.debug(str);
-         throw new ClusteringNotSupportedException(str);
-      }
+      }  
+   }
+   
+   public JBossCacheService(PojoCacheMBean pojoCache)
+   {
+      this.proxy_ = pojoCache;
 
       cacheWrapper_ = new JBossCacheWrapper(proxy_);
       
       useTreeCacheMarshalling_ = proxy_.getUseRegionBasedMarshalling();
    }
+   
+   public JBossCacheService(String treeCacheObjectName) throws ClusteringNotSupportedException
+   {
+      this(getPojoCacheMBean(treeCacheObjectName));
+   }
 
    public void start(ClassLoader tcl, JBossCacheManager manager)
    {
@@ -280,7 +286,7 @@
          }
          catch (Exception e)
          {
-            log_.error("loadSession(): id: " + realId + "exception occurred during serialization: " +e);
+            log_.error("loadSession(): id: " + realId + " exception occurred during deserialization", e);
             return null;
          }
          finally {

Modified: branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/resources/webserver-xmbean.xml
===================================================================
--- branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/resources/webserver-xmbean.xml	2008-07-10 00:04:56 UTC (rev 75570)
+++ branches/JBPAPP_4_2_0_GA-JBPAPP-947/tomcat/src/resources/webserver-xmbean.xml	2008-07-10 01:53:54 UTC (rev 75571)
@@ -87,6 +87,11 @@
      <type>boolean</type>
    </attribute>
 
+   <attribute access="read-write" getMethod="getMaxUnreplicatedInterval" setMethod="setMaxUnreplicatedInterval">
+     <name>MaxUnreplicatedInterval</name>
+     <type>int</type>
+   </attribute>
+
    <attribute access="read-write" getMethod="getDomain" setMethod="setDomain">
      <name>Domain</name>
      <type>java.lang.String</type>




More information about the jboss-cvs-commits mailing list