hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject [32/50] httpcomponents-core git commit: Non-blocking connection pool to avoid scanning the entire queue of pending connection requests on each connection lease / release operation (under heavy load the request queue can contain a significant number of pe
Date Tue, 09 May 2017 20:03:23 GMT
Non-blocking connection pool to avoid scanning the entire queue of pending connection requests
on each connection lease / release operation (under heavy load the request queue can contain
a significant number of pending requests, a full linear scan of which can cause massive performance
degradation)

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpcore/branches/4.2.x@1478038
13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/commit/579fdb55
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/tree/579fdb55
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/diff/579fdb55

Branch: refs/heads/4.2.x
Commit: 579fdb559c623c21b1ca1c00774fd5c11017fcb1
Parents: a8c8e4e
Author: Oleg Kalnichevski <olegk@apache.org>
Authored: Wed May 1 14:58:17 2013 +0000
Committer: Oleg Kalnichevski <olegk@apache.org>
Committed: Wed May 1 14:58:17 2013 +0000

----------------------------------------------------------------------
 RELEASE_NOTES.txt                               |   9 +
 .../http/nio/pool/AbstractNIOConnPool.java      | 164 ++++++++++---------
 2 files changed, 99 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/579fdb55/RELEASE_NOTES.txt
----------------------------------------------------------------------
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index bada959..0338632 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -1,6 +1,15 @@
 Changes since Release 4.2.4
 -------------------
 
+* Non-blocking connection pool to avoid scanning the entire queue of pending connection requests

+  on each connection lease / release operation (under heavy load the request queue can contain

+  a significant number of pending requests, a full linear scan of which can cause massive

+  performance degradation).
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* Use bulk ByteBuffer#put method instead of single byte ByteBuffer#put
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
 * [HTTPCORE-336]  Unhandled CancelledKeyException leads to a shutdown of the underlying IOReactor.
   Contributed by Thomas Dudek <mail.dudek at gmail.com> 
 

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/579fdb55/httpcore-nio/src/main/java/org/apache/http/nio/pool/AbstractNIOConnPool.java
----------------------------------------------------------------------
diff --git a/httpcore-nio/src/main/java/org/apache/http/nio/pool/AbstractNIOConnPool.java
b/httpcore-nio/src/main/java/org/apache/http/nio/pool/AbstractNIOConnPool.java
index 4754c26..2344a96 100644
--- a/httpcore-nio/src/main/java/org/apache/http/nio/pool/AbstractNIOConnPool.java
+++ b/httpcore-nio/src/main/java/org/apache/http/nio/pool/AbstractNIOConnPool.java
@@ -187,9 +187,9 @@ public abstract class AbstractNIOConnPool<T, C, E extends PoolEntry<T,
C>>
             long timeout = connectTimeout > 0 ? tunit.toMillis(connectTimeout) : 0;
             BasicFuture<E> future = new BasicFuture<E>(callback);
             LeaseRequest<T, C, E> request = new LeaseRequest<T, C, E>(route,
state, timeout, future);
-            this.leasingRequests.add(request);
-
-            processPendingRequests();
+            if (!processPendingRequest(request)) {
+                this.leasingRequests.add(request);
+            }
             return future;
         } finally {
             this.lock.unlock();
@@ -221,7 +221,7 @@ public abstract class AbstractNIOConnPool<T, C, E extends PoolEntry<T,
C>>
                 } else {
                     entry.close();
                 }
-                processPendingRequests();
+                processNextPendingRequest();
             }
         } finally {
             this.lock.unlock();
@@ -232,85 +232,101 @@ public abstract class AbstractNIOConnPool<T, C, E extends PoolEntry<T,
C>>
         ListIterator<LeaseRequest<T, C, E>> it = this.leasingRequests.listIterator();
         while (it.hasNext()) {
             LeaseRequest<T, C, E> request = it.next();
+            if (processPendingRequest(request)) {
+                it.remove();
+            }
+        }
+    }
 
