[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