8265367: [macos-aarch64] 3 java/net/httpclient/websocket tests fail with "IOException: No buffer space available"

Reviewed-by: chegar
This commit is contained in:
Daniel Fuchs 2021-05-28 14:21:11 +00:00
parent 1413f9e070
commit 24bf35f862
14 changed files with 114 additions and 55 deletions

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, 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
@ -1290,6 +1290,14 @@ final class HttpClientImpl extends HttpClient implements Trackable {
);
}
// used for testing
int getSendBufferSize() {
return Utils.getIntegerNetProperty(
"jdk.httpclient.sendBufferSize",
0 // only set the size if > 0
);
}
// Optimization for reading SSL encrypted data
// --------------------------------------------

@ -210,7 +210,7 @@ class PlainHttpConnection extends HttpConnection {
* On some platforms, a ConnectEvent may be raised and a ConnectionException
* may occur with the message "Connection timed out: no further information"
* before our actual connection timeout has expired. In this case, this
* method will be called with a {@code connect} state of {@code ConnectState.RETRY)
* method will be called with a {@code connect} state of {@code ConnectState.RETRY)}
* and we will retry once again.
* @param connect indicates whether the connection was successful or should be retried
* @param failed the failure if the connection failed
@ -267,10 +267,23 @@ class PlainHttpConnection extends HttpConnection {
try {
this.chan = SocketChannel.open();
chan.configureBlocking(false);
trySetReceiveBufferSize(client.getReceiveBufferSize());
if (debug.on()) {
int bufsize = getInitialBufferSize();
int bufsize = getSoReceiveBufferSize();
debug.log("Initial receive buffer size is: %d", bufsize);
bufsize = getSoSendBufferSize();
debug.log("Initial send buffer size is: %d", bufsize);
}
if (trySetReceiveBufferSize(client.getReceiveBufferSize())) {
if (debug.on()) {
int bufsize = getSoReceiveBufferSize();
debug.log("Receive buffer size configured: %d", bufsize);
}
}
if (trySetSendBufferSize(client.getSendBufferSize())) {
if (debug.on()) {
int bufsize = getSoSendBufferSize();
debug.log("Send buffer size configured: %d", bufsize);
}
}
chan.setOption(StandardSocketOptions.TCP_NODELAY, true);
// wrap the channel in a Tube for async reading and writing
@ -280,26 +293,52 @@ class PlainHttpConnection extends HttpConnection {
}
}
private int getInitialBufferSize() {
private int getSoReceiveBufferSize() {
try {
return chan.getOption(StandardSocketOptions.SO_RCVBUF);
} catch(IOException x) {
} catch (IOException x) {
if (debug.on())
debug.log("Failed to get initial receive buffer size on %s", chan);
}
return 0;
}
private void trySetReceiveBufferSize(int bufsize) {
private int getSoSendBufferSize() {
try {
return chan.getOption(StandardSocketOptions.SO_SNDBUF);
} catch (IOException x) {
if (debug.on())
debug.log("Failed to get initial receive buffer size on %s", chan);
}
return 0;
}
private boolean trySetReceiveBufferSize(int bufsize) {
try {
if (bufsize > 0) {
chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize);
return true;
}
} catch(IOException x) {
} catch (IOException x) {
if (debug.on())
debug.log("Failed to set receive buffer size to %d on %s",
bufsize, chan);
}
return false;
}
private boolean trySetSendBufferSize(int bufsize) {
try {
if (bufsize > 0) {
chan.setOption(StandardSocketOptions.SO_SNDBUF, bufsize);
return true;
}
} catch (IOException x) {
if (debug.on())
debug.log("Failed to set send buffer size to %d on %s",
bufsize, chan);
}
return false;
}
@Override

@ -610,11 +610,6 @@ java/net/MulticastSocket/SetGetNetworkInterfaceTest.java 8219083 windows-
java/net/ServerSocket/AcceptInheritHandle.java 8211854 aix-ppc64
java/net/httpclient/websocket/PendingBinaryPongClose.java 8265367 macosx-aarch64
java/net/httpclient/websocket/PendingBinaryPingClose.java 8265367 macosx-aarch64
java/net/httpclient/websocket/PendingPongBinaryClose.java 8265367 macosx-aarch64
java/net/MulticastSocket/Promiscuous.java 8265369 macosx-aarch64
############################################################################

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -43,7 +43,6 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.newHttpClient;
import static org.testng.Assert.assertFalse;
public class BlowupOutputQueue extends PendingOperations {
@ -103,7 +102,7 @@ public class BlowupOutputQueue extends PendingOperations {
return null;
}
};
webSocket = newHttpClient().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), listener)
.join();
CharBuffer data = CharBuffer.allocate(65536);