-            T route = request.getRoute();
-            Object state = request.getState();
-            long deadline = request.getDeadline();
-            BasicFuture<E> future = request.getFuture();
-
-            long now = System.currentTimeMillis();
-            if (now > deadline) {
+    private void processNextPendingRequest() {
+        ListIterator<LeaseRequest<T, C, E>> it = this.leasingRequests.listIterator();
+        while (it.hasNext()) {
+            LeaseRequest<T, C, E> request = it.next();
+            if (processPendingRequest(request)) {
                 it.remove();
-                future.failed(new TimeoutException());
-                continue;
+                return;
             }
+        }
+    }
 
-            RouteSpecificPool<T, C, E> pool = getPool(route);
-            E entry = null;
-            for (;;) {
-                entry = pool.getFree(state);
-                if (entry == null) {
-                    break;
-                }
-                if (entry.isClosed() || entry.isExpired(System.currentTimeMillis())) {
-                    entry.close();
-                    this.available.remove(entry);
-                    pool.free(entry, false);
-                } else {
-                    break;
-                }
+    private boolean processPendingRequest(final LeaseRequest<T, C, E> request) {
+        T route = request.getRoute();
+        Object state = request.getState();
+        long deadline = request.getDeadline();
+        BasicFuture<E> future = request.getFuture();
+
+        long now = System.currentTimeMillis();
+        if (now > deadline) {
+            future.failed(new TimeoutException());
+            return true;
+        }
+
+        RouteSpecificPool<T, C, E> pool = getPool(route);
+        E entry = null;
+        for (;;) {
+            entry = pool.getFree(state);
+            if (entry == null) {
+                break;
             }
-            if (entry != null) {
-                it.remove();
+            if (entry.isClosed() || entry.isExpired(System.currentTimeMillis())) {
+                entry.close();
                 this.available.remove(entry);
-                this.leased.add(entry);
-                future.completed(entry);
-                continue;
+                pool.free(entry, false);
+            } else {
+                break;
             }
-
-            // New connection is needed
-            int maxPerRoute = getMax(route);
-            // Shrink the pool prior to allocating a new connection
-            int excess = Math.max(0, pool.getAllocatedCount() + 1 - maxPerRoute);
-            if (excess > 0) {
-                for (int i = 0; i < excess; i++) {
-                    E lastUsed = pool.getLastUsed();
-                    if (lastUsed == null) {
-                        break;
-                    }
-                    lastUsed.close();
-                    this.available.remove(lastUsed);
-                    pool.remove(lastUsed);
+        }
+        if (entry != null) {
+            this.available.remove(entry);
+            this.leased.add(entry);
+            future.completed(entry);
+            return true;
+        }
+
+        // New connection is needed
+        int maxPerRoute = getMax(route);
+        // Shrink the pool prior to allocating a new connection
+        int excess = Math.max(0, pool.getAllocatedCount() + 1 - maxPerRoute);
+        if (excess > 0) {
+            for (int i = 0; i < excess; i++) {
+                E lastUsed = pool.getLastUsed();
+                if (lastUsed == null) {
+                    break;
                 }
+                lastUsed.close();
+                this.available.remove(lastUsed);
+                pool.remove(lastUsed);
             }
+        }
 
-            if (pool.getAllocatedCount() < maxPerRoute) {
-                int totalUsed = this.pending.size() + this.leased.size();
-                int freeCapacity = Math.max(this.maxTotal - totalUsed, 0);
-                if (freeCapacity == 0) {
-                    continue;
-                }
-                int totalAvailable = this.available.size();
-                if (totalAvailable > freeCapacity - 1) {
-                    if (!this.available.isEmpty()) {
-                        E lastUsed = this.available.removeLast();
-                        lastUsed.close();
-                        RouteSpecificPool<T, C, E> otherpool = getPool(lastUsed.getRoute());
-                        otherpool.remove(lastUsed);
-                    }
+        if (pool.getAllocatedCount() < maxPerRoute) {
+            int totalUsed = this.pending.size() + this.leased.size();
+            int freeCapacity = Math.max(this.maxTotal - totalUsed, 0);
+            if (freeCapacity == 0) {
+                return false;
+            }
+            int totalAvailable = this.available.size();
+            if (totalAvailable > freeCapacity - 1) {
+                if (!this.available.isEmpty()) {
+                    E lastUsed = this.available.removeLast();
+                    lastUsed.close();
+                    RouteSpecificPool<T, C, E> otherpool = getPool(lastUsed.getRoute());
+                    otherpool.remove(lastUsed);
                 }
-                it.remove();
-                SessionRequest sessionRequest = this.ioreactor.connect(
-                        resolveRemoteAddress(route),
-                        resolveLocalAddress(route),
-                        route,
-                        this.sessionRequestCallback);
-                int timout = request.getConnectTimeout() < Integer.MAX_VALUE ?
-                        (int) request.getConnectTimeout() : Integer.MAX_VALUE;
-                sessionRequest.setConnectTimeout(timout);
-                this.pending.add(sessionRequest);
-                pool.addPending(sessionRequest, future);
             }
+            SessionRequest sessionRequest = this.ioreactor.connect(
+                    resolveRemoteAddress(route),
+                    resolveLocalAddress(route),
+                    route,
+                    this.sessionRequestCallback);
+            int timout = request.getConnectTimeout() < Integer.MAX_VALUE ?
+                    (int) request.getConnectTimeout() : Integer.MAX_VALUE;
+            sessionRequest.setConnectTimeout(timout);
+            this.pending.add(sessionRequest);
+            pool.addPending(sessionRequest, future);
+            return true;
+        } else {
+            return false;
         }
     }
 
@@ -369,7 +385,7 @@ public abstract class AbstractNIOConnPool<T, C, E extends PoolEntry<T,
C>>
             this.pending.remove(request);
             RouteSpecificPool<T, C, E> pool = getPool(route);
             pool.cancelled(request);
-            processPendingRequests();
+            processNextPendingRequest();
         } finally {
             this.lock.unlock();
         }
@@ -386,7 +402,7 @@ public abstract class AbstractNIOConnPool<T, C, E extends PoolEntry<T,
C>>
             this.pending.remove(request);
             RouteSpecificPool<T, C, E> pool = getPool(route);
             pool.failed(request, request.getException());
-            processPendingRequests();
+            processNextPendingRequest();
         } finally {
             this.lock.unlock();
         }
@@ -403,7 +419,7 @@ public abstract class AbstractNIOConnPool<T, C, E extends PoolEntry<T,
C>>
             this.pending.remove(request);
             RouteSpecificPool<T, C, E> pool = getPool(route);
             pool.timeout(request);
-            processPendingRequests();
+            processNextPendingRequest();
         } finally {
             this.lock.unlock();
         }


Mime
View raw message