Hello,
I have finally implemented the context capturing which is probably also
interesting for @Futurable.
The commit also includes code for deleting specific beans from a
context. This is implemented by using AlterableContext.destroy if
available and otherwise via OWB/Weld-native mechanisms. Note that there
are some bugs in the AlterableContext.destroy implementations which
require some hacks to get around.
Destroying beans is necessary for testing the session and application
scopes.
The implementation of the context capturing is not really nice since it
requires some reflection hacks but it gets the job done. Would be nice
if the CDI spec itself already came with a mechanism to capture contexts ;)
I extended the JSF Playground with an example that can be used to test
the functionality.
Data1 - Data4 tests create beans in the request thread and check if the
sub-threads can see the values.
Data5 - Data8 tests create beans in the sub-threads and check if the
request thread can see the values.
You can find the commit here
https://github.com/beikov/deltaspike/commit/3a15d6c3b804166a51346981aad12c36cd779b7d
I would very much appreciate feedback on the implementation and would
like to get that code into deltaspike.
Mit freundlichen Grüßen,
------------------------------------------------------------------------
*Christian Beikov*
Am 09.04.2016 um 12:34 schrieb Gerhard Petracek:
#1 you would need large(r) buffers (which might get an issue depending on
your concrete needs)
#2 furthermore, you can't use "early flush before the html-body" -> you
benefit in the first step, but it impacts further optimizations
#3 if you wait in the callback anyway, you can just do the parallel loading
(or the delegation to parallel loading) there - that just won't work
(easily) with a producer-centric style
#4 page-beans which delegate to other beans (which do almost the same as
your producers) vs. a producers-only style is imo a choice which depends a
lot on your application
(+ el-resolvers of di-frameworks can just provide optimizations if you have
as few diff. names as possible - per page-request).
based on what i've seen so far in a "typical" jsf-application, the benefit
you get with such a parallelization isn't that huge - given that you can't
benefit from other possible optimizations.
regards,
gerhard
2016-04-09 11:59 GMT+02:00 Christian Beikov <[email protected]>:
Wouldn't setting the buffer size to an appropriate size deal with the
problem with redirecting on an error?
We could also await all async loads before exiting the phase listener,
thus having loaded everything before the rendering starts.
Caching the data in a page bean is of course a possibility, but I moved
away from this kind of style because then you have to spread all your data
reloads in every possible action method. I find it nicer to define a scope
for a producer that most of the time is a perfect fit and if necessary, I
can still invalidate it. Having referenced producers now makes it easy to
achieve a speedup without having to do anything manually(except for
annotating the safe producer methods with the interceptor annotation).
Mit freundlichen Grüßen,
------------------------------------------------------------------------
*Christian Beikov*
Am 09.04.2016 um 11:23 schrieb Gerhard Petracek:
hi @ all,
i considered something similar some days ago.
(the benefit of @Futureable in combination with @PreRenderView callbacks.)
the main issue is that it isn't a nice idea to start with the rendering
before all data was loaded
(and you know that you don't need to render a diff. page - like an
error-page).
usually it's enough to cache the loaded data in a page-bean (just load
multiple parts in parallel - e.g. in a @PreRenderView callback).
regards,
gerhard
2016-04-09 9:55 GMT+02:00 Christian Beikov <[email protected]>:
I extract the "bindings" map of every UIComponent and analyze all "simple"
expressions further.
Simple expression are ones that don't contain a dot in the expression
string. Since named producers will always have a simple name this will
filter out most of the unnecessary expressions. Then I check whether the
last few expressions resolve to beans and if so, I check if the bean is
annotated with the @PreloadingSafe annotation. If all that is true, then
the bean can be preloaded.
You are right that this might be a considerable overhead. I will have to
check what the performance impact of that strategy is. Still I think that
since it's nicely cacheable, it will only add a few milliseconds (if at
all) the first time the tree is traversed.
What do you think about the strategy? Do you have any ideas how I could
improve it?
Mit freundlichen Grüßen,
------------------------------------------------------------------------
*Christian Beikov*
Am 09.04.2016 um 09:44 schrieb Thomas Andraschko:
The traversal itself is ok but how do you analyze the expression? I think
you have to do it for every component and every value attribute. Thats
something i would like to avoid.
2016-04-09 9:38 GMT+02:00 Christian Beikov <[email protected]
:
Hello Thomas,
well scanning the tree shouldn't be such a big problem I guess since
the
JSF lifecycle already traverses the tree multiple times. Doing it
another
time shouldn't do that much damage I think, especially because the
traversal would be aware of the client ids that should be rendered in
an
ajax request. I also think that it is fairly easy to optimize since I
could
cache the preloadable EL-Expressions along with the client ids that
they
belong to for a view. So this would only require a traversal once.
The whole idea and use case for which I am implementing this was to
make
the preloading in an automatic fashion without the need to touch the
views.
Having a preload tag would be definitely another way, but I would like
to
first test the performance impact of scanning the expressions. The
preload
tag would also be problematic in the ajax use case since it will
probably
be located outside of the components that are rendered.
I was also thinking about collecting statistics for the methods that
are
used and try to start preloading opportunistically based on that data.
Mit freundlichen Grüßen,
------------------------------------------------------------------------
*Christian Beikov*
Am 09.04.2016 um 09:18 schrieb Thomas Andraschko:
Hi Christian,
basically thats an interesting idea, just not sure if we could
implement
it
in a nicer way.
I think scanning the component tree and analyzing every EL expression
feels
a little risky and slow.
Using a bytecode library isn't the problem in the JSF module, we
already
use there our proxy module.
Couldn't we just reuse our @Futureable?
Sure, the handling in the UI would be little bit different
(supplierNames
vs supplierNames.get()) but Future should work, right?
Regards,
Thomas
2016-04-09 8:06 GMT+02:00 Christian Beikov <
[email protected]
:
Hello,
I am implementing some POCs for parallel preloading of named producer
methods and think I have a working prototype.
I wanted to know if you are interested in including this into
Deltaspike
and if so, how I should contribute it.
It is separated into two parts, one is the context capturing in one
thread
and the possibility to start these contexts for a new thread.
The other part is a phase listener that scans the component tree for
UEL-Expressions that evaluate to a named producer method which is
annotated
with a special interceptor annotation(@PreloadingSafe). These
producers
are
then invoked in the before render response phase in parallel. This
currently works by creating a proxy from the returned interface. The
invocation handler behind it, just delegates to the result of the
future
that was received by submitting the producer method to an
ExecutorService.
It would be nice if this could also work with non-interface types but
that
would require some bytecode library which I didn't want to introduce
yet.
Here some example code:
public class SomeProducerBean {
@PreloadingSafe
@Named
@Produces
@RequestScoped
public List<String> getSupplierNames() { /* Some DB call */ }
}
<html>
...
<ui:repeat value="#{supplierNames}" var="supplName">
#{supplName}
<ui:repeat>
...
</html>
So the rendering until it reaches the ui:repeat runs in parallel to
the
preloading of the supplier names. When the JSF-Component tries the
evaluate
the expression it might need to block. Also note that other
expressions
will still be evaluated in parallel even if one blocks so this can
be a
huge boost for performance.
It's not fully tested yet. The easy case works but I haven't tested
more
complex scenarios or possible threading issues yet.
What do you say?
--
Mit freundlichen Grüßen,
------------------------------------------------------------------------
*Christian Beikov*