From 28d0c975bc0c0dbc2485201c04736c82b512f011 Mon Sep 17 00:00:00 2001 From: Hua Jiang Date: Tue, 15 Jul 2025 13:15:01 +0800 Subject: [PATCH 1/2] Do release in the channel's event loop if it's safe --- .../nio/netty/internal/http2/HttpOrHttp2ChannelPool.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/HttpOrHttp2ChannelPool.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/HttpOrHttp2ChannelPool.java index 5815cab683c6..a9e53d92468b 100644 --- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/HttpOrHttp2ChannelPool.java +++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/HttpOrHttp2ChannelPool.java @@ -194,9 +194,12 @@ public Future release(Channel channel) { @Override public Future release(Channel channel, Promise promise) { - doInEventLoop(eventLoop, - () -> release0(channel, promise), - promise); + // If protocolImpl != null, it’s already visible, so we call protocolImpl.release + // directly in the channel event loop. Otherwise — whether unassigned or not yet + // visible — we fall back to the safe path. Since protocolImpl is assigned only + // once, there's no risk of calling it on an incorrect instance. + if (protocolImpl != null) protocolImpl.release(channel, promise); + else doInEventLoop(eventLoop, () -> release0(channel, promise), promise); return promise; } From 8d563a9e4b865dcb069277925c4f8dd368f440e8 Mon Sep 17 00:00:00 2001 From: Hua Jiang Date: Wed, 16 Jul 2025 20:55:33 +0800 Subject: [PATCH 2/2] make protocolImpl volatile to avoid dirty read --- .../http/nio/netty/internal/http2/HttpOrHttp2ChannelPool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/HttpOrHttp2ChannelPool.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/HttpOrHttp2ChannelPool.java index a9e53d92468b..c84df0c8b2da 100644 --- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/HttpOrHttp2ChannelPool.java +++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/HttpOrHttp2ChannelPool.java @@ -51,7 +51,7 @@ public class HttpOrHttp2ChannelPool implements SdkChannelPool { private boolean protocolImplPromiseInitializationStarted = false; private Promise protocolImplPromise; - private BetterFixedChannelPool protocolImpl; + private volatile BetterFixedChannelPool protocolImpl; private boolean closed; public HttpOrHttp2ChannelPool(ChannelPool delegatePool,