Open shlusiak opened 3 years ago
Hey, @shlusiak
It would be great if you can open a PR for this when you have some spare time. I rely on you on this traversal topic as you shown that you have understanding. Feel free to contact me if you have interest for some general rewrite and restructure of the SDK - I'm looking for some help for the next-gen Parse SDK for the JVM.
PS. If this is something already fixed in some of your previous PRs, please let me know to close this.
Thanks!
Looking forward, Asen
@L3K0V It has been a while since I encountered this but I remember I had a crack at it and gave up because the ParseTraverser was reused and I couldn't easily change it's behaviour as I needed it in this different scenario. There are obviously quite a lot of cases to consider and it turned complex enough for me to give up after I understood what was happening, and I resorted in our production code to know when this is happening and manually persist in two stages to avoid this crash. So no, I'm not aware of this being fixed yet.
I might spend some time refreshing the context of all this and look at it again. I'm not finding much free time to contribute to this more than my work required and as I implemented a workaround that driver it is harder for me to dedicate some time to it. But that may change and I'll keep this in mind and might try to pick it up again.
Are you thinking of a gradual rewrite of the existing code base, or of a green field approach of building this up from scatch? I would love a cleaner version that gets rid of the Bolts-Tasks dependency and uses coroutines instead, there are a lot of places where the current design is almost impossible to just "fix" (see local data store performance).
@shlusiak I have started a discussion here https://github.com/parse-community/Parse-SDK-Android/issues/1100 and define some plan. Next steps for me should be:
I have tried several time to rewrite everything to Kotlin but every time I hit some walls. I tried to start from scratch here https://github.com/L3K0V/ParseKt and again I hit some walls. It's not for a person alone, so I'm looking for someone to work together on next-gen Parse SDK for the JVM or KMM
Parse version: 1.25.0
Where this is thrown there is a comment that this should never actually happen:
https://github.com/parse-community/Parse-SDK-Android/blob/797786ff42223094c20d2dadd7af9e616020175a/parse/src/main/java/com/parse/ParseObject.java#L728-L732
Sample test case that triggers this
Expected behaviour
This should succeed, because
child1
andchild2
can be persisted first, and once they both have an objectIdparent
can be persisted to resolve the cycle.Actual behaviour
This setup does contain a cycle but one that can be resolved because the parent has an objectId. The logic in
collectDirtyChildren
only looks for direct cycles involving unsaved objects, which cannot be resolved because neither object can be saved first.In the scenario above the batching code would be expected to serialise and save
child1
andchild2
in the first iteration, and thenparent
in the second iteration, once the objectIds of all children are known.However the
canBeSerialized()
method is usingParseTraverser
, which does a deep traverse of the given object.https://github.com/parse-community/Parse-SDK-Android/blob/797786ff42223094c20d2dadd7af9e616020175a/parse/src/main/java/com/parse/ParseObject.java#L2905-L2929
This will return
false
if any node is found that has noobjectId
, which makes every object in the above scenario un-serializable, because they all contain a node in the tree without anobjectId
(parent
cannot be saved, becausechild1
is found,child1
cannot be saved becausechild2
is found,child2
cannot be saved becausechild1
is found).I feel what we'd want here is to set
setTraverseParseObjects
tofalse
to only traverse this object but not do a deep traversal, but the way the ParseTraverser is written this means thatParseObjects
will not even be visited. 🙄