[jboss-cvs] JBossAS SVN: r102796 - in branches/JBPAPP_4_2_0_GA_CP: testsuite/src/main/org/jboss/test/cluster/web/mocks and 1 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Tue Mar 23 11:53:52 EDT 2010


Author: dereed
Date: 2010-03-23 11:53:51 -0400 (Tue, 23 Mar 2010)
New Revision: 102796

Added:
   branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/ClusteredSessionUnitTestCase.java
   branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/ConcurrentFailoverRequestsTestCase.java
   branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/JBossCacheUtil.java
   branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/JGroupsSystemPropertySupport.java
   branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/web/mocks/ConcurrentRequestHandler.java
Modified:
   branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/SessionTestUtil.java
   branches/JBPAPP_4_2_0_GA_CP/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
   branches/JBPAPP_4_2_0_GA_CP/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
Log:
[JBPAPP-2928] Port JBAS-7379 to EAP 4.x


Added: branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/ClusteredSessionUnitTestCase.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/ClusteredSessionUnitTestCase.java	                        (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/ClusteredSessionUnitTestCase.java	2010-03-23 15:53:51 UTC (rev 102796)
@@ -0,0 +1,98 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009 Red Hat Middleware, Inc. 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.test.cluster.test;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+
+import org.jboss.test.cluster.web.util.CacheConfigTestSetup;
+import org.jboss.cache.aop.PojoCache;
+import org.jboss.metadata.WebMetaData;
+import org.jboss.test.cluster.web.util.WebSessionTestUtil;
+import org.jboss.web.tomcat.service.session.ClusteredSession;
+import org.jboss.web.tomcat.service.session.JBossCacheManager;
+
+/**
+ * Unit tests of {@link ClusteredSession}.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class ClusteredSessionUnitTestCase extends TestCase
+{
+   /**
+    * Create a new ClusteredSessionUnitTestCase.
+    * 
+    * @param name
+    */
+   public ClusteredSessionUnitTestCase(String name)
+   {
+      super(name);
+   }
+   
+   protected static PojoCache[] pojoCaches = new PojoCache[1];
+   public static Test suite() throws Exception
+   {
+      return CacheConfigTestSetup.getTestSetup(ClusteredSessionUnitTestCase.class, pojoCaches, false, true, false);
+   }
+
+   /**
+    * Validates the behavior of isOutdated() with respect to returning
+    * true until a creation time is set.
+    * <p>
+    * Note: the use of creation time is a convenience; it's just a field that
+    * isn't set at construction but rather after the session is either loaded
+    * from the distributed cache or is added as a brand new session.
+    * 
+    * @throws Exception
+    */
+   public void testNewSessionIsOutdated() throws Exception
+   {
+      //JBossCacheManager mgr = new JBossCacheManager ();
+      JBossCacheManager mgr = WebSessionTestUtil.createManager("test.war", 1800, pojoCaches[0], null );
+      WebMetaData metadata = WebSessionTestUtil.getWebMetaData(WebMetaData.REPLICATION_GRANULARITY_SESSION, WebMetaData.SESSION_INVALIDATE_SET_AND_NON_PRIMITIVE_GET, true, 60);
+      mgr.init("blah.war", metadata, false, true);
+      //WebSessionTestUtil.setupContainer("test", null, mgr);
+      mgr.start();
+      
+      mgr.setReplicationGranularityString("SESSION");
+      ClusteredSession sess = (ClusteredSession) mgr.createEmptySession();
+      assertTrue(sess.isOutdated());
+      sess.setCreationTime(System.currentTimeMillis());
+      assertFalse(sess.isOutdated());
+      
+      mgr.setReplicationGranularityString("ATTRIBUTE");
+      sess = (ClusteredSession) mgr.createEmptySession();
+      assertTrue(sess.isOutdated());
+      sess.setCreationTime(System.currentTimeMillis());
+      assertFalse(sess.isOutdated());
+      
+      mgr.setReplicationGranularityString("FIELD");
+      sess = (ClusteredSession) mgr.createEmptySession();
+      assertTrue(sess.isOutdated());
+      sess.setCreationTime(System.currentTimeMillis());
+      assertFalse(sess.isOutdated());
+   }
+
+}

