-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Request scope performance improvements #12752
Request scope performance improvements #12752
Conversation
Previously this required 3 ThreadLocal operations: - isActive() - create(Contextual) - create(Contextual, CreationalContext) This PR provides a single operation so that these can be accomplished with only a single ThreadLocal op
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 really like the optimization of ArcContainerImpl#getActiveContext()
- this will definitely save one ArrayList allocation in 90% scenarios. So +100!
I'm not so sure about the other changes.
Previously we did:
- Find the context (one
context.isActive()
volatilethread-local read) - Try
RequestContext.get(Contextual<T>)
first (onecurrentContext.get()
volatilethread-local read) -> final operation once the bean was already created - Call
RequestContext.get(Contextual<T>,CreationalContext)
(onecurrentContext.get()
volatilethread-local read) -> only used the first time the bean was accessed
In this PR we do:
- Call
ArcContainerImpl.normalScopedInstance()
(one context.isActive()volatilethread-local read) - Call
RequestContext.getOrCreate(Contextual<T>)
(one currentContext.get()volatilethread-local read)
So with this new approach you will only save one volatilethread-local read plus few method invocations during the first invocation upon a @RequestScoped
bean and the changes include a lot of duplicit code which is harder to maintain and understand.
Also is there a perf bottleneck use case we're trying to solve? Or is it purely a hunt for better results in a perf benchmark?
CC @manovotn |
They are ThreadLocal reads that are the main issue rather than volatile ones. There is no isActive in ArcContainerImpl.normalScopedInstance() call in normal circumstances, this will only happen if you have two contexts backing the same scope. Basically once the bean has been created, if there is another scope it could come from this is checked if active. I am mostly looking at the setup of CurrentVertxRequest, as something that happens every request and is not always used, at the moment this is 3 thread local ops, this changes it to one. |
Oh, sorry... yes I was talking about thread local reads of course.
I see.
Hm, the I'd recommend to change the @Dependent // just to make sure the static producer is discovered
class CurrentVertxRequest {
private static final ThreadLocal<RoutingContext> current;
@Produces
@RequestScoped
public static RoutingContext getCurrent() {
return current.get();
}
public void setCurrent(RoutingContext current) {
this.current.set(current);
}
} @stuartwdouglas WDYT? |
That was an oversight, the public field is not actually used anywhere.
Then you need to implement MP context propagation for our new thread local. If you start doing context propagation you are now propagating two contexts instead of one. You also then need to manage the lifecycle of your new ThreadLocal so that everywhere that would start or stop the request context now also needs to deal with our custom ThreadLocal instead. This is request scoped data, it belongs in the request scope, we should not be implementing our own custom ThreadLocal versions of this.
|
I agree that the
That's a good point. MP context propagation uff... in order to make it work we must set the current In that case, I don't have any other arguments, except that I find the changes not worth the "tangle" (from maintainability POV). Do you have some perf numbers? |
It made a measurable difference to perf. IMHO this makes things simpler rather than more complex as it removes the logic from the generated bytecode in the client proxies, and into a normal method. This also makes it much easier to step into a debug client proxy calls. |
So what do we do for this one? :) |
I need to go through the code again and try to find some compromise. I'm -1 for merging as it is though. "measurable difference" is a good argument (although quite vague) but I'd rather avoid changes like this just because we want to improve some benchmark a little bit... |
I've tried to keep the original idea but polish the API a little bit (e.g. rename the I think it's a good compromise. It would be great if @stuartwdouglas can validate that this modified version still makes a measurable difference. @manovotn pls verify the API and correctness ;-). |
17f6d69
to
15eed2d
Compare
Ah, there is a formatting problem again... |
15eed2d
to
8a46439
Compare
The test failure is related... |
- add ArcContainer.getContexts() - remove ArcContainer.normalScopedInstance() - rename InjectableContext.getOrCreate() to getIfActive() - add ClientProxies util class
8a46439
to
5442ec4
Compare
Ok, the PR is now ready for final review. @manovotn @stuartwdouglas |
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 good. There should still be the perf improvement since you are leveraging getIfActive
but I am +1 to have Stuart glance at this as well.
Previously this required 3 ThreadLocal operations:
This PR provides a single operation so that these can
be accomplished with only a single ThreadLocal op