hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r1643671 - in /httpcomponents/httpclient/trunk/httpclient/src: examples/org/apache/http/examples/client/ main/java/org/apache/http/impl/client/ test/java/org/apache/http/impl/client/ test/java/org/apache/http/impl/client/integration/
Date Sun, 07 Dec 2014 12:42:20 GMT
Author: olegk
Date: Sun Dec  7 12:42:19 2014
New Revision: 1643671

URL: http://svn.apache.org/r1643671
Log:
HTTPCLIENT-1583: optional connection eviction thread for non-shared connection managers to
pro-actively evict expired / idle persistent connections from the connection pool

Added:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java
  (with props)
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java
  (with props)
Modified:
    httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientEvictExpiredConnections.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestIdleConnectionEviction.java

Modified: httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientEvictExpiredConnections.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientEvictExpiredConnections.java?rev=1643671&r1=1643670&r2=1643671&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientEvictExpiredConnections.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientEvictExpiredConnections.java
Sun Dec  7 12:42:19 2014
@@ -30,10 +30,10 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.conn.HttpClientConnectionManager;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.pool.PoolStats;
 import org.apache.http.util.EntityUtils;
 
 /**
@@ -47,6 +47,8 @@ public class ClientEvictExpiredConnectio
         cm.setMaxTotal(100);
         CloseableHttpClient httpclient = HttpClients.custom()
                 .setConnectionManager(cm)
+                .evictExpiredConnections()
+                .evictIdleConnections(5L, TimeUnit.SECONDS)
                 .build();
         try {
             // create an array of URIs to perform GETs on
@@ -56,9 +58,6 @@ public class ClientEvictExpiredConnectio
                 "http://hc.apache.org/httpcomponents-client-ga/",
             };
 
-            IdleConnectionEvictor connEvictor = new IdleConnectionEvictor(cm);
-            connEvictor.start();
-
             for (int i = 0; i < urisToGet.length; i++) {
                 String requestURI = urisToGet[i];
                 HttpGet request = new HttpGet(requestURI);
@@ -75,54 +74,18 @@ public class ClientEvictExpiredConnectio
                 }
             }
 
+            PoolStats stats1 = cm.getTotalStats();
+            System.out.println("Connections kept alive: " + stats1.getAvailable());
+
             // Sleep 10 sec and let the connection evictor do its job
-            Thread.sleep(20000);
+            Thread.sleep(10000);
 
-            // Shut down the evictor thread
-            connEvictor.shutdown();
-            connEvictor.join();
+            PoolStats stats2 = cm.getTotalStats();
+            System.out.println("Connections kept alive: " + stats2.getAvailable());
 
         } finally {
             httpclient.close();
         }
     }
 
-    public static class IdleConnectionEvictor extends Thread {
-
-        private final HttpClientConnectionManager connMgr;
-
-        private volatile boolean shutdown;
-
-        public IdleConnectionEvictor(HttpClientConnectionManager 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();
-            }
-        }
-
-    }
-
 }

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java?rev=1643671&r1=1643670&r2=1643671&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
Sun Dec  7 12:42:19 2014
@@ -197,6 +197,10 @@ public class HttpClientBuilder {
     private SocketConfig defaultSocketConfig;
     private ConnectionConfig defaultConnectionConfig;
     private RequestConfig defaultRequestConfig;
+    private boolean evictExpiredConnections;
+    private boolean evictIdleConnections;
+    private long maxIdleTime;
+    private TimeUnit maxIdleTimeUnit;
 
     private boolean systemProperties;
     private boolean redirectHandlingDisabled;
@@ -749,7 +753,60 @@ public class HttpClientBuilder {
      * implementations.
      */
     public final HttpClientBuilder useSystemProperties() {
-        systemProperties = true;
+        this.systemProperties = true;
+        return this;
+    }
+
+    /**
+     * Makes this instance of HttpClient proactively evict expired connections from the
+     * connection pool using a background thread.
+     * <p>
+     * One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
+     * to stop and release the background thread.
+     * <p>
+     * Please note this method has no effect if the instance of HttpClient is configuted
to
+     * use a shared connection manager.
+     * <p>
+     * Please note this method may not be used when the instance of HttpClient is created
+     * inside an EJB container.
+     *
+     * @see #setConnectionManagerShared(boolean)
+     * @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
+     *
+     * @since 4.4
+     */
+    public final HttpClientBuilder evictExpiredConnections() {
+        evictExpiredConnections = true;
+        return this;
+    }
+
+    /**
+     * Makes this instance of HttpClient proactively evict idle connections from the
+     * connection pool using a background thread.
+     * <p>
+     * One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
+     * to stop and release the background thread.
+     * <p>
+     * Please note this method has no effect if the instance of HttpClient is configuted
to
+     * use a shared connection manager.
+     * <p>
+     * Please note this method may not be used when the instance of HttpClient is created
+     * inside an EJB container.
+     *
+     * @see #setConnectionManagerShared(boolean)
+     * @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
+     *
+     * @param maxIdleTime maxium time persistent connections can stay idle while kept alive
+     * in the connection pool. Connections whose inactivity period exceeds this value will
+     * get closed and evicted from the pool.
+     * @param maxIdleTimeUnit time unit for the above parameter.
+     *
+     * @since 4.4
+     */
+    public final HttpClientBuilder evictIdleConnections(final Long maxIdleTime, final TimeUnit
maxIdleTimeUnit) {
+        this.evictIdleConnections = true;
+        this.maxIdleTime = maxIdleTime;
+        this.maxIdleTimeUnit = maxIdleTimeUnit;
         return this;
     }
 