Added: branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/ConcurrentFailoverRequestsTestCase.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/ConcurrentFailoverRequestsTestCase.java	                        (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/ConcurrentFailoverRequestsTestCase.java	2010-03-23 15:53:51 UTC (rev 102796)
@@ -0,0 +1,279 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009 Red Hat, Inc. 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.test.cluster.test;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.apache.catalina.Valve;
+import org.apache.catalina.connector.Request;
+import org.jboss.cache.TreeCache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.aop.PojoCache;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.WebMetaData;
+import org.jboss.test.cluster.test.JBossCacheUtil;
+import org.jboss.test.cluster.test.JGroupsSystemPropertySupport;
+import org.jboss.test.cluster.web.util.WebSessionTestUtil;
+import org.jboss.test.cluster.web.mocks.BasicRequestHandler;
+import org.jboss.test.cluster.web.mocks.ConcurrentRequestHandler;
+import org.jboss.test.cluster.web.mocks.SetAttributesRequestHandler;
+import org.jboss.web.tomcat.service.session.JBossCacheManager;
+
+/**
+ * JBAS-7379. Tests that multiple concurrent failover requests for
+ * the same session are handled properly.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 85945 $
+ */
+public class ConcurrentFailoverRequestsTestCase extends TestCase
+{
+   private static final Logger log = Logger.getLogger(ConcurrentFailoverRequestsTestCase.class);
+   
+   private static long testCount = System.currentTimeMillis();
+   
+   private final JGroupsSystemPropertySupport jgSupport = new JGroupsSystemPropertySupport();
+   private Set<PojoCache> caches = new HashSet<PojoCache>();
+   
+   private ExecutorService threadPool;
+   
+   /**
+    * Create a new ConcurrentFailoverRequestsTestCase.
+    * 
+    * @param name
+    */
+   public ConcurrentFailoverRequestsTestCase(String name)
+   {
+      super(name);
+   } 
+
+   @Override
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+      
+      jgSupport.setUpProperties();
+   }
+
+   @Override
+   protected void tearDown() throws Exception
+   {
+      try
+      {
+         super.tearDown();
+      }
+      finally
+      {      
+         jgSupport.restoreProperties();
+         
+         if (threadPool != null)
+         {
+            threadPool.shutdownNow();
+         }
+         
+         //SessionTestUtil.clearDistributedCacheManagerFactory();
+         
+         for (PojoCache cache : caches)
+         { 
+            // Try to clean up so we avoid loading sessions 
+            // from storage in later tests
+            try
+            {
+               log.info("Removing /JSESSION from " + cache.getLocalAddress());
+               cache.remove(Fqn.fromString("/JSESSION"));
+            }
+            catch (Exception e)
+            {
+               log.error("Cache " + cache.getLocalAddress() + ": " + e.getMessage(), e);
+            }
+            
+            try
+            {
+               cache.stop();
+               cache.destroy();
+            }
+            catch (Exception e)
+            {
+               log.error("Cache " + cache.getLocalAddress() + ": " + e.getMessage(), e);
+            }
+            
+         }
+         
+         caches.clear();
+      }
+   }
+
+   public void testConcurrentFailoverRequests() throws Exception
+   {
+      ++testCount;
+      
+      WebMetaData webMetaData = WebSessionTestUtil.getWebMetaData(WebMetaData.REPLICATION_GRANULARITY_SESSION, WebMetaData.SESSION_INVALIDATE_SET_AND_NON_PRIMITIVE_GET, false, 0);
+      String warName = "test" + testCount;
+      JBossCacheManager jbcm0 = WebSessionTestUtil.createManager(warName, 30, false, false, false, null, caches);
+      jbcm0.init(warName, webMetaData, false, true);      
+      jbcm0.start();
+      
+      JBossCacheManager jbcm1 = WebSessionTestUtil.createManager(warName, 30, false, false, false, null, caches);
+      jbcm1.init(warName, webMetaData, false, true);      
+      jbcm1.start();
+      
+      TreeCache[] array = new TreeCache[caches.size()];
+      int index = 0;
+      for (PojoCache c : caches)
+      {
+         array[index] = c;
+         index++;
+      }
+      JBossCacheUtil.blockUntilViewsReceived(array, 10000);
+      
+      Object value = "0";
+      Map<String, Object> attrs = Collections.unmodifiableMap(Collections.singletonMap("count", value));
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(attrs, false);
+      SessionTestUtil.invokeRequest(jbcm0, setHandler, null);
+      
+      String id1 = setHandler.getSessionId();
+      assertNotNull(id1);
+      
+      // Add a second session that we can check for replication; this is a proxy
+      // for checking that first session has replicated
+      setHandler = new SetAttributesRequestHandler(attrs, false);
+      SessionTestUtil.invokeRequest(jbcm0, setHandler, null);
+      
+      String id2 = setHandler.getSessionId();
+      assertNotNull(id1);
+      
+      assertFalse(id1.equals(id2));
+      
+      // Ensure replication of session 2 has occurred
+      boolean found = false;
+      for (int i = 0; i < 10; i++)
+      {
+         BasicRequestHandler getHandler = new BasicRequestHandler(attrs.keySet(), false);
+         SessionTestUtil.invokeRequest(jbcm1, getHandler, id2);
+         if (getHandler.getCheckedAttributes() != null && value.equals(getHandler.getCheckedAttributes().get("count")))
+         {
+            found = true;
+            break;
+         }
+         Thread.sleep(50);            
+      }
+      assertTrue("sessions replicated", found);
+      
+      jbcm0.stop();
+      
+      int THREADS = 10;
+      threadPool = Executors.newFixedThreadPool(THREADS);
+      
+      CountDownLatch startingGun = new CountDownLatch(THREADS + 1);
+      CountDownLatch finishedSignal = new CountDownLatch(THREADS);
+      ConcurrentRequestHandler concurrentHandler = new ConcurrentRequestHandler();
+      Valve pipelineHead = SessionTestUtil.setupPipeline(jbcm1, concurrentHandler);
+      Loader[] loaders = new Loader[THREADS];
+      
+      for (int i = 0; i < loaders.length; i++)
+      {
+         loaders[i] = new Loader(pipelineHead, concurrentHandler, jbcm1, id1, attrs.keySet(), startingGun, finishedSignal);
+         threadPool.execute(loaders[i]);
+      }
+      
+      startingGun.countDown();
+      
+      assertTrue("loaders completed on time", finishedSignal.await(45, TimeUnit.SECONDS));     
+      
+      for (int i = 0; i < loaders.length; i++)
+      {         
+         assertNotNull("got checked attributes for " + i, loaders[i].checkedAttributes);
+         assertTrue("checked 'count' attribute for " + i, loaders[i].checkedAttributes.containsKey("count"));
+         assertEquals("correct value for " + i, value, loaders[i].checkedAttributes.get("count"));
+      }
+   }
+   
+   private static class Loader implements Runnable
+   {
+      private final Valve pipelineHead;
+      private final ConcurrentRequestHandler concurrentHandler;
+      private final Manager manager;
+      private final String sessionId;
+      private final Set<String> attributeKeys;
+      private final CountDownLatch startingGun;
+      private final CountDownLatch finishedSignal;
+      
+      private Map<String, Object> checkedAttributes;
+
+      private Loader(Valve pipelineHead, ConcurrentRequestHandler concurrentHandler,
+            Manager manager, String sessionId, Set<String> attributeKeys, 
+            CountDownLatch startingGun, CountDownLatch finishedSignal)
+      {
+         this.pipelineHead = pipelineHead;
+         this.concurrentHandler = concurrentHandler;
+         this.manager = manager;
+         this.sessionId = sessionId;
+         this.attributeKeys = attributeKeys;
+         this.startingGun = startingGun;
+         this.finishedSignal = finishedSignal;
+      }
+      
+      public void run()
+      {
+         try
+         {
+            BasicRequestHandler getHandler = new BasicRequestHandler(attributeKeys, false);
+            concurrentHandler.registerHandler(getHandler);
+            Request request = SessionTestUtil.setupRequest(manager, sessionId);
+            startingGun.countDown();
+            startingGun.await();
+            System.out.println("started");
+            
+            SessionTestUtil.invokeRequest(pipelineHead, request);
+            this.checkedAttributes = getHandler.getCheckedAttributes();
+            if (this.checkedAttributes != null)
+            {
+               System.out.println(this.checkedAttributes.keySet());
+            }
+         }
+         catch (Exception e)
+         {
+            e.printStackTrace(System.out);
+         }
+         finally
+         {
+            finishedSignal.countDown();
+            
+            concurrentHandler.unregisterHandler();
+         }
+         
+      }
+      
+   }
+}

