Saturday, October 19, 2013

Re: RequestFactory issue with return operation processing if entities referenced in collection are processed after the collection they appear in is processed

Hi Thomas,

I attached a small project which should show the issue. In the project the client should always receive a UserGroup with users where none of the users would have null as their id. An assertion should throw the error when that's not the case along with console output.
Below is a request and response example from the project of when the issue would occur. You can see that the newly persisted entity operation appears after the UserGroup entity operation where it is referenced in the users collection.

There's no error that occurs, however the collection, when it returns from the server, is not correct since the collection has an unpopulated entity in the spot where the newly persisted entity was supposed to be. 
So for example:
The test project sends a UserGroup that has users with ids 0,1,2,3 along with a newly created user with id 4 to the server for saving, so when the request returns the users in the collection should still be 0,1,2,3, and 4. However when this issue
occurs the collection will return users with ids 0,1,2,3, and null because request factory added a new proxy in 4's spot because it saw the collection reference before the operation reference to the newly persisted 4. Note: in the test project attached
it won't necessarily be user 4, it could be any of the newly created ones since it depends on which request the newly persisted user operation will appear after the user group operation in the payload.

Thanks again,

-Seth

Request:

  1. O[{T:_AfG0AGGHor6iBIVMKE8Tgj35Y4=, V:MC4w, P:{id:TestUserGroup,…}, S:IlRlc3RVc2VyR3JvdXAi, O:UPDATE},…]
    1. 0{T:_AfG0AGGHor6iBIVMKE8Tgj35Y4=, V:MC4w, P:{id:TestUserGroup,…}, S:IlRlc3RVc2VyR3JvdXAi, O:UPDATE}
      1. O"UPDATE"
      2. P{id:TestUserGroup,…}
        1. id"TestUserGroup"
        2. users[{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, S:IlVzZXIwIg==}, {T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, S:IlVzZXIxIg==},…]
          1. 0{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, S:IlVzZXIwIg==}
          2. 1{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, S:IlVzZXIxIg==}
          3. 2{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, S:IlVzZXIyIg==}
          4. 3{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, S:IlVzZXIzIg==}
          5. 4{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, S:IkNsaWVudFVzZXI0Ig==}
          6. 5{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, S:IkNsaWVudFVzZXI1Ig==}
      3. S"IlRlc3RVc2VyR3JvdXAi"
      4. T"_AfG0AGGHor6iBIVMKE8Tgj35Y4="
      5. V"MC4w"
    2. 1{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, V:MC4w, P:{id:ClientUser5}, S:IkNsaWVudFVzZXI1Ig==, C:3, O:PERSIST}   <---- appears after the collection in which it is referenced above
    3. 2{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, V:MC4w, P:{id:ClientUser4}, S:IkNsaWVudFVzZXI0Ig==, O:UPDATE}
    4. 3{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, V:MC4w, P:{id:User3}, S:IlVzZXIzIg==, O:UPDATE}
    5. 4{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, V:MC4w, P:{id:User0}, S:IlVzZXIwIg==, O:UPDATE}
    6. 5{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, V:MC4w, P:{id:User2}, S:IlVzZXIyIg==, O:UPDATE}
    7. 6{T:S4$4ROBKr3uKwY3ECAYdM66u3Xg=, V:MC4w, P:{id:User1}, S:IlVzZXIxIg==, O:UPDATE}

Response:

"O":[{"T":"_AfG0AGGHor6iBIVMKE8Tgj35Y4=","V":"MC4w","P":{"id":"TestUserGroup","users":[{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","S":"IlVzZXIwIg=="},{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","S":"IlVzZXIxIg=="},{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","S":"IlVzZXIyIg=="},{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","S":"IlVzZXIzIg=="},{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","S":"IkNsaWVudFVzZXI0Ig=="},{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","S":"IkNsaWVudFVzZXI1Ig=="}]},"S":"IlRlc3RVc2VyR3JvdXAi","O":"UPDATE"},
{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","V":"MC4w","P":{"id":"ClientUser5"},"S":"IkNsaWVudFVzZXI1Ig==","C":3,"O":"PERSIST"},  <---- appears after the collection in which it is referenced above
{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","V":"MC4w","P":{"id":"ClientUser4"},"S":"IkNsaWVudFVzZXI0Ig==","O":"UPDATE"},
{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","V":"MC4w","P":{"id":"User3"},"S":"IlVzZXIzIg==","O":"UPDATE"},
{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","V":"MC4w","P":{"id":"User0"},"S":"IlVzZXIwIg==","O":"UPDATE"},
{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","V":"MC4w","P":{"id":"User2"},"S":"IlVzZXIyIg==","O":"UPDATE"},
{"T":"S4$4ROBKr3uKwY3ECAYdM66u3Xg=","V":"MC4w","P":{"id":"User1"},"S":"IlVzZXIxIg==","O":"UPDATE"}]


On Friday, October 18, 2013 10:47:31 AM UTC+2, Thomas Broyer wrote:
It's been so long I haven't worked on RF I'm not sure I follow you…
Would you mind posting the request and response payloads, and if possible a simple project reproducing the issue?
Also, you're not clear what exactly happens (the symptoms: an error? which one?)

On Thursday, October 17, 2013 6:06:28 PM UTC+2, GWTter wrote:
Hi all,

I'm pretty sure this is RF issue but thought I'd post here first just in case.

This involves the case where you update a an entity with a collection in which another entity is being persisted. When the response returns from the server and the operation messages are processed the following will occur:

The ClientId is always zero when parsed out from collections and thus the simpleproxyID lookup in the collection is always done by serverkey. This means that if the collection contains an entity that was created on the client and persisted is processed first then a new simple proxy will be created for that serverkey combo. Now when the actual related entity is processed (afterward) the clientId will be populated and so the system will do the lookup by the client ID for the simpleproxyID and then associate that simpleproxyID
with the serverkey which will override the simpleproxyID mapping created when the factory saw the serverkey first. Since that old mapping was overridden then the related proxy in the collection is not updated and returned as if it were still new with all fields unpopulated. 

This doesn't occur if the persisted entity is processed before the collection since after the IdFactory sees an entity that has both a clienID
and a serverID then it will retrieve the original simpleproxyID and update it the mapping to using the serverID, thus when the serverID is used in the lookup to populate the collection afterward it will find the correct simpleproxyID.

Again, this issue becomes all the more hard to spot since it ONLY occurs if the persisted entity is processed AFTER the collection it is referenced in. Since the order in which the operations being built client side is indeterminate (from the map) you can't tell when the entity will appear afterward.

The fix I had in mind with the big problem being that the returnedProxies mapping must always map from the correct simpleproxyId:
when processing the returned operations if the clientId > 0, we should first check if there's already a simpleproxyid for the serverid, if there is then we need to swap that mapping in state.returnedProxies when the simpleproxyid returned from using the serverid and non-zero client id. That way the mapping in state.returnProxies always maps from the correct simpleproxyid. Since a call to getId always creates a simpleproxyid then we would also need to be able to access the ephemeralId map in order to check it without creating a simpleidproxy. 


Any thoughts?

-Seth

--
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.

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home


Real Estate