-
Notifications
You must be signed in to change notification settings - Fork 14k
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
Disable inlining of Scala library methods. #9548
Conversation
Previously, the Scala compiler was configured to inline all usages of symbols in under the `scala` package. This is problematic because it means that published Kafka jars must run with the exact same version of the Scala library that the Kafka jar was compiled with. If the runtime uses a different version of the Scala library then users risk getting a crash like this: ``` java.lang.NoClassDefFoundError: scala/math/Ordering$$anon$7 ``` This commit disables inlining from the `scala` package to prevent crashes like this. The downside to this change is it may introduce performance regressions.
@olafurpg Thanks for the PR. Can you please elaborate why there are conflicting versions of the Scala library when the core jar is used? The core jar doesn't export a public API and the assumption was that the same Scala library would be used at runtime. |
Even if users can't directly reference APIs of the core Kafka jar, the bytecode of the core jar is still evaluated at runtime. With the inliner enabled, the core Kafka jar directly references private anonymous classes from scala-library:2.12.11 that are no longer present in scala-library:2.12.12. For example, assuming you have
The scala-library:2.12.11 jar defines this anonymous class but it's missing from scala-library:2.12.12
The related upstream commit appears to be scala/scala@44318c8#diff-3b590b82493a8dbfc177f6113ee07ac4772d666d99fe808c6f6da01227ad1c6d. My understanding is that the inliner flags are only safe to enable for applications "at the end of the world", not libraries. |
To put it differently, enabling the inliner allows Kafka to access private symbols from |
I understand that, the point is that the core jar is not meant to be a library. It has no public APIs. The clients jar is meant to be a library. |
To elaborate a bit more, there are two cases where two cases where this can cause problems that I can think of:
Neither of those are recommended. I'm not opposed to changing these settings for now, but I'm also interested in understanding the specifics of why users are doing 1, 2 or something else that is deviating from our expectations. |
@ijuma , here is the callstack, and you can see why Kafka core is pulled in from the client side (due to using KafakEmbedded in testing):
|
Another related case (akka/alpakka-kafka#1212) is also from using |
I see, so it's for tests. Note that https://kafka.apache.org/26/javadoc/overview-summary.html Apache Kafka doesn't offer a test api though (I had started https://cwiki.apache.org/confluence/display/KAFKA/KIP-139%3A+Kafka+TestKit+library, but didn't complete it) so I understand why may go down that path. |
@ijuma Thank you for the clarification! I wasn't aware that |
@olafurpg I think you should keep this open. I think we may want to apply a change along the lines you submitted here given the example you gave. Even though it's relying on internal APIs, there isn't a good supported alternative. Sorry for the delay, I'll take a closer look in the next few days. |
Feel free to commandeer this PR if you still think it’s a good idea. I totally understand the reasoning to keep things unchanged so I’m not sure I’m the best person to push this through. I apologize the noise and thank you for all of your help! 🙏 |
Any update? Even KafkaEmbedded is internal but we actually used it in many places for our unitest. So we would love to find a good alternative solutions. (Our current workaround is ugly, as we have to rebuild Kafka core with different scala version). |
I think I'll have time to look into this later this week. |
As mentioned in apache#9548, users currently use the kafka jar (`core` module) for integration testing and the current inlining behavior causes problems when the user's classpath contains a different Scala version than the one that was used for compilation. An example error: `java.lang.NoClassDefFoundError: scala/math/Ordering$$anon$7` We disable inlining of the `scala` package by default, but make it easy to enable it for those who so desire (a good option if you can ensure the scala library version matches the one used for compilation). While at it, we make it possible to disable scala compiler optimizations (`none`) or to use only method local optimizations (`method`). This can be useful if optimizing for compilation time during development. Verified behavior by running gradlew with `--debug` and checking the output after `[zinc] The Scala compiler is invoked with:`
Out of curiosity, are you still using Apache Kafka 2.5.x or have you upgraded to something more recent since? |
…10174) As mentioned in #9548, users currently use the kafka jar (`core` module) for integration testing and the current inlining behavior causes problems when the user's classpath contains a different Scala version than the one that was used for compilation (e.g. 2.13.4 versus 2.13.3). An example error: `java.lang.NoClassDefFoundError: scala/math/Ordering$$anon$7` We now disable inlining of the `scala` package by default, but make it easy to enable it for those who so desire (a good option if you can ensure the scala library version matches the one used for compilation). While at it, we make it possible to disable scala compiler optimizations (`none`) or to use only method local optimizations (`method`). This can be useful if optimizing for compilation time during development. Verified behavior by running gradlew with `--debug` and checking the output after `[zinc] The Scala compiler is invoked with:` Reviewers: Chia-Ping Tsai <[email protected]>
…10174) As mentioned in #9548, users currently use the kafka jar (`core` module) for integration testing and the current inlining behavior causes problems when the user's classpath contains a different Scala version than the one that was used for compilation (e.g. 2.13.4 versus 2.13.3). An example error: `java.lang.NoClassDefFoundError: scala/math/Ordering$$anon$7` We now disable inlining of the `scala` package by default, but make it easy to enable it for those who so desire (a good option if you can ensure the scala library version matches the one used for compilation). While at it, we make it possible to disable scala compiler optimizations (`none`) or to use only method local optimizations (`method`). This can be useful if optimizing for compilation time during development. Verified behavior by running gradlew with `--debug` and checking the output after `[zinc] The Scala compiler is invoked with:` Reviewers: Chia-Ping Tsai <[email protected]>
Previously, the Scala compiler was configured to inline all usages of
symbols in under the
scala
package. This is problematic because itmeans that published Kafka jars must run with the exact same version of
the Scala library that the Kafka jar was compiled with. If the runtime
uses a different version of the Scala library then users risk getting a
crash like this:
This commit disables inlining from the
scala
package to preventcrashes like this. The downside to this change is it may introduce
performance regressions.
Committer Checklist (excluded from commit message)