Added: branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/JBossCacheUtil.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/JBossCacheUtil.java	                        (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/JBossCacheUtil.java	2010-03-23 15:53:51 UTC (rev 102796)
@@ -0,0 +1,174 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009 Red Hat, Inc. 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.test.cluster.test;
+
+import java.util.List;
+
+import org.jboss.cache.TreeCache;
+
+/**
+ * Utilities related to dealing with JBoss Cache.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class JBossCacheUtil
+{
+
+   /**
+    * Loops, continually calling {@link #areCacheViewsComplete(org.jboss.cache.Cache[])}
+    * until it either returns true or <code>timeout</code> ms have elapsed.
+    *
+    * @param caches  caches which must all have consistent views
+    * @param timeout max number of ms to loop
+    * @throws RuntimeException if <code>timeout</code> ms have elapse without
+    *                          all caches having the same number of members.
+    */
+   public static void blockUntilViewsReceived(TreeCache[] caches, long timeout)
+   {
+      long failTime = System.currentTimeMillis() + timeout;
+
+      while (System.currentTimeMillis() < failTime)
+      {
+         sleepThread(100);
+         if (areCacheViewsComplete(caches))
+         {
+            return;
+         }
+      }
+
+      throw new RuntimeException("timed out before caches had complete views" + views(caches));
+   }
+
+   /**
+    * Checks each cache to see if the number of elements in the array
+    * returned by {@link TreeCache#getMembers()} matches the size of
+    * the <code>caches</code> parameter.
+    *
+    * @param caches caches that should form a View
+    * @return <code>true</code> if all caches have
+    *         <code>caches.length</code> members; false otherwise
+    * @throws IllegalStateException if any of the caches have MORE view
+    *                               members than caches.length
+    */
+   public static boolean areCacheViewsComplete(TreeCache[] caches)
+   {
+      return areCacheViewsComplete(caches, true);
+   }
+
+   public static boolean areCacheViewsComplete(TreeCache[] caches, boolean barfIfTooManyMembers)
+   {
+      int memberCount = caches.length;
+
+      for (int i = 0; i < memberCount; i++)
+      {
+         if (!isCacheViewComplete(caches[i], memberCount, barfIfTooManyMembers))
+         {
+            return false;
+         }
+      }
+
+      return true;
+   }
+
+   public static boolean isCacheViewComplete(TreeCache c, int memberCount)
+   {
+      return isCacheViewComplete(c, memberCount, true);
+   }
+
+   public static boolean isCacheViewComplete(TreeCache cache, int memberCount, boolean barfIfTooManyMembers)
+   {
+      List members = cache.getMembers();
+      if (members == null || memberCount > members.size())
+      {
+         return false;
+      }
+      else if (memberCount < members.size())
+      {
+         if (barfIfTooManyMembers)
+         {
+            // This is an exceptional condition
+            StringBuilder sb = new StringBuilder("Cache at address ");
+            sb.append(cache.getLocalAddress());
+            sb.append(" had ");
+            sb.append(members.size());
+            sb.append(" members; expecting ");
+            sb.append(memberCount);
+            sb.append(". Members were (");
+            for (int j = 0; j < members.size(); j++)
+            {
+               if (j > 0)
+               {
+                  sb.append(", ");
+               }
+               sb.append(members.get(j));
+            }
+            sb.append(')');
+
+            throw new IllegalStateException(sb.toString());
+         }
+         else return false;
+      }
+
+      return true;
+   }
+
+
+   /**
+    * Puts the current thread to sleep for the desired number of ms, suppressing
+    * any exceptions.
+    *
+    * @param sleeptime number of ms to sleep
+    */
+   public static void sleepThread(long sleeptime)
+   {
+      try
+      {
+         Thread.sleep(sleeptime);
+      }
+      catch (InterruptedException ie)
+      {
+      }
+   }
+
+   private static String views(TreeCache... caches)
+   {
+      StringBuilder builder = new StringBuilder("[\n");
+      for (TreeCache c:caches)
+      {
+         builder.append("   ").append(c.getLocalAddress()).append("->").append(c.getMembers()).append("\n");
+      }
+      builder.append("]");
+      return builder.toString();
+   }
+
+   /**
+    * Prevent instantiation 
+    */
+   private JBossCacheUtil()
+   {
+      // TODO Auto-generated constructor stub
+   }
+
+}

