From df81aece514f19a9fcbc9fa2b5d44700f857604a Mon Sep 17 00:00:00 2001 From: Zixuan Chen Date: Tue, 31 Dec 2024 13:26:52 +0800 Subject: [PATCH] Fix-better-event-order (#595) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The event will now be ordered by (depth, container counter). Therefore, two container creation events within the same layer will be sorted based on the containers’ counter values. This approach can prevent the issue where child tree node events are received before the parent tree node events --- .changeset/tricky-bees-peel.md | 5 +++++ crates/loro-internal/src/state.rs | 11 ++++++++++- crates/loro/tests/loro_rust_test.rs | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 .changeset/tricky-bees-peel.md diff --git a/.changeset/tricky-bees-peel.md b/.changeset/tricky-bees-peel.md new file mode 100644 index 00000000..5130f0d3 --- /dev/null +++ b/.changeset/tricky-bees-peel.md @@ -0,0 +1,5 @@ +--- +"loro-crdt": patch +--- + +Better event ordering diff --git a/crates/loro-internal/src/state.rs b/crates/loro-internal/src/state.rs index 9ef61f1c..9c1b8e2f 100644 --- a/crates/loro-internal/src/state.rs +++ b/crates/loro-internal/src/state.rs @@ -1302,7 +1302,16 @@ impl DocState { // Sort by path length, so caller can apply the diff from the root to the leaf. // Otherwise, the caller may use a wrong path to apply the diff. - diff.sort_by_key(|x| x.path.len()); + + diff.sort_by_key(|x| { + ( + x.path.len(), + match &x.id { + ContainerID::Root { .. } => 0, + ContainerID::Normal { counter, .. } => *counter + 1, + }, + ) + }); DocDiff { from, to, diff --git a/crates/loro/tests/loro_rust_test.rs b/crates/loro/tests/loro_rust_test.rs index 193132d5..ebbd33d2 100644 --- a/crates/loro/tests/loro_rust_test.rs +++ b/crates/loro/tests/loro_rust_test.rs @@ -2350,6 +2350,23 @@ fn test_detach_and_attach() { assert!(!doc.is_detached()); } +#[test] +fn test_event_order() { + let doc = LoroDoc::new(); + let _sub = doc.subscribe_root(Arc::new(|e| { + let e0 = &e.events[0].diff; + assert!(e0.is_map()); + let e1 = &e.events[1].diff; + assert!(e1.is_list()); + let e2 = &e.events[2].diff; + assert!(e2.is_tree()); + })); + doc.get_map("map").insert("key", "value").unwrap(); + doc.get_list("list").insert(0, "item").unwrap(); + doc.get_tree("tree").create(None).unwrap(); + doc.commit(); +} + #[test] fn test_rust_get_value_by_path() { let doc = LoroDoc::new();