8302732: sun/net/www/http/HttpClient/MultiThreadTest.java still failing intermittently

Reviewed-by: dfuchs
This commit is contained in:
Daniel Jeliński 2023-02-27 07:52:03 +00:00
parent db217c9ad6
commit a2c5a4ac9e
2 changed files with 54 additions and 73 deletions
src/java.base/share/classes/sun/net/www/http
test/jdk/sun/net/www/http/HttpClient

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,7 +36,6 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import jdk.internal.misc.InnocuousThread;
@ -51,7 +50,7 @@ import sun.util.logging.PlatformLogger;
* @author Dave Brown
*/
public class KeepAliveCache
extends HashMap<KeepAliveKey, ClientVector>
extends HashMap<KeepAliveKey, KeepAliveCache.ClientVector>
implements Runnable {
@java.io.Serial
private static final long serialVersionUID = -2937172892064557949L;
@ -243,32 +242,32 @@ public class KeepAliveCache
// Remove all outdated HttpClients.
cacheLock.lock();
try {
if (isEmpty()) {
// cache not used in the last LIFETIME - exit
keepAliveTimer = null;
break;
}
long currentTime = System.currentTimeMillis();
List<KeepAliveKey> keysToRemove = new ArrayList<>();
for (KeepAliveKey key : keySet()) {
ClientVector v = get(key);
v.lock();
try {
KeepAliveEntry e = v.peekLast();
while (e != null) {
if ((currentTime - e.idleStartTime) > v.nap) {
v.pollLast();
if (closeList == null) {
closeList = new ArrayList<>();
}
closeList.add(e.hc);
} else {
break;
KeepAliveEntry e = v.peekLast();
while (e != null) {
if ((currentTime - e.idleStartTime) > v.nap) {
v.pollLast();
if (closeList == null) {
closeList = new ArrayList<>();
}
e = v.peekLast();
closeList.add(e.hc);
} else {
break;
}
e = v.peekLast();
}
if (v.isEmpty()) {
keysToRemove.add(key);
}
} finally {
v.unlock();
if (v.isEmpty()) {
keysToRemove.add(key);
}
}
@ -284,7 +283,7 @@ public class KeepAliveCache
}
}
}
} while (!isEmpty());
} while (keepAliveTimer == Thread.currentThread());
}
/*
@ -301,27 +300,24 @@ public class KeepAliveCache
{
throw new NotSerializableException();
}
}
/* LIFO order for reusing HttpClients. Most recent entries at the front.
* If > maxConns are in use, discard oldest.
*/
class ClientVector extends ArrayDeque<KeepAliveEntry> {
@java.io.Serial
private static final long serialVersionUID = -8680532108106489459L;
private final ReentrantLock lock = new ReentrantLock();
/* LIFO order for reusing HttpClients. Most recent entries at the front.
* If > maxConns are in use, discard oldest.
*/
class ClientVector extends ArrayDeque<KeepAliveEntry> {
@java.io.Serial
private static final long serialVersionUID = -8680532108106489459L;
// sleep time in milliseconds, before cache clear
int nap;
// sleep time in milliseconds, before cache clear
int nap;
ClientVector(int nap) {
this.nap = nap;
}
ClientVector(int nap) {
this.nap = nap;
}
/* return a still valid, idle HttpClient */
HttpClient get() {
lock();
try {
/* return a still valid, idle HttpClient */
HttpClient get() {
assert cacheLock.isHeldByCurrentThread();
// check the most recent connection, use if still valid
KeepAliveEntry e = peekFirst();
if (e == null) {
@ -339,49 +335,34 @@ class ClientVector extends ArrayDeque<KeepAliveEntry> {
}
return e.hc;
}
} finally {
unlock();
}
}
HttpClient put(HttpClient h) {
HttpClient staleClient = null;
lock();
try {
HttpClient put(HttpClient h) {
assert cacheLock.isHeldByCurrentThread();
HttpClient staleClient = null;
assert KeepAliveCache.getMaxConnections() > 0;
if (size() >= KeepAliveCache.getMaxConnections()) {
// remove oldest connection
staleClient = removeLast().hc;
}
addFirst(new KeepAliveEntry(h, System.currentTimeMillis()));
} finally {
unlock();
// close after releasing the locks
return staleClient;
}
// close after releasing the locks
return staleClient;
}
final void lock() {
lock.lock();
}
/*
* Do not serialize this class!
*/
@java.io.Serial
private void writeObject(ObjectOutputStream stream) throws IOException {
throw new NotSerializableException();
}
final void unlock() {
lock.unlock();
}
/*
* Do not serialize this class!
*/
@java.io.Serial
private void writeObject(ObjectOutputStream stream) throws IOException {
throw new NotSerializableException();
}
@java.io.Serial
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
throw new NotSerializableException();
@java.io.Serial
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
throw new NotSerializableException();
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1230,7 +1230,7 @@ public class KeepAliveTest {
System.out.println("ProxyHostUsingSystemProperty:" + System.getProperty("http.proxyHost"));
System.out.println("http.keepAlive.time.server=" + System.getProperty("http.keepAlive.time.server"));
System.out.println("http.keepAlive.time.proxy=" + System.getProperty("http.keepAlive.time.proxy"));
Class clientVectorClass = Class.forName("sun.net.www.http.ClientVector");
Class clientVectorClass = Class.forName("sun.net.www.http.KeepAliveCache$ClientVector");
// System.out.println("clientVectorClass=" + clientVectorClass);
Field napField = clientVectorClass.getDeclaredField("nap");
napField.setAccessible(true);