From 4f5f809bb63cf59fa39613f7d351406ec77f0918 Mon Sep 17 00:00:00 2001 From: leeeon233 Date: Tue, 7 Mar 2023 10:49:24 +0800 Subject: [PATCH] fix: remove temp, add checker fix: map lamport order --- crates/loro-internal/src/container.rs | 3 +- crates/loro-internal/src/container/checker.rs | 105 +-- .../src/container/list/list_container.rs | 39 +- .../src/container/map/map_container.rs | 15 +- .../loro-internal/src/container/registry.rs | 14 +- crates/loro-internal/src/container/temp.rs | 101 --- .../src/container/text/text_container.rs | 39 +- .../src/container/text/tracker/cursor_map.rs | 6 +- .../src/container/text/tracker/y_span.rs | 4 +- .../src/container/text/tracker/yata_impl.rs | 2 +- crates/loro-internal/src/fuzz/recursive.rs | 2 +- .../loro-internal/src/fuzz/recursive_txn.rs | 710 +++++++++++++++--- .../src/log_store/encoding/encode_changes.rs | 4 +- crates/loro-internal/src/loro.rs | 2 +- crates/loro-internal/src/transaction.rs | 89 ++- 15 files changed, 765 insertions(+), 370 deletions(-) delete mode 100644 crates/loro-internal/src/container/temp.rs diff --git a/crates/loro-internal/src/container.rs b/crates/loro-internal/src/container.rs index 91186f22..a652624b 100644 --- a/crates/loro-internal/src/container.rs +++ b/crates/loro-internal/src/container.rs @@ -29,7 +29,6 @@ use self::{pool_mapping::StateContent, registry::ContainerIdx}; mod checker; pub mod pool_mapping; pub mod registry; -pub mod temp; pub mod list; pub mod map; @@ -199,7 +198,7 @@ pub trait ContainerTrait: Debug + Any + Unpin + Send + Sync { hierarchy.unsubscribe(subscription); } - fn apply_txn_op(&mut self, store: &mut LogStore, op: &TransactionOp) -> Vec; + fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec; } /// [ContainerID] includes the Op's [ID] and the type. So it's impossible to have diff --git a/crates/loro-internal/src/container/checker.rs b/crates/loro-internal/src/container/checker.rs index 8d10e705..40e8e83c 100644 --- a/crates/loro-internal/src/container/checker.rs +++ b/crates/loro-internal/src/container/checker.rs @@ -1,9 +1,8 @@ use fxhash::FxHashSet; -use crate::delta::DeltaItem; use crate::{container::registry::ContainerIdx, InternalString, LoroError}; -use crate::transaction::op::{ListTxnOps, MapTxnOps, TextTxnOps}; +use crate::transaction::op::MapTxnOps; /// [ListChecker] maintains the length of all list container during one transaction, /// when a op is be inserted, it will check whether the position or the length of deletion is valid. @@ -41,81 +40,41 @@ impl ListChecker { } } - pub(crate) fn check(&mut self, ops: &ListTxnOps) -> Result<(), LoroError> { - let mut index = 0; - for op in ops.items() { - match op { - DeltaItem::Insert { value, .. } => { - index += value.len(); - self.current_length += value.len() - } - DeltaItem::Retain { len, .. } => { - index += len; - if *len > self.current_length { - return Err(LoroError::TransactionError( - format!("`List-{:?}` index out of bounds: the len is {} but the index is {}", self.idx, self.current_length, len).into(), - )); - } - } - DeltaItem::Delete(l) => { - if index + *l > self.current_length { - return Err(LoroError::TransactionError( - format!("`List-{:?}` can not apply delete op: the current len is {} but the delete range is {:?}", self.idx, self.current_length, index..index+*l).into(), - )); - } - self.current_length -= *l; - } - } - } - Ok(()) - } -} - -impl TextChecker { - pub(crate) fn new(idx: ContainerIdx, current_length: usize) -> Self { - Self { - idx, - current_length, - } - } - - pub(crate) fn from_idx(idx: ContainerIdx) -> Self { - Self { - idx, - current_length: 0, - } - } - pub(crate) fn check(&mut self, ops: &TextTxnOps) -> Result<(), LoroError> { - // TODO utf-16 - let mut index = 0; - for op in ops.items() { - match op { - DeltaItem::Insert { value, .. } => { - index += value.len(); - self.current_length += value.len() - } - DeltaItem::Retain { len, .. } => { - index += len; - if *len > self.current_length { - return Err(LoroError::TransactionError( - format!("`Text-{:?}` index out of bounds: the len is {} but the index is {}", self.idx, self.current_length, len).into(), - )); - } - } - DeltaItem::Delete(l) => { - if index + *l > self.current_length { - return Err(LoroError::TransactionError( - format!("`Text-{:?}` can not apply delete op: the current len is {} but the delete range is {:?}", self.idx, self.current_length, index..index+*l).into(), - )); - } - self.current_length -= *l; - } - } + pub(crate) fn check_insert(&mut self, pos: usize, len: usize) -> Result<(), LoroError> { + if pos > self.current_length { + return Err(LoroError::TransactionError( + format!( + "`ContainerIdx-{:?}` index out of bounds: the len is {} but the index is {}", + self.idx, self.current_length, pos + ) + .into(), + )); } + self.current_length += len; + Ok(()) + } + + pub(crate) fn check_delete(&mut self, pos: usize, len: usize) -> Result<(), LoroError> { + if pos > self.current_length { + return Err(LoroError::TransactionError( + format!( + "`ContainerIdx-{:?}` index out of bounds: the len is {} but the index is {}", + self.idx, self.current_length, pos + ) + .into(), + )); + } + if pos + len > self.current_length { + return Err(LoroError::TransactionError( + format!("`ContainerIdx-{:?}` can not apply delete op: the current len is {} but the delete range is {:?}", self.idx, self.current_length, pos..pos+len).into(), + )); + } + self.current_length -= len; Ok(()) } } +// TODO impl MapChecker { pub(crate) fn new(idx: ContainerIdx, keys: FxHashSet) -> Self { Self { idx, keys } @@ -127,7 +86,7 @@ impl MapChecker { keys: Default::default(), } } - pub(crate) fn check(&mut self, ops: &MapTxnOps) -> Result<(), LoroError> { + pub(crate) fn check_insert(&mut self, ops: &MapTxnOps) -> Result<(), LoroError> { self.keys.extend(ops.added.keys().cloned()); self.keys.retain(|k| !ops.deleted.contains(k)); Ok(()) diff --git a/crates/loro-internal/src/container/list/list_container.rs b/crates/loro-internal/src/container/list/list_container.rs index 332bec6b..a96f102b 100644 --- a/crates/loro-internal/src/container/list/list_container.rs +++ b/crates/loro-internal/src/container/list/list_container.rs @@ -9,20 +9,19 @@ use smallvec::SmallVec; use crate::{ container::{ + checker::ListChecker, list::list_op::ListOp, pool, pool_mapping::{PoolMapping, StateContent}, registry::{ ContainerIdx, ContainerInner, ContainerInstance, ContainerRegistry, ContainerWrapper, }, - temp::ContainerTemp, text::{ text_content::{ListSlice, SliceRange}, tracker::{Effect, Tracker}, }, ContainerID, ContainerTrait, ContainerType, }, - context::Context, delta::{Delta, DeltaItem}, event::{Diff, Index}, hierarchy::Hierarchy, @@ -62,14 +61,13 @@ impl ListContainer { } } - fn apply_txn_op_impl(&mut self, store: &mut LogStore, op: &ListTxnOps) -> Vec { + fn apply_txn_op_impl(&mut self, store: &mut LogStore, op: ListTxnOps) -> Vec { let mut index = 0; let mut ops = Vec::new(); let id = store.next_id(); let mut offset = 0; - for item in op.items() { - // TODO avoid clone - let item = item.clone().into_event_format(); + for item in op.inner() { + let item = item.into_event_format(); match item { DeltaItem::Retain { len, .. } => index += len, DeltaItem::Insert { value, .. } => { @@ -482,8 +480,8 @@ impl ContainerTrait for ListContainer { } } - fn apply_txn_op(&mut self, store: &mut LogStore, op: &TransactionOp) -> Vec { - let op = op.as_list().unwrap().1; + fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec { + let op = op.list_inner(); self.apply_txn_op_impl(store, op) } } @@ -493,6 +491,7 @@ pub struct List { container: ContainerInner, client_id: ClientID, container_idx: ContainerIdx, + checker: ListChecker, } impl List { @@ -500,19 +499,25 @@ impl List { instance: Weak>, client_id: ClientID, ) -> Self { - let container_idx = instance.upgrade().unwrap().try_lock().unwrap().idx(); + let (container_idx, current_length) = { + let list = instance.upgrade().unwrap(); + let list = list.try_lock().unwrap(); + (list.idx(), list.as_list().unwrap().values_len()) + }; Self { container: ContainerInner::from(instance), client_id, container_idx, + checker: ListChecker::new(container_idx, current_length), } } pub(crate) fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self { Self { - container: ContainerInner::from(ContainerTemp::new(idx, ContainerType::List)), + container: ContainerInner::from(idx), client_id, container_idx: idx, + checker: ListChecker::from_idx(idx), } } @@ -528,15 +533,14 @@ impl List { pos: usize, value: P, ) -> Result, LoroError> { + self.checker.check_insert(pos, 1)?; self.with_transaction_checked(txn, |txn, _x| { let (value, maybe_container) = value.convert_value()?; if let Some(prelim) = maybe_container { let type_ = value.into_container().unwrap(); let idx = txn.next_container_idx(); - txn.push( - TransactionOp::insert_list_container(self.idx(), pos, type_, idx), - Some(idx), - )?; + let op = TransactionOp::insert_list_container(self.idx(), pos, type_, idx); + txn.push(op, Some(idx))?; prelim.integrate(txn, idx)?; let container = match type_ { ContainerType::List => Container::from(List::from_idx(idx, self.client_id)), @@ -562,6 +566,7 @@ impl List { pos: usize, values: Vec, ) -> Result<(), LoroError> { + self.checker.check_insert(pos, values.len())?; self.with_transaction_checked(txn, |txn, _| { txn.push( TransactionOp::insert_list_batch_value(self.idx(), pos, values), @@ -608,6 +613,7 @@ impl List { pos: usize, len: usize, ) -> Result<(), LoroError> { + self.checker.check_delete(pos, len)?; self.with_transaction_checked(txn, |txn, _x| { txn.push(TransactionOp::delete_list(self.idx(), pos, len), None) })? @@ -631,10 +637,7 @@ impl List { } pub fn len(&self) -> usize { - match &self.container { - ContainerInner::Instance(_) => self.with_container(|x| x.values_len()).unwrap(), - ContainerInner::Temp(temp) => temp.as_list().unwrap().len(), - } + self.checker.current_length } // pub fn for_each(&self, f: F) { diff --git a/crates/loro-internal/src/container/map/map_container.rs b/crates/loro-internal/src/container/map/map_container.rs index 058281bb..1c18dea1 100644 --- a/crates/loro-internal/src/container/map/map_container.rs +++ b/crates/loro-internal/src/container/map/map_container.rs @@ -5,7 +5,6 @@ use crate::{ container::{ pool_mapping::{MapPoolMapping, StateContent}, registry::{ContainerIdx, ContainerInner, ContainerRegistry}, - temp::ContainerTemp, }, delta::MapDiff, id::ID, @@ -97,8 +96,7 @@ impl MapContainer { } } - fn apply_txn_op_impl(&mut self, store: &mut LogStore, ops: &MapTxnOps) -> Vec { - let ops = ops.clone(); + fn apply_txn_op_impl(&mut self, store: &mut LogStore, ops: MapTxnOps) -> Vec { let mut store_ops = Vec::with_capacity(ops.added.len() + ops.deleted.len()); let mut offset = 0; let id = store.next_id(); @@ -295,6 +293,7 @@ impl ContainerTrait for MapContainer { }, ); } + println!(""); } fn track_apply(&mut self, _: &mut Hierarchy, op: &RichOp, _: &mut ImportContext) { @@ -392,8 +391,8 @@ impl ContainerTrait for MapContainer { } } - fn apply_txn_op(&mut self, store: &mut LogStore, op: &TransactionOp) -> Vec { - let op = op.as_map().unwrap().1; + fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec { + let op = op.map_inner(); self.apply_txn_op_impl(store, op) } } @@ -420,7 +419,7 @@ impl Map { pub(crate) fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self { Self { - container: ContainerInner::from(ContainerTemp::new(idx, ContainerType::Map)), + container: ContainerInner::from(idx), client_id, container_idx: idx, } @@ -486,7 +485,7 @@ impl Map { pub fn keys(&self) -> Vec { match &self.container { ContainerInner::Instance(_) => self.with_container(|x| x.keys()).unwrap(), - ContainerInner::Temp(temp) => temp.as_map().unwrap().keys(), + ContainerInner::Temp(idx) => unimplemented!(), } } @@ -521,7 +520,7 @@ impl Map { pub fn len(&self) -> usize { match &self.container { ContainerInner::Instance(_) => self.with_container(|x| x.len()).unwrap(), - ContainerInner::Temp(temp) => temp.as_map().unwrap().len(), + ContainerInner::Temp(idx) => unimplemented!(), } } diff --git a/crates/loro-internal/src/container/registry.rs b/crates/loro-internal/src/container/registry.rs index b912c6ea..033a4f8b 100644 --- a/crates/loro-internal/src/container/registry.rs +++ b/crates/loro-internal/src/container/registry.rs @@ -26,21 +26,21 @@ use crate::{ }; use super::{ - list::ListContainer, map::MapContainer, pool_mapping::StateContent, temp::ContainerTemp, - text::TextContainer, ContainerID, ContainerTrait, ContainerType, + list::ListContainer, map::MapContainer, pool_mapping::StateContent, text::TextContainer, + ContainerID, ContainerTrait, ContainerType, }; #[derive(Debug, Clone, EnumAsInner)] pub enum ContainerInner { Instance(Weak>), - Temp(ContainerTemp), + Temp(ContainerIdx), } impl ContainerInner { pub fn idx(&self) -> ContainerIdx { match self { ContainerInner::Instance(i) => i.upgrade().unwrap().try_lock().unwrap().idx(), - ContainerInner::Temp(t) => t.idx(), + ContainerInner::Temp(idx) => *idx, } } } @@ -51,8 +51,8 @@ impl From>> for ContainerInner { } } -impl From for ContainerInner { - fn from(value: ContainerTemp) -> Self { +impl From for ContainerInner { + fn from(value: ContainerIdx) -> Self { Self::Temp(value) } } @@ -245,7 +245,7 @@ impl ContainerTrait for ContainerInstance { } } - fn apply_txn_op(&mut self, store: &mut LogStore, op: &TransactionOp) -> Vec { + fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec { match self { ContainerInstance::List(x) => x.apply_txn_op(store, op), ContainerInstance::Map(x) => x.apply_txn_op(store, op), diff --git a/crates/loro-internal/src/container/temp.rs b/crates/loro-internal/src/container/temp.rs deleted file mode 100644 index 3a3c0fbb..00000000 --- a/crates/loro-internal/src/container/temp.rs +++ /dev/null @@ -1,101 +0,0 @@ -use enum_as_inner::EnumAsInner; -use fxhash::FxHashSet; - -use crate::{ContainerType, InternalString}; - -use super::{ - checker::{ListChecker, MapChecker, TextChecker}, - registry::ContainerIdx, -}; - -#[derive(Debug, Clone, EnumAsInner)] -pub enum ContainerTemp { - List(ListTemp), - Map(MapTemp), - Text(TextTemp), -} - -impl ContainerTemp { - pub(crate) fn new(idx: ContainerIdx, type_: ContainerType) -> Self { - match type_ { - ContainerType::List => Self::List(ListTemp::from_idx(idx)), - ContainerType::Map => Self::Map(MapTemp::from_idx(idx)), - ContainerType::Text => Self::Text(TextTemp::from_idx(idx)), - } - } - - pub fn idx(&self) -> ContainerIdx { - match self { - ContainerTemp::List(x) => x.idx, - ContainerTemp::Map(x) => x.idx, - ContainerTemp::Text(x) => x.idx, - } - } - - pub fn type_(&self) -> ContainerType { - match self { - ContainerTemp::List(_) => ContainerType::List, - ContainerTemp::Map(_) => ContainerType::Map, - ContainerTemp::Text(_) => ContainerType::Text, - } - } -} - -#[derive(Debug, Clone)] -pub struct ListTemp { - idx: ContainerIdx, - checker: ListChecker, -} - -#[derive(Debug, Clone)] -pub struct MapTemp { - idx: ContainerIdx, - checker: MapChecker, -} - -#[derive(Debug, Clone)] -pub struct TextTemp { - idx: ContainerIdx, - checker: TextChecker, -} - -impl ListTemp { - fn from_idx(idx: ContainerIdx) -> Self { - ListTemp { - idx, - checker: ListChecker::from_idx(idx), - } - } - - pub(crate) fn len(&self) -> usize { - self.checker.current_length - } -} - -impl MapTemp { - fn from_idx(idx: ContainerIdx) -> Self { - MapTemp { - idx, - checker: MapChecker::from_idx(idx), - } - } - pub(crate) fn keys(&self) -> Vec { - self.checker.keys.iter().cloned().collect() - } - - pub(crate) fn len(&self) -> usize { - self.checker.keys.len() - } -} - -impl TextTemp { - fn from_idx(idx: ContainerIdx) -> Self { - TextTemp { - idx, - checker: TextChecker::from_idx(idx), - } - } - pub(crate) fn len(&self) -> usize { - self.checker.current_length - } -} diff --git a/crates/loro-internal/src/container/text/text_container.rs b/crates/loro-internal/src/container/text/text_container.rs index a2b4963e..3c2cf3d5 100644 --- a/crates/loro-internal/src/container/text/text_container.rs +++ b/crates/loro-internal/src/container/text/text_container.rs @@ -7,10 +7,10 @@ use tracing::instrument; use crate::{ container::{ + checker::ListChecker, list::list_op::{InnerListOp, ListOp}, pool_mapping::{PoolMapping, StateContent}, registry::{ContainerIdx, ContainerInner, ContainerInstance, ContainerWrapper}, - temp::ContainerTemp, ContainerID, ContainerTrait, ContainerType, }, delta::{Delta, DeltaItem}, @@ -54,26 +54,26 @@ impl TextContainer { } } - pub(crate) fn apply_txn_op_impl(&mut self, store: &mut LogStore, op: &TextTxnOps) -> Vec { + pub(crate) fn apply_txn_op_impl(&mut self, store: &mut LogStore, op: TextTxnOps) -> Vec { let mut index = 0; let mut ops = Vec::new(); let mut offset = 0; let id = store.next_id(); - for item in op.items() { + for item in op.inner() { match item { DeltaItem::Retain { len, .. } => index += len, DeltaItem::Insert { value, .. } => { let len = value.len(); let id = id.inc(offset); offset += len as i32; - let op = self.apply_insert(index, value, id); + let op = self.apply_insert(index, &value, id); index += len; ops.push(op); } DeltaItem::Delete(len) => { let id = id.inc(offset); - offset += *len as i32; - let op = self.apply_delete(index, *len, id); + offset += len as i32; + let op = self.apply_delete(index, len, id); ops.push(op); } } @@ -450,8 +450,8 @@ impl ContainerTrait for TextContainer { } } - fn apply_txn_op(&mut self, store: &mut LogStore, op: &TransactionOp) -> Vec { - let op = op.as_text().unwrap().1; + fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec { + let op = op.text_inner(); self.apply_txn_op_impl(store, op) } } @@ -461,23 +461,31 @@ pub struct Text { container: ContainerInner, client_id: ClientID, container_idx: ContainerIdx, + // TODO: use text checker + checker: ListChecker, } impl Text { pub fn from_instance(instance: Weak>, client_id: ClientID) -> Self { - let container_idx = instance.upgrade().unwrap().try_lock().unwrap().idx(); + let (container_idx, current_length) = { + let x = instance.upgrade().unwrap(); + let x = x.try_lock().unwrap(); + (x.idx(), x.as_text().unwrap().text_len()) + }; Self { container: ContainerInner::from(instance), client_id, container_idx, + checker: ListChecker::new(container_idx, current_length), } } pub fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self { Self { - container: ContainerInner::from(ContainerTemp::new(idx, ContainerType::Text)), + container: ContainerInner::from(idx), client_id, container_idx: idx, + checker: ListChecker::from_idx(idx), } } @@ -502,6 +510,7 @@ impl Text { if text.is_empty() { return Ok(()); } + self.checker.check_insert(pos, text.len())?; self.with_transaction_checked(txn, |txn, _| { txn.push(TransactionOp::insert_text(self.idx(), pos, text), None) })? @@ -522,10 +531,11 @@ impl Text { pos: usize, len: usize, ) -> Result<(), crate::LoroError> { + if len == 0 { + return Ok(()); + } + self.checker.check_delete(pos, len)?; self.with_transaction_checked(txn, |txn, _| { - if len == 0 { - return Ok(()); - } txn.push(TransactionOp::delete_text(self.idx(), pos, len), None) })? } @@ -555,7 +565,8 @@ impl Text { pub fn len(&self) -> usize { // TODO - self.with_container(|x| x.text_len()).unwrap() + // self.with_container(|x| x.text_len()).unwrap() + self.checker.current_length } #[must_use] diff --git a/crates/loro-internal/src/container/text/tracker/cursor_map.rs b/crates/loro-internal/src/container/text/tracker/cursor_map.rs index ff029d04..6de28ddf 100644 --- a/crates/loro-internal/src/container/text/tracker/cursor_map.rs +++ b/crates/loro-internal/src/container/text/tracker/cursor_map.rs @@ -8,7 +8,7 @@ use enum_as_inner::EnumAsInner; use rle::{ range_map::RangeMap, - rle_tree::{node::LeafNode, BumpMode, Position, SafeCursor, SafeCursorMut, UnsafeCursor}, + rle_tree::{node::LeafNode, HeapMode, Position, SafeCursor, SafeCursorMut, UnsafeCursor}, HasLength, Mergable, RleVecWithLen, Sliceable, ZeroElement, }; @@ -195,10 +195,10 @@ impl Mergable for Marker { } #[derive(Debug, Default)] -pub(super) struct CursorMap(RangeMap); +pub(super) struct CursorMap(RangeMap); impl Deref for CursorMap { - type Target = RangeMap; + type Target = RangeMap; fn deref(&self) -> &Self::Target { &self.0 diff --git a/crates/loro-internal/src/container/text/tracker/y_span.rs b/crates/loro-internal/src/container/text/tracker/y_span.rs index d2558da5..0db3a8a3 100644 --- a/crates/loro-internal/src/container/text/tracker/y_span.rs +++ b/crates/loro-internal/src/container/text/tracker/y_span.rs @@ -7,12 +7,12 @@ use crate::{ ContentType, InsertContentTrait, ID, }; use rle::{ - rle_tree::{tree_trait::CumulateTreeTrait, BumpMode}, + rle_tree::{tree_trait::CumulateTreeTrait, HeapMode}, HasLength, Mergable, Sliceable, }; const MAX_CHILDREN_SIZE: usize = 16; -pub(super) type YSpanTreeTrait = CumulateTreeTrait; +pub(super) type YSpanTreeTrait = CumulateTreeTrait; /// 80 bytes #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/loro-internal/src/container/text/tracker/yata_impl.rs b/crates/loro-internal/src/container/text/tracker/yata_impl.rs index bbf29f19..81963b86 100644 --- a/crates/loro-internal/src/container/text/tracker/yata_impl.rs +++ b/crates/loro-internal/src/container/text/tracker/yata_impl.rs @@ -8,7 +8,7 @@ use crdt_list::{ use fxhash::FxHashSet; use rle::{ range_map::{RangeMap, WithStartEnd}, - rle_tree::{iter::IterMut, node::LeafNode, BumpMode, SafeCursorMut}, + rle_tree::{iter::IterMut, node::LeafNode, HeapMode, SafeCursorMut}, HasLength, }; diff --git a/crates/loro-internal/src/fuzz/recursive.rs b/crates/loro-internal/src/fuzz/recursive.rs index 7e98c56e..7d324c58 100644 --- a/crates/loro-internal/src/fuzz/recursive.rs +++ b/crates/loro-internal/src/fuzz/recursive.rs @@ -11,7 +11,7 @@ use tabled::{TableIteratorExt, Tabled}; use crate::{ array_mut_ref, - container::{temp::ContainerTemp, ContainerID}, + container::ContainerID, delta::DeltaItem, event::{Diff, Observer}, id::ClientID, diff --git a/crates/loro-internal/src/fuzz/recursive_txn.rs b/crates/loro-internal/src/fuzz/recursive_txn.rs index 7c114184..21a683e9 100644 --- a/crates/loro-internal/src/fuzz/recursive_txn.rs +++ b/crates/loro-internal/src/fuzz/recursive_txn.rs @@ -79,7 +79,13 @@ impl Actor { let root_value = Arc::clone(&actor.value_tracker); actor.loro.subscribe_deep(Box::new(move |event| { let mut root_value = root_value.lock().unwrap(); + if id == 0 { + println!("event {:?}\n\nvalue {:?}", event, root_value); + } root_value.apply(&event.relative_path, &event.diff); + if id == 0 { + println!("after value {:?}\n", root_value); + } })); let log_store = actor.loro.log_store.write().unwrap(); @@ -1312,31 +1318,33 @@ mod failed_tests { } #[test] - fn list_slice_err() { + fn failed() { test_multi_sites( 5, &mut [ - Text { - site: 2, + Map { + site: 0, container_idx: 0, - pos: 0, - value: 39064, - is_del: false, + key: 0, + value: Container(C::Text), }, - Sync { from: 2, to: 3 }, - Text { - site: 2, + Map { + site: 4, container_idx: 0, - pos: 2, - value: 39064, - is_del: false, + key: 0, + value: I32(-2021161081), }, - Text { - site: 2, + Map { + site: 0, container_idx: 0, - pos: 0, - value: 39064, - is_del: false, + key: 255, + value: Container(C::List), + }, + List { + site: 0, + container_idx: 1, + key: 0, + value: I32(1), }, ], ) @@ -1348,84 +1356,600 @@ mod failed_tests { minify_error( 5, vec![ - Text { - site: 2, - container_idx: 0, - pos: 0, - value: 39064, - is_del: false, - }, - Text { - site: 2, - container_idx: 0, - pos: 5, - value: 152, - is_del: false, - }, - Sync { from: 2, to: 3 }, - Text { - site: 3, - container_idx: 0, - pos: 10, - value: 2, - is_del: true, - }, - Text { - site: 2, - container_idx: 0, - pos: 0, - value: 39064, - is_del: false, - }, - Sync { from: 2, to: 3 }, - Text { - site: 2, - container_idx: 0, - pos: 16, - value: 39064, - is_del: false, - }, - Text { - site: 2, - container_idx: 0, - pos: 8, - value: 39064, - is_del: false, - }, - Text { - site: 2, - container_idx: 0, - pos: 28, - value: 39064, - is_del: false, - }, - Text { - site: 2, - container_idx: 0, - pos: 0, - value: 39064, - is_del: false, - }, - Text { - site: 2, - container_idx: 0, - pos: 41, - value: 45232, - is_del: false, - }, - Sync { from: 1, to: 2 }, - Text { - site: 2, - container_idx: 0, - pos: 48, - value: 39064, - is_del: false, - }, - List { - site: 1, + Map { + site: 0, container_idx: 0, key: 0, - value: I32(-1734829928), + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Container(C::Text), + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 14, + container_idx: 14, + key: 0, + value: I32(-2021161081), + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Sync { from: 5, to: 0 }, + Map { + site: 0, + container_idx: 0, + key: 170, + value: I32(10), + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 14, + container_idx: 14, + key: 14, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 14, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 92, + value: Null, + }, + Map { + site: 255, + container_idx: 255, + key: 255, + value: Container(C::List), + }, + List { + site: 255, + container_idx: 255, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 4, + container_idx: 4, + key: 4, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 4, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Container(C::Text), + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, + }, + Map { + site: 0, + container_idx: 0, + key: 0, + value: Null, }, ], test_multi_sites, diff --git a/crates/loro-internal/src/log_store/encoding/encode_changes.rs b/crates/loro-internal/src/log_store/encoding/encode_changes.rs index 869c921d..6207fe30 100644 --- a/crates/loro-internal/src/log_store/encoding/encode_changes.rs +++ b/crates/loro-internal/src/log_store/encoding/encode_changes.rs @@ -379,7 +379,9 @@ pub(super) fn decode_changes_to_inner_format( } } } - + if store.this_client_id == 0 && changes_ans.len()==1{ + println!("################################"); + } // TODO: using the one with fewer changes to import Ok(changes_ans) } diff --git a/crates/loro-internal/src/loro.rs b/crates/loro-internal/src/loro.rs index 4dd89d12..92478f16 100644 --- a/crates/loro-internal/src/loro.rs +++ b/crates/loro-internal/src/loro.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Mutex, RwLock}; use crate::{ - container::{registry::ContainerIdx, temp::ContainerTemp, ContainerID}, + container::{registry::ContainerIdx, ContainerID}, context::Context, event::{ObserverHandler, RawEvent}, hierarchy::Hierarchy, diff --git a/crates/loro-internal/src/transaction.rs b/crates/loro-internal/src/transaction.rs index 79ede1e6..4f3894e0 100644 --- a/crates/loro-internal/src/transaction.rs +++ b/crates/loro-internal/src/transaction.rs @@ -121,60 +121,59 @@ impl Transaction { let mut events = Vec::with_capacity(compressed_op.len()); for op in compressed_op { let idx = op.container_idx(); + let type_ = op.container_type(); + // TODO: diff remove vec! + let diff = vec![match type_ { + ContainerType::List => { + Diff::List(op.as_list().unwrap().1.clone().into_event_format()) + } + ContainerType::Map => { + let container = store.reg.get_by_idx(&idx).unwrap(); + let map = Map::from_instance(container, store.this_client_id); + Diff::Map(op.as_map().unwrap().1.clone().into_event_format(&map)) + } + ContainerType::Text => Diff::Text(op.as_text().unwrap().1.clone()), + }]; let container = store.reg.get_by_idx(&idx).unwrap(); let container = container.upgrade().unwrap(); let mut container = container.try_lock().unwrap(); let container_id = container.id().clone(); - let type_ = container_id.container_type(); - let store_ops = container.apply_txn_op(store, &op); + let store_ops = container.apply_txn_op(store, op); drop(container); let (old_version, new_version) = store.append_local_ops(&store_ops); let new_version = new_version.into(); let event = if hierarchy.should_notify(&container_id) { match type_ { - ContainerType::List => { - let delta = op.into_list().unwrap().1.into_event_format(); - hierarchy - .get_abs_path(&store.reg, &container_id) - .map(|abs_path| RawEvent { - container_id, - old_version, - new_version, - diff: vec![Diff::List(delta)], - local: true, - abs_path, - }) - } - ContainerType::Text => { - let delta = op.into_text().unwrap().1; - hierarchy - .get_abs_path(&store.reg, &container_id) - .map(|abs_path| RawEvent { - container_id, - old_version, - new_version, - diff: vec![Diff::Text(delta)], - local: true, - abs_path, - }) - } - ContainerType::Map => { - let delta = { - let map = store.get_container(&container_id).unwrap(); - let map = Map::from_instance(map, store.this_client_id); - op.into_map().unwrap().1.into_event_format(&map) - }; - hierarchy - .get_abs_path(&store.reg, &container_id) - .map(|abs_path| RawEvent { - container_id, - old_version, - new_version, - diff: vec![Diff::Map(delta)], - local: true, - abs_path, - }) - } + ContainerType::List => hierarchy + .get_abs_path(&store.reg, &container_id) + .map(|abs_path| RawEvent { + container_id, + old_version, + new_version, + diff, + local: true, + abs_path, + }), + ContainerType::Text => hierarchy + .get_abs_path(&store.reg, &container_id) + .map(|abs_path| RawEvent { + container_id, + old_version, + new_version, + diff, + local: true, + abs_path, + }), + ContainerType::Map => hierarchy + .get_abs_path(&store.reg, &container_id) + .map(|abs_path| RawEvent { + container_id, + old_version, + new_version, + diff, + local: true, + abs_path, + }), } } else { None