mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-23 05:24:51 +00:00
fix: remove temp, add checker
fix: map lamport order
This commit is contained in:
parent
707fdc5b55
commit
4f5f809bb6
15 changed files with 765 additions and 370 deletions
|
@ -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
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue