-
Notifications
You must be signed in to change notification settings - Fork 28.5k
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
[SPARK-17714][Core][test-maven][test-hadoop2.6]Avoid using ExecutorClassLoader to load Netty generated classes #16859
Conversation
@@ -2599,14 +2599,10 @@ private[spark] object Utils extends Logging { | |||
|
|||
private[util] object CallerContext extends Logging { | |||
val callerContextSupported: Boolean = { | |||
SparkHadoopUtil.get.conf.getBoolean("hadoop.caller.context.enabled", false) && { | |||
SparkHadoopUtil.get.conf.getBoolean("hadoop.caller.context.enabled", true) && { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will change default value to false
later. Just to test if this PR fixes the issue on Jenkins.
@@ -48,7 +47,7 @@ | |||
* on the channel for at least `requestTimeoutMs`. Note that this is duplex traffic; we will not | |||
* timeout if the client is continuously sending but getting no responses, for simplicity. | |||
*/ | |||
public class TransportChannelHandler extends SimpleChannelInboundHandler<Message> { | |||
public class TransportChannelHandler extends ChannelInboundHandlerAdapter { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SimpleChannelInboundHandler also uses Javassist to generate a matcher class. Since SimpleChannelInboundHandler
provides little value for us, I just changed to extend ChannelInboundHandlerAdapter
directly.
Test build #72598 has finished for PR 16859 at commit
|
retest this please |
Test build #72599 has finished for PR 16859 at commit
|
cc @vanzin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks ok; you have a typo in the description (calls -> class).
public static final MessageDecoder INSTANCE = new MessageDecoder(); | ||
|
||
private MessageDecoder() { | ||
super(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: not really necessary (also in the other class)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
btw I think you want |
Test build #3570 has finished for PR 16859 at commit
|
Retest this please |
Test build #72655 has finished for PR 16859 at commit
|
I'm going to change the default value back since ReplSuite passed in |
Test build #72660 has finished for PR 16859 at commit
|
Test build #72665 has finished for PR 16859 at commit
|
Thanks! Merging to master and 2.1. |
…lassLoader to load Netty generated classes ## What changes were proposed in this pull request? Netty's `MessageToMessageEncoder` uses [Javassist](https://github.com/netty/netty/blob/91a0bdc17a8298437d6de08a8958d753799bd4a6/common/src/main/java/io/netty/util/internal/JavassistTypeParameterMatcherGenerator.java#L62) to generate a matcher class and the implementation calls `Class.forName` to check if this class is already generated. If `MessageEncoder` or `MessageDecoder` is created in `ExecutorClassLoader.findClass`, it will cause `ClassCircularityError`. This is because loading this Netty generated class will call `ExecutorClassLoader.findClass` to search this class, and `ExecutorClassLoader` will try to use RPC to load it and cause to load the non-exist matcher class again. JVM will report `ClassCircularityError` to prevent such infinite recursion. ##### Why it only happens in Maven builds It's because Maven and SBT have different class loader tree. The Maven build will set a URLClassLoader as the current context class loader to run the tests and expose this issue. The class loader tree is as following: ``` bootstrap class loader ------ ... ----- REPL class loader ---- ExecutorClassLoader | | URLClasssLoader ``` The SBT build uses the bootstrap class loader directly and `ReplSuite.test("propagation of local properties")` is the first test in ReplSuite, which happens to load `io/netty/util/internal/__matchers__/org/apache/spark/network/protocol/MessageMatcher` into the bootstrap class loader (Note: in maven build, it's loaded into URLClasssLoader so it cannot be found in ExecutorClassLoader). This issue can be reproduced in SBT as well. Here are the produce steps: - Enable `hadoop.caller.context.enabled`. - Replace `Class.forName` with `Utils.classForName` in `object CallerContext`. - Ignore `ReplSuite.test("propagation of local properties")`. - Run `ReplSuite` using SBT. This PR just creates a singleton MessageEncoder and MessageDecoder and makes sure they are created before switching to ExecutorClassLoader. TransportContext will be created when creating RpcEnv and that happens before creating ExecutorClassLoader. ## How was this patch tested? Jenkins Author: Shixiong Zhu <shixiong@databricks.com> Closes #16859 from zsxwing/SPARK-17714. (cherry picked from commit 905fdf0) Signed-off-by: Shixiong Zhu <shixiong@databricks.com>
@vanzin I just merged this one. If you have other comments, I will address them in a separate PR. Thanks! |
Nope, don't have anything else. |
…lassLoader to load Netty generated classes ## What changes were proposed in this pull request? Netty's `MessageToMessageEncoder` uses [Javassist](https://github.com/netty/netty/blob/91a0bdc17a8298437d6de08a8958d753799bd4a6/common/src/main/java/io/netty/util/internal/JavassistTypeParameterMatcherGenerator.java#L62) to generate a matcher class and the implementation calls `Class.forName` to check if this class is already generated. If `MessageEncoder` or `MessageDecoder` is created in `ExecutorClassLoader.findClass`, it will cause `ClassCircularityError`. This is because loading this Netty generated class will call `ExecutorClassLoader.findClass` to search this class, and `ExecutorClassLoader` will try to use RPC to load it and cause to load the non-exist matcher class again. JVM will report `ClassCircularityError` to prevent such infinite recursion. ##### Why it only happens in Maven builds It's because Maven and SBT have different class loader tree. The Maven build will set a URLClassLoader as the current context class loader to run the tests and expose this issue. The class loader tree is as following: ``` bootstrap class loader ------ ... ----- REPL class loader ---- ExecutorClassLoader | | URLClasssLoader ``` The SBT build uses the bootstrap class loader directly and `ReplSuite.test("propagation of local properties")` is the first test in ReplSuite, which happens to load `io/netty/util/internal/__matchers__/org/apache/spark/network/protocol/MessageMatcher` into the bootstrap class loader (Note: in maven build, it's loaded into URLClasssLoader so it cannot be found in ExecutorClassLoader). This issue can be reproduced in SBT as well. Here are the produce steps: - Enable `hadoop.caller.context.enabled`. - Replace `Class.forName` with `Utils.classForName` in `object CallerContext`. - Ignore `ReplSuite.test("propagation of local properties")`. - Run `ReplSuite` using SBT. This PR just creates a singleton MessageEncoder and MessageDecoder and makes sure they are created before switching to ExecutorClassLoader. TransportContext will be created when creating RpcEnv and that happens before creating ExecutorClassLoader. ## How was this patch tested? Jenkins Author: Shixiong Zhu <shixiong@databricks.com> Closes apache#16859 from zsxwing/SPARK-17714.
What changes were proposed in this pull request?
Netty's
MessageToMessageEncoder
uses Javassist to generate a matcher class and the implementation callsClass.forName
to check if this class is already generated. IfMessageEncoder
orMessageDecoder
is created inExecutorClassLoader.findClass
, it will causeClassCircularityError
. This is because loading this Netty generated class will callExecutorClassLoader.findClass
to search this class, andExecutorClassLoader
will try to use RPC to load it and cause to load the non-exist matcher class again. JVM will reportClassCircularityError
to prevent such infinite recursion.Why it only happens in Maven builds
It's because Maven and SBT have different class loader tree. The Maven build will set a URLClassLoader as the current context class loader to run the tests and expose this issue. The class loader tree is as following:
The SBT build uses the bootstrap class loader directly and
ReplSuite.test("propagation of local properties")
is the first test in ReplSuite, which happens to loadio/netty/util/internal/__matchers__/org/apache/spark/network/protocol/MessageMatcher
into the bootstrap class loader (Note: in maven build, it's loaded into URLClasssLoader so it cannot be found in ExecutorClassLoader). This issue can be reproduced in SBT as well. Here are the produce steps:hadoop.caller.context.enabled
.Class.forName
withUtils.classForName
inobject CallerContext
.ReplSuite.test("propagation of local properties")
.ReplSuite
using SBT.This PR just creates a singleton MessageEncoder and MessageDecoder and makes sure they are created before switching to ExecutorClassLoader. TransportContext will be created when creating RpcEnv and that happens before creating ExecutorClassLoader.
How was this patch tested?
Jenkins