diff --git a/crates/fuzz/tests/test.rs b/crates/fuzz/tests/test.rs index b6628072..1a9c2ec7 100644 --- a/crates/fuzz/tests/test.rs +++ b/crates/fuzz/tests/test.rs @@ -9572,6 +9572,270 @@ fn tree_none() { ) } +#[test] +fn checkout_text_err() { + test_multi_sites( + 5, + vec![FuzzTarget::All], + &mut [ + Handle { + site: 25, + target: 25, + container: 193, + action: Generic(GenericAction { + value: I32(1644825), + bool: false, + key: 393216, + pos: 27487790694400, + length: 1808504320951976800, + prop: 18446744073709551385, + }), + }, + SyncAll, + Handle { + site: 25, + target: 25, + container: 25, + action: Generic(GenericAction { + value: Container(Unknown(255)), + bool: true, + key: 436207615, + pos: 1808504320951916825, + length: 16131858542891077913, + prop: 18437701552104792031, + }), + }, + SyncAll, + Handle { + site: 25, + target: 34, + container: 25, + action: Generic(GenericAction { + value: Container(Unknown(255)), + bool: true, + key: 4294967295, + pos: 18446744073709551615, + length: 18446744073709551615, + prop: 18381750949675392991, + }), + }, + SyncAll, + Handle { + site: 25, + target: 25, + container: 25, + action: Generic(GenericAction { + value: I32(-538976367), + bool: true, + key: 685760479, + pos: 16131858456979185696, + length: 1811037595742312729, + prop: 1849036717598251289, + }), + }, + Handle { + site: 0, + target: 0, + container: 0, + action: Generic(GenericAction { + value: I32(421068800), + bool: true, + key: 432014617, + pos: 18446744073694419225, + length: 18446744073709551615, + prop: 16131858542891098079, + }), + }, + SyncAll, + Handle { + site: 25, + target: 25, + container: 255, + action: Generic(GenericAction { + value: Container(Text), + bool: true, + key: 421075225, + pos: 16131858204548733209, + length: 2314885568395206623, + prop: 1808505174690352095, + }), + }, + Handle { + site: 25, + target: 25, + container: 25, + action: Generic(GenericAction { + value: Container(Text), + bool: true, + key: 25, + pos: 1808476725365964800, + length: 11031876360607176985, + prop: 18446744073709486086, + }), + }, + SyncAll, + Handle { + site: 33, + target: 33, + container: 255, + action: Generic(GenericAction { + value: Container(Unknown(255)), + bool: true, + key: 553582865, + pos: 18446744073709551615, + length: 18446744073709551615, + prop: 18446744073709551615, + }), + }, + Handle { + site: 25, + target: 25, + container: 25, + action: Generic(GenericAction { + value: Container(Unknown(25)), + bool: true, + key: 421075225, + pos: 16131858204548733209, + length: 2314885568395206623, + prop: 1808505174690352095, + }), + }, + Handle { + site: 25, + target: 25, + container: 25, + action: Generic(GenericAction { + value: Container(Text), + bool: true, + key: 25, + pos: 1808476725365964800, + length: 1808505037875966233, + prop: 18446744073709551385, + }), + }, + SyncAll, + Handle { + site: 25, + target: 25, + container: 25, + action: Generic(GenericAction { + value: Container(Unknown(223)), + bool: true, + key: 538976296, + pos: 1808505174690352095, + length: 1808504321102911769, + prop: 1808504323367835929, + }), + }, + Handle { + site: 0, + target: 0, + container: 0, + action: Generic(GenericAction { + value: I32(85530905), + bool: false, + key: 421075225, + pos: 18446744073709551615, + length: 16131858680869027839, + prop: 18437701552104792031, + }), + }, + SyncAll, + Handle { + site: 0, + target: 0, + container: 0, + action: Generic(GenericAction { + value: I32(421117957), + bool: true, + key: 4294967065, + pos: 18446744073709551615, + length: 16131858542891106303, + prop: 18446744073170575327, + }), + }, + SyncAll, + Undo { + site: 115, + op_len: 1936946035, + }, + Handle { + site: 25, + target: 255, + container: 255, + action: Generic(GenericAction { + value: Container(Text), + bool: true, + key: 421075225, + pos: 16131858541569448217, + length: 16077885992209473503, + prop: 1808504324286832587, + }), + }, + Handle { + site: 25, + target: 25, + container: 25, + action: Generic(GenericAction { + value: I32(421075225), + bool: true, + key: 0, + pos: 1808504213156659200, + length: 18417779746705245465, + prop: 18446744073709551615, + }), + }, + SyncAll, + Handle { + site: 255, + target: 255, + container: 255, + action: Generic(GenericAction { + value: Container(Text), + bool: true, + key: 421075225, + pos: 16131858542885935385, + length: 14690495831856439263, + prop: 1808504320964943839, + }), + }, + SyncAll, + Handle { + site: 25, + target: 34, + container: 25, + action: Generic(GenericAction { + value: Container(Unknown(255)), + bool: true, + key: 4294967295, + pos: 18446744073709551615, + length: 18446744073709551615, + prop: 18381750949675392991, + }), + }, + SyncAll, + Undo { + site: 115, + op_len: 1936946035, + }, + SyncAll, + Handle { + site: 0, + target: 0, + container: 0, + action: Generic(GenericAction { + value: I32(85530905), + bool: false, + key: 2568558873, + pos: 18446744073709551615, + length: 16131858542885935615, + prop: 16131858542891098079, + }), + }, + ], + ) +} + #[test] fn minify() { minify_error( diff --git a/crates/loro-internal/src/container/richtext/tracker.rs b/crates/loro-internal/src/container/richtext/tracker.rs index ceb64e96..d23c493e 100644 --- a/crates/loro-internal/src/container/richtext/tracker.rs +++ b/crates/loro-internal/src/container/richtext/tracker.rs @@ -156,7 +156,7 @@ impl Tracker { pub(crate) fn delete( &mut self, mut op_id: ID, - target_start_id: ID, + mut target_start_id: ID, pos: usize, mut len: usize, reverse: bool, @@ -165,6 +165,7 @@ impl Tracker { // the op is partially included, need to slice the op let start = (applied_counter_end - op_id.counter) as usize; op_id.counter = applied_counter_end; + target_start_id = target_start_id.inc(start as i32); len -= start; // If reverse, don't need to change the pos, because it's deleting backwards. // If not reverse, we don't need to change the pos either, because the `start` chars after it are already deleted diff --git a/crates/loro-internal/src/container/richtext/tracker/crdt_rope.rs b/crates/loro-internal/src/container/richtext/tracker/crdt_rope.rs index a6409ffe..6c3c901c 100644 --- a/crates/loro-internal/src/container/richtext/tracker/crdt_rope.rs +++ b/crates/loro-internal/src/container/richtext/tracker/crdt_rope.rs @@ -246,6 +246,7 @@ impl CrdtRope { } if reversed && len > 1 { + // TODO: PERF: optimize this let mut ans = SmallVec::with_capacity(len); for i in (0..len).rev() { let a = self.delete( diff --git a/crates/loro-internal/src/diff_calc.rs b/crates/loro-internal/src/diff_calc.rs index f7917b20..e232d00d 100644 --- a/crates/loro-internal/src/diff_calc.rs +++ b/crates/loro-internal/src/diff_calc.rs @@ -15,7 +15,7 @@ use loro_common::{ }; use loro_delta::DeltaRope; use smallvec::SmallVec; -use tracing::{info, instrument}; +use tracing::{info_span, instrument}; use crate::{ change::Lamport, @@ -333,27 +333,30 @@ impl DiffCalculator { let id = oplog.arena.idx_to_id(container_idx).unwrap(); let bring_back = new_containers.remove(&id); - let (diff, diff_mode) = calc.calculate_diff(oplog, before, after, |c| { - new_containers.insert(c.clone()); - container_id_to_depth.insert(c.clone(), depth.and_then(|d| d.checked_add(1))); - oplog.arena.register_container(c); + info_span!("CalcDiff", ?id).in_scope(|| { + let (diff, diff_mode) = calc.calculate_diff(oplog, before, after, |c| { + new_containers.insert(c.clone()); + container_id_to_depth + .insert(c.clone(), depth.and_then(|d| d.checked_add(1))); + oplog.arena.register_container(c); + }); + calc.finish_this_round(); + if !diff.is_empty() || bring_back { + ans.insert( + container_idx, + ( + *depth, + InternalContainerDiff { + idx: container_idx, + bring_back, + is_container_deleted: false, + diff: diff.into(), + diff_mode, + }, + ), + ); + } }); - calc.finish_this_round(); - if !diff.is_empty() || bring_back { - ans.insert( - container_idx, - ( - *depth, - InternalContainerDiff { - idx: container_idx, - bring_back, - is_container_deleted: false, - diff: diff.into(), - diff_mode, - }, - ), - ); - } } }