You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2014/05/23 11:04:12 UTC

svn commit: r1597035 - in /httpcomponents/httpasyncclient/trunk: ./ httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/ httpasyncclient/src/test/java/org/apache/http/impl/nio/conn/

Author: olegk
Date: Fri May 23 09:04:11 2014
New Revision: 1597035

URL: http://svn.apache.org/r1597035
Log:
Replaced dynamic proxies with custom proxy classes to reduce thread contention

Modified:
    httpcomponents/httpasyncclient/trunk/RELEASE_NOTES.txt
    httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/CPoolProxy.java
    httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/conn/TestPoolingHttpClientAsyncConnectionManager.java

Modified: httpcomponents/httpasyncclient/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/RELEASE_NOTES.txt?rev=1597035&r1=1597034&r2=1597035&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/trunk/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpasyncclient/trunk/RELEASE_NOTES.txt Fri May 23 09:04:11 2014
@@ -1,6 +1,9 @@
 Changes since 4.0.1
 -------------------
 
+* Replaced dynamic proxies with custom proxy classes to reduce thread contention.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
 * [HTTPASYNC-73] Original request headers are not copied upon redirect
   Contributed by Oleg Kalnichevski <olegk at apache.org>
 

Modified: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/CPoolProxy.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/CPoolProxy.java?rev=1597035&r1=1597034&r2=1597035&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/CPoolProxy.java (original)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/conn/CPoolProxy.java Fri May 23 09:04:11 2014
@@ -27,37 +27,23 @@
 package org.apache.http.impl.nio.conn;
 
 import java.io.IOException;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
+import java.net.InetAddress;
 
-import org.apache.http.HttpConnection;
+import javax.net.ssl.SSLSession;
+
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
 import org.apache.http.annotation.NotThreadSafe;
 import org.apache.http.impl.conn.ConnectionShutdownException;
-import org.apache.http.nio.IOControl;
 import org.apache.http.nio.NHttpClientConnection;
 import org.apache.http.nio.conn.ManagedNHttpClientConnection;
-import org.apache.http.util.Asserts;
+import org.apache.http.nio.reactor.IOSession;
+import org.apache.http.protocol.HttpContext;
 
 @NotThreadSafe
