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 2021/04/02 08:58:55 UTC

[httpcomponents-core] branch 5.1.x updated: Bug fix: fixes race condition when a connection request completes successfully and times out at the same time causing a pool entry leak

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch 5.1.x
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git


The following commit(s) were added to refs/heads/5.1.x by this push:
     new e849f64  Bug fix: fixes race condition when a connection request completes successfully and times out at the same time causing a pool entry leak
e849f64 is described below

commit e849f6427053c51fe22bfdfb4f7e66fc258af4b3
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Wed Mar 31 16:15:03 2021 +0200

    Bug fix: fixes race condition when a connection request completes successfully and times out at the same time causing a pool entry leak
---
 .../main/java/org/apache/hc/core5/pool/ConnPool.java   |  6 +++++-
 .../java/org/apache/hc/core5/pool/LaxConnPool.java     | 18 +++++++++++++++++-
 .../java/org/apache/hc/core5/pool/StrictConnPool.java  | 18 +++++++++++++++++-
 3 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/pool/ConnPool.java b/httpcore5/src/main/java/org/apache/hc/core5/pool/ConnPool.java
index 5d648bf..0d50d63 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/pool/ConnPool.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/pool/ConnPool.java
@@ -46,13 +46,17 @@ public interface ConnPool<T, C extends ModalCloseable> {
     /**
      * Attempts to lease a connection for the given route and with the given
      * state from the pool.
+     * <p>
+     * Please note the connection request can get automatically cancelled by the pool
+     * in case of a request timeout.
      *
      * @param route route of the connection.
      * @param state arbitrary object that represents a particular state
      *  (usually a security principal or a unique token identifying
      *  the user whose credentials have been used while establishing the connection).
      *  May be {@code null}.
-     * @param requestTimeout request timeout.
+     * @param requestTimeout request timeout. In case of a timeout the request
+     *                       can get automatically cancelled by the pool.
      * @param callback operation completion callback.
      *
      * @return future for a leased pool entry.
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/pool/LaxConnPool.java b/httpcore5/src/main/java/org/apache/hc/core5/pool/LaxConnPool.java
index 26b56e6..b1d43d0 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/pool/LaxConnPool.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/pool/LaxConnPool.java
@@ -33,7 +33,10 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
@@ -466,7 +469,20 @@ public class LaxConnPool<T, C extends ModalCloseable> implements ManagedConnPool
                 final Timeout requestTimeout,
                 final FutureCallback<PoolEntry<T, C>> callback) {
             Asserts.check(!terminated.get(), "Connection pool shut down");
-            final BasicFuture<PoolEntry<T, C>> future = new BasicFuture<>(callback);
+            final BasicFuture<PoolEntry<T, C>> future = new BasicFuture<PoolEntry<T, C>>(callback) {
+
+                @Override
+                public synchronized PoolEntry<T, C> get(
+                        final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                    try {
+                        return super.get(timeout, unit);
+                    } catch (final TimeoutException ex) {
+                        cancel();
+                        throw ex;
+                    }
+                }
+
+            };
             final long releaseState = releaseSeqNum.get();
             PoolEntry<T, C> entry = null;
             if (pending.isEmpty()) {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/pool/StrictConnPool.java b/httpcore5/src/main/java/org/apache/hc/core5/pool/StrictConnPool.java
index a222bd8..3ad6cd0 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/pool/StrictConnPool.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/pool/StrictConnPool.java
@@ -34,7 +34,10 @@ import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
@@ -172,7 +175,20 @@ public class StrictConnPool<T, C extends ModalCloseable> implements ManagedConnP
         Args.notNull(requestTimeout, "Request timeout");
         Asserts.check(!this.isShutDown.get(), "Connection pool shut down");
         final Deadline deadline = Deadline.calculate(requestTimeout);
-        final BasicFuture<PoolEntry<T, C>> future = new BasicFuture<>(callback);
+        final BasicFuture<PoolEntry<T, C>> future = new BasicFuture<PoolEntry<T, C>>(callback) {
+
+            @Override
+            public synchronized PoolEntry<T, C> get(
+                    final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                try {
+                    return super.get(timeout, unit);
+                } catch (final TimeoutException ex) {
+                    cancel();
+                    throw ex;
+                }
+            }
+
+        };
         final boolean acquiredLock;
 
         try {