diff --git a/crates/loro-internal/src/oplog.rs b/crates/loro-internal/src/oplog.rs index 7ab3abd4..420ceb40 100644 --- a/crates/loro-internal/src/oplog.rs +++ b/crates/loro-internal/src/oplog.rs @@ -177,7 +177,7 @@ impl std::fmt::Debug for OpLog { } } -pub(crate) struct EnsureChangeDepsAreAtTheEnd; +pub(crate) struct EnsureDagNodeDepsAreAtTheEnd; impl OpLog { #[inline] @@ -240,7 +240,7 @@ impl OpLog { } /// This is the **only** place to update the `OpLog.changes` - pub(crate) fn insert_new_change(&mut self, change: Change, _: EnsureChangeDepsAreAtTheEnd) { + pub(crate) fn insert_new_change(&mut self, change: Change, _: EnsureDagNodeDepsAreAtTheEnd) { self.op_groups.insert_by_change(&change); self.change_store.insert_change(change.clone()); self.register_container_and_parent_link(&change); @@ -291,7 +291,7 @@ impl OpLog { pub(crate) fn update_dag_on_new_change( &mut self, change: &Change, - ) -> EnsureChangeDepsAreAtTheEnd { + ) -> EnsureDagNodeDepsAreAtTheEnd { let len = change.content_len(); if change.deps_on_self() { // don't need to push new element to dag because it only depends on itself @@ -344,11 +344,19 @@ impl OpLog { let target = self.dag.get_mut(*dep).unwrap(); if target.ctr_last() == dep.counter { target.has_succ = true; + } else { + // We need to split the target node into two part + // so that we can ensure the new change depends on the + // last id of a dag node. + let new_node = + target.slice(dep.counter as usize - target.cnt as usize, target.len); + target.len -= new_node.len; + self.dag.map.insert(new_node.id_start(), new_node); } } } - EnsureChangeDepsAreAtTheEnd + EnsureDagNodeDepsAreAtTheEnd } /// Trim the known part of change diff --git a/crates/loro-internal/src/oplog/dag.rs b/crates/loro-internal/src/oplog/dag.rs index 9e6b4cad..177d8e4e 100644 --- a/crates/loro-internal/src/oplog/dag.rs +++ b/crates/loro-internal/src/oplog/dag.rs @@ -7,6 +7,7 @@ use crate::id::{Counter, ID}; use crate::span::{HasId, HasLamport}; use crate::version::{Frontiers, ImVersionVector, VersionVector}; use loro_common::{HasCounter, HasCounterSpan, HasIdSpan}; +use once_cell::sync::OnceCell; use rle::{HasIndex, HasLength, Mergable, Sliceable}; use super::{AppDag, AppDagNode}; @@ -28,8 +29,18 @@ impl Sliceable for AppDagNode { peer: self.peer, cnt: self.cnt + from as Counter, lamport: self.lamport + from as Lamport, - deps: Default::default(), - vv: Default::default(), + deps: if from > 0 { + Frontiers::from_id(self.id_start().inc(from as Counter - 1)) + } else { + self.deps.clone() + }, + vv: if let Some(vv) = self.vv.get() { + let mut new = vv.clone(); + new.insert(self.peer, self.cnt + from as Counter); + OnceCell::with_value(new) + } else { + OnceCell::new() + }, has_succ: if to == self.len { self.has_succ } else { true }, len: to - from, }