From 5c55a59de4a6cd9cb8075848874e1423cfb4474d Mon Sep 17 00:00:00 2001
From: Francesco Nigro <nigro.fra@gmail.com>
Date: Tue, 19 Dec 2023 14:20:22 +0100
Subject: [PATCH] Redo fix scalability issue due to checkcast on context's
 invoke operations

Motivation:

ChannelDuplexHandler can implements both ChannelOutboundHandler and ChannelInboundHandler causing a scalability issue due to checkcast due to https://bugs.openjdk.org/browse/JDK-8180450
Not only: there are different classes eg Http2ConnectionHandler, which implement them transitively, by using one of the 2 existing adapters (ChannelInboundAdapter, ChanneOutboundAdapters).
The existing change at https://github.com/netty/netty/pull/12806 was fixing only the duplex cases, but others like the above one was still affected.

Modifications:

Replace the duplex type checks with broader inbound adapter ones, given that duplex is still based on it.
Add outbound adapters type checks in addition to duplex ones.

Result:

More scalable adapters-based channel handler operations.
---
 .../AbstractChannelHandlerContext.java        | 40 +++++++++++++------
 1 file changed, 28 insertions(+), 12 deletions(-)

diff --git a/transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java b/transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java
index 0128e776b071..d3953f47626e 100644
--- a/transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java
+++ b/transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java
@@ -170,8 +170,8 @@ private void invokeChannelRegistered() {
                 final DefaultChannelPipeline.HeadContext headContext = pipeline.head;
                 if (handler == headContext) {
                     headContext.channelRegistered(this);
-                } else if (handler instanceof ChannelDuplexHandler) {
-                    ((ChannelDuplexHandler) handler).channelRegistered(this);
+                } else if (handler instanceof ChannelInboundHandlerAdapter) {
+                    ((ChannelInboundHandlerAdapter) handler).channelRegistered(this);
                 } else {
                     ((ChannelInboundHandler) handler).channelRegistered(this);
                 }
@@ -213,8 +213,8 @@ private void invokeChannelUnregistered() {
                 final DefaultChannelPipeline.HeadContext headContext = pipeline.head;
                 if (handler == headContext) {
                     headContext.channelUnregistered(this);
-                } else if (handler instanceof ChannelDuplexHandler) {
-                    ((ChannelDuplexHandler) handler).channelUnregistered(this);
+                } else if (handler instanceof ChannelInboundHandlerAdapter) {
+                    ((ChannelInboundHandlerAdapter) handler).channelUnregistered(this);
                 } else {
                     ((ChannelInboundHandler) handler).channelUnregistered(this);
                 }
@@ -256,8 +256,8 @@ private void invokeChannelActive() {
                 final DefaultChannelPipeline.HeadContext headContext = pipeline.head;
                 if (handler == headContext) {
                     headContext.channelActive(this);
-                } else if (handler instanceof ChannelDuplexHandler) {
-                    ((ChannelDuplexHandler) handler).channelActive(this);
+                } else if (handler instanceof ChannelInboundHandlerAdapter) {
+                    ((ChannelInboundHandlerAdapter) handler).channelActive(this);
                 } else {
                     ((ChannelInboundHandler) handler).channelActive(this);
                 }
@@ -299,8 +299,8 @@ private void invokeChannelInactive() {
                 final DefaultChannelPipeline.HeadContext headContext = pipeline.head;
                 if (handler == headContext) {
                     headContext.channelInactive(this);
-                } else if (handler instanceof ChannelDuplexHandler) {
-                    ((ChannelDuplexHandler) handler).channelInactive(this);
+                } else if (handler instanceof ChannelInboundHandlerAdapter) {
+                    ((ChannelInboundHandlerAdapter) handler).channelInactive(this);
                 } else {
                     ((ChannelInboundHandler) handler).channelInactive(this);
                 }
@@ -394,8 +394,8 @@ private void invokeUserEventTriggered(Object event) {
                 final DefaultChannelPipeline.HeadContext headContext = pipeline.head;
                 if (handler == headContext) {
                     headContext.userEventTriggered(this, event);
-                } else if (handler instanceof ChannelDuplexHandler) {
-                    ((ChannelDuplexHandler) handler).userEventTriggered(this, event);
+                } else if (handler instanceof ChannelInboundHandlerAdapter) {
+                    ((ChannelInboundHandlerAdapter) handler).userEventTriggered(this, event);
                 } else {
                     ((ChannelInboundHandler) handler).userEventTriggered(this, event);
                 }
@@ -522,8 +522,8 @@ private void invokeChannelWritabilityChanged() {
                 final DefaultChannelPipeline.HeadContext headContext = pipeline.head;
                 if (handler == headContext) {
                     headContext.channelWritabilityChanged(this);
-                } else if (handler instanceof ChannelDuplexHandler) {
-                    ((ChannelDuplexHandler) handler).channelWritabilityChanged(this);
+                } else if (handler instanceof ChannelInboundHandlerAdapter) {
+                    ((ChannelInboundHandlerAdapter) handler).channelWritabilityChanged(this);
                 } else {
                     ((ChannelInboundHandler) handler).channelWritabilityChanged(this);
                 }
@@ -600,6 +600,8 @@ private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
                     headContext.bind(this, localAddress, promise);
                 } else if (handler instanceof ChannelDuplexHandler) {
                     ((ChannelDuplexHandler) handler).bind(this, localAddress, promise);
+                } else if (handler instanceof ChannelOutboundHandlerAdapter) {
+                    ((ChannelOutboundHandlerAdapter) handler).bind(this, localAddress, promise);
                 } else {
                     ((ChannelOutboundHandler) handler).bind(this, localAddress, promise);
                 }
@@ -653,6 +655,8 @@ private void invokeConnect(SocketAddress remoteAddress, SocketAddress localAddre
                     headContext.connect(this, remoteAddress, localAddress, promise);
                 } else if (handler instanceof ChannelDuplexHandler) {
                     ((ChannelDuplexHandler) handler).connect(this, remoteAddress, localAddress, promise);
+                } else if (handler instanceof ChannelOutboundHandlerAdapter) {
+                    ((ChannelOutboundHandlerAdapter) handler).connect(this, remoteAddress, localAddress, promise);
                 } else {
                     ((ChannelOutboundHandler) handler).connect(this, remoteAddress, localAddress, promise);
                 }
@@ -703,6 +707,8 @@ private void invokeDisconnect(ChannelPromise promise) {
                     headContext.disconnect(this, promise);
                 } else if (handler instanceof ChannelDuplexHandler) {
                     ((ChannelDuplexHandler) handler).disconnect(this, promise);
+                } else if (handler instanceof ChannelOutboundHandlerAdapter) {
+                    ((ChannelOutboundHandlerAdapter) handler).disconnect(this, promise);
                 } else {
                     ((ChannelOutboundHandler) handler).disconnect(this, promise);
                 }
@@ -749,6 +755,8 @@ private void invokeClose(ChannelPromise promise) {
                     headContext.close(this, promise);
                 } else if (handler instanceof ChannelDuplexHandler) {
                     ((ChannelDuplexHandler) handler).close(this, promise);
+                } else if (handler instanceof ChannelOutboundHandlerAdapter) {
+                    ((ChannelOutboundHandlerAdapter) handler).close(this, promise);
                 } else {
                     ((ChannelOutboundHandler) handler).close(this, promise);
                 }
@@ -795,6 +803,8 @@ private void invokeDeregister(ChannelPromise promise) {
                     headContext.deregister(this, promise);
                 } else if (handler instanceof ChannelDuplexHandler) {
                     ((ChannelDuplexHandler) handler).deregister(this, promise);
+                } else if (handler instanceof ChannelOutboundHandlerAdapter) {
+                    ((ChannelOutboundHandlerAdapter) handler).deregister(this, promise);
                 } else {
                     ((ChannelOutboundHandler) handler).deregister(this, promise);
                 }
@@ -835,6 +845,8 @@ private void invokeRead() {
                     headContext.read(this);
                 } else if (handler instanceof ChannelDuplexHandler) {
                     ((ChannelDuplexHandler) handler).read(this);
+                } else if (handler instanceof ChannelOutboundHandlerAdapter) {
+                    ((ChannelOutboundHandlerAdapter) handler).read(this);
                 } else {
                     ((ChannelOutboundHandler) handler).read(this);
                 }
@@ -877,6 +889,8 @@ private void invokeWrite0(Object msg, ChannelPromise promise) {
                 headContext.write(this, msg, promise);
             } else if (handler instanceof ChannelDuplexHandler) {
                 ((ChannelDuplexHandler) handler).write(this, msg, promise);
+            } else if (handler instanceof ChannelOutboundHandlerAdapter) {
+                ((ChannelOutboundHandlerAdapter) handler).write(this, msg, promise);
             } else {
                 ((ChannelOutboundHandler) handler).write(this, msg, promise);
             }
@@ -921,6 +935,8 @@ private void invokeFlush0() {
                 headContext.flush(this);
             } else if (handler instanceof ChannelDuplexHandler) {
                 ((ChannelDuplexHandler) handler).flush(this);
+            } else if (handler instanceof ChannelOutboundHandlerAdapter) {
+                ((ChannelOutboundHandlerAdapter) handler).flush(this);
             } else {
                 ((ChannelOutboundHandler) handler).flush(this);
             }
