Summary:
I spent the last several days thinking about state reconciliation issues, some crashes (T65586949) that suspiciously happen somewhere inside, and a bunch of issues that might be connected to that (possibly, some of T65516263 sub-task).
I cannot see some obvious problems in the current state reconciliation algorithm that might cause the crash (because of some use-after-free or other pure C++ issues), but I suspect some of the problems we experience might be caused by some details of how we reconcile states.
In the current approach, we rank all states based on the "hierarchical" history of their creation (state version is being calculated based on the version of the base tree). That's usually fine but in some cases when trees are being constructed concurrently, a logical version of a based tree does not correspond to the local version of a committed tree. In other words, the linear history of commits does not always correspond to the "hierarchical" history of trees generation that was done by different parties (e.g. React vs native state update pipeline).
In this diff, I tried to change the approach to change the algorithm to follow this logic: If some state is `obsolete` (already been committed and then replaced with newer one), we replace that with the most recent one. This change does not introduce the `obsolete` flag; is already used by State infra to avoid cloning nodes with an outdated state.
Interestingly, it fixes the issue with an empty BottomSheet on Android (T66177144). See the attached video. The hope is that it's also will
This change theoretically might affect all things that use State, so it hard to predict what can break and how. So, if we don't see obvious problems here, I would set up a GK/QE and run the experiment in prod.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: JoshuaGross
Differential Revision: D21295137
fbshipit-source-id: e5613218d3e11a56623cab9bbf2540495b2b24e8
Summary:
This change removes the concept of `StateTarget`, replacing its role with `ShadowNodeFamily`.
When `StateTarget` was built, we didn't have a concept of `Family`, and when we added it we introduced a retain-cycle: ShadowNode -> Family -> StateTarget -> ShadowNode. This diff fixes that.
This change does not change conceptually how the state behaves, it just adjusts internal machinery.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D19799013
fbshipit-source-id: c1360bfbf6b8ac34e2a856a40047eafeb50ed070
Summary:
Changelog: [internal]
`ShadowNodeFamily` can be used as target in state updates instead of `ShadowNode`.
Reviewed By: shergin
Differential Revision: D19517428
fbshipit-source-id: 6831357e749239d5afec1dfd2d44a26ca6553e51
Summary:
Changelog: [internal]
Merges all of responsibilities of `StateCoordinator` into `ShadowNodeFamily`.
Reviewed By: shergin
Differential Revision: D19500104
fbshipit-source-id: f31ffded5a840e722fd898eef6a9f52cd2186df7
Summary:
Changelog: [internal]
1. Use `ShadowNode::Shared` instead of `SharedShadowNode`.
2. Initialise `ShadowNodeFamily` before `ShadowNode`.
Why?
This is a step in order to merge `StateCoordinator` into `ShadowNodeFamily` and use it as target for state updates.
Reviewed By: shergin
Differential Revision: D19471399
fbshipit-source-id: 2f67901c901349d238c711f9eeaadb19fe7c1110
Summary:
Changelog: [internal]
1. Moves `ShadowNode::getAncestors` to `ShadowNodeFamily`.
2. Exposes shadowNode's family through `ShadowNode::getFamily()`.
# Why?
This is a first step in order to merge `StateCoordinator` into `ShadowNodeFamily` and use it as target for state updates.
Reviewed By: shergin
Differential Revision: D19465188
fbshipit-source-id: b5a3625aa21c040301259de02beedbf97e11f20e
Summary:
Before this change, all methods `ShadowNode::getComponentHandle()` and `ShadowNode::getComponentHandle()` returned the values directly from a `ComponentDescriptor` (via `ShadowNodeFamily`). Now, we store/cache those values in ShadowNodeFamily object (and ShadowNode's methods use that).
We need that to ensure that calling those methods doesn't access the `ComponentDescriptor` object because it's difficult to guarantee that this object overlives all `ShadowNode`s. This is especially important when we build `ShadowView`s from `ShadowNode`s: this might happen way after the code is already deallocated and the only living objects are MountingTransactionCoordinator and essentially two pointers to root nodes of before and after trees (that still needs to be mounted).
This diff introduces no actual changes in the ownership model.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: mdvacca
Differential Revision: D18290024
fbshipit-source-id: 4135a277515a84b053fe0d0dde48fba59bf2aae3
Summary:
One of the core feature of ShadowNodeFamily is having a pointer to a parent family. This diff implements it.
I don't think there is a hard retain cycle there, but for more lean memory usage we use weak_ptr here.
Reviewed By: JoshuaGross
Differential Revision: D14416948
fbshipit-source-id: 05fd2c4833146f007228363b1d958776b4a2a9cf
Summary:
ShadowNodeFamily is a new concept that allows us to implement an efficient way to solve the problem of finding a path to some ancestor node (practically reimplement ShadowNode::constructAncestorPath() in some efficient way).
This diff is the first one in the series. It introduces a new class and moves some data into it.
Reviewed By: JoshuaGross
Differential Revision: D14416947
fbshipit-source-id: c93865a8929a2128498e34d3589487696aac6283