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 2019/12/13 08:14:16 UTC
[httpcomponents-core] branch master updated: Allow for timeout
while acquiring lock in StrictConnPool. (#163)
This is an automated email from the ASF dual-hosted git repository.
olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git
The following commit(s) were added to refs/heads/master by this push:
new 6d6f1fa Allow for timeout while acquiring lock in StrictConnPool. (#163)
6d6f1fa is described below
commit 6d6f1fa4a6e3a4d33c8ae51f9d284e4e900eb8a1
Author: cwildman <ch...@chriswildman.com>
AuthorDate: Fri Dec 13 00:14:07 2019 -0800
Allow for timeout while acquiring lock in StrictConnPool. (#163)
Allow for timeout while acquiring lock in StrictConnPool
---
.../org/apache/hc/core5/pool/StrictConnPool.java | 37 +++++++----
.../apache/hc/core5/pool/TestStrictConnPool.java | 71 ++++++++++++++++++++++
2 files changed, 97 insertions(+), 11 deletions(-)
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 19c2e36..dfd5b36 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
@@ -171,21 +171,36 @@ public class StrictConnPool<T, C extends ModalCloseable> implements ManagedConnP
Args.notNull(route, "Route");
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);
- this.lock.lock();
+ final boolean acquiredLock;
+
try {
- final LeaseRequest<T, C> request = new LeaseRequest<>(route, state, requestTimeout, future);
- final boolean completed = processPendingRequest(request);
- if (!request.isDone() && !completed) {
- this.leasingRequests.add(request);
- }
- if (request.isDone()) {
- this.completedRequests.add(request);
+ acquiredLock = this.lock.tryLock(requestTimeout.getDuration(), requestTimeout.getTimeUnit());
+ } catch (final InterruptedException interruptedException) {
+ Thread.currentThread().interrupt();
+ future.cancel();
+ return future;
+ }
+
+ if (acquiredLock) {
+ try {
+ final LeaseRequest<T, C> request = new LeaseRequest<>(route, state, requestTimeout, future);
+ final boolean completed = processPendingRequest(request);
+ if (!request.isDone() && !completed) {
+ this.leasingRequests.add(request);
+ }
+ if (request.isDone()) {
+ this.completedRequests.add(request);
+ }
+ } finally {
+ this.lock.unlock();
}
- } finally {
- this.lock.unlock();
+ fireCallbacks();
+ } else {
+ future.failed(DeadlineTimeoutException.from(deadline));
}
- fireCallbacks();
+
return future;
}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/pool/TestStrictConnPool.java b/httpcore5/src/test/java/org/apache/hc/core5/pool/TestStrictConnPool.java
index 610b091..7aa5c50 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/pool/TestStrictConnPool.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/pool/TestStrictConnPool.java
@@ -27,11 +27,16 @@
package org.apache.hc.core5.pool;
import java.util.Collections;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import org.apache.hc.core5.function.Callback;
import org.apache.hc.core5.http.HttpConnection;
import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.util.DeadlineTimeoutException;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.junit.Assert;
@@ -512,6 +517,72 @@ public class TestStrictConnPool {
Assert.assertTrue(future3.isDone());
}
+ private static class HoldInternalLockThread extends Thread {
+ private HoldInternalLockThread(final StrictConnPool<String, HttpConnection> pool, final CountDownLatch lockHeld) {
+ super(new Runnable() {
+ @Override
+ public void run() {
+ pool.lease("somehost", null); // lease a connection so we have something to enumLeased()
+ pool.enumLeased(new Callback<PoolEntry<String, HttpConnection>>() {
+ @Override
+ public void execute(final PoolEntry<String, HttpConnection> object) {
+ try {
+ lockHeld.countDown();
+ Thread.sleep(Long.MAX_VALUE);
+ } catch (final InterruptedException ignored) {
+ }
+ }
+ });
+ }
+ });
+ }
+ }
+
+ @Test
+ public void testLeaseRequestLockTimeout() throws Exception {
+ final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(1, 1);
+ final CountDownLatch lockHeld = new CountDownLatch(1);
+ final Thread holdInternalLock = new HoldInternalLockThread(pool, lockHeld);
+
+ holdInternalLock.start(); // Start a thread to grab the internal conn pool lock
+ lockHeld.await(); // Wait until we know the internal lock is held
+
+ // Attempt to get a connection while lock is held
+ final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null, Timeout.ofMilliseconds(10), null);
+
+ try {
+ future2.get();
+ } catch (final ExecutionException executionException) {
+ Assert.assertTrue(executionException.getCause() instanceof DeadlineTimeoutException);
+ holdInternalLock.interrupt(); // Cleanup
+ return;
+ }
+ Assert.fail("Expected deadline timeout.");
+ }
+
+ @Test
+ public void testLeaseRequestInterrupted() throws Exception {
+ final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(1, 1);
+ final CountDownLatch lockHeld = new CountDownLatch(1);
+ final Thread holdInternalLock = new HoldInternalLockThread(pool, lockHeld);
+
+ holdInternalLock.start(); // Start a thread to grab the internal conn pool lock
+ lockHeld.await(); // Wait until we know the internal lock is held
+
+ Thread.currentThread().interrupt();
+ // Attempt to get a connection while lock is held and thread is interrupted
+ final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null, Timeout.ofMilliseconds(10), null);
+
+ Assert.assertTrue(Thread.interrupted());
+ try {
+ future2.get();
+ } catch (final CancellationException cancellationException) {
+ holdInternalLock.interrupt(); // Cleanup
+ return;
+ }
+ Assert.fail("Expected interrupted exception.");
+ }
+
@Test
public void testLeaseRequestCanceled() throws Exception {
final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(1, 1);