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
Synchronize variable reification against real class. #5919
Conversation
This is likely at least a partial fix for jruby#5910, where it appears that multiple threads all trigger reificatin of a class's variables at the same time, leading to some of those threads choosing a different reified type and ultimately class casting exceptions. The change here synchronizes against the class's "real" class, which should be the one on which we attach the allocated. This should force multiple threads all allocating the first instance at once to wait for each other, eventually falling back on the new allocator that does not re-reify the type. This will eventually be moot once individual object instances hold a reference to their own layout managers.
cb4812e
to
1385578
Compare
looks reasonable (given no further details #5910 - still weird that there's only one pathological case). would it make sense to reduce the lock duration to the bare minimum of (double-checking) and setting the generated class-and-allocator?, moving 'only' these parts under the critical section: https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/specialized/RubyObjectSpecializer.java#L152-L153 |
I am pretty interested in seeing how much lock contention this ends up bringing into the mix. Allocating the same type at the same time across Rails threads seems like it will be common. If we can notice the impact then perhaps as kares says we can shorten the lock somehow? Or perhaps it is just the price we have to pay?
Secondly, I would like to make sure this fixes the original reporters problem before putting out 9.2.9 assuming they can test it without too much trouble.
I have been pondering impact of this and I believe the ordinary classes will not be much of an impact because there are just not that many types in a typical application. A few thousand locks when most happen early in an app does not seem like a big deal. Singleton types perhaps in some DCI pattern? Two threads singletonizing the same object at the same time already hurts my head. We must already synch on that? Trying to think of patterns where a framework would endlessly make new types. Seems like the main worry to more locking here. |
The only thing that could move out would be the walking of all classes and methods in the type's hierarchy. Seems like that should be ok; the structures involved are all safe. |
* Synchronize only around the reification and assignment of the new allocator, to limit contention. * Move all code-walking logic into IRMethod. * Improve code-walking logic to walk AST if present rather than forcing code to compile.
It turns out that the related Ruby code in #5910 was actually buggy to begin with; it allowed uninitialized classes to be constructed, which led to us seeing multiple views of instance variables in defined methods. I've detailed that here: #5910 (comment) We can't fix that, but it did expose some weaknesses in our variable reification that I have fixed in the most recent commit:
|
This is likely at least a partial fix for #5910, where it appears
that multiple threads all trigger reificatin of a class's
variables at the same time, leading to some of those threads
choosing a different reified type and ultimately class casting
exceptions.
The change here synchronizes against the class's "real" class,
which should be the one on which we attach the allocated. This
should force multiple threads all allocating the first instance
at once to wait for each other, eventually falling back on the
new allocator that does not re-reify the type.
This will eventually be moot once individual object instances hold
a reference to their own layout managers.