fix: remove temp, add checker

fix: map lamport order
This commit is contained in:
leeeon233 2023-03-07 10:49:24 +08:00
parent 707fdc5b55
commit 4f5f809bb6
15 changed files with 765 additions and 370 deletions

View file

@ -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<Op>;
fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec<Op>;
}
/// [ContainerID] includes the Op's [ID] and the type. So it's impossible to have

View file

@ -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<InternalString>) -> 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(())

View file

@ -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<Op> {
fn apply_txn_op_impl(&mut self, store: &mut LogStore, op: ListTxnOps) -> Vec<Op> {
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<Op> {
let op = op.as_list().unwrap().1;
fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec<Op> {
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<Mutex<ContainerInstance>>,
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<Option<Container>, 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<LoroValue>,
) -> 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<F: FnMut((usize, &LoroValue))>(&self, f: F) {

View file

@ -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<Op> {
let ops = ops.clone();
fn apply_txn_op_impl(&mut self, store: &mut LogStore, ops: MapTxnOps) -> Vec<Op> {
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<Op> {
let op = op.as_map().unwrap().1;
fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec<Op> {
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<InternalString> {
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!(),
}
}

View file

@ -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<Mutex<ContainerInstance>>),
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<Weak<Mutex<ContainerInstance>>> for ContainerInner {
}
}
impl From<ContainerTemp> for ContainerInner {
fn from(value: ContainerTemp) -> Self {
impl From<ContainerIdx> 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<Op> {
fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec<Op> {
match self {
ContainerInstance::List(x) => x.apply_txn_op(store, op),
ContainerInstance::Map(x) => x.apply_txn_op(store, op),

View file

@ -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<InternalString> {
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
}
}

View file

@ -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<Op> {
pub(crate) fn apply_txn_op_impl(&mut self, store: &mut LogStore, op: TextTxnOps) -> Vec<Op> {
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<Op> {
let op = op.as_text().unwrap().1;
fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec<Op> {
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<Mutex<ContainerInstance>>, 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]

View file

@ -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<u128, Marker, BumpMode>);
pub(super) struct CursorMap(RangeMap<u128, Marker, HeapMode>);
impl Deref for CursorMap {
type Target = RangeMap<u128, Marker, BumpMode>;
type Target = RangeMap<u128, Marker, HeapMode>;
fn deref(&self) -> &Self::Target {
&self.0

View file

@ -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<YSpan, MAX_CHILDREN_SIZE, BumpMode>;
pub(super) type YSpanTreeTrait = CumulateTreeTrait<YSpan, MAX_CHILDREN_SIZE, HeapMode>;
/// 80 bytes
#[derive(Debug, Clone, PartialEq, Eq)]

View file

@ -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,
};

View file

@ -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,

View file

@ -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,

View file

@ -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)
}

View file

@ -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,

View file

@ -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