[jboss-cvs] JBossAS SVN: r86807 - in trunk: tomcat/src/main/org/jboss/web/tomcat/service/session and 1 other directory.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Sat Apr 4 23:20:08 EDT 2009
Author: pferraro
Date: 2009-04-04 23:20:08 -0400 (Sat, 04 Apr 2009)
New Revision: 86807
Added:
trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/CleanShutdownTestCase.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/LockingValve.java
Modified:
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
Log:
[JBAS-6534] Ported fix from Branch_5_x
Added: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/CleanShutdownTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/CleanShutdownTestCase.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/CleanShutdownTestCase.java 2009-04-05 03:20:08 UTC (rev 86807)
@@ -0,0 +1,183 @@
+/*
+ * 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 = "%s/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;
+ String baseURL;
+
+ 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.baseURL = this.getHttpURLs()[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());
+ }
+
+ // Subsequent request should return 404
+ Assert.assertEquals(404, new RequestTask(0).call().intValue());
+ }
+ 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, CleanShutdownTestCase.this.baseURL, this.sleep));
+
+ try
+ {
+ return CleanShutdownTestCase.this.client.executeMethod(method);
+ }
+ finally
+ {
+ method.releaseConnection();
+ }
+ }
+ }
+}
Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java 2009-04-05 02:04:42 UTC (rev 86806)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java 2009-04-05 03:20:08 UTC (rev 86807)
@@ -31,7 +31,11 @@
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.MalformedObjectNameException;
import javax.management.ObjectName;
@@ -81,6 +85,8 @@
*/
private static final String info_ = "JBossCacheManager/1.0";
+ private static final int TOTAL_PERMITS = Integer.MAX_VALUE;
+
// ------------------------------------------------------------------ Fields
/** The transaction manager. */
@@ -143,6 +149,9 @@
private ReplicationConfig replicationConfig_;
+ private Semaphore semaphore = new Semaphore(TOTAL_PERMITS, true);
+ private Lock valveLock = new SemaphoreLock(this.semaphore);
+
// ---------------------------------------------------------- Constructors
public JBossCacheManager() throws ClusteringNotSupportedException
@@ -648,6 +657,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");
}
@@ -664,6 +687,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)
{
@@ -1995,7 +2036,10 @@
* Add a JvmRouteValve and BatchReplicationClusteredSessionValve if needed.
*/
private void installValves()
- {
+ {
+ log_.debug("Adding LockingValve");
+ this.installContextValve(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)
@@ -2365,7 +2409,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: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/LockingValve.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/LockingValve.java (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/LockingValve.java 2009-04-05 03:20:08 UTC (rev 86807)
@@ -0,0 +1,109 @@
+/*
+ * 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;
+
+/**
+ * Generic valve that applies a given lock to a request.
+ *
+ * @author Paul Ferraro
+ */
+public class LockingValve extends ValveBase
+{
+ private final Lock lock;
+
+ public LockingValve(Lock lock)
+ {
+ this.lock = lock;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @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();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @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