Skip to content

Commit

Permalink
HTTPCLIENT-953: IllegalStateException thrown by RouteSpecificPool
Browse files Browse the repository at this point in the history
Contributed by Guillaume <gueugaie at gmail.com>


git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/branches/4.0.x@954259 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
ok2c committed Jun 13, 2010
1 parent 807f67b commit e0780d9
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
7 changes: 7 additions & 0 deletions RELEASE_NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
Changes since 4.0.1
-------------------

* [HTTPCLIENT-953] IllegalStateException thrown by RouteSpecificPool.
Contributed by Guillaume <gueugaie at gmail.com>


Release 4.0.1
-------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ protected BasicPoolEntry getEntryBlocking(
} 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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,83 @@ public void run() {

}

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.getServicePort();
this.localServer.register("*", new SimpleService());

// We build a client with 2 max active // connections, and 2 max per route.
HttpParams params = defaultParams.copy();
ConnManagerParams.setMaxTotalConnections(params, maxConn);
ConnManagerParams.setMaxConnectionsPerRoute(params,
new ConnPerRouteBean(maxConn));

ThreadSafeClientConnManager connMngr = new ThreadSafeClientConnManager(
params, supportedSchemes);

DefaultHttpClient client = new DefaultHttpClient(connMngr, params);

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();
}

}

}

0 comments on commit e0780d9

Please sign in to comment.