@@ -1098,6 +1155,20 @@ public class HttpClientBuilder {
                 closeablesCopy = new ArrayList<Closeable>(1);
             }
             final HttpClientConnectionManager cm = connManagerCopy;
+
+            if (evictExpiredConnections || evictIdleConnections) {
+                final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
+                        maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ?
maxIdleTimeUnit : TimeUnit.SECONDS);
+                closeablesCopy.add(new Closeable() {
+
+                    @Override
+                    public void close() throws IOException {
+                        connectionEvictor.shutdown();
+                    }
+
+                });
+                connectionEvictor.start();
+            }
             closeablesCopy.add(new Closeable() {
 
                 @Override

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java?rev=1643671&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java
Sun Dec  7 12:42:19 2014
@@ -0,0 +1,123 @@
+/*
+ * ====================================================================
+ * 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.impl.client;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.util.Args;
+
+/**
+ * This class maintains a background thread to enforce an eviction policy for expired / idle
+ * persistent connections kept alive in the connection pool.
+ *
+ * @since 4.4
+ */
+public final class IdleConnectionEvictor {
+
+    private final HttpClientConnectionManager connectionManager;
+    private final ThreadFactory threadFactory;
+    private final Thread thread;
+    private final long sleepTimeMs;
+    private final long maxIdleTimeMs;
+
+    private volatile Exception exception;
+
+    public IdleConnectionEvictor(
+            final HttpClientConnectionManager connectionManager,
+            final ThreadFactory threadFactory,
+            final long sleepTime, final TimeUnit sleepTimeUnit,
+            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
+        this.connectionManager = Args.notNull(connectionManager, "Connection manager");
+        this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory();
+        this.sleepTimeMs = sleepTimeUnit != null ? sleepTimeUnit.toMillis(sleepTime) : sleepTime;
+        this.maxIdleTimeMs = maxIdleTimeUnit != null ? maxIdleTimeUnit.toMillis(maxIdleTime)
: maxIdleTime;
+        this.thread = this.threadFactory.newThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    while (!Thread.currentThread().isInterrupted()) {
+                        Thread.sleep(sleepTimeMs);
+                        connectionManager.closeExpiredConnections();
+                        if (maxIdleTimeMs > 0) {
+                            connectionManager.closeIdleConnections(maxIdleTimeMs, TimeUnit.MILLISECONDS);
+                        }
+                    }
+                } catch (Exception ex) {
+                    exception = ex;
+                }
+
+            }
+        });
+    }
+
+    public IdleConnectionEvictor(
+            final HttpClientConnectionManager connectionManager,
+            final long sleepTime, final TimeUnit sleepTimeUnit,
+            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
+        this(connectionManager, null, sleepTime, sleepTimeUnit, maxIdleTime, maxIdleTimeUnit);
+    }
+
+    public IdleConnectionEvictor(
+            final HttpClientConnectionManager connectionManager,
+            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
+        this(connectionManager, null,
+                maxIdleTime > 0 ? maxIdleTime : 5, maxIdleTimeUnit != null ? maxIdleTimeUnit
: TimeUnit.SECONDS,
+                maxIdleTime, maxIdleTimeUnit);
+    }
+
+    public void start() {
+        thread.start();
+    }
+
+    public void shutdown() {
+        thread.interrupt();
+    }
+
+    public boolean isRunning() {
+        return thread.isAlive();
+    }
+
+    public void awaitTermination(final long time, final TimeUnit tunit) throws InterruptedException
{
+        thread.join((tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(time));
+    }
+
+    static class DefaultThreadFactory implements ThreadFactory {
+
+        @Override
+        public Thread newThread(final Runnable r) {
+            final Thread t = new Thread(r, "Connection evictor");
+            t.setDaemon(true);
+            return t;
+        }
+
+    };
+
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java?rev=1643671&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java
Sun Dec  7 12:42:19 2014
@@ -0,0 +1,80 @@
+/*
+ * ====================================================================
+ * 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.impl.client;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Unit tests for {@link org.apache.http.impl.client.IdleConnectionEvictor}.
+ */
+public class TestIdleConnectionEvictor {
+
+    @Test
+    public void testEvictExpiredAndIdle() throws Exception {
+        final HttpClientConnectionManager cm = Mockito.mock(HttpClientConnectionManager.class);
+        final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
+                500, TimeUnit.MILLISECONDS, 3, TimeUnit.SECONDS);
+        connectionEvictor.start();
+
+        Thread.sleep(1000);
+
+        Mockito.verify(cm, Mockito.atLeast(1)).closeExpiredConnections();
+        Mockito.verify(cm, Mockito.atLeast(1)).closeIdleConnections(3000, TimeUnit.MILLISECONDS);
+
+        Assert.assertTrue(connectionEvictor.isRunning());
+
+        connectionEvictor.shutdown();
+        connectionEvictor.awaitTermination(1, TimeUnit.SECONDS);
+        Assert.assertFalse(connectionEvictor.isRunning());
+    }
+
+    @Test
+    public void testEvictExpiredOnly() throws Exception {
+        final HttpClientConnectionManager cm = Mockito.mock(HttpClientConnectionManager.class);
+        final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
+                500, TimeUnit.MILLISECONDS, 0, TimeUnit.SECONDS);
+        connectionEvictor.start();
+
+        Thread.sleep(1000);
+
+        Mockito.verify(cm, Mockito.atLeast(1)).closeExpiredConnections();
+        Mockito.verify(cm, Mockito.never()).closeIdleConnections(Mockito.anyLong(), Mockito.<TimeUnit>any());
+
+        Assert.assertTrue(connectionEvictor.isRunning());
+
+        connectionEvictor.shutdown();
+        connectionEvictor.awaitTermination(1, TimeUnit.SECONDS);
+        Assert.assertFalse(connectionEvictor.isRunning());
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestIdleConnectionEviction.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestIdleConnectionEviction.java?rev=1643671&r1=1643670&r2=1643671&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestIdleConnectionEviction.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestIdleConnectionEviction.java
Sun Dec  7 12:42:19 2014
@@ -35,7 +35,7 @@ import org.apache.http.client.ClientProt
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.impl.client.IdleConnectionEvictor;
 import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.util.EntityUtils;
 import org.junit.Test;
@@ -49,7 +49,8 @@ public class TestIdleConnectionEviction
 
         final HttpHost target = start();
 
-        final IdleConnectionMonitor idleConnectionMonitor = new IdleConnectionMonitor(this.connManager);
+        final IdleConnectionEvictor idleConnectionMonitor = new IdleConnectionEvictor(
+                this.connManager, 50, TimeUnit.MILLISECONDS);
         idleConnectionMonitor.start();
 
         final HttpGet httpget = new HttpGet("/random/1024");
@@ -114,39 +115,5 @@ public class TestIdleConnectionEviction
         }
 
     }
-
-    public static class IdleConnectionMonitor extends Thread {
-
-        private final HttpClientConnectionManager cm;
-        private volatile boolean shutdown;
-
-        public IdleConnectionMonitor(final HttpClientConnectionManager cm) {
-            super();
-            this.cm = cm;
-            setDaemon(true);
-        }
-
-        @Override
-        public void run() {
-            try {
-                while (!this.shutdown) {
-                    synchronized (this) {
-                        wait(250);
-                        this.cm.closeIdleConnections(1, TimeUnit.MILLISECONDS);
-                    }
-                }
-            } catch (final InterruptedException ex) {
-                // terminate
-            }
-        }
-
-        public void shutdown() {
-            this.shutdown = true;
-            synchronized (this) {
-                notifyAll();
-            }
-        }
-
-    }
 
 }



Mime
View raw message