Added: branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/JGroupsSystemPropertySupport.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/JGroupsSystemPropertySupport.java	                        (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/JGroupsSystemPropertySupport.java	2010-03-23 15:53:51 UTC (rev 102796)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, 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.test.cluster.test;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Utility class that sets and clears JGroups-related system properties.
+ * 
+ * @author Brian Stansberry
+ */
+public class JGroupsSystemPropertySupport
+{
+   private String bind_addr = System.getProperty("jgroups.bind_addr");
+   private String mcast_addr = System.getProperty("jgroups.udp.mcast_addr");
+   private String mcast_port =  System.getProperty("jgroups.udp.mcast_port");
+   
+   public void setUpProperties() throws UnknownHostException
+   {
+      System.setProperty("jgroups.bind_addr", System.getProperty("jbosstest.cluster.node1", InetAddress.getLocalHost().getHostAddress()));
+      String udpGroup = System.getProperty("jbosstest.udpGroup", "233.54.54.54");
+      if (udpGroup.trim().length() ==0)
+         udpGroup = "233.54.54.54";
+      System.setProperty("jgroups.udp.mcast_addr", udpGroup);
+      System.setProperty("jgroups.udp.mcast_port", String.valueOf(54545));
+   }
+   
+   public void restoreProperties()
+   {
+      if (bind_addr == null)
+         System.clearProperty("jgroups.bind_addr");
+      else
+         System.setProperty("jgroups.bind_addr", bind_addr);
+      if (mcast_addr == null)
+         System.clearProperty("jgroups.udp.mcast_addr");
+      else
+         System.setProperty("jgroups.udp.mcast_addr", mcast_addr);
+      if (mcast_port == null)
+         System.clearProperty("jgroups.udp.mcast_port");
+      else
+         System.setProperty("jgroups.udp.mcast_port", mcast_port);      
+   }
+}

Modified: branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/SessionTestUtil.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/SessionTestUtil.java	2010-03-23 15:51:59 UTC (rev 102795)
+++ branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/test/SessionTestUtil.java	2010-03-23 15:53:51 UTC (rev 102796)
@@ -21,15 +21,26 @@
  */
 package org.jboss.test.cluster.test;
 
+import java.io.IOException;
 import java.util.Iterator;
 import java.util.Set;
 
 import javax.management.MBeanServerConnection;
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
+import javax.servlet.ServletException;
 
+import org.apache.catalina.Context;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Valve;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
 import org.jboss.cache.Fqn;
 import org.jboss.jmx.adaptor.rmi.RMIAdaptor;
+import org.jboss.test.cluster.web.mocks.MockRequest;
+import org.jboss.test.cluster.web.mocks.RequestHandler;
+import org.jboss.test.cluster.web.mocks.RequestHandlerValve;
 
 /**
  * Utilities for session testing.
@@ -88,5 +99,61 @@
       return replVersion;
    }
 
+   public static void invokeRequest(Manager manager, RequestHandler handler, String sessionId)
+      throws ServletException, IOException
+   {
+      Valve valve = setupPipeline(manager, handler);
+      Request request = setupRequest(manager, sessionId);
+      invokeRequest(valve, request);
+   }
+   
+   public static void invokeRequest(Valve pipelineHead, Request request)
+      throws ServletException, IOException
+   {
+      pipelineHead.invoke(request, request.getResponse());
+      // StandardHostValve calls request.getSession(false) on way out, so we will too
+      request.getSession(false);
+      request.recycle();
+   }
+   
+   public static Valve setupPipeline(Manager manager, RequestHandler requestHandler)
+   {
+      Pipeline pipeline = manager.getContainer().getPipeline();
+      
+      // Clean out any existing request handler
+      Valve[] valves = pipeline.getValves();
+      RequestHandlerValve mockValve = null;
+      for (Valve valve: valves)
+      {
+         if (valve instanceof RequestHandlerValve)         
+         {
+            mockValve = (RequestHandlerValve) valve;
+            break;
+         }
+      }
+      
+      if (mockValve == null)
+      {
+         mockValve = new RequestHandlerValve(requestHandler);
+         pipeline.addValve(mockValve);
+      }
+      else
+      {
+         mockValve.setRequestHandler(requestHandler);
+      }
+      
+      return pipeline.getFirst();
+   }
+
+   public static Request setupRequest(Manager manager, String sessionId)
+   {
+      MockRequest request = new MockRequest();
+      request.setRequestedSessionId(sessionId);
+      request.setContext((Context) manager.getContainer());
+      Response response = new Response();
+      request.setResponse(response);
+      return request;
+   }
+   
    private SessionTestUtil() {}
 }

Added: branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/web/mocks/ConcurrentRequestHandler.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/web/mocks/ConcurrentRequestHandler.java	                        (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/testsuite/src/main/org/jboss/test/cluster/web/mocks/ConcurrentRequestHandler.java	2010-03-23 15:53:51 UTC (rev 102796)
@@ -0,0 +1,74 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009 Red Hat, Inc. 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.test.cluster.web.mocks;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+
+/**
+ * Uses a ThreadLocal to allow a single RequestHandlerValve to concurrently
+ * handle requests.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class ConcurrentRequestHandler implements RequestHandler
+{
+   private final ThreadLocal<RequestHandler> threadHandler = new ThreadLocal<RequestHandler>();
+   private final Set<RequestHandler> handlers = new HashSet<RequestHandler>();
+   
+   public void registerHandler(RequestHandler handler)
+   {
+      threadHandler.set(handler);
+   }
+   
+   public void unregisterHandler()
+   {
+      threadHandler.remove();
+   }
+   
+   public void clear()
+   {
+/*
+      for (RequestHandler handler : handlers)
+      {
+         handler.clear();
+      }
+*/
+   }
+
+   public void handleRequest(Request request, Response response)
+   {
+      RequestHandler handler = threadHandler.get();
+      if (handler == null)
+      {
+         throw new IllegalStateException("No handler; call registerHandler before executing requet");
+      }
+      handler.handleRequest(request, response);      
+   }
+
+}

