Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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
Expand Down Expand Up @@ -1290,6 +1290,14 @@ int getReceiveBufferSize() {
);
}

// used for testing
int getSendBufferSize() {
return Utils.getIntegerNetProperty(
"jdk.httpclient.sendBufferSize",
0 // only set the size if > 0
);
}

// Optimization for reading SSL encrypted data
// --------------------------------------------

Expand Down
Expand Up @@ -210,7 +210,7 @@ public CompletableFuture<Void> connectAsync(Exchange<?> exchange) {
* 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
Expand Down Expand Up @@ -267,10 +267,23 @@ final FlowTube getConnectionFlow() {
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
Expand All @@ -280,26 +293,52 @@ final FlowTube getConnectionFlow() {
}
}

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 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 void trySetReceiveBufferSize(int bufsize) {
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
Expand Down
5 changes: 0 additions & 5 deletions test/jdk/ProblemList.txt
Expand Up @@ -608,11 +608,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

############################################################################
Expand Down
5 changes: 2 additions & 3 deletions test/jdk/java/net/httpclient/websocket/BlowupOutputQueue.java
@@ -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
Expand Down Expand Up @@ -43,7 +43,6 @@
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 {
Expand Down Expand Up @@ -103,7 +102,7 @@ protected CompletionStage<?> onPing0(WebSocket webSocket,
return null;
}
};
webSocket = newHttpClient().newWebSocketBuilder()
webSocket = httpClient().newWebSocketBuilder()
.buildAsync(server.getURI(), listener)
.join();
CharBuffer data = CharBuffer.allocate(65536);
Expand Down
15 changes: 15 additions & 0 deletions test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java
Expand Up @@ -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;
Expand Down Expand Up @@ -217,6 +218,11 @@ public ByteBuffer read() throws InterruptedException {
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)) {
Expand All @@ -225,6 +231,15 @@ public void open() throws IOException {
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();
Expand Down
@@ -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
Expand Down Expand Up @@ -37,8 +37,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;

public class PendingBinaryPingClose extends PendingOperations {

Expand All @@ -51,7 +49,7 @@ public void pendingBinaryPingClose(boolean last) throws Exception {
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);
Expand Down
@@ -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
Expand Down Expand Up @@ -51,7 +51,7 @@ public void pendingBinaryPongClose(boolean last) throws Exception {
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);
Expand Down
25 changes: 21 additions & 4 deletions test/jdk/java/net/httpclient/websocket/PendingOperations.java
Expand Up @@ -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 {

Expand All @@ -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();
Expand Down Expand Up @@ -81,8 +92,8 @@ static boolean isWindows() {

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;
Expand All @@ -101,10 +112,16 @@ static void repeatable(Callable<Void> callable,
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);
}
Expand Down
@@ -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
Expand Down Expand Up @@ -39,8 +39,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;

public class PendingPingBinaryClose extends PendingOperations {

Expand All @@ -53,7 +51,7 @@ public void pendingPingBinaryClose(boolean last) throws Exception {
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);
Expand Down
@@ -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
Expand Down Expand Up @@ -39,8 +39,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;

public class PendingPingTextClose extends PendingOperations {

Expand All @@ -55,9 +53,8 @@ public void pendingPingTextClose(boolean last) throws Exception {
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;
Expand Down
@@ -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
Expand Down Expand Up @@ -39,8 +39,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;

public class PendingPongBinaryClose extends PendingOperations {

Expand All @@ -53,7 +51,7 @@ public void pendingPongBinaryClose(boolean last) throws Exception {
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);
Expand Down