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

View file

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

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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("ProxyHostUsingSystemProperty:" + System.getProperty("http.proxyHost"));
System.out.println("http.keepAlive.time.server=" + System.getProperty("http.keepAlive.time.server")); 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")); 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); // System.out.println("clientVectorClass=" + clientVectorClass);
Field napField = clientVectorClass.getDeclaredField("nap"); Field napField = clientVectorClass.getDeclaredField("nap");
napField.setAccessible(true); napField.setAccessible(true);