HTTPCLIENT-953: IllegalStateException thrown by RouteSpecificPool

Contributed by Guillaume <gueugaie at gmail.com>


git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@954258 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2010-06-13 16:40:04 +00:00
parent 5f8e3d49de
commit 0bb63c609a
3 changed files with 82 additions and 0 deletions

View File

@ -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>

View File

@ -333,6 +333,9 @@ public class ConnPoolByRoute extends AbstractConnPool {
} 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 {

View File

@ -198,4 +198,80 @@ public class TestStatefulConnManagement extends ServerTestBase {
}
@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();
}
}
}