[jboss-cvs] JBossAS SVN: r85652 - in branches/Branch_5_x: testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test and 2 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Mon Mar 9 17:27:03 EDT 2009
Author: pferraro
Date: 2009-03-09 17:27:02 -0400 (Mon, 09 Mar 2009)
New Revision: 85652
Added:
branches/Branch_5_x/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/CleanShutdownTestCase.java
branches/Branch_5_x/testsuite/src/resources/cluster/http/sleep.jsp
branches/Branch_5_x/tomcat/src/main/org/jboss/web/tomcat/service/session/LockingValve.java
Modified:
branches/Branch_5_x/testsuite/imports/config/tests-clustering.xml
branches/Branch_5_x/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
Log:
[JBAS-6534] Graceful shutdown of JBoss Web service does not wait for accepted requests to complete before stopping dependent services
Modified: branches/Branch_5_x/testsuite/imports/config/tests-clustering.xml
===================================================================
--- branches/Branch_5_x/testsuite/imports/config/tests-clustering.xml 2009-03-09 17:43:09 UTC (rev 85651)
+++ branches/Branch_5_x/testsuite/imports/config/tests-clustering.xml 2009-03-09 21:27:02 UTC (rev 85652)
@@ -174,16 +174,15 @@
<echo message="Going to call target tests-clustering-unit again for FIELD granularity tests (ASYNC, no BR)"/>
- <antcall target="tests-clustering-unit">
+ <antcall target="tests-clustering-unit">
<param name="cluster.includes.refid" value="${cluster.http.field.includes}"/>
<param name="jboss-junit-configuration" value="Default-${jboss-junit-configuration}"/>
<param name="jbosstest.cluster.web.cache.config" value="field-granularity-session-cache"/>
- <param name="jbosstest.cluster.web.cache.pojo" value="true"/>
+ <param name="jbosstest.cluster.web.cache.pojo" value="true"/>
<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>
-
<server:stop name="cluster-${jboss-junit-configuration}-0"/>
<server:stop name="cluster-${jboss-junit-configuration}-1"/>
Added: branches/Branch_5_x/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/CleanShutdownTestCase.java
===================================================================
--- branches/Branch_5_x/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/CleanShutdownTestCase.java (rev 0)
+++ branches/Branch_5_x/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/CleanShutdownTestCase.java 2009-03-09 21:27:02 UTC (rev 85652)
@@ -0,0 +1,178 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, 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.defaultcfg.web.test;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import junit.framework.Assert;
+import junit.framework.Test;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
+import org.jboss.test.JBossClusteredTestCase;
+
+/**
+ * A CleanShutdownTestCase.
+ *
+ * @author Paul Ferraro
+ */
+public class CleanShutdownTestCase extends JBossClusteredTestCase
+{
+ private static final String SERVER_NAME = "jboss.web.deployment:war=/http-sr";
+ private static final String SHUTDOWN_METHOD = "stop";
+ private static final String URL = "http://localhost:8080/http-sr/sleep.jsp?sleep=%d";
+ private static final int MAX_THREADS = 2;
+ private static final int REQUEST_DURATION = 10000;
+
+ ObjectName name;
+ MBeanServerConnection server;
+ HttpClient client;
+
+ private MultiThreadedHttpConnectionManager manager;
+
+ public static Test suite() throws Exception
+ {
+ return JBossClusteredTestCase.getDeploySetup(CleanShutdownTestCase.class, "http-sr.war");
+ }
+
+ /**
+ * Create a new CleanShutdownTestCase.
+ *
+ * @param name
+ * @throws MalformedObjectNameException
+ */
+ public CleanShutdownTestCase(String name) throws MalformedObjectNameException
+ {
+ super(name);
+ }
+
+ /**
+ * @see org.jboss.test.JBossClusteredTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ this.name = ObjectName.getInstance(SERVER_NAME);
+ this.server = this.getAdaptors()[0];
+
+ this.manager = new MultiThreadedHttpConnectionManager();
+
+ HttpConnectionManagerParams params = new HttpConnectionManagerParams();
+ params.setDefaultMaxConnectionsPerHost(MAX_THREADS);
+ params.setMaxTotalConnections(MAX_THREADS);
+
+ this.manager.setParams(params);
+
+ this.client = new HttpClient();
+ }
+
+ /**
+ * @see org.jboss.test.JBossTestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception
+ {
+ this.manager.shutdown();
+
+ try
+ {
+ super.tearDown();
+ }
+ catch (Exception e)
+ {
+ // Webapp undeploy failed because server has shutdown
+ }
+ }
+
+ public void testShutdown() throws Exception
+ {
+ ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);
+
+ try
+ {
+ // Make sure a normal request will succeed
+ Assert.assertEquals(200, new RequestTask(0).call().intValue());
+
+ // Send a long request - in parallel
+ Future<Integer> future = executor.submit(new RequestTask(REQUEST_DURATION));
+
+ // Make sure long request has started
+ Thread.sleep(1000);
+
+ // Shutdown server
+ this.server.invoke(this.name, SHUTDOWN_METHOD, null, null);
+
+ // Get result of long request
+ // This request should succeed since it initiated before server shutdown
+ try
+ {
+ Assert.assertEquals(200, future.get().intValue());
+ }
+ catch (ExecutionException e)
+ {
+ e.printStackTrace(System.err);
+
+ Assert.fail(e.getCause().getMessage());
+ }
+ }
+ finally
+ {
+ executor.shutdownNow();
+ }
+ }
+
+ private class RequestTask implements Callable<Integer>
+ {
+ private final int sleep;
+
+ RequestTask(int sleep)
+ {
+ this.sleep = sleep;
+ }
+
+ public Integer call() throws Exception
+ {
+ GetMethod method = new GetMethod(String.format(URL, this.sleep));
+
+ try
+ {
+ return CleanShutdownTestCase.this.client.executeMethod(method);
+ }
+ finally
+ {
+ method.releaseConnection();
+ }
+ }
+ }
+}
Added: branches/Branch_5_x/testsuite/src/resources/cluster/http/sleep.jsp
===================================================================
--- branches/Branch_5_x/testsuite/src/resources/cluster/http/sleep.jsp (rev 0)
+++ branches/Branch_5_x/testsuite/src/resources/cluster/http/sleep.jsp 2009-03-09 21:27:02 UTC (rev 85652)
@@ -0,0 +1,15 @@
+<%
+ String sleep = request.getParameter("sleep");
+
+ if (sleep != null)
+ {
+ long ms = Long.parseLong(sleep);
+
+ if (ms > 0)
+ {
+ Thread.sleep(ms);
+ }
+
+ session.setAttribute("sleep", sleep);
+ }
+%>
\ No newline at end of file
Modified: branches/Branch_5_x/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- branches/Branch_5_x/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java 2009-03-09 17:43:09 UTC (rev 85651)
+++ branches/Branch_5_x/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java 2009-03-09 21:27:02 UTC (rev 85652)
@@ -31,11 +31,17 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
+import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Session;
@@ -81,6 +87,8 @@
*/
private static final String info_ = "JBossCacheManager/1.0";
+ private static final int TOTAL_PERMITS = Integer.MAX_VALUE;
+
// ------------------------------------------------------------------ Fields
/** The transaction manager. */
@@ -143,6 +151,9 @@
private ReplicationConfig replicationConfig_;
+ private Semaphore semaphore = new Semaphore(TOTAL_PERMITS, true);
+ private Lock valveLock = new SemaphoreLock(this.semaphore);
+
// ---------------------------------------------------------- Constructors
public JBossCacheManager() throws ClusteringNotSupportedException
@@ -635,6 +646,20 @@
startUnembedded();
}
+ // Handle re-entrance
+ if (!this.semaphore.tryAcquire())
+ {
+ log_.debug("Opening up LockingValve");
+
+ // Make all permits available to locking valve
+ this.semaphore.release(TOTAL_PERMITS);
+ }
+ else
+ {
+ // Release the one we just acquired
+ this.semaphore.release();
+ }
+
log_.debug("Started");
}
@@ -651,6 +676,24 @@
log_.debug("Stopping");
+ // Handle re-entrance
+ if (this.semaphore.tryAcquire())
+ {
+ try
+ {
+ log_.debug("Closing off LockingValve");
+
+ // Acquire all remaining permits, shutting off locking valve
+ this.semaphore.acquire(TOTAL_PERMITS - 1);
+ }
+ catch (InterruptedException e)
+ {
+ this.semaphore.release();
+
+ throw new LifecycleException(e);
+ }
+ }
+
// Block for any ongoing backgroundProcess, then disable
synchronized (backgroundProcessAllowed)
{
@@ -2003,7 +2046,10 @@
* Add a JvmRouteValve and BatchReplicationClusteredSessionValve if needed.
*/
private void installValves()
- {
+ {
+ log_.debug("Adding LockingValve");
+ this.installValve(new LockingValve(this.valveLock));
+
// If JK usage wasn't explicitly configured, default to enabling
// it if jvmRoute is set on our containing Engine
if (useJK_ == null)
@@ -2014,8 +2060,8 @@
if (getUseJK())
{
log_.debug("We are using JK for load-balancing. Adding JvmRouteValve.");
- installContextValve(new JvmRouteValve(this));
- }
+ this.installValve(new JvmRouteValve(this));
+ }
// Handle batch replication if needed.
// TODO -- should we add this even if not FIELD in case a cross-context
@@ -2031,7 +2077,7 @@
// Add clustered session valve
ClusteredSessionValve valve = new ClusteredSessionValve(this, valveBM);
log_.debug("Adding ClusteredSessionValve");
- installContextValve(valve);
+ this.installValve(valve);
}
/**
@@ -2071,7 +2117,7 @@
snapshotManager_.start();
}
- private void installContextValve(Valve valve)
+ private void installValve(Valve valve)
{
boolean installed = false;
@@ -2079,43 +2125,51 @@
// with the way the overall context is created in TomcatDeployer.
// We can't do this in unembedded mode because we are called
// before our Context is registered with the MBean server
- if (embedded_ && getContextObjectName() != null) {
- try
+ if (embedded_)
+ {
+ ObjectName name = this.getObjectName(this.container_);
+
+ if (name != null)
{
- getMBeanServer().invoke(getContextObjectName(), "addValve",
- new Object[]{valve},
- new String[]{"org.apache.catalina.Valve"});
- installed = true;
+ try
+ {
+ MBeanServer server = this.getMBeanServer();
+
+ server.invoke(name, "addValve", new Object[] { valve }, new String[] { Valve.class.getName() });
+
+ installed = true;
+ }
+ catch (Exception e)
+ {
+ // JBAS-2422. If the context is restarted via JMX, the above
+ // JMX call will fail as the context will not be registered
+ // when it's made. So we catch the exception and fall back
+ // to adding the valve directly.
+ // TODO consider skipping adding via JMX and just do it directly
+ log_.debug("Caught exception installing valve to Context", e);
+ }
}
- catch (Exception e)
- {
- // JBAS-2422. If the context is restarted via JMX, the above
- // JMX call will fail as the context will not be registered
- // when it's made. So we catch the exception and fall back
- // to adding the valve directly.
- // TODO consider skipping adding via JMX and just do it directly
- log_.debug("Caught exception installing valve to Context", e);
- }
}
if (!installed)
{
// If possible install via the ContainerBase.addValve() API.
- if (container_ instanceof ContainerBase)
+ if (this.container_ instanceof ContainerBase)
{
- ((ContainerBase) container_).addValve(valve);
+ ((ContainerBase) this.container_).addValve(valve);
}
else
{
// No choice; have to add it to the context's pipeline
- container_.getPipeline().addValve(valve);
+ this.container_.getPipeline().addValve(valve);
}
}
}
- private ObjectName getContextObjectName()
+ private ObjectName getObjectName(Container container)
{
- String oname = container_.getObjectName();
+ String oname = container.getObjectName();
+
try
{
return (oname == null) ? null : new ObjectName(oname);
@@ -2126,7 +2180,7 @@
return null;
}
}
-
+
/**
* Clear the underlying cache store.
*/
@@ -2373,7 +2427,63 @@
long anotherVal = o.getLastUpdate();
return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
}
+ }
+
+ private static class SemaphoreLock implements Lock
+ {
+ private final Semaphore semaphore;
+ SemaphoreLock(Semaphore semaphore)
+ {
+ this.semaphore = semaphore;
+ }
+ /**
+ * @see java.util.concurrent.locks.Lock#lock()
+ */
+ public void lock()
+ {
+ this.semaphore.acquireUninterruptibly();
+ }
+
+ /**
+ * @see java.util.concurrent.locks.Lock#lockInterruptibly()
+ */
+ public void lockInterruptibly() throws InterruptedException
+ {
+ this.semaphore.acquire();
+ }
+
+ /**
+ * @see java.util.concurrent.locks.Lock#newCondition()
+ */
+ public Condition newCondition()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see java.util.concurrent.locks.Lock#tryLock()
+ */
+ public boolean tryLock()
+ {
+ return this.semaphore.tryAcquire();
+ }
+
+ /**
+ * @see java.util.concurrent.locks.Lock#tryLock(long, java.util.concurrent.TimeUnit)
+ */
+ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException
+ {
+ return this.semaphore.tryAcquire(timeout, unit);
+ }
+
+ /**
+ * @see java.util.concurrent.locks.Lock#unlock()
+ */
+ public void unlock()
+ {
+ this.semaphore.release();
+ }
}
}
Added: branches/Branch_5_x/tomcat/src/main/org/jboss/web/tomcat/service/session/LockingValve.java
===================================================================
--- branches/Branch_5_x/tomcat/src/main/org/jboss/web/tomcat/service/session/LockingValve.java (rev 0)
+++ branches/Branch_5_x/tomcat/src/main/org/jboss/web/tomcat/service/session/LockingValve.java 2009-03-09 21:27:02 UTC (rev 85652)
@@ -0,0 +1,101 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.web.tomcat.service.session;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.valves.ValveBase;
+import org.jboss.servlet.http.HttpEvent;
+
+public class LockingValve extends ValveBase
+{
+ private final Lock lock;
+
+ public LockingValve(Lock lock)
+ {
+ this.lock = lock;
+ }
+
+ @Override
+ public void invoke(Request request, Response response) throws IOException, ServletException
+ {
+ try
+ {
+ if (this.lock.tryLock(0, TimeUnit.SECONDS))
+ {
+ try
+ {
+ this.next.invoke(request, response);
+ }
+ finally
+ {
+ this.lock.unlock();
+ }
+ }
+ else
+ {
+ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ /**
+ * @see org.apache.catalina.valves.ValveBase#event(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response, org.jboss.servlet.http.HttpEvent)
+ */
+ @Override
+ public void event(Request request, Response response, HttpEvent event) throws IOException, ServletException
+ {
+ try
+ {
+ if (this.lock.tryLock(0, TimeUnit.SECONDS))
+ {
+ try
+ {
+ this.next.event(request, response, event);
+ }
+ finally
+ {
+ this.lock.unlock();
+ }
+ }
+ else
+ {
+ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+}
\ No newline at end of file
More information about the jboss-cvs-commits
mailing list