-class CPoolProxy implements InvocationHandler {
-
-    private static final Method CLOSE_METHOD;
-    private static final Method SHUTDOWN_METHOD;
-    private static final Method IS_OPEN_METHOD;
-    private static final Method IS_STALE_METHOD;
-
-    static {
-        try {
-            CLOSE_METHOD = HttpConnection.class.getMethod("close");
-            SHUTDOWN_METHOD = HttpConnection.class.getMethod("shutdown");
-            IS_OPEN_METHOD = HttpConnection.class.getMethod("isOpen");
-            IS_STALE_METHOD = HttpConnection.class.getMethod("isStale");
-        } catch (final NoSuchMethodException ex) {
-            throw new Error(ex);
-        }
-    }
+class CPoolProxy implements ManagedNHttpClientConnection {
 
     private volatile CPoolEntry poolEntry;
 
@@ -76,7 +62,7 @@ class CPoolProxy implements InvocationHa
         return local;
     }
 
-    NHttpClientConnection getConnection() {
+    ManagedNHttpClientConnection getConnection() {
         final CPoolEntry local = this.poolEntry;
         if (local == null) {
             return null;
@@ -84,6 +70,15 @@ class CPoolProxy implements InvocationHa
         return local.getConnection();
     }
 
+    ManagedNHttpClientConnection getValidConnection() {
+        final ManagedNHttpClientConnection conn = getConnection();
+        if (conn == null) {
+            throw new ConnectionShutdownException();
+        }
+        return conn;
+    }
+
+    @Override
     public void close() throws IOException {
         final CPoolEntry local = this.poolEntry;
         if (local != null) {
@@ -91,6 +86,7 @@ class CPoolProxy implements InvocationHa
         }
     }
 
+    @Override
     public void shutdown() throws IOException {
         final CPoolEntry local = this.poolEntry;
         if (local != null) {
@@ -98,6 +94,64 @@ class CPoolProxy implements InvocationHa
         }
     }
 
+    @Override
+    public HttpConnectionMetrics getMetrics() {
+        return getValidConnection().getMetrics();
+    }
+
+    @Override
+    public void requestInput() {
+        final NHttpClientConnection conn = getConnection();
+        if (conn != null) {
+            conn.requestInput();
+        }
+    }
+
+    @Override
+    public void suspendInput() {
+        final NHttpClientConnection conn = getConnection();
+        if (conn != null) {
+            conn.suspendInput();
+        }
+    }
+
+    @Override
+    public void requestOutput() {
+        final NHttpClientConnection conn = getConnection();
+        if (conn != null) {
+            conn.requestOutput();
+        }
+    }
+
+    @Override
+    public void suspendOutput() {
+        final NHttpClientConnection conn = getConnection();
+        if (conn != null) {
+            conn.suspendOutput();
+        }
+    }
+
+    @Override
+    public InetAddress getLocalAddress() {
+        return getValidConnection().getLocalAddress();
+    }
+
+    @Override
+    public int getLocalPort() {
+        return getValidConnection().getLocalPort();
+    }
+
+    @Override
+    public InetAddress getRemoteAddress() {
+        return getValidConnection().getRemoteAddress();
+    }
+
+    @Override
+    public int getRemotePort() {
+        return getValidConnection().getRemotePort();
+    }
+
+    @Override
     public boolean isOpen() {
         final CPoolEntry local = this.poolEntry;
         if (local != null) {
@@ -107,6 +161,7 @@ class CPoolProxy implements InvocationHa
         }
     }
 
+    @Override
     public boolean isStale() {
         final NHttpClientConnection conn = getConnection();
         if (conn != null) {
@@ -116,59 +171,69 @@ class CPoolProxy implements InvocationHa
         }
     }
 
-    public Object invoke(
-            final Object proxy, final Method method, final Object[] args) throws Throwable {
-        if (method.equals(CLOSE_METHOD)) {
-            close();
-            return null;
-        } else if (method.equals(SHUTDOWN_METHOD)) {
-            shutdown();
-            return null;
-        } else if (method.equals(IS_OPEN_METHOD)) {
-            return Boolean.valueOf(isOpen());
-        } else if (method.equals(IS_STALE_METHOD)) {
-            return Boolean.valueOf(isStale());
-        } else {
-            final NHttpClientConnection conn = getConnection();
-            if (conn == null) {
-                if (method.getDeclaringClass().equals(IOControl.class)) {
-                    // Ignore IOControl operations on closed connections
-                    return null;
-                } else {
-                    throw new ConnectionShutdownException();
-                }
-            }
-            try {
-                return method.invoke(conn, args);
-            } catch (final InvocationTargetException ex) {
-                final Throwable cause = ex.getCause();
-                if (cause != null) {
-                    throw cause;
-                } else {
-                    throw ex;
-                }
-            }
-        }
+    @Override
+    public void setSocketTimeout(final int i) {
+        getValidConnection().setSocketTimeout(i);
+    }
+
+    @Override
+    public int getSocketTimeout() {
+        return getValidConnection().getSocketTimeout();
+    }
+
+    @Override
+    public void submitRequest(final HttpRequest request) throws IOException, HttpException {
+        getValidConnection().submitRequest(request);
+    }
+
+    @Override
+    public boolean isRequestSubmitted() {
+        return getValidConnection().isRequestSubmitted();
+    }
+
+    @Override
+    public void resetOutput() {
+        getValidConnection().resetOutput();
+    }
+
+    @Override
+    public void resetInput() {
+        getValidConnection().resetInput();
+    }
+
+    @Override
+    public int getStatus() {
+        return getValidConnection().getStatus();
+    }
+
+    @Override
+    public HttpRequest getHttpRequest() {
+        return getValidConnection().getHttpRequest();
+    }
+
+    @Override
+    public HttpResponse getHttpResponse() {
+        return getValidConnection().getHttpResponse();
+    }
+
+    @Override
+    public HttpContext getContext() {
+        return getValidConnection().getContext();
+    }
+
+    public static NHttpClientConnection newProxy(final CPoolEntry poolEntry) {
+        return new CPoolProxy(poolEntry);
     }
 
-    public static NHttpClientConnection newProxy(
-            final CPoolEntry poolEntry) {
-        return (NHttpClientConnection) Proxy.newProxyInstance(
-                CPoolProxy.class.getClassLoader(),
-                new Class<?>[] { ManagedNHttpClientConnection.class },
-                new CPoolProxy(poolEntry));
-    }
-
-    private static CPoolProxy getHandler(
-            final NHttpClientConnection proxy) {
-        final InvocationHandler handler = Proxy.getInvocationHandler(proxy);
-        Asserts.check(CPoolProxy.class.isInstance(handler),
-                "Unexpected proxy handler class: %s", handler.getClass());
-        return CPoolProxy.class.cast(handler);
+    private static CPoolProxy getProxy(final NHttpClientConnection conn) {
+        if (!CPoolProxy.class.isInstance(conn)) {
+            throw new IllegalStateException("Unexpected connection proxy class: " + conn.getClass());
+        }
+        return CPoolProxy.class.cast(conn);
     }
 
     public static CPoolEntry getPoolEntry(final NHttpClientConnection proxy) {
-        final CPoolEntry entry = getHandler(proxy).getPoolEntry();
+        final CPoolEntry entry = getProxy(proxy).getPoolEntry();
         if (entry == null) {
             throw new ConnectionShutdownException();
         }
@@ -176,7 +241,40 @@ class CPoolProxy implements InvocationHa
     }
 
     public static CPoolEntry detach(final NHttpClientConnection proxy) {
-        return getHandler(proxy).detach();
+        return getProxy(proxy).detach();
+    }
+
+    @Override
+    public String getId() {
+        return getValidConnection().getId();
+    }
+
+    @Override
+    public void bind(final IOSession iosession) {
+        getValidConnection().bind(iosession);
+    }
+
+    @Override
+    public IOSession getIOSession() {
+        return getValidConnection().getIOSession();
+    }
+
+    @Override
+    public SSLSession getSSLSession() {
+        return getValidConnection().getSSLSession();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("CPoolProxy{");
+        final ManagedNHttpClientConnection conn = getConnection();
+        if (conn != null) {
+            sb.append(conn);
+        } else {
+            sb.append("detached");
+        }
+        sb.append('}');
+        return sb.toString();
     }
 
 }

Modified: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/conn/TestPoolingHttpClientAsyncConnectionManager.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/conn/TestPoolingHttpClientAsyncConnectionManager.java?rev=1597035&r1=1597034&r2=1597035&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/conn/TestPoolingHttpClientAsyncConnectionManager.java (original)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/conn/TestPoolingHttpClientAsyncConnectionManager.java Fri May 23 09:04:11 2014
@@ -26,7 +26,6 @@
  */
 package org.apache.http.impl.nio.conn;
 
-import java.lang.reflect.Proxy;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.util.Calendar;
@@ -34,8 +33,6 @@ import java.util.concurrent.ExecutionExc
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
-import junit.framework.Assert;
-
 import org.apache.commons.logging.Log;
 import org.apache.http.HttpHost;
 import org.apache.http.concurrent.FutureCallback;
@@ -58,6 +55,7 @@ import org.apache.http.nio.reactor.IOSes
 import org.apache.http.nio.reactor.SessionRequest;
 import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.protocol.HttpContext;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -146,7 +144,6 @@ public class TestPoolingHttpClientAsyncC
 
         Assert.assertTrue(future.isDone());
         final NHttpClientConnection managedConn = future.get();
-        Assert.assertTrue(Proxy.isProxyClass(managedConn.getClass()));
         Mockito.verify(connCallback).completed(Mockito.<NHttpClientConnection>any());
 
         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
@@ -182,7 +179,6 @@ public class TestPoolingHttpClientAsyncC
 
         Assert.assertTrue(future.isDone());
         final NHttpClientConnection managedConn = future.get();
-        Assert.assertTrue(Proxy.isProxyClass(managedConn.getClass()));
         Mockito.verify(connCallback).completed(Mockito.<NHttpClientConnection>any());
 
         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);