You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by rs...@apache.org on 2026/02/27 20:21:01 UTC
(httpcomponents-core) branch 5.4.x updated: LaxConnPool: Deallocate pool entry upon discarding expired connection
This is an automated email from the ASF dual-hosted git repository.
rschmitt pushed a commit to branch 5.4.x
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git
The following commit(s) were added to refs/heads/5.4.x by this push:
new 02ac6862c LaxConnPool: Deallocate pool entry upon discarding expired connection
02ac6862c is described below
commit 02ac6862cc1cfd6d41c7f3c5c0393eb125731420
Author: Ryan Schmitt <rs...@apache.org>
AuthorDate: Fri Feb 27 11:05:07 2026 -0800
LaxConnPool: Deallocate pool entry upon discarding expired connection
---
.../java/org/apache/hc/core5/pool/LaxConnPool.java | 1 +
.../org/apache/hc/core5/pool/TestLaxConnPool.java | 28 ++++++++++++++++++++++
2 files changed, 29 insertions(+)
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 8370bc035..9478fdcfa 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
@@ -444,6 +444,7 @@ private PoolEntry<T, C> getAvailableEntry(final Object state) {
it.remove();
if (entry.getExpiryDeadline().isExpired() || !Objects.equals(entry.getState(), state)) {
entry.discardConnection(CloseMode.GRACEFUL);
+ deallocatePoolEntry();
} else {
return entry;
}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/pool/TestLaxConnPool.java b/httpcore5/src/test/java/org/apache/hc/core5/pool/TestLaxConnPool.java
index c2e01c065..c1a7aa20b 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/pool/TestLaxConnPool.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/pool/TestLaxConnPool.java
@@ -475,4 +475,32 @@ void testGetMaxPerRoute() {
Assertions.assertEquals(max, pool.getMaxPerRoute(route));
}
}
+
+ @Test
+ void testExpiredEntryDeallocatesSlot() throws Exception {
+ final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
+
+ try (final LaxConnPool<String, HttpConnection> pool = new LaxConnPool<>(1)) {
+ // Lease, assign, expire, then release back to available
+ final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null);
+ final PoolEntry<String, HttpConnection> entry1 = future1.get();
+ entry1.assignConnection(conn1);
+ entry1.updateExpiry(TimeValue.of(1, TimeUnit.MILLISECONDS));
+ pool.release(entry1, true);
+
+ Thread.sleep(10);
+
+ // Lease again — the expired entry should be discarded and the slot freed
+ final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null);
+ Assertions.assertTrue(future2.isDone());
+ final PoolEntry<String, HttpConnection> entry2 = future2.get();
+ Assertions.assertNotNull(entry2);
+
+ // The expired entry was discarded, so a new entry was allocated.
+ // With maxPerRoute=1, this only works if the expired entry's slot was deallocated.
+ final PoolStats stats = pool.getStats("somehost");
+ Assertions.assertEquals(1, stats.getLeased());
+ Assertions.assertEquals(0, stats.getAvailable());
+ }
+ }
}