Modified: branches/JBPAPP_4_2_0_GA_CP/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2010-03-23 15:51:59 UTC (rev 102795)
+++ branches/JBPAPP_4_2_0_GA_CP/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2010-03-23 15:53:51 UTC (rev 102796)
@@ -223,7 +223,9 @@
     */
    public boolean isOutdated()
    {
-      return thisAccessedTime < outdatedTime;
+      // if creationTime == 0 we've neither been synced with the
+      // distributed cache nor had creation time set (i.e. brand new session)
+      return thisAccessedTime < outdatedTime || this.creationTime == 0;
    }
 
    /**

Modified: branches/JBPAPP_4_2_0_GA_CP/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2010-03-23 15:51:59 UTC (rev 102795)
+++ branches/JBPAPP_4_2_0_GA_CP/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2010-03-23 15:53:51 UTC (rev 102796)
@@ -30,6 +30,7 @@
 import java.util.Set;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import javax.management.MBeanServer;
 import javax.management.MalformedObjectNameException;
@@ -89,6 +90,12 @@
     */
    private Map unloadedSessions_ = new ConcurrentHashMap();
 
+   /** 
+    * Sessions that have been created but not yet loaded. Used to ensure
+    * concurrent threads trying to load the same session
+    */
+   private final ConcurrentMap embryonicSessions = new ConcurrentHashMap();
+
    /** Our TreeCache's ObjectName */
    private String cacheObjectNameString_ = JBossWeb.DEFAULT_CACHE_NAME;
 
@@ -1032,17 +1039,35 @@
       long begin = System.currentTimeMillis();
       boolean mustAdd = false;
       ClusteredSession session = (ClusteredSession) sessions_.get(realId);
+      boolean initialLoad = false;
       if (session == null)
       {
+         initialLoad = true;
          // 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
          mustAdd = true;
          session = createEmptyClusteredSession();
+
+         // JBAS-7379 Ensure concurrent threads trying to load same session id
+         // use the same session
+         ClusteredSession embryo = (ClusteredSession)this.embryonicSessions.putIfAbsent(realId, session);
+         if (embryo != null)
+         {
+            session = embryo;
+         }
       }
 
       synchronized (session)
       {
+         // JBAS-7379 check if we lost the race to the sync block
+         // and another thread has already loaded this session
+         if (initialLoad && session.isOutdated() == false)
+         {
+            // some one else loaded this
+            return session;
+         }
+
          boolean doTx = false;      
          try
          {




More information about the jboss-cvs-commits mailing list