* Cleaned up expired / idle connection eviction code

* Added sample of expired / idle connection eviction
* Cleaned up examples 


git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@749322 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2009-03-02 14:51:22 +00:00
parent 1bd224cab2
commit 8849e82869
22 changed files with 261 additions and 49 deletions

View File

@ -61,6 +61,11 @@ public class ClientAbortMethod {
// Do not feel like reading the response body
// Call abort on the request object
httpget.abort();
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -65,5 +65,10 @@ public class ClientAuthentication {
if (entity != null) {
entity.consumeContent();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -81,6 +81,11 @@ public class ClientChunkEncodedPost {
if (resEntity != null) {
resEntity.consumeContent();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -94,6 +94,11 @@ public class ClientConnectionRelease {
}
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -86,6 +86,11 @@ public class ClientCustomContext {
entity.consumeContent();
System.out.println("----------------------------------------");
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -76,6 +76,11 @@ public class ClientCustomSSL {
if (entity != null) {
entity.consumeContent();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -0,0 +1,154 @@
/*
* $HeadURL:$
* $Revision:$
* $Date:$
*
* ====================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.examples.client;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
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.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
/**
* Example demonstrating how to evict expired and idle connections
* from the connection pool.
*/
public class ClientEvictExpiredConnections {
public static void main(String[] args) throws Exception {
// Create and initialize HTTP parameters
HttpParams params = new BasicHttpParams();
ConnManagerParams.setMaxTotalConnections(params, 100);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
// Create and initialize scheme registry
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
HttpClient httpclient = new DefaultHttpClient(cm, params);
// create an array of URIs to perform GETs on
String[] urisToGet = {
"http://jakarta.apache.org/",
"http://jakarta.apache.org/commons/",
"http://jakarta.apache.org/commons/httpclient/",
"http://svn.apache.org/viewvc/jakarta/httpcomponents/"
};
IdleConnectionEvictor connEvictor = new IdleConnectionEvictor(cm);
connEvictor.start();
for (int i = 0; i < urisToGet.length; i++) {
String requestURI = urisToGet[i];
HttpGet req = new HttpGet(requestURI);
System.out.println("executing request " + requestURI);
HttpResponse rsp = httpclient.execute(req);
HttpEntity entity = rsp.getEntity();
System.out.println("----------------------------------------");
System.out.println(rsp.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
}
System.out.println("----------------------------------------");
if (entity != null) {
entity.consumeContent();
}
}
// Sleep 10 sec and let the connection evictor do its job
Thread.sleep(20000);
// Shut down the evictor thread
connEvictor.shutdown();
connEvictor.join();
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
public static class IdleConnectionEvictor extends Thread {
private final ClientConnectionManager connMgr;
private volatile boolean shutdown;
public IdleConnectionEvictor(ClientConnectionManager connMgr) {
super();
this.connMgr = connMgr;
}
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(5000);
// Close expired connections
connMgr.closeExpiredConnections();
// Optionally, close connections
// that have been idle longer than 5 sec
connMgr.closeIdleConnections(5, TimeUnit.SECONDS);
}
}
} catch (InterruptedException ex) {
// terminate
}
}
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}
}

View File

@ -34,17 +34,16 @@ package org.apache.http.examples.client;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
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.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
@ -79,7 +78,7 @@ public class ClientExecuteDirect {
supportedSchemes);
DefaultHttpClient httpclient = new DefaultHttpClient(connMgr, params);
HttpRequest req = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
HttpGet req = new HttpGet("/");
System.out.println("executing request to " + target);
@ -97,6 +96,11 @@ public class ClientExecuteDirect {
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -34,10 +34,10 @@ package org.apache.http.examples.client;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.PlainSocketFactory;
@ -46,7 +46,6 @@ import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
@ -88,7 +87,7 @@ public class ClientExecuteProxy {
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
HttpRequest req = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
HttpGet req = new HttpGet("/");
System.out.println("executing request to " + target + " via " + proxy);
HttpResponse rsp = httpclient.execute(target, req);
@ -105,6 +104,11 @@ public class ClientExecuteProxy {
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -99,5 +99,10 @@ public class ClientFormLogin {
System.out.println("- " + cookies.get(i).toString());
}
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -120,6 +120,11 @@ public class ClientGZipContentCompression {
System.out.println("----------------------------------------");
System.out.println("Uncompressed size: "+content.length());
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
static class GzipDecompressingEntity extends HttpEntityWrapper {

View File

@ -113,5 +113,10 @@ public class ClientInteractiveAuthentication {
trying = false;
}
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -40,7 +40,6 @@ import org.apache.http.conn.params.ConnManagerParams;
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.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
@ -66,8 +65,6 @@ public class ClientMultiThreadedExecution {
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(
new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
// Create an HttpClient with the ThreadSafeClientConnManager.
// This connection manager must be used if more than one thread will
@ -77,10 +74,10 @@ public class ClientMultiThreadedExecution {
// create an array of URIs to perform GETs on
String[] urisToGet = {
"http://jakarta.apache.org/",
"http://jakarta.apache.org/commons/",
"http://jakarta.apache.org/commons/httpclient/",
"http://svn.apache.org/viewvc/jakarta/httpcomponents/"
"http://hc.apache.org/",
"http://hc.apache.org/httpcomponents-core/",
"http://hc.apache.org/httpcomponents-client/",
"http://svn.apache.org/viewvc/httpcomponents/"
};
// create a thread for each URI
@ -95,6 +92,15 @@ public class ClientMultiThreadedExecution {
threads[j].start();
}
// join the threads
for (int j = 0; j < threads.length; j++) {
threads[j].join();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpClient.getConnectionManager().shutdown();
}
/**

View File

@ -98,6 +98,11 @@ public class ClientPreemptiveBasicAuthentication {
entity.consumeContent();
}
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
static class PreemptiveAuth implements HttpRequestInterceptor {

View File

@ -104,6 +104,11 @@ public class ClientPreemptiveDigestAuthentication {
entity.consumeContent();
}
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
static class PreemptiveAuth implements HttpRequestInterceptor {

View File

@ -54,8 +54,7 @@ public class ClientProxyAuthentication {
HttpHost targetHost = new HttpHost("www.verisign.com", 443, "https");
HttpHost proxy = new HttpHost("localhost", 8080);
httpclient.getParams().setParameter
(ConnRoutePNames.DEFAULT_PROXY, proxy);
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
HttpGet httpget = new HttpGet("/");
@ -74,5 +73,10 @@ public class ClientProxyAuthentication {
if (entity != null) {
entity.consumeContent();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -57,6 +57,11 @@ public class ClientWithResponseHandler {
System.out.println(responseBody);
System.out.println("----------------------------------------");
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

View File

@ -111,18 +111,15 @@ public class IdleConnectionHandler {
*
* @param idleTime the minimum idle time, in milliseconds, for connections to be closed
*/
//@@@ add TimeUnit argument here?
public void closeIdleConnections(long idleTime) {
// the latest time for which connections will be closed
long idleTimeout = System.currentTimeMillis() - idleTime;
if (log.isDebugEnabled()) {
log.debug("Checking for connections, idleTimeout: " + idleTimeout);
log.debug("Checking for connections, idle timeout: " + idleTimeout);
}
Iterator<HttpConnection> connectionIter =
connectionToTimes.keySet().iterator();
Iterator<HttpConnection> connectionIter = connectionToTimes.keySet().iterator();
while (connectionIter.hasNext()) {
HttpConnection conn = connectionIter.next();
@ -130,9 +127,8 @@ public class IdleConnectionHandler {
long connectionTime = times.timeAdded;
if (connectionTime <= idleTimeout) {
if (log.isDebugEnabled()) {
log.debug("Closing connection, connection time: " + connectionTime);
log.debug("Closing idle connection, connection time: " + connectionTime);
}
connectionIter.remove();
try {
conn.close();
} catch (IOException ex) {
@ -159,7 +155,6 @@ public class IdleConnectionHandler {
if (log.isDebugEnabled()) {
log.debug("Closing connection, expired @: " + times.timeExpires);
}
connectionIter.remove();
try {
conn.close();
} catch (IOException ex) {

View File

@ -262,8 +262,6 @@ public abstract class AbstractConnPool implements RefQueueHandler {
}
//@@@ revise this cleanup stuff (closeIdle+deleteClosed), it's not good
/**
* Deletes all entries for closed connections.
*/
@ -325,9 +323,5 @@ public abstract class AbstractConnPool implements RefQueueHandler {
}
}
} // class AbstractConnPool

View File

@ -638,15 +638,10 @@ public class ConnPoolByRoute extends AbstractConnPool {
}
//@@@ revise this cleanup stuff
//@@@ move method to base class when deleteEntry() is fixed
// non-javadoc, see base class AbstractConnPool
@Override
public void deleteClosedConnections() {
poolLock.lock();
try {
Iterator<BasicPoolEntry> iter = freeConnections.iterator();
while (iter.hasNext()) {
BasicPoolEntry entry = iter.next();
@ -655,7 +650,6 @@ public class ConnPoolByRoute extends AbstractConnPool {
deleteEntry(entry);
}
}
} finally {
poolLock.unlock();
}
@ -677,6 +671,11 @@ public class ConnPoolByRoute extends AbstractConnPool {
while (ibpe.hasNext()) {
BasicPoolEntry entry = ibpe.next();
ibpe.remove();
if (log.isDebugEnabled()) {
log.debug("Closing connection"
+ " [" + entry.getPlannedRoute() + "][" + entry.getState() + "]");
}
closeConnection(entry.getConnection());
}

View File

@ -33,11 +33,6 @@ package org.apache.http.impl.conn.tsccm;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A worker thread for processing queued references.
* {@link Reference Reference}s can be
@ -51,8 +46,6 @@ import org.apache.commons.logging.LogFactory;
*/
public class RefQueueWorker implements Runnable {
private final Log log = LogFactory.getLog(getClass());
/** The reference queue to monitor. */
protected final ReferenceQueue<?> refQueue;
@ -103,12 +96,7 @@ public class RefQueueWorker implements Runnable {
// remove the next reference and process it
Reference<?> ref = refQueue.remove();
refHandler.handleReference(ref);
} catch (InterruptedException e) {
//@@@ is logging really necessary? this here is the
//@@@ only reason for having a log in this class
if (log.isDebugEnabled()) {
log.debug(this.toString() + " interrupted", e);
}
} catch (InterruptedException ignore) {
}
}
}

View File

@ -231,6 +231,7 @@ public class ThreadSafeClientConnManager implements ClientConnectionManager {
// non-javadoc, see interface ClientConnectionManager
public void shutdown() {
log.debug("Shutting down");
connectionPool.shutdown();
}
@ -268,12 +269,15 @@ public class ThreadSafeClientConnManager implements ClientConnectionManager {
// non-javadoc, see interface ClientConnectionManager
public void closeIdleConnections(long idleTimeout, TimeUnit tunit) {
// combine these two in a single call?
if (log.isDebugEnabled()) {
log.debug("Closing connections idle for " + idleTimeout + " " + tunit);
}
connectionPool.closeIdleConnections(idleTimeout, tunit);
connectionPool.deleteClosedConnections();
}
public void closeExpiredConnections() {
log.debug("Closing expired connections");
connectionPool.closeExpiredConnections();
connectionPool.deleteClosedConnections();
}