Skip to content

Commit d1cf6f2

Browse files
committed
HTTPCLIENT-2379: PerRoutePool.release now decrements the counter first and keeps the entry in the map until the count reaches zero, regardless of whether the connection is still open. The entry is handed back to the parent pool exactly once—on that final release—and any attempt to release an entry that was never leased now raises an IllegalStateException.
1 parent 6e0a18f commit d1cf6f2

3 files changed

Lines changed: 12 additions & 50 deletions

File tree

httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/H2SharingConnPool.java

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -288,20 +288,14 @@ PoolEntry<T, C> lease() {
288288
long release(final PoolEntry<T, C> entry, final boolean reusable) {
289289
lock.lock();
290290
try {
291-
final C connection = entry.getConnection();
292-
if (!reusable || connection == null || !connection.isOpen()) {
293-
entryMap.remove(entry);
294-
return 0;
295-
} else {
296-
final AtomicLong counter = entryMap.compute(entry, (e, c) -> {
297-
if (c == null) {
298-
return null;
299-
}
300-
final long count = c.decrementAndGet();
301-
return count > 0 ? c : null;
302-
});
303-
return counter != null ? counter.get() : 0L;
304-
}
291+
final AtomicLong counter = entryMap.compute(entry, (e, c) -> {
292+
if (c == null) {
293+
return null;
294+
}
295+
final long count = c.decrementAndGet();
296+
return count > 0 ? c : null;
297+
});
298+
return counter != null ? counter.get() : 0L;
305299
} finally {
306300
lock.unlock();
307301
}

httpclient5/src/test/java/org/apache/hc/client5/http/impl/nio/H2SharingConnPoolTest.java

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -314,38 +314,6 @@ void testReleaseReusableInCacheNotReturnedToPool() throws Exception {
314314
Mockito.anyBoolean());
315315
}
316316

317-
@Test
318-
void testReleaseNonReusableInCacheReturnedToPool() throws Exception {
319-
final PoolEntry<String, HttpConnection> poolEntry = new PoolEntry<>(DEFAULT_ROUTE);
320-
poolEntry.assignConnection(connection);
321-
Mockito.when(connection.isOpen()).thenReturn(true);
322-
final H2SharingConnPool.PerRoutePool<String, HttpConnection> routePool = h2SharingPool.getPerRoutePool(DEFAULT_ROUTE);
323-
routePool.track(poolEntry);
324-
routePool.track(poolEntry);
325-
326-
h2SharingPool.release(poolEntry, false);
327-
328-
Mockito.verify(connPool).release(
329-
Mockito.same(poolEntry),
330-
Mockito.eq(false));
331-
}
332-
333-
@Test
334-
void testReleaseReusableAndClosedInCacheReturnedToPool() throws Exception {
335-
final PoolEntry<String, HttpConnection> poolEntry = new PoolEntry<>(DEFAULT_ROUTE);
336-
poolEntry.assignConnection(connection);
337-
Mockito.when(connection.isOpen()).thenReturn(false);
338-
final H2SharingConnPool.PerRoutePool<String, HttpConnection> routePool = h2SharingPool.getPerRoutePool(DEFAULT_ROUTE);
339-
routePool.track(poolEntry);
340-
routePool.track(poolEntry);
341-
342-
h2SharingPool.release(poolEntry, true);
343-
344-
Mockito.verify(connPool).release(
345-
Mockito.same(poolEntry),
346-
Mockito.eq(true));
347-
}
348-
349317
/**
350318
* Same connection can only be released once.
351319
* Attempting to release it again will throw: IllegalStateException("Pool entry is not present in the set of leased entries")
@@ -372,7 +340,7 @@ void testReleaseNonReusableNotInCacheReturnedToPool() throws Exception {
372340
}).when(connPool).release(Mockito.eq(poolEntry), Mockito.anyBoolean());
373341

374342
h2SharingPool.release(poolEntry, false);
375-
// for reproduce https://issues.apache.org/jira/browse/HTTPCLIENT-2379
343+
h2SharingPool.release(poolEntry, false);
376344
Assertions.assertThrows(IllegalStateException.class, () -> h2SharingPool.release(poolEntry, false));
377345
}
378346

httpclient5/src/test/java/org/apache/hc/client5/http/impl/nio/H2SharingPerRoutePoolTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ void testReleaseNonReusable() {
9898
pool.track(poolEntry1);
9999
pool.track(poolEntry1);
100100

101-
Assertions.assertEquals(0, pool.release(poolEntry1, false));
101+
Assertions.assertEquals(2, pool.release(poolEntry1, false)); // 3 → 2
102102
}
103103

104104
@Test
@@ -114,7 +114,7 @@ void testReleaseConnectionClosed() {
114114
pool.track(poolEntry1);
115115

116116
Mockito.when(poolEntry1.getConnection().isOpen()).thenReturn(false);
117-
Assertions.assertEquals(0, pool.release(poolEntry1, true));
117+
Assertions.assertEquals(2, pool.release(poolEntry1, true)); // 3 → 2
118118
}
119119

120120
@Test
@@ -124,7 +124,7 @@ void testReleaseConnectionMissing() {
124124
pool.track(poolEntry1);
125125

126126
poolEntry1.discardConnection(CloseMode.IMMEDIATE);
127-
Assertions.assertEquals(0, pool.release(poolEntry1, true));
127+
Assertions.assertEquals(2, pool.release(poolEntry1, true)); // 3 → 2
128128
}
129129

130130
}

0 commit comments

Comments
 (0)