HTTPCLIENT-1000: Maximum connection lifetimes settings for ThreadSafeClientConnManager.
Contributed by Michajlo Matijkiw <michajlo_matijkiw at comcast.com> git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1001144 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
86c464d15e
commit
1e70d5a39e
|
@ -1,6 +1,9 @@
|
|||
Changes since 4.1 ALPHA2
|
||||
-------------------
|
||||
|
||||
* [HTTPCLIENT-1000] Maximum connection lifetimes settings for ThreadSafeClientConnManager.
|
||||
Contributed by Michajlo Matijkiw <michajlo_matijkiw at comcast.com>
|
||||
|
||||
* [HTTPCLIENT-960] HttpMultipart doesn't generate Content-Type header for binary parts in
|
||||
BROWSER_COMPATIBLE mode.
|
||||
Contributed by Oleg Kalnichevski <olegk at apache.org>
|
||||
|
|
|
@ -46,6 +46,7 @@ public class BasicPoolEntry extends AbstractPoolEntry {
|
|||
private final long created;
|
||||
|
||||
private long updated;
|
||||
private long validUntil;
|
||||
private long expiry;
|
||||
|
||||
/**
|
||||
|
@ -60,6 +61,8 @@ public class BasicPoolEntry extends AbstractPoolEntry {
|
|||
throw new IllegalArgumentException("HTTP route may not be null");
|
||||
}
|
||||
this.created = System.currentTimeMillis();
|
||||
this.validUntil = Long.MAX_VALUE;
|
||||
this.expiry = this.validUntil;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,11 +73,32 @@ public class BasicPoolEntry extends AbstractPoolEntry {
|
|||
*/
|
||||
public BasicPoolEntry(ClientConnectionOperator op,
|
||||
HttpRoute route) {
|
||||
this(op, route, -1, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new pool entry with a specified maximum lifetime.
|
||||
*
|
||||
* @param op the connection operator
|
||||
* @param route the planned route for the connection
|
||||
* @param connTTL maximum lifetime of this entry, <=0 implies "infinity"
|
||||
* @param timeunit TimeUnit of connTTL
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
public BasicPoolEntry(ClientConnectionOperator op,
|
||||
HttpRoute route, long connTTL, TimeUnit timeunit) {
|
||||
super(op, route);
|
||||
if (route == null) {
|
||||
throw new IllegalArgumentException("HTTP route may not be null");
|
||||
}
|
||||
this.created = System.currentTimeMillis();
|
||||
if (connTTL > 0) {
|
||||
this.validUntil = this.created + timeunit.toMillis(connTTL);
|
||||
} else {
|
||||
this.validUntil = Long.MAX_VALUE;
|
||||
}
|
||||
this.expiry = this.validUntil;
|
||||
}
|
||||
|
||||
protected final OperatedClientConnection getConnection() {
|
||||
|
@ -116,16 +140,22 @@ public class BasicPoolEntry extends AbstractPoolEntry {
|
|||
return this.expiry;
|
||||
}
|
||||
|
||||
public long getValidUntil() {
|
||||
return this.validUntil;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.1
|
||||
*/
|
||||
public void updateExpiry(long time, TimeUnit timeunit) {
|
||||
this.updated = System.currentTimeMillis();
|
||||
long newExpiry;
|
||||
if (time > 0) {
|
||||
this.expiry = this.updated + timeunit.toMillis(time);
|
||||
newExpiry = this.updated + timeunit.toMillis(time);
|
||||
} else {
|
||||
this.expiry = Long.MAX_VALUE;
|
||||
newExpiry = Long.MAX_VALUE;
|
||||
}
|
||||
this.expiry = Math.min(validUntil, newExpiry);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -90,6 +90,10 @@ public class ConnPoolByRoute extends AbstractConnPool { //TODO: remove dependenc
|
|||
/** Map of route-specific pools */
|
||||
protected final Map<HttpRoute, RouteSpecificPool> routeToPool;
|
||||
|
||||
private final long connTTL;
|
||||
|
||||
private final TimeUnit connTTLTimeUnit;
|
||||
|
||||
protected volatile boolean shutdown;
|
||||
|
||||
protected volatile int maxTotalConnections;
|
||||
|
@ -105,6 +109,18 @@ public class ConnPoolByRoute extends AbstractConnPool { //TODO: remove dependenc
|
|||
final ClientConnectionOperator operator,
|
||||
final ConnPerRoute connPerRoute,
|
||||
int maxTotalConnections) {
|
||||
this(operator, connPerRoute, maxTotalConnections, -1, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.1
|
||||
*/
|
||||
public ConnPoolByRoute(
|
||||
final ClientConnectionOperator operator,
|
||||
final ConnPerRoute connPerRoute,
|
||||
int maxTotalConnections,
|
||||
long connTTL,
|
||||
final TimeUnit connTTLTimeUnit) {
|
||||
super();
|
||||
if (operator == null) {
|
||||
throw new IllegalArgumentException("Connection operator may not be null");
|
||||
|
@ -120,6 +136,8 @@ public class ConnPoolByRoute extends AbstractConnPool { //TODO: remove dependenc
|
|||
this.freeConnections = createFreeConnQueue();
|
||||
this.waitingThreads = createWaitingThreadQueue();
|
||||
this.routeToPool = createRouteToPoolMap();
|
||||
this.connTTL = connTTL;
|
||||
this.connTTLTimeUnit = connTTLTimeUnit;
|
||||
}
|
||||
|
||||
protected Lock getLock() {
|
||||
|
@ -532,7 +550,7 @@ public class ConnPoolByRoute extends AbstractConnPool { //TODO: remove dependenc
|
|||
}
|
||||
|
||||
// the entry will create the connection when needed
|
||||
BasicPoolEntry entry = new BasicPoolEntry(op, rospl.getRoute());
|
||||
BasicPoolEntry entry = new BasicPoolEntry(op, rospl.getRoute(), connTTL, connTTLTimeUnit);
|
||||
|
||||
poolLock.lock();
|
||||
try {
|
||||
|
|
|
@ -87,6 +87,20 @@ public class ThreadSafeClientConnManager implements ClientConnectionManager {
|
|||
* @param schreg the scheme registry.
|
||||
*/
|
||||
public ThreadSafeClientConnManager(final SchemeRegistry schreg) {
|
||||
this(schreg, -1, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new thread safe connection manager.
|
||||
*
|
||||
* @param schreg the scheme registry.
|
||||
* @param connTTL max connection lifetime, <=0 implies "infinity"
|
||||
* @param connTTLTimeUnit TimeUnit of connTTL
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
public ThreadSafeClientConnManager(final SchemeRegistry schreg,
|
||||
long connTTL, TimeUnit connTTLTimeUnit) {
|
||||
super();
|
||||
if (schreg == null) {
|
||||
throw new IllegalArgumentException("Scheme registry may not be null");
|
||||
|
@ -95,7 +109,7 @@ public class ThreadSafeClientConnManager implements ClientConnectionManager {
|
|||
this.schemeRegistry = schreg;
|
||||
this.connPerRoute = new ConnPerRouteBean();
|
||||
this.connOperator = createConnectionOperator(schreg);
|
||||
this.pool = createConnectionPool() ;
|
||||
this.pool = createConnectionPool(connTTL, connTTLTimeUnit) ;
|
||||
this.connectionPool = this.pool;
|
||||
}
|
||||
|
||||
|
@ -149,8 +163,8 @@ public class ThreadSafeClientConnManager implements ClientConnectionManager {
|
|||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
protected ConnPoolByRoute createConnectionPool() {
|
||||
return new ConnPoolByRoute(connOperator, connPerRoute, 20);
|
||||
protected ConnPoolByRoute createConnectionPool(long connTTL, TimeUnit connTTLTimeUnit) {
|
||||
return new ConnPoolByRoute(connOperator, connPerRoute, 20, connTTL, connTTLTimeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -81,9 +81,14 @@ public class TestTSCCMWithServer extends ServerTestBase {
|
|||
* @return a connection manager to test
|
||||
*/
|
||||
public ThreadSafeClientConnManager createTSCCM(SchemeRegistry schreg) {
|
||||
return createTSCCM(schreg, -1, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public ThreadSafeClientConnManager createTSCCM(SchemeRegistry schreg,
|
||||
long connTTL, TimeUnit connTTLTimeUnit) {
|
||||
if (schreg == null)
|
||||
schreg = supportedSchemes;
|
||||
return new ThreadSafeClientConnManager(schreg);
|
||||
return new ThreadSafeClientConnManager(schreg, connTTL, connTTLTimeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -354,7 +359,7 @@ public class TestTSCCMWithServer extends ServerTestBase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCloseExpiredConnections() throws Exception {
|
||||
public void testCloseExpiredIdleConnections() throws Exception {
|
||||
|
||||
ThreadSafeClientConnManager mgr = createTSCCM(null);
|
||||
mgr.setMaxTotal(1);
|
||||
|
@ -390,6 +395,44 @@ public class TestTSCCMWithServer extends ServerTestBase {
|
|||
mgr.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseExpiredTTLConnections() throws Exception {
|
||||
|
||||
ThreadSafeClientConnManager mgr = createTSCCM(null, 100, TimeUnit.MILLISECONDS);
|
||||
mgr.setMaxTotal(1);
|
||||
|
||||
final HttpHost target = getServerHttp();
|
||||
final HttpRoute route = new HttpRoute(target, null, false);
|
||||
|
||||
ManagedClientConnection conn = getConnection(mgr, route);
|
||||
conn.open(route, httpContext, defaultParams);
|
||||
|
||||
Assert.assertEquals("connectionsInPool", 1, mgr.getConnectionsInPool());
|
||||
Assert.assertEquals("connectionsInPool(host)", 1, mgr.getConnectionsInPool(route));
|
||||
// Release, let remain idle for forever
|
||||
mgr.releaseConnection(conn, -1, TimeUnit.MILLISECONDS);
|
||||
|
||||
// Released, still active.
|
||||
Assert.assertEquals("connectionsInPool", 1, mgr.getConnectionsInPool());
|
||||
Assert.assertEquals("connectionsInPool(host)", 1, mgr.getConnectionsInPool(route));
|
||||
|
||||
mgr.closeExpiredConnections();
|
||||
|
||||
// Time has not expired yet.
|
||||
Assert.assertEquals("connectionsInPool", 1, mgr.getConnectionsInPool());
|
||||
Assert.assertEquals("connectionsInPool(host)", 1, mgr.getConnectionsInPool(route));
|
||||
|
||||
Thread.sleep(150);
|
||||
|
||||
mgr.closeExpiredConnections();
|
||||
|
||||
// TTL expired now, connections are destroyed.
|
||||
Assert.assertEquals("connectionsInPool", 0, mgr.getConnectionsInPool());
|
||||
Assert.assertEquals("connectionsInPool(host)", 0, mgr.getConnectionsInPool(route));
|
||||
|
||||
mgr.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests releasing connection from #abort method called from the
|
||||
* main execution thread while there is no blocking I/O operation.
|
||||
|
|
|
@ -27,20 +27,20 @@
|
|||
|
||||
package org.apache.http.impl.conn.tsccm;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.conn.ClientConnectionOperator;
|
||||
import org.apache.http.conn.ClientConnectionRequest;
|
||||
import org.apache.http.conn.ManagedClientConnection;
|
||||
import org.apache.http.conn.params.ConnPerRoute;
|
||||
import org.apache.http.conn.routing.HttpRoute;
|
||||
import org.apache.http.conn.scheme.PlainSocketFactory;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||
import org.apache.http.conn.scheme.SchemeSocketFactory;
|
||||
import org.apache.http.conn.params.ConnPerRoute;
|
||||
|
||||
import org.apache.http.impl.conn.GetConnThread;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -101,7 +101,7 @@ public class TestSpuriousWakeup {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ConnPoolByRoute createConnectionPool() {
|
||||
protected ConnPoolByRoute createConnectionPool(long connTTL, TimeUnit connTTLUnit) {
|
||||
extendedCPBR = new XConnPoolByRoute(connOperator, connPerRoute, 20);
|
||||
// no connection GC required
|
||||
return extendedCPBR;
|
||||
|
|
Loading…
Reference in New Issue