@ -92,6 +92,7 @@ public class DummyWebSocketServer implements Closeable {
private volatile InetSocketAddress address;
private ByteBuffer read = ByteBuffer.allocate(16384);
private final CountDownLatch readReady = new CountDownLatch(1);
private volatile int receiveBufferSize;
private static class Credentials {
private final String name;
@ -217,6 +218,11 @@ public class DummyWebSocketServer implements Closeable {
return read.duplicate().asReadOnlyBuffer().flip();
}
public void setReceiveBufferSize(int bufsize) {
assert ssc == null : "Must configure before calling open()";
this.receiveBufferSize = bufsize;
}
public void open() throws IOException {
err.println("Starting");
if (!started.compareAndSet(false, true)) {
@ -225,6 +231,15 @@ public class DummyWebSocketServer implements Closeable {
ssc = ServerSocketChannel.open();
try {
ssc.configureBlocking(true);
var bufsize = receiveBufferSize;
if (bufsize > 0) {
err.printf("Configuring receive buffer size to %d%n", bufsize);
try {
ssc.setOption(StandardSocketOptions.SO_RCVBUF, bufsize);
} catch (IOException x) {
err.printf("Failed to configure receive buffer size to %d%n", bufsize);
}
}
ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
address = (InetSocketAddress) ssc.getLocalAddress();
thread.start();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -37,8 +37,6 @@ import java.nio.ByteBuffer;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;
public class PendingBinaryPingClose extends PendingOperations {
@ -51,7 +49,7 @@ public class PendingBinaryPingClose extends PendingOperations {
repeatable(() -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(65536);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -51,7 +51,7 @@ public class PendingBinaryPongClose extends PendingOperations {
repeatable(() -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(65536);

@ -21,16 +21,20 @@
* questions.
*/
import org.testng.annotations.AfterTest;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.DataProvider;
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.BooleanSupplier;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;
/* Common infrastructure for tests that check pending operations */
public class PendingOperations {
@ -45,8 +49,15 @@ public class PendingOperations {
DummyWebSocketServer server;
WebSocket webSocket;
@AfterTest
protected HttpClient httpClient() {
return newBuilder().proxy(NO_PROXY).build();
}
@AfterMethod
public void cleanup() {
// make sure we have a trace both on System.out and System.err
// to help with diagnosis.
System.out.println("cleanup: Closing server");
System.err.println("cleanup: Closing server");
server.close();
webSocket.abort();
@ -81,8 +92,8 @@ public class PendingOperations {
private static final int ITERATIONS = 3;
static void repeatable(Callable<Void> callable,
BooleanSupplier repeatCondition)
void repeatable(Callable<Void> callable,
BooleanSupplier repeatCondition)
throws Exception
{
int iterations = 0;
@ -101,10 +112,16 @@ public class PendingOperations {
if ((isMac || isWindows) && repeat) {
// ## This is loathsome, but necessary because of observed
// ## automagic socket buffer resizing on recent macOS platforms
try { cleanup(); } catch (Throwable x) {}
continue;
} else {
throw e;
}
} finally {
// gives some time to gc to cleanup any resource that might
// be eligible for garbage collection
System.gc();
Thread.sleep(100);
}
} while (iterations <= ITERATIONS);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -39,8 +39,6 @@ import java.nio.ByteBuffer;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;
public class PendingPingBinaryClose extends PendingOperations {
@ -53,7 +51,7 @@ public class PendingPingBinaryClose extends PendingOperations {
repeatable( () -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(125);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -39,8 +39,6 @@ import java.nio.ByteBuffer;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;
public class PendingPingTextClose extends PendingOperations {
@ -55,9 +53,8 @@ public class PendingPingTextClose extends PendingOperations {
repeatable(() -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() {
})
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(125);
boolean done = false;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -39,8 +39,6 @@ import java.nio.ByteBuffer;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;
public class PendingPongBinaryClose extends PendingOperations {
@ -53,7 +51,7 @@ public class PendingPongBinaryClose extends PendingOperations {
repeatable( () -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(125);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -40,10 +40,6 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;
import static java.net.http.HttpClient.newHttpClient;
public class PendingPongTextClose extends PendingOperations {
CompletableFuture<WebSocket> cfText;
@ -55,7 +51,7 @@ public class PendingPongTextClose extends PendingOperations {
repeatable( () -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
ByteBuffer data = ByteBuffer.allocate(125);
@ -80,7 +76,7 @@ public class PendingPongTextClose extends PendingOperations {
cfClose = webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
assertHangs(cfClose);
assertNotDone(cfPong);
return null;
return null;
}, () -> cfPong.isDone());
webSocket.abort();
assertFails(IOE, cfPong);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -27,6 +27,7 @@
* @run testng/othervm
* -Djdk.internal.httpclient.debug=true
* -Djdk.internal.httpclient.websocket.debug=true
* -Djdk.httpclient.sendBufferSize=8192
* PendingTextPingClose
*/
@ -38,8 +39,6 @@ import java.nio.CharBuffer;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;
public class PendingTextPingClose extends PendingOperations {
@ -51,8 +50,9 @@ public class PendingTextPingClose extends PendingOperations {
public void pendingTextPingClose(boolean last) throws Exception {
repeatable(() -> {
server = Support.notReadingServer();
server.setReceiveBufferSize(1024);
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
CharBuffer data = CharBuffer.allocate(65536);
@ -61,6 +61,7 @@ public class PendingTextPingClose extends PendingOperations {
System.out.printf("begin cycle #%s at %s%n", i, start);
cfText = webSocket.sendText(data, last);
try {
if (!cfText.isDone()) System.gc();
cfText.get(MAX_WAIT_SEC, TimeUnit.SECONDS);
data.clear();
} catch (TimeoutException e) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -38,8 +38,6 @@ import java.nio.CharBuffer;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.newBuilder;
public class PendingTextPongClose extends PendingOperations {
@ -52,7 +50,7 @@ public class PendingTextPongClose extends PendingOperations {
repeatable(() -> {
server = Support.notReadingServer();
server.open();
webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), new WebSocket.Listener() { })
.join();
CharBuffer data = CharBuffer.allocate(65536);