mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-23 13:39:12 +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;
|
mod checker;
|
||||||
pub mod pool_mapping;
|
pub mod pool_mapping;
|
||||||
pub mod registry;
|
pub mod registry;
|
||||||
pub mod temp;
|
|
||||||
|
|
||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
|
@ -199,7 +198,7 @@ pub trait ContainerTrait: Debug + Any + Unpin + Send + Sync {
|
||||||
hierarchy.unsubscribe(subscription);
|
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
|
/// [ContainerID] includes the Op's [ID] and the type. So it's impossible to have
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use fxhash::FxHashSet;
|
use fxhash::FxHashSet;
|
||||||
|
|
||||||
use crate::delta::DeltaItem;
|
|
||||||
use crate::{container::registry::ContainerIdx, InternalString, LoroError};
|
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,
|
/// [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.
|
/// 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> {
|
pub(crate) fn check_insert(&mut self, pos: usize, len: usize) -> Result<(), LoroError> {
|
||||||
let mut index = 0;
|
if pos > self.current_length {
|
||||||
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(
|
return Err(LoroError::TransactionError(
|
||||||
format!("`List-{:?}` index out of bounds: the len is {} but the index is {}", self.idx, self.current_length, len).into(),
|
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(())
|
||||||
}
|
}
|
||||||
DeltaItem::Delete(l) => {
|
|
||||||
if index + *l > self.current_length {
|
pub(crate) fn check_delete(&mut self, pos: usize, len: usize) -> Result<(), LoroError> {
|
||||||
|
if pos > self.current_length {
|
||||||
return Err(LoroError::TransactionError(
|
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(),
|
format!(
|
||||||
|
"`ContainerIdx-{:?}` index out of bounds: the len is {} but the index is {}",
|
||||||
|
self.idx, self.current_length, pos
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
self.current_length -= *l;
|
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(),
|
||||||
}
|
));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.current_length -= len;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
impl MapChecker {
|
impl MapChecker {
|
||||||
pub(crate) fn new(idx: ContainerIdx, keys: FxHashSet<InternalString>) -> Self {
|
pub(crate) fn new(idx: ContainerIdx, keys: FxHashSet<InternalString>) -> Self {
|
||||||
Self { idx, keys }
|
Self { idx, keys }
|
||||||
|
@ -127,7 +86,7 @@ impl MapChecker {
|
||||||
keys: Default::default(),
|
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.extend(ops.added.keys().cloned());
|
||||||
self.keys.retain(|k| !ops.deleted.contains(k));
|
self.keys.retain(|k| !ops.deleted.contains(k));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -9,20 +9,19 @@ use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
container::{
|
container::{
|
||||||
|
checker::ListChecker,
|
||||||
list::list_op::ListOp,
|
list::list_op::ListOp,
|
||||||
pool,
|
pool,
|
||||||
pool_mapping::{PoolMapping, StateContent},
|
pool_mapping::{PoolMapping, StateContent},
|
||||||
registry::{
|
registry::{
|
||||||
ContainerIdx, ContainerInner, ContainerInstance, ContainerRegistry, ContainerWrapper,
|
ContainerIdx, ContainerInner, ContainerInstance, ContainerRegistry, ContainerWrapper,
|
||||||
},
|
},
|
||||||
temp::ContainerTemp,
|
|
||||||
text::{
|
text::{
|
||||||
text_content::{ListSlice, SliceRange},
|
text_content::{ListSlice, SliceRange},
|
||||||
tracker::{Effect, Tracker},
|
tracker::{Effect, Tracker},
|
||||||
},
|
},
|
||||||
ContainerID, ContainerTrait, ContainerType,
|
ContainerID, ContainerTrait, ContainerType,
|
||||||
},
|
},
|
||||||
context::Context,
|
|
||||||
delta::{Delta, DeltaItem},
|
delta::{Delta, DeltaItem},
|
||||||
event::{Diff, Index},
|
event::{Diff, Index},
|
||||||
hierarchy::Hierarchy,
|
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 index = 0;
|
||||||
let mut ops = Vec::new();
|
let mut ops = Vec::new();
|
||||||
let id = store.next_id();
|
let id = store.next_id();
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for item in op.items() {
|
for item in op.inner() {
|
||||||
// TODO avoid clone
|
let item = item.into_event_format();
|
||||||
let item = item.clone().into_event_format();
|
|
||||||
match item {
|
match item {
|
||||||
DeltaItem::Retain { len, .. } => index += len,
|
DeltaItem::Retain { len, .. } => index += len,
|
||||||
DeltaItem::Insert { value, .. } => {
|
DeltaItem::Insert { value, .. } => {
|
||||||
|
@ -482,8 +480,8 @@ impl ContainerTrait for ListContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
let op = op.as_list().unwrap().1;
|
let op = op.list_inner();
|
||||||
self.apply_txn_op_impl(store, op)
|
self.apply_txn_op_impl(store, op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,6 +491,7 @@ pub struct List {
|
||||||
container: ContainerInner,
|
container: ContainerInner,
|
||||||
client_id: ClientID,
|
client_id: ClientID,
|
||||||
container_idx: ContainerIdx,
|
container_idx: ContainerIdx,
|
||||||
|
checker: ListChecker,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl List {
|
impl List {
|
||||||
|
@ -500,19 +499,25 @@ impl List {
|
||||||
instance: Weak<Mutex<ContainerInstance>>,
|
instance: Weak<Mutex<ContainerInstance>>,
|
||||||
client_id: ClientID,
|
client_id: ClientID,
|
||||||
) -> Self {
|
) -> 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 {
|
Self {
|
||||||
container: ContainerInner::from(instance),
|
container: ContainerInner::from(instance),
|
||||||
client_id,
|
client_id,
|
||||||
container_idx,
|
container_idx,
|
||||||
|
checker: ListChecker::new(container_idx, current_length),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
|
pub(crate) fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
|
||||||
Self {
|
Self {
|
||||||
container: ContainerInner::from(ContainerTemp::new(idx, ContainerType::List)),
|
container: ContainerInner::from(idx),
|
||||||
client_id,
|
client_id,
|
||||||
container_idx: idx,
|
container_idx: idx,
|
||||||
|
checker: ListChecker::from_idx(idx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,15 +533,14 @@ impl List {
|
||||||
pos: usize,
|
pos: usize,
|
||||||
value: P,
|
value: P,
|
||||||
) -> Result<Option<Container>, LoroError> {
|
) -> Result<Option<Container>, LoroError> {
|
||||||
|
self.checker.check_insert(pos, 1)?;
|
||||||
self.with_transaction_checked(txn, |txn, _x| {
|
self.with_transaction_checked(txn, |txn, _x| {
|
||||||
let (value, maybe_container) = value.convert_value()?;
|
let (value, maybe_container) = value.convert_value()?;
|
||||||
if let Some(prelim) = maybe_container {
|
if let Some(prelim) = maybe_container {
|
||||||
let type_ = value.into_container().unwrap();
|
let type_ = value.into_container().unwrap();
|
||||||
let idx = txn.next_container_idx();
|
let idx = txn.next_container_idx();
|
||||||
txn.push(
|
let op = TransactionOp::insert_list_container(self.idx(), pos, type_, idx);
|
||||||
TransactionOp::insert_list_container(self.idx(), pos, type_, idx),
|
txn.push(op, Some(idx))?;
|
||||||
Some(idx),
|
|
||||||
)?;
|
|
||||||
prelim.integrate(txn, idx)?;
|
prelim.integrate(txn, idx)?;
|
||||||
let container = match type_ {
|
let container = match type_ {
|
||||||
ContainerType::List => Container::from(List::from_idx(idx, self.client_id)),
|
ContainerType::List => Container::from(List::from_idx(idx, self.client_id)),
|
||||||
|
@ -562,6 +566,7 @@ impl List {
|
||||||
pos: usize,
|
pos: usize,
|
||||||
values: Vec<LoroValue>,
|
values: Vec<LoroValue>,
|
||||||
) -> Result<(), LoroError> {
|
) -> Result<(), LoroError> {
|
||||||
|
self.checker.check_insert(pos, values.len())?;
|
||||||
self.with_transaction_checked(txn, |txn, _| {
|
self.with_transaction_checked(txn, |txn, _| {
|
||||||
txn.push(
|
txn.push(
|
||||||
TransactionOp::insert_list_batch_value(self.idx(), pos, values),
|
TransactionOp::insert_list_batch_value(self.idx(), pos, values),
|
||||||
|
@ -608,6 +613,7 @@ impl List {
|
||||||
pos: usize,
|
pos: usize,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<(), LoroError> {
|
) -> Result<(), LoroError> {
|
||||||
|
self.checker.check_delete(pos, len)?;
|
||||||
self.with_transaction_checked(txn, |txn, _x| {
|
self.with_transaction_checked(txn, |txn, _x| {
|
||||||
txn.push(TransactionOp::delete_list(self.idx(), pos, len), None)
|
txn.push(TransactionOp::delete_list(self.idx(), pos, len), None)
|
||||||
})?
|
})?
|
||||||
|
@ -631,10 +637,7 @@ impl List {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
match &self.container {
|
self.checker.current_length
|
||||||
ContainerInner::Instance(_) => self.with_container(|x| x.values_len()).unwrap(),
|
|
||||||
ContainerInner::Temp(temp) => temp.as_list().unwrap().len(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn for_each<F: FnMut((usize, &LoroValue))>(&self, f: F) {
|
// pub fn for_each<F: FnMut((usize, &LoroValue))>(&self, f: F) {
|
||||||
|
|
|
@ -5,7 +5,6 @@ use crate::{
|
||||||
container::{
|
container::{
|
||||||
pool_mapping::{MapPoolMapping, StateContent},
|
pool_mapping::{MapPoolMapping, StateContent},
|
||||||
registry::{ContainerIdx, ContainerInner, ContainerRegistry},
|
registry::{ContainerIdx, ContainerInner, ContainerRegistry},
|
||||||
temp::ContainerTemp,
|
|
||||||
},
|
},
|
||||||
delta::MapDiff,
|
delta::MapDiff,
|
||||||
id::ID,
|
id::ID,
|
||||||
|
@ -97,8 +96,7 @@ impl MapContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_txn_op_impl(&mut self, store: &mut LogStore, ops: &MapTxnOps) -> Vec<Op> {
|
fn apply_txn_op_impl(&mut self, store: &mut LogStore, ops: MapTxnOps) -> Vec<Op> {
|
||||||
let ops = ops.clone();
|
|
||||||
let mut store_ops = Vec::with_capacity(ops.added.len() + ops.deleted.len());
|
let mut store_ops = Vec::with_capacity(ops.added.len() + ops.deleted.len());
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
let id = store.next_id();
|
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) {
|
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> {
|
fn apply_txn_op(&mut self, store: &mut LogStore, op: TransactionOp) -> Vec<Op> {
|
||||||
let op = op.as_map().unwrap().1;
|
let op = op.map_inner();
|
||||||
self.apply_txn_op_impl(store, op)
|
self.apply_txn_op_impl(store, op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,7 +419,7 @@ impl Map {
|
||||||
|
|
||||||
pub(crate) fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
|
pub(crate) fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
|
||||||
Self {
|
Self {
|
||||||
container: ContainerInner::from(ContainerTemp::new(idx, ContainerType::Map)),
|
container: ContainerInner::from(idx),
|
||||||
client_id,
|
client_id,
|
||||||
container_idx: idx,
|
container_idx: idx,
|
||||||
}
|
}
|
||||||
|
@ -486,7 +485,7 @@ impl Map {
|
||||||
pub fn keys(&self) -> Vec<InternalString> {
|
pub fn keys(&self) -> Vec<InternalString> {
|
||||||
match &self.container {
|
match &self.container {
|
||||||
ContainerInner::Instance(_) => self.with_container(|x| x.keys()).unwrap(),
|
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 {
|
pub fn len(&self) -> usize {
|
||||||
match &self.container {
|
match &self.container {
|
||||||
ContainerInner::Instance(_) => self.with_container(|x| x.len()).unwrap(),
|
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::{
|
use super::{
|
||||||
list::ListContainer, map::MapContainer, pool_mapping::StateContent, temp::ContainerTemp,
|
list::ListContainer, map::MapContainer, pool_mapping::StateContent, text::TextContainer,
|
||||||
text::TextContainer, ContainerID, ContainerTrait, ContainerType,
|
ContainerID, ContainerTrait, ContainerType,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, EnumAsInner)]
|
#[derive(Debug, Clone, EnumAsInner)]
|
||||||
pub enum ContainerInner {
|
pub enum ContainerInner {
|
||||||
Instance(Weak<Mutex<ContainerInstance>>),
|
Instance(Weak<Mutex<ContainerInstance>>),
|
||||||
Temp(ContainerTemp),
|
Temp(ContainerIdx),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContainerInner {
|
impl ContainerInner {
|
||||||
pub fn idx(&self) -> ContainerIdx {
|
pub fn idx(&self) -> ContainerIdx {
|
||||||
match self {
|
match self {
|
||||||
ContainerInner::Instance(i) => i.upgrade().unwrap().try_lock().unwrap().idx(),
|
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 {
|
impl From<ContainerIdx> for ContainerInner {
|
||||||
fn from(value: ContainerTemp) -> Self {
|
fn from(value: ContainerIdx) -> Self {
|
||||||
Self::Temp(value)
|
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 {
|
match self {
|
||||||
ContainerInstance::List(x) => x.apply_txn_op(store, op),
|
ContainerInstance::List(x) => x.apply_txn_op(store, op),
|
||||||
ContainerInstance::Map(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::{
|
use crate::{
|
||||||
container::{
|
container::{
|
||||||
|
checker::ListChecker,
|
||||||
list::list_op::{InnerListOp, ListOp},
|
list::list_op::{InnerListOp, ListOp},
|
||||||
pool_mapping::{PoolMapping, StateContent},
|
pool_mapping::{PoolMapping, StateContent},
|
||||||
registry::{ContainerIdx, ContainerInner, ContainerInstance, ContainerWrapper},
|
registry::{ContainerIdx, ContainerInner, ContainerInstance, ContainerWrapper},
|
||||||
temp::ContainerTemp,
|
|
||||||
ContainerID, ContainerTrait, ContainerType,
|
ContainerID, ContainerTrait, ContainerType,
|
||||||
},
|
},
|
||||||
delta::{Delta, DeltaItem},
|
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 index = 0;
|
||||||
let mut ops = Vec::new();
|
let mut ops = Vec::new();
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
let id = store.next_id();
|
let id = store.next_id();
|
||||||
for item in op.items() {
|
for item in op.inner() {
|
||||||
match item {
|
match item {
|
||||||
DeltaItem::Retain { len, .. } => index += len,
|
DeltaItem::Retain { len, .. } => index += len,
|
||||||
DeltaItem::Insert { value, .. } => {
|
DeltaItem::Insert { value, .. } => {
|
||||||
let len = value.len();
|
let len = value.len();
|
||||||
let id = id.inc(offset);
|
let id = id.inc(offset);
|
||||||
offset += len as i32;
|
offset += len as i32;
|
||||||
let op = self.apply_insert(index, value, id);
|
let op = self.apply_insert(index, &value, id);
|
||||||
index += len;
|
index += len;
|
||||||
ops.push(op);
|
ops.push(op);
|
||||||
}
|
}
|
||||||
DeltaItem::Delete(len) => {
|
DeltaItem::Delete(len) => {
|
||||||
let id = id.inc(offset);
|
let id = id.inc(offset);
|
||||||
offset += *len as i32;
|
offset += len as i32;
|
||||||
let op = self.apply_delete(index, *len, id);
|
let op = self.apply_delete(index, len, id);
|
||||||
ops.push(op);
|
ops.push(op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,8 +450,8 @@ impl ContainerTrait for TextContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
let op = op.as_text().unwrap().1;
|
let op = op.text_inner();
|
||||||
self.apply_txn_op_impl(store, op)
|
self.apply_txn_op_impl(store, op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,23 +461,31 @@ pub struct Text {
|
||||||
container: ContainerInner,
|
container: ContainerInner,
|
||||||
client_id: ClientID,
|
client_id: ClientID,
|
||||||
container_idx: ContainerIdx,
|
container_idx: ContainerIdx,
|
||||||
|
// TODO: use text checker
|
||||||
|
checker: ListChecker,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Text {
|
impl Text {
|
||||||
pub fn from_instance(instance: Weak<Mutex<ContainerInstance>>, client_id: ClientID) -> Self {
|
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 {
|
Self {
|
||||||
container: ContainerInner::from(instance),
|
container: ContainerInner::from(instance),
|
||||||
client_id,
|
client_id,
|
||||||
container_idx,
|
container_idx,
|
||||||
|
checker: ListChecker::new(container_idx, current_length),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
|
pub fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
|
||||||
Self {
|
Self {
|
||||||
container: ContainerInner::from(ContainerTemp::new(idx, ContainerType::Text)),
|
container: ContainerInner::from(idx),
|
||||||
client_id,
|
client_id,
|
||||||
container_idx: idx,
|
container_idx: idx,
|
||||||
|
checker: ListChecker::from_idx(idx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,6 +510,7 @@ impl Text {
|
||||||
if text.is_empty() {
|
if text.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
self.checker.check_insert(pos, text.len())?;
|
||||||
self.with_transaction_checked(txn, |txn, _| {
|
self.with_transaction_checked(txn, |txn, _| {
|
||||||
txn.push(TransactionOp::insert_text(self.idx(), pos, text), None)
|
txn.push(TransactionOp::insert_text(self.idx(), pos, text), None)
|
||||||
})?
|
})?
|
||||||
|
@ -522,10 +531,11 @@ impl Text {
|
||||||
pos: usize,
|
pos: usize,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<(), crate::LoroError> {
|
) -> Result<(), crate::LoroError> {
|
||||||
self.with_transaction_checked(txn, |txn, _| {
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
self.checker.check_delete(pos, len)?;
|
||||||
|
self.with_transaction_checked(txn, |txn, _| {
|
||||||
txn.push(TransactionOp::delete_text(self.idx(), pos, len), None)
|
txn.push(TransactionOp::delete_text(self.idx(), pos, len), None)
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
@ -555,7 +565,8 @@ impl Text {
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
// TODO
|
// TODO
|
||||||
self.with_container(|x| x.text_len()).unwrap()
|
// self.with_container(|x| x.text_len()).unwrap()
|
||||||
|
self.checker.current_length
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
|
@ -8,7 +8,7 @@ use enum_as_inner::EnumAsInner;
|
||||||
|
|
||||||
use rle::{
|
use rle::{
|
||||||
range_map::RangeMap,
|
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,
|
HasLength, Mergable, RleVecWithLen, Sliceable, ZeroElement,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,10 +195,10 @@ impl Mergable for Marker {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(super) struct CursorMap(RangeMap<u128, Marker, BumpMode>);
|
pub(super) struct CursorMap(RangeMap<u128, Marker, HeapMode>);
|
||||||
|
|
||||||
impl Deref for CursorMap {
|
impl Deref for CursorMap {
|
||||||
type Target = RangeMap<u128, Marker, BumpMode>;
|
type Target = RangeMap<u128, Marker, HeapMode>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
|
|
|
@ -7,12 +7,12 @@ use crate::{
|
||||||
ContentType, InsertContentTrait, ID,
|
ContentType, InsertContentTrait, ID,
|
||||||
};
|
};
|
||||||
use rle::{
|
use rle::{
|
||||||
rle_tree::{tree_trait::CumulateTreeTrait, BumpMode},
|
rle_tree::{tree_trait::CumulateTreeTrait, HeapMode},
|
||||||
HasLength, Mergable, Sliceable,
|
HasLength, Mergable, Sliceable,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_CHILDREN_SIZE: usize = 16;
|
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
|
/// 80 bytes
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crdt_list::{
|
||||||
use fxhash::FxHashSet;
|
use fxhash::FxHashSet;
|
||||||
use rle::{
|
use rle::{
|
||||||
range_map::{RangeMap, WithStartEnd},
|
range_map::{RangeMap, WithStartEnd},
|
||||||
rle_tree::{iter::IterMut, node::LeafNode, BumpMode, SafeCursorMut},
|
rle_tree::{iter::IterMut, node::LeafNode, HeapMode, SafeCursorMut},
|
||||||
HasLength,
|
HasLength,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use tabled::{TableIteratorExt, Tabled};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
array_mut_ref,
|
array_mut_ref,
|
||||||
container::{temp::ContainerTemp, ContainerID},
|
container::ContainerID,
|
||||||
delta::DeltaItem,
|
delta::DeltaItem,
|
||||||
event::{Diff, Observer},
|
event::{Diff, Observer},
|
||||||
id::ClientID,
|
id::ClientID,
|
||||||
|
|
|
@ -79,7 +79,13 @@ impl Actor {
|
||||||
let root_value = Arc::clone(&actor.value_tracker);
|
let root_value = Arc::clone(&actor.value_tracker);
|
||||||
actor.loro.subscribe_deep(Box::new(move |event| {
|
actor.loro.subscribe_deep(Box::new(move |event| {
|
||||||
let mut root_value = root_value.lock().unwrap();
|
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);
|
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();
|
let log_store = actor.loro.log_store.write().unwrap();
|
||||||
|
@ -1312,31 +1318,33 @@ mod failed_tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_slice_err() {
|
fn failed() {
|
||||||
test_multi_sites(
|
test_multi_sites(
|
||||||
5,
|
5,
|
||||||
&mut [
|
&mut [
|
||||||
Text {
|
Map {
|
||||||
site: 2,
|
site: 0,
|
||||||
container_idx: 0,
|
container_idx: 0,
|
||||||
pos: 0,
|
key: 0,
|
||||||
value: 39064,
|
value: Container(C::Text),
|
||||||
is_del: false,
|
|
||||||
},
|
},
|
||||||
Sync { from: 2, to: 3 },
|
Map {
|
||||||
Text {
|
site: 4,
|
||||||
site: 2,
|
|
||||||
container_idx: 0,
|
container_idx: 0,
|
||||||
pos: 2,
|
key: 0,
|
||||||
value: 39064,
|
value: I32(-2021161081),
|
||||||
is_del: false,
|
|
||||||
},
|
},
|
||||||
Text {
|
Map {
|
||||||
site: 2,
|
site: 0,
|
||||||
container_idx: 0,
|
container_idx: 0,
|
||||||
pos: 0,
|
key: 255,
|
||||||
value: 39064,
|
value: Container(C::List),
|
||||||
is_del: false,
|
},
|
||||||
|
List {
|
||||||
|
site: 0,
|
||||||
|
container_idx: 1,
|
||||||
|
key: 0,
|
||||||
|
value: I32(1),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -1348,84 +1356,600 @@ mod failed_tests {
|
||||||
minify_error(
|
minify_error(
|
||||||
5,
|
5,
|
||||||
vec![
|
vec![
|
||||||
Text {
|
Map {
|
||||||
site: 2,
|
site: 0,
|
||||||
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,
|
|
||||||
container_idx: 0,
|
container_idx: 0,
|
||||||
key: 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,
|
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
|
// TODO: using the one with fewer changes to import
|
||||||
Ok(changes_ans)
|
Ok(changes_ans)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
container::{registry::ContainerIdx, temp::ContainerTemp, ContainerID},
|
container::{registry::ContainerIdx, ContainerID},
|
||||||
context::Context,
|
context::Context,
|
||||||
event::{ObserverHandler, RawEvent},
|
event::{ObserverHandler, RawEvent},
|
||||||
hierarchy::Hierarchy,
|
hierarchy::Hierarchy,
|
||||||
|
|
|
@ -121,60 +121,59 @@ impl Transaction {
|
||||||
let mut events = Vec::with_capacity(compressed_op.len());
|
let mut events = Vec::with_capacity(compressed_op.len());
|
||||||
for op in compressed_op {
|
for op in compressed_op {
|
||||||
let idx = op.container_idx();
|
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 = store.reg.get_by_idx(&idx).unwrap();
|
||||||
let container = container.upgrade().unwrap();
|
let container = container.upgrade().unwrap();
|
||||||
let mut container = container.try_lock().unwrap();
|
let mut container = container.try_lock().unwrap();
|
||||||
let container_id = container.id().clone();
|
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);
|
drop(container);
|
||||||
let (old_version, new_version) = store.append_local_ops(&store_ops);
|
let (old_version, new_version) = store.append_local_ops(&store_ops);
|
||||||
let new_version = new_version.into();
|
let new_version = new_version.into();
|
||||||
let event = if hierarchy.should_notify(&container_id) {
|
let event = if hierarchy.should_notify(&container_id) {
|
||||||
match type_ {
|
match type_ {
|
||||||
ContainerType::List => {
|
ContainerType::List => hierarchy
|
||||||
let delta = op.into_list().unwrap().1.into_event_format();
|
|
||||||
hierarchy
|
|
||||||
.get_abs_path(&store.reg, &container_id)
|
.get_abs_path(&store.reg, &container_id)
|
||||||
.map(|abs_path| RawEvent {
|
.map(|abs_path| RawEvent {
|
||||||
container_id,
|
container_id,
|
||||||
old_version,
|
old_version,
|
||||||
new_version,
|
new_version,
|
||||||
diff: vec![Diff::List(delta)],
|
diff,
|
||||||
local: true,
|
local: true,
|
||||||
abs_path,
|
abs_path,
|
||||||
})
|
}),
|
||||||
}
|
ContainerType::Text => hierarchy
|
||||||
ContainerType::Text => {
|
|
||||||
let delta = op.into_text().unwrap().1;
|
|
||||||
hierarchy
|
|
||||||
.get_abs_path(&store.reg, &container_id)
|
.get_abs_path(&store.reg, &container_id)
|
||||||
.map(|abs_path| RawEvent {
|
.map(|abs_path| RawEvent {
|
||||||
container_id,
|
container_id,
|
||||||
old_version,
|
old_version,
|
||||||
new_version,
|
new_version,
|
||||||
diff: vec![Diff::Text(delta)],
|
diff,
|
||||||
local: true,
|
local: true,
|
||||||
abs_path,
|
abs_path,
|
||||||
})
|
}),
|
||||||
}
|
ContainerType::Map => hierarchy
|
||||||
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)
|
.get_abs_path(&store.reg, &container_id)
|
||||||
.map(|abs_path| RawEvent {
|
.map(|abs_path| RawEvent {
|
||||||
container_id,
|
container_id,
|
||||||
old_version,
|
old_version,
|
||||||
new_version,
|
new_version,
|
||||||
diff: vec![Diff::Map(delta)],
|
diff,
|
||||||
local: true,
|
local: true,
|
||||||
abs_path,
|
abs_path,
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
Loading…
Reference in a new issue