You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2010/06/13 18:40:05 UTC

svn commit: r954258 - in /httpcomponents/httpclient/trunk: RELEASE_NOTES.txt httpclient/src/main/java/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java httpclient/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java

Author: olegk
Date: Sun Jun 13 16:40:04 2010
New Revision: 954258

URL: http://svn.apache.org/viewvc?rev=954258&view=rev
Log:
HTTPCLIENT-953: IllegalStateException thrown by RouteSpecificPool
Contributed by Guillaume <gueugaie at gmail.com>

Modified:
    httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java

Modified: httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/RELEASE_NOTES.txt?rev=954258&r1=954257&r2=954258&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpclient/trunk/RELEASE_NOTES.txt Sun Jun 13 16:40:04 2010
@@ -1,6 +1,9 @@
 Changes since 4.1 ALPHA2
 -------------------
 
+* [HTTPCLIENT-953] IllegalStateException thrown by RouteSpecificPool.
+  Contributed by Guillaume <gueugaie at gmail.com>
+
 * [HTTPCLIENT-952] Trust store parameter is ingored by SSLSocketFactory 
   (affects version 4.1-alpha2 only)
   Contributed by Oleg Kalnichevski <olegk at apache.org>

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java?rev=954258&r1=954257&r2=954258&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java Sun Jun 13 16:40:04 2010
@@ -333,6 +333,9 @@ public class ConnPoolByRoute extends Abs
                 } else if (hasCapacity && !freeConnections.isEmpty()) {
 
                     deleteLeastUsedEntry();
+                    // if least used entry's route was the same as rospl,
+                    // rospl is now out of date : we preemptively refresh
+                    rospl = getRoutePool(route, true);
                     entry = createEntry(rospl, operator);
 
                 } else {

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java?rev=954258&r1=954257&r2=954258&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java Sun Jun 13 16:40:04 2010
@@ -198,4 +198,80 @@ public class TestStatefulConnManagement 
 
     }
 
+    @Test
+    public void testRouteSpecificPoolRecylcing() throws Exception {
+        // This tests what happens when a maxed connection pool needs
+        // to kill the last idle connection to a route to build a new
+        // one to the same route.
+
+        int maxConn = 2;
+
+        int port = this.localServer.getServiceAddress().getPort();
+        this.localServer.register("*", new SimpleService());
+
+        // We build a client with 2 max active // connections, and 2 max per route.
+        ThreadSafeClientConnManager connMngr = new ThreadSafeClientConnManager(supportedSchemes);
+        connMngr.setMaxTotalConnections(maxConn);
+        connMngr.setDefaultMaxPerRoute(maxConn);
+
+        DefaultHttpClient client = new DefaultHttpClient(connMngr);
+
+        client.setUserTokenHandler(new UserTokenHandler() {
+
+            public Object getUserToken(final HttpContext context) {
+                return context.getAttribute("user");
+            }
+
+        });
+
+        // Bottom of the pool : a *keep alive* connection to Route 1.
+        HttpContext context1 = new BasicHttpContext();
+        context1.setAttribute("user", "stuff");
+        HttpResponse response1 = client.execute(
+                new HttpHost("localhost", port), new HttpGet("/"), context1);
+        HttpEntity entity1 = response1.getEntity();
+        if (entity1 != null) {
+            entity1.consumeContent();
+        }
+
+        // The ConnPoolByRoute now has 1 free connection, out of 2 max
+        // The ConnPoolByRoute has one RouteSpcfcPool, that has one free connection
+        // for [localhost][stuff]
+
+        Thread.sleep(100);
+
+        // Send a very simple HTTP get (it MUST be simple, no auth, no proxy, no 302, no 401, ...)
+        // Send it to another route. Must be a keepalive.
+        HttpContext context2 = new BasicHttpContext();
+        HttpResponse response2 = client.execute(
+                new HttpHost("127.0.0.1", port), new HttpGet("/"), context2);
+        HttpEntity entity2 = response2.getEntity();
+        if (entity2 != null) {
+            entity2.consumeContent();
+        }
+        // ConnPoolByRoute now has 2 free connexions, out of its 2 max.
+        // The [localhost][stuff] RouteSpcfcPool is the same as earlier
+        // And there is a [127.0.0.1][null] pool with 1 free connection
+
+        Thread.sleep(100);
+
+        // This will put the ConnPoolByRoute to the targeted state :
+        // [localhost][stuff] will not get reused because this call is [localhost][null]
+        // So the ConnPoolByRoute will need to kill one connection (it is maxed out globally).
+        // The killed conn is the oldest, which means the first HTTPGet ([localhost][stuff]).
+        // When this happens, the RouteSpecificPool becomes empty.
+        HttpContext context3 = new BasicHttpContext();
+        HttpResponse response3 = client.execute(
+                new HttpHost("localhost", port), new HttpGet("/"), context3);
+
+        // If the ConnPoolByRoute did not behave coherently with the RouteSpecificPool
+        // this may fail. Ex : if the ConnPool discared the route pool because it was empty,
+        // but still used it to build the request3 connection.
+        HttpEntity entity3 = response3.getEntity();
+        if (entity3 != null) {
+            entity3.consumeContent();
+        }
+
+    }
+
 }