Tuesday, November 19, 2013

Re: Implementation alternatives to improve GWT RequestFactory read and write based use cases

I have an update on this thread, sorry for the delay.

Upon a much deeper dive into the write side of this issue, there have been found a number of contributing factors that was causing an unnecessarily long end user wait time upon save/write. Most of these have nothing to do with GWT, RequestFactory, or Hibernate. While we have addressed those issues a bit, one part does standout as a pattern for this type of situation when using RequestFactory.

The part that did help reduce response time was to eagerly load the extents of this noted graph in the ServiceLocator for the A class. Such that when the A graph is returned from the find() method in AServiceLocator, all of the relationships in the graph have been fully initialized and hydrated. All of those OneToMany relationships are housed in java.util.ArrayList typed instance variables in our case, and Hibernate won't let you eagerly load more than one of those typed relationships in one query (shaking my fist at you Hibernate!), so instead we just wrote code to walk the graph once the A instance had hydrated via EntityManager, and that resulted in a significant reduction in database i/o to hydrate the full extents of the A graph.

While the "Eagerly load aggregate graph in aggregate ServiceLocator on write" trick did help quite a bit, it was just a portion of all of the optimizing we needed to put in place to get the system response time for the write use case ratcheted down to more acceptable levels.

Thanks for the help.

Doug



On Thursday, November 7, 2013 12:53:48 AM UTC-8, Thomas Broyer wrote:
Anyone volunteers to profile the code to have hints about what's slow?

IMO, one solution could be to switch to code generation rather than reflection (particularly the AutoBeans), but that's only if reflection is the bottleneck.

On Thursday, November 7, 2013 8:50:08 AM UTC+1, Ümit Seren wrote:
Well that's weird. you could put a breakpoint in the getter for the sub-references and see if it gets called when you save without with(). 


On Wed, Nov 6, 2013 at 10:22 PM, Doug Gschwind <doug.g...@gmail.com> wrote:
Hi Umit,

Oh, I like the idea of the wildcarding in those String instances passed to with(), would help with refactoring efforts if properties change or are moved to other classes in a graph.

According to my testing though, I see no difference in results if upon save we do, or do not use, a valid call to with(args). Given that, I will likely abandon any tweaks in that area.

Thanks,

Doug


On Wednesday, November 6, 2013 12:08:08 AM UTC-8, Ümit Seren wrote:
The reason why you have to specify the references in `with()` is exactly that sometimey you don't need the entire domain graph on the client. This way you can specify what you really want to have sent over the wire, potentially saving bandwith and improve de-serialization speed. 

There is an issue in the issue tracker (can't find it tough) to support wildcards a la `with('A.*')` or 'with(A.**)`, if you really need to load the entire graph. But I am not sure if that is already implemented 


On Tue, Nov 5, 2013 at 9:42 PM, Doug Gschwind <doug.g...@gmail.com> wrote:
Hi Umit,

Thanks for those thoughts. I failed to mention our use of with() in this area. When we read the graph from the server, we do in fact make use of with() with an extensive list of Strings to force the EntityProxy graph population as we need.

Interestingly, when we make the call back to the server from client code to persist end user edits, we do NOT use with(). I can experiment with that to see if providing a reduced list of Strings with with() provides any relief. That is an interesting thought. I personally dislike the fact that I have to specify with() at all, when my EntityProxy declarations already indicate which properties I expect to be in existence on the client side. With our graph being so deep, a Domain Model refactoring causes an undesirable ripple through those Strings. Providing another list of Strings for the write based path would add to my discomfort. However, I will do some experimenting to see if that can provide any relief.

Thanks,

Doug


On Monday, November 4, 2013 11:50:46 PM UTC-8, Ümit Seren wrote:

@Doug: Sorry I missed the part in your first post where you mentioned that you already return true in the isLive method.

RequestFactory uses reflection on the server-side which might be an issue with a huge graph (although I believe it uses caches to speed up things in subsequent calls.
I guess you pass the entire graph in the with() call when you retrieve the instance A.
If you don't need to change anything in the sub-nodes (B,C,Ex) you could leave out the with() call for the write action.
Or alternatively you could create additional EntityProxys that contain only a subset of the sub-nodes.



On Tue, Nov 5, 2013 at 3:13 AM, Doug Gschwind <doug.g...@gmail.com> wrote:
Thanks Umit. Indeed we do that too. We have a ServiceLocator supertype which all of our concrete ServiceLocator concrete subclasses extend, and isLive() is implemented to unconditionally return true in that implementation.

Thanks,

Doug


On Monday, November 4, 2013 1:31:28 AM UTC-8, Ümit Seren wrote:

If you don't care about EntityChangeEvents you can also override the isLive() method and return true (see here).
This improved performance quite a bit at least in my case.

On Friday, November 1, 2013 1:20:14 AM UTC+1, Doug Gschwind wrote:

Hello everyone,

We are using GWT 2.5.1, Hibernate 4.x as a JPA 2.x provider, Oracle database 11g, and RequestFactory for our application. One of the areas of our application is slightly slow at read time and is noticeably slower at write time. The use case in particular is a fairly complex editor where the read part of the puzzle is used to render the complex UI and the write part of the puzzle is used to save end user edits made in this complex editor UI. In this particular use case, we use RequestFactory. In other areas of our application we have some GWT-RPC in use, but we are migrating away from its use in favor of using RequestFactory.

In our RequestFactory use, we use the ServiceLocator pattern and our ServiceLocator's unconditionally return true from isLive(), for background information. We are not using the Editor framework in this area of the application.

We have been working on this set of use cases some time and are quite comfortable with the Domain Model that we have in place, which to simplify looks like the following :

class A
    |
    -- class B
        |
        -- class C
            |
            -- class D
                |
                -- class E
                    |
                    -- class E1
                    |
                    -- class E2
                    |
                    -- class E3

There are OneToMany relationships between the following classes : A -> B, B -> C, C-> D, D-> E, E -> E1, E -> E2, E -> E3, with back pointing ManyToOne relationships throughout. Each of these classes are not transportable, in the RequestFactory sense, so we have an EntityProxy for each class.

When an end user saves their edits, lots of db query traffic can be seen, which appears to be due to hydrating the entire graph of objects and stitching them together. I suspect that we could reduce the system response time of the save/write use case if all of this ServiceLocator find() infrastructure was subverted since once we read/find the A instance, it can be used to apply all edits without a find() call per node in the graph.

Have any of you faced this type of problem and were you able to find an implementation alternative which proved faster by using maybe GWT-JSON or GWT-RPC or some other means?

If you got here, thanks for reading and your replies in advance.

Doug
            

--
You received this message because you are subscribed to a topic in the Google Groups "Google Web Toolkit" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit/6ihnfmnuJy8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To post to this group, send email to google-we...@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "Google Web Toolkit" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit/6ihnfmnuJy8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To post to this group, send email to google-we...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/groups/opt_out.

--
You received this message because you are subscribed to a topic in the Google Groups "Google Web Toolkit" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit/6ihnfmnuJy8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To post to this group, send email to google-we...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/groups/opt_out.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.
Visit this group at http://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/groups/opt_out.

No comments:

Post a Comment