[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