fix: two sites sync issue

This commit is contained in:
Zixuan Chen 2022-10-21 10:46:48 +08:00
parent 788808b055
commit 69521a97ef
6 changed files with 93 additions and 40 deletions

View file

@ -66,9 +66,10 @@ impl TextContainer {
},
self.id.clone(),
);
let last_id = op.id_last();
store.append_local_ops(vec![op]);
self.head = smallvec![id];
self.vv.set_last(id);
self.head = smallvec![last_id];
self.vv.set_last(last_id);
id
} else {
unimplemented!()
@ -88,8 +89,11 @@ impl TextContainer {
self.id.clone(),
);
let last_id = op.id_last();
store.append_local_ops(vec![op]);
self.state.delete_range(Some(pos), Some(pos + len));
self.head = smallvec![last_id];
self.vv.set_last(last_id);
id
} else {
unimplemented!()
@ -121,20 +125,23 @@ impl Container for TextContainer {
fn apply(&mut self, op: &OpProxy, store: &LogStore) {
let new_op_id = op.id_last();
// TODO: may reduce following two into one op
let common = store.find_common_ancestor(&[new_op_id], &self.head);
let path_to_store_head = store.find_path(&common, &self.head);
let mut common_vv = self.vv.clone();
common_vv.retreat(&path_to_store_head.right);
let common_ancestors = store.find_common_ancestor(&[new_op_id], &self.head);
let path_to_head = store.find_path(&common_ancestors, &self.head);
let mut ancestors_vv = self.vv.clone();
ancestors_vv.retreat(&path_to_head.right);
let mut latest_head: SmallVec<[ID; 2]> = self.head.clone();
latest_head.push(new_op_id);
if common.is_empty() || !common.iter().all(|x| self.tracker.contains(*x)) {
self.tracker = Tracker::new(common_vv);
if common_ancestors.is_empty()
|| !common_ancestors.iter().all(|x| self.tracker.contains(*x))
{
self.tracker = Tracker::new(ancestors_vv);
} else {
self.tracker.checkout(&self.vv);
}
// stage 1
self.tracker.checkout(&self.vv);
let path = store.find_path(&common, &latest_head);
for iter in store.iter_partial(&common, path.right) {
let path = store.find_path(&common_ancestors, &latest_head);
for iter in store.iter_partial(&common_ancestors, path.right) {
self.tracker.retreat(&iter.retreat);
self.tracker.forward(&iter.forward);
// TODO: avoid this clone
@ -152,7 +159,12 @@ impl Container for TextContainer {
// stage 2
let path = store.find_path(&latest_head, &self.head);
self.tracker.retreat(&path.left);
// println!(
// "Iterate path: {:?} from {:?} => {:?}",
// path.left, &self.head, &latest_head
// );
for effect in self.tracker.iter_effects(path.left) {
// println!("{:?}", &effect);
match effect {
Effect::Del { pos, len } => self.state.delete_range(Some(pos), Some(pos + len)),
Effect::Ins { pos, content } => {
@ -163,6 +175,7 @@ impl Container for TextContainer {
self.head.push(new_op_id);
self.vv.set_last(new_op_id);
// println!("------------------------------------------------------------------------");
}
fn checkout_version(&mut self, _vv: &crate::VersionVector) {

View file

@ -77,11 +77,11 @@ impl Tracker {
Tracker {
content,
id_to_cursor,
start_vv,
#[cfg(feature = "fuzzing")]
client_id: 0,
head_vv: Default::default(),
all_vv: Default::default(),
head_vv: start_vv.clone(),
all_vv: start_vv.clone(),
start_vv,
}
}

View file

@ -45,33 +45,37 @@ impl<'a> Iterator for EffectIter<'a> {
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(ref mut delete_targets) = self.current_delete_targets {
let target = delete_targets.pop().unwrap();
let result = self
.tracker
.id_to_cursor
.get_first_cursors_at_id_span(target)
.unwrap();
let (id, cursor) = result.as_ins().unwrap();
assert_eq!(*id, target.id_start());
if cursor.len != target.len() {
delete_targets.push(IdSpan {
client_id: target.client_id,
counter: CounterSpan::new(
id.counter + cursor.len as Counter,
target.counter.end,
),
if let Some(target) = delete_targets.pop() {
let result = self
.tracker
.id_to_cursor
.get_first_cursors_at_id_span(target)
.unwrap();
let (id, cursor) = result.as_ins().unwrap();
assert_eq!(*id, target.id_start());
if cursor.len != target.len() {
let new_target = IdSpan {
client_id: target.client_id,
counter: CounterSpan::new(
id.counter + cursor.len as Counter,
target.counter.end,
),
};
if new_target.len() > 0 {
delete_targets.push(new_target);
}
}
// SAFETY: we know that the cursor is valid here
let pos = unsafe { cursor.get_index() };
let changed_len = self
.tracker
.update_cursors(smallvec![*cursor], StatusChange::Delete);
return Some(Effect::Del {
pos,
len: (-changed_len) as usize,
});
}
// SAFETY: we know that the cursor is valid here
let pos = unsafe { cursor.get_index() };
let changed_len = self
.tracker
.update_cursors(smallvec![*cursor], StatusChange::Delete);
return Some(Effect::Del {
pos,
len: (-changed_len) as usize,
});
}
if let Some(ref mut current) = self.current_span {

View file

@ -177,7 +177,7 @@ impl LogStore {
self.this_client_id
}
#[inline]
#[inline(always)]
pub fn frontier(&self) -> &[ID] {
&self.frontier
}
@ -299,6 +299,11 @@ impl LogStore {
pub(crate) fn iter_op(&self) -> iter::OpIter<'_> {
iter::OpIter::new(&self.changes)
}
#[inline(always)]
pub fn get_vv(&self) -> &VersionVector {
&self.vv
}
}
impl Dag for LogStore {

View file

@ -14,6 +14,7 @@ use crate::{
text::text_container::TextContainer,
ContainerID, ContainerType,
},
dag::DagUtils,
id::ClientID,
InternalString, LogStore, VersionVector,
};
@ -41,6 +42,10 @@ impl LoroCore {
}
}
pub fn vv(&self) -> VersionVector {
self.log_store.read().unwrap().get_vv().clone()
}
pub fn get_container(
&mut self,
name: InternalString,

View file

@ -22,6 +22,32 @@ fn test() {
let value = text_container.get_value();
let value = value.as_string().unwrap();
assert_eq!(value.as_str(), "0563412");
text_container.delete(0, 2);
text_container.insert(4, "789");
let value = text_container.get_value();
let value = value.as_string().unwrap();
assert_eq!(value.as_str(), "63417892");
drop(text_container);
store.import(store_b.export(store.vv()));
let mut text_container = store.get_text_container("haha".into());
let value = text_container.get_value();
let value = value.as_string().unwrap();
assert_eq!(value.as_str(), "63417892");
text_container.delete(0, 8);
text_container.insert(0, "abc");
let value = text_container.get_value();
let value = value.as_string().unwrap();
assert_eq!(value.as_str(), "abc");
drop(text_container);
store_b.import(store.export(Default::default()));
let mut text_container = store_b.get_text_container("haha".into());
text_container.check();
let value = text_container.get_value();
let value = value.as_string().unwrap();
assert_eq!(value.as_str(), "abc");
}
#[ctor]