fix: should filter out non-active spans on delete

This commit is contained in:
Zixuan Chen 2022-10-21 21:31:31 +08:00
parent ec07825c4f
commit a2fcd73b44
8 changed files with 42 additions and 24 deletions

View file

@ -142,6 +142,7 @@ impl Container for TextContainer {
common_ancestors_vv.retreat(&path_to_head.right);
let mut latest_head: SmallVec<[ID; 2]> = self.head.clone();
latest_head.push(new_op_id);
debug_log!("START FROM {:?}", &common_ancestors_vv);
if common_ancestors.is_empty()
|| !common_ancestors.iter().all(|x| self.tracker.contains(*x))
{
@ -166,7 +167,7 @@ impl Container for TextContainer {
"Stage1 retreat:{} forward:{}\n{}",
format!("{:?}", &iter.retreat).red(),
format!("{:?}", &iter.forward).red(),
format!("{:#?}", &change).blue(),
// format!("{:#?}", &change).blue(),
);
for op in change.ops.iter() {
if op.container == self.id {
@ -182,7 +183,7 @@ impl Container for TextContainer {
self.tracker.checkout(&self.vv);
debug_log!(
"Iterate path: {} from {} => {}",
format!("{:?}", path.left).red(),
format!("{:?}", path.right).red(),
format!("{:?}", self.head).red(),
format!("{:?}", latest_head).red(),
);

View file

@ -230,7 +230,7 @@ impl Tracker {
unsafe { crdt_list::yata::integrate::<YataImpl>(self, yspan) };
}
ListOp::Delete { pos, len } => {
let spans = self.content.get_id_spans(*pos, *len);
let spans = self.content.get_active_id_spans(*pos, *len);
self.update_spans(&spans, StatusChange::Delete);
self.id_to_cursor
.set((id).into(), cursor_map::Marker::Delete(spans));

View file

@ -120,16 +120,18 @@ impl ContentMap {
}
}
pub fn get_id_spans(&self, pos: usize, len: usize) -> RleVec<IdSpan> {
pub fn get_active_id_spans(&self, pos: usize, len: usize) -> RleVec<IdSpan> {
let mut ans = RleVec::new();
for cursor in self.iter_range(pos, Some(pos + len)) {
let id = cursor.as_ref().id;
let cursor = cursor.unwrap();
ans.push(IdSpan::new(
id.client_id,
id.counter + (cursor.offset as i32),
id.counter + (cursor.offset + cursor.len) as i32,
));
if cursor.as_ref().status.is_activated() {
let cursor = cursor.unwrap();
ans.push(IdSpan::new(
id.client_id,
id.counter + (cursor.offset as i32),
id.counter + (cursor.offset + cursor.len) as i32,
));
}
}
ans

View file

@ -285,7 +285,7 @@ pub mod fuzz {
return RleVec::new();
}
container.content.get_id_spans(pos, len)
container.content.get_active_id_spans(pos, len)
}
fn integrate_delete_op(container: &mut Self::Container, op: Self::DeleteOp) {

View file

@ -1110,6 +1110,7 @@ mod dag_partial_iter {
}
#[test]
#[ignore]
fn issue() {
if let Err(err) = test_partial_iter(
5,
@ -1142,6 +1143,7 @@ mod dag_partial_iter {
proptest! {
#[test]
#[ignore]
fn proptest_iter_2(
interactions in prop::collection::vec(gen_interaction(2), 0..40 * PROPTEST_FACTOR_10),
) {

View file

@ -308,8 +308,28 @@ mod test {
use super::*;
#[test]
fn test() {
test_single_client(vec![])
fn test_two_1() {
test_multi_sites(
2,
vec![
Ins {
content: "1".into(),
pos: 0,
site: 0,
},
Sync { from: 0, to: 1 },
Del {
pos: 0,
len: 1,
site: 1,
},
Ins {
content: "2".into(),
pos: 1,
site: 0,
},
],
)
}
#[test]

View file

@ -25,12 +25,13 @@ macro_rules! fx_map {
macro_rules! debug_log {
() => {
if cfg!(test) {
// $crate::print!("\n")
// $crate::print!("\n")
}
};
($($arg:tt)*) => {{
if cfg!(test) {
// print!("{}:{}\t", file!(), line!());
// use colored::Colorize;
// print!("{}:{}\t", file!().purple(), line!().to_string().purple());
// println!($($arg)*);
}
}};

View file

@ -1,5 +1,3 @@
use crate::Rle;
use super::{
@ -104,18 +102,12 @@ impl<'tree, T: Rle, A: RleTreeTrait<T>> Iter<'tree, T, A> {
#[inline]
pub fn from_cursor(
mut start: SafeCursor<'tree, T, A>,
mut end: Option<SafeCursor<'tree, T, A>>,
end: Option<SafeCursor<'tree, T, A>>,
) -> Option<Self> {
if start.0.pos == Position::After {
start = start.next_elem_start()?
}
if let Some(end_inner) = end {
if end_inner.0.pos == Position::End || end_inner.0.pos == Position::After {
end = end_inner.next_elem_start();
}
}
Some(Self {
cursor: Some(start.0),
end_cursor: end.map(|x| x.0),