Support concurrent merge and split operations in Tree
Opened this issue · 0 comments
What would you like to be added:
Through the PRs #659 and #705, Yorkie now supports merge and split operations in Tree.
However, concurrent edits for these operations are not implemented yet.
It is necessary to support concurrent merge and split operations as a next step.
Why is this needed:
Problem
The current implementation of Tree can't support concurrent edits for merge and split operations.
This is mainly because these operations inherently involves the movement of child nodes to another parent node.
In concurrent editing situations, it becomes challenging to determine the destination or source of the child nodes solely based on the from
or to
in the operation.
Let's examine this with the following example.
Initial
<r><p>a</p><p>b</p></r>
Before sync
User A: Merge(Edit(2,4)) -> <r><p>ab</p></r>
User B: Delete(Edit(3,6)) -> <r><p>a</p></r>
After sync
Expected: <r><p>a</p></r>
User A Actual: <r><p>ab</p></r> <-- Text "b" stays alive
User B Actual: <r><p>a</p></r>
![tree-concurrent-merge-delete](https://private-user-images.githubusercontent.com/46182768/294824930-c18fa950-f8cc-489b-8be8-31bfedfcd9e6.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQ2OTI1MTUsIm5iZiI6MTcyNDY5MjIxNSwicGF0aCI6Ii80NjE4Mjc2OC8yOTQ4MjQ5MzAtYzE4ZmE5NTAtZjhjYy00ODliLThiZTgtMzFiZmVkZmNkOWU2LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODI2VDE3MTAxNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWE1YWZhZmFlZWIzM2M1MTFjNGYyMGJjMjVmYTFjNjJhMGY1ZDI3NzgzNGJkMmJiOTJkNTk4ZmJlZDRkY2VmMDgmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.7Hld-kQJvC1W-n1-popQhmPe4Ms-7pK3Vel6DemDG3s)
You can see more examples in the following PRs.
- Go-SDK: #751
- JS-SDK
Solution
One possible solution for this issue is re-ordering concurrent operations, which means that the Tree CRDT doesn't depend solely on the commutative rule between operations anymore.
To be specific, when more than one operations are considered to be concurrent by means of TimeTicketContext
(a.k.a. latestCreatedAtMapByActor
), it can roll back the current state to the nearest snapshot, re-order the concurrent operations, and apply them successively.
The ordering between operations should be determined by whether it preserves users' intention well in concurrent edits.
For instance, we can use Delete(Merge) > Split > Insert
as the ordering for operations.
This mechanism is closely related to Tree.Move, which is described in #634.