-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
Binary backwards-incompatibily in 1.33.0 #7552
Comments
@njhill what errors do you get when you try to use the existing libraries with 1.33.0? AFAICS no members of any super class/interface are lost and no user code should be referencing |
@sanjaypujare see the example above, it is only referencing The error I get is:
|
Okay, I was able to reproduce it. The code generated with the previous grpc version (1.32.1 in my case) for the
which references
This was moved to @sergiitk @ejona86 looks like this issue needs to be resolved? |
The goal of the change was to remove the
While it is the primary transport, the primary way to use the transport is via ManagedChannelBuilder, not NettyChannelBuilder directly. That said, yes, there's a lot of users of this API. A strategy to allow a graceful migration would be to have FowardingChannelBuilder extend AbstractManagedChannelImplBuilder. AbstractManagedChannelImplBuilder itself could just have every method throw or call super. It should only implement methods it previously implemented. That would cause recompilations to use the FowardingChannelBuilder return type instead of AbstractManagedChannelImplBuilder with compatibility methods generated by javac for the older ABI. After 6 months or a year we would remove AbstractManagedChannelImplBuilder. The question that remains for me is whether we should expose FowardingChannelBuilder as a parent class of NettyChannelBuilder. We could just re-define all the methods. That does make maintenance harder as we are more likely to forget to add support for new methods. But it would avoid this sort of problem in the future and it would avoid needing to expose the internal class to FowardingChannelBuilder's hierarchy. |
@ejona86 right, that's what I was alluding to above. I think it should not even be necessary for such a placeholder |
I don't think so, since I think Javac only duplicates methods based on what it knows is shadowed. My testing confirms that behavior; we need to re-define the methods. |
@sergiitk, it seems 25 methods from ForwardingChannelBuilder aren't shadowed by NettyChannelBuilder. That's a lot. That means we'll want to continue using ForwardingChannelBuilder. It looks like we can change the generics of ForwardingChannelBuilder from Unfortunately, we can't change to the weaker generics in ForwardingChannelBuilder and have it extend AbstractManagedChannelImplBuilder. That makes it unclear how to proceed. |
On top of that, other Server and Channel Builders are affected, see v.1.33.0 release notes:
EDIT: all -> other |
For the short-term, we're going to copy ForwardingChannelBuilder (and server) to the old AbstractManagedChannelImplBuider name to restore the previous API. We'll release a 1.33.1. That will then give us time to figure out what we want to do. I am expecting we'll need to break at least one ABI, and make use of the ExperimentalAPI allowance to do so, but we need to figure out which and how we want users to react. |
Thanks @ejona86
Are you sure? This appears to work for me: public abstract class AbstractManagedChannelImplBuilder<T extends ManagedChannelBuilder<T>>
extends ManagedChannelBuilder<T> {}
public abstract class ForwardingChannelBuilder<T extends AbstractManagedChannelImplBuilder<T>>
extends AbstractManagedChannelImplBuilder<T> {
// ... contents of class unchanged
} Note generic param of |
@njhill, in your example I was suggesting having |
@ejona86 I see what you mean, that makes sense. and might you consider changing |
Yes, it could. But that is of dubious value. New invocations of javac will still use the AbstractManagedChannelImplBuilder-returning methods.
No. It isn't a new class. It's actually pretty old. We can do that with ForwardingServerBuilder, but it is probably better to just remove/hide the class in the short-term. |
This reduces ABI issues caused by returning the more precise XdsServerBuilder in the API. See grpc#7552. ForwardingServerBuilder isn't yet public, so just copy it; it'll be easy to clean up.
This reduces ABI issues caused by returning the more precise XdsServerBuilder in the API. See grpc#7552. ForwardingServerBuilder isn't yet public, so just copy it; it'll be easy to clean up. Since ForwardingServerBuilder is package-private, the JavaDoc isn't particularly pretty. But I think that's the best we can do at the moment.
This reduces ABI issues caused by returning the more precise XdsServerBuilder in the API. See grpc#7552.
This reduces ABI issues caused by returning the more precise XdsServerBuilder in the API. See #7552.
Dunno if it is a good idea, but .class rewriting may be a good enough hack to ease migration. Even if it works, I think we'd remove it after a few releases; we don't want this long-term. Option 1. Change the generics to the ideal and generate methods with the old method signature. It is possible to do that via .class constant rewriting, but I also found a tool that makes it easier. c8140e6 Option 2. Let javac generate both method signatures like today, but rewrite the generics in the class file, When javac compiles other code, it sees the rewritten generics. e51c509 Seems to work for Java. Dunno if it breaks things like Kotlin, but I mostly expect not. |
This reduces ABI issues caused by returning the more precise XdsServerBuilder in the API. See grpc#7552.
For posterity, here's some details on reproducing, fixing, and understanding this issue: https://gist.github.com/sergiitk/39583f20906df1813f5e170317a35dc4 |
This provides us a path forward with grpc#7211 (hiding AbstractManagedChannelImplBuilder and AbstractServerImplBuilder) while providing users a migration path to manage the ABI breakage (grpc#7552). We do a .class hack so that recompiling avoids the internal class reference yet the old methods are still available. Leaving the classes as-is causes javac to compile two versions of each method, one returning the public class (e.g. ServerBuilder) and one returning the internal class (e.g., AbstractServerImplBuilder). However, we rewrite the signature that is used at compile time so that new compilations will not reference internal-returning methods. This is intended to be temporary, just to give a migration path. Once we have given users some time to recompile we will remove this rewriting and change the generics to use public classes.
This provides us a path forward with #7211 (hiding AbstractManagedChannelImplBuilder and AbstractServerImplBuilder) while providing users a migration path to manage the ABI breakage (#7552). We do a .class hack so that recompiling avoids the internal class reference yet the old methods are still available. Leaving the classes as-is causes javac to compile two versions of each method, one returning the public class (e.g. ServerBuilder) and one returning the internal class (e.g., AbstractServerImplBuilder). However, we rewrite the signature that is used at compile time so that new compilations will not reference internal-returning methods. This is intended to be temporary, just to give a migration path. Once we have given users some time to recompile we will remove this rewriting and change the generics to use public classes.
My library contains code like:
which breaks when moving from pre-1.33.0 to 1.33.0, unless recompiled (and then the new binary would not be compatible with versions < 1.33.0). This is because a class (
AbstractManagedChannelImplBuilder
) was removed from the direct superclass heriarchy:I know that technically netty transport is still considered experimental (per #1784), but (a) it's the primary transport and (b) it's been that way for more than 4 years.
Was this intentional/known or is it a case of "it's experimental, tough!"?
It should be easy to avoid I think by for example just adding an empty
abstract class AbstractManagedChannelImplBuilder extends ForwardingChannelBuilder
... maybe in a 1.33.1? :)The text was updated successfully, but these errors were encountered: