mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-22 12:57:20 +00:00
refactor: only keep counter on op
This commit is contained in:
parent
6e03c9c04b
commit
d62fa09e99
6 changed files with 77 additions and 46 deletions
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
log_store::LogStoreWeakRef,
|
log_store::LogStoreWeakRef,
|
||||||
op::{InsertContent, Op, RichOp},
|
op::{InsertContent, Op, RichOp},
|
||||||
op::{OpContent, RemoteOp},
|
op::{OpContent, RemoteOp},
|
||||||
span::{HasId, IdSpan},
|
span::IdSpan,
|
||||||
value::{InsertValue, LoroValue},
|
value::{InsertValue, LoroValue},
|
||||||
version::TotalOrderStamp,
|
version::TotalOrderStamp,
|
||||||
InternalString, LogStore,
|
InternalString, LogStore,
|
||||||
|
@ -57,7 +57,7 @@ impl MapContainer {
|
||||||
let counter = id.counter;
|
let counter = id.counter;
|
||||||
let container = store.get_container_idx(self_id).unwrap();
|
let container = store.get_container_idx(self_id).unwrap();
|
||||||
store.append_local_ops(&[Op {
|
store.append_local_ops(&[Op {
|
||||||
id,
|
counter: id.counter,
|
||||||
container,
|
container,
|
||||||
content: OpContent::Normal {
|
content: OpContent::Normal {
|
||||||
content: InsertContent::Dyn(Box::new(MapSet {
|
content: InsertContent::Dyn(Box::new(MapSet {
|
||||||
|
@ -109,7 +109,7 @@ impl Container for MapContainer {
|
||||||
let v: &MapSet = content.as_map().unwrap();
|
let v: &MapSet = content.as_map().unwrap();
|
||||||
let order = TotalOrderStamp {
|
let order = TotalOrderStamp {
|
||||||
lamport,
|
lamport,
|
||||||
client_id: op.id_start().client_id,
|
client_id: id_span.client_id,
|
||||||
};
|
};
|
||||||
if let Some(slot) = self.state.get_mut(&v.key) {
|
if let Some(slot) = self.state.get_mut(&v.key) {
|
||||||
if slot.order < order {
|
if slot.order < order {
|
||||||
|
@ -123,7 +123,7 @@ impl Container for MapContainer {
|
||||||
ValueSlot {
|
ValueSlot {
|
||||||
value: v.value.clone(),
|
value: v.value.clone(),
|
||||||
order,
|
order,
|
||||||
counter: op.id_start().counter,
|
counter: op.counter,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use rle::{rle_tree::tree_trait::CumulateTreeTrait, RleTree, Sliceable};
|
use rle::{rle_tree::tree_trait::CumulateTreeTrait, HasLength, RleTree, Sliceable};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
log_store::LogStoreWeakRef,
|
log_store::LogStoreWeakRef,
|
||||||
op::{InsertContent, Op, OpContent, RemoteOp},
|
op::{InsertContent, Op, OpContent, RemoteOp},
|
||||||
smstring::SmString,
|
smstring::SmString,
|
||||||
span::{HasIdSpan, IdSpan},
|
span::{HasCounter, HasCounterSpan, HasIdSpan, IdSpan},
|
||||||
value::LoroValue,
|
value::LoroValue,
|
||||||
LogStore, VersionVector,
|
LogStore, VersionVector,
|
||||||
};
|
};
|
||||||
|
@ -82,7 +82,10 @@ impl TextContainer {
|
||||||
},
|
},
|
||||||
store.get_or_create_container_idx(&self.id),
|
store.get_or_create_container_idx(&self.id),
|
||||||
);
|
);
|
||||||
let last_id = op.id_last();
|
let last_id = ID::new(
|
||||||
|
store.this_client_id,
|
||||||
|
op.counter + op.atom_len() as Counter - 1,
|
||||||
|
);
|
||||||
store.append_local_ops(&[op]);
|
store.append_local_ops(&[op]);
|
||||||
self.head = smallvec![last_id];
|
self.head = smallvec![last_id];
|
||||||
self.vv.set_last(last_id);
|
self.vv.set_last(last_id);
|
||||||
|
@ -106,7 +109,7 @@ impl TextContainer {
|
||||||
store.get_or_create_container_idx(&self.id),
|
store.get_or_create_container_idx(&self.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
let last_id = op.id_last();
|
let last_id = ID::new(store.this_client_id, op.ctr_last());
|
||||||
store.append_local_ops(&[op]);
|
store.append_local_ops(&[op]);
|
||||||
self.state.delete_range(Some(pos), Some(pos + len));
|
self.state.delete_range(Some(pos), Some(pos + len));
|
||||||
self.head = smallvec![last_id];
|
self.head = smallvec![last_id];
|
||||||
|
@ -198,7 +201,13 @@ impl Container for TextContainer {
|
||||||
for op in change.ops.iter() {
|
for op in change.ops.iter() {
|
||||||
if op.container == self_idx {
|
if op.container == self_idx {
|
||||||
// TODO: convert op to local
|
// TODO: convert op to local
|
||||||
self.tracker.apply(op.id, &op.content)
|
self.tracker.apply(
|
||||||
|
ID {
|
||||||
|
client_id: change.id.client_id,
|
||||||
|
counter: op.counter,
|
||||||
|
},
|
||||||
|
&op.content,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use crate::{
|
||||||
id::{ClientID, Counter},
|
id::{ClientID, Counter},
|
||||||
isomorph::{Irc, IsoRw, IsoWeak},
|
isomorph::{Irc, IsoRw, IsoWeak},
|
||||||
op::RemoteOp,
|
op::RemoteOp,
|
||||||
span::{HasIdSpan, HasLamportSpan, IdSpan},
|
span::{HasCounterSpan, HasIdSpan, HasLamportSpan, IdSpan},
|
||||||
Lamport, Op, Timestamp, VersionVector, ID,
|
Lamport, Op, Timestamp, VersionVector, ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -257,7 +257,9 @@ impl LogStore {
|
||||||
client_id: self.this_client_id,
|
client_id: self.this_client_id,
|
||||||
counter: self.get_next_counter(self.this_client_id),
|
counter: self.get_next_counter(self.this_client_id),
|
||||||
};
|
};
|
||||||
let last_id = ops.last().unwrap().id_last();
|
let last = ops.last().unwrap();
|
||||||
|
let last_ctr = last.ctr_last();
|
||||||
|
let last_id = ID::new(self.this_client_id, last_ctr);
|
||||||
let change = Change {
|
let change = Change {
|
||||||
id,
|
id,
|
||||||
deps: std::mem::replace(&mut self.frontier, smallvec::smallvec![last_id]),
|
deps: std::mem::replace(&mut self.frontier, smallvec::smallvec![last_id]),
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::Op;
|
use crate::Op;
|
||||||
|
|
||||||
use crate::change::Lamport;
|
use crate::change::Lamport;
|
||||||
use crate::container::ContainerID;
|
|
||||||
|
|
||||||
use crate::id::ClientID;
|
use crate::id::ClientID;
|
||||||
use crate::id::ContainerIdx;
|
use crate::id::ContainerIdx;
|
||||||
|
@ -93,7 +92,7 @@ impl<'a> Iterator for OpSpanIter<'a> {
|
||||||
|
|
||||||
return Some(RichOp {
|
return Some(RichOp {
|
||||||
op,
|
op,
|
||||||
lamport: (op.id.counter - change.id.counter) as Lamport + change.lamport,
|
lamport: (op.counter - change.id.counter) as Lamport + change.lamport,
|
||||||
timestamp: change.timestamp,
|
timestamp: change.timestamp,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
change::{Lamport, Timestamp},
|
change::{Lamport, Timestamp},
|
||||||
container::ContainerID,
|
container::ContainerID,
|
||||||
id::{Counter, ID},
|
id::{Counter, ID},
|
||||||
span::HasId,
|
span::HasCounter,
|
||||||
LogStore,
|
LogStore,
|
||||||
};
|
};
|
||||||
use rle::{HasIndex, HasLength, Mergable, Sliceable};
|
use rle::{HasIndex, HasLength, Mergable, Sliceable};
|
||||||
|
@ -31,14 +31,14 @@ pub enum OpType {
|
||||||
/// A Op may have multiple atomic operations, since Op can be merged.
|
/// A Op may have multiple atomic operations, since Op can be merged.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Op {
|
pub struct Op {
|
||||||
pub(crate) id: ID,
|
pub(crate) counter: Counter,
|
||||||
pub(crate) container: u32,
|
pub(crate) container: u32,
|
||||||
pub(crate) content: OpContent,
|
pub(crate) content: OpContent,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RemoteOp {
|
pub struct RemoteOp {
|
||||||
pub(crate) id: ID,
|
pub(crate) counter: Counter,
|
||||||
pub(crate) container: ContainerID,
|
pub(crate) container: ContainerID,
|
||||||
pub(crate) content: OpContent,
|
pub(crate) content: OpContent,
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ impl Op {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new(id: ID, content: OpContent, container: u32) -> Self {
|
pub(crate) fn new(id: ID, content: OpContent, container: u32) -> Self {
|
||||||
Op {
|
Op {
|
||||||
id,
|
counter: id.counter,
|
||||||
content,
|
content,
|
||||||
container,
|
container,
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ impl Op {
|
||||||
pub(crate) fn convert(self, log: &LogStore) -> RemoteOp {
|
pub(crate) fn convert(self, log: &LogStore) -> RemoteOp {
|
||||||
let container = log.get_container_id(self.container).clone();
|
let container = log.get_container_id(self.container).clone();
|
||||||
RemoteOp {
|
RemoteOp {
|
||||||
id: self.id,
|
counter: self.counter,
|
||||||
container,
|
container,
|
||||||
content: self.content,
|
content: self.content,
|
||||||
}
|
}
|
||||||
|
@ -78,11 +78,10 @@ impl Op {
|
||||||
|
|
||||||
impl RemoteOp {
|
impl RemoteOp {
|
||||||
pub(crate) fn convert(self, log: &mut LogStore) -> Op {
|
pub(crate) fn convert(self, log: &mut LogStore) -> Op {
|
||||||
let id = self.id;
|
|
||||||
let container = log.get_or_create_container_idx(&self.container);
|
let container = log.get_or_create_container_idx(&self.container);
|
||||||
let content = self.content;
|
let content = self.content;
|
||||||
Op {
|
Op {
|
||||||
id,
|
counter: self.counter,
|
||||||
container,
|
container,
|
||||||
content,
|
content,
|
||||||
}
|
}
|
||||||
|
@ -91,7 +90,7 @@ impl RemoteOp {
|
||||||
|
|
||||||
impl Mergable for Op {
|
impl Mergable for Op {
|
||||||
fn is_mergable(&self, other: &Self, cfg: &()) -> bool {
|
fn is_mergable(&self, other: &Self, cfg: &()) -> bool {
|
||||||
self.id.is_connected_id(&other.id, self.content_len())
|
self.counter + self.content_len() as Counter == other.counter
|
||||||
&& self.content.is_mergable(&other.content, cfg)
|
&& self.content.is_mergable(&other.content, cfg)
|
||||||
&& self.container == other.container
|
&& self.container == other.container
|
||||||
}
|
}
|
||||||
|
@ -135,10 +134,7 @@ impl Sliceable for Op {
|
||||||
assert!(to > from);
|
assert!(to > from);
|
||||||
let content: OpContent = self.content.slice(from, to);
|
let content: OpContent = self.content.slice(from, to);
|
||||||
Op {
|
Op {
|
||||||
id: ID {
|
counter: (self.counter + from as Counter),
|
||||||
client_id: self.id.client_id,
|
|
||||||
counter: (self.id.counter + from as Counter),
|
|
||||||
},
|
|
||||||
content,
|
content,
|
||||||
container: self.container.clone(),
|
container: self.container.clone(),
|
||||||
}
|
}
|
||||||
|
@ -147,7 +143,7 @@ impl Sliceable for Op {
|
||||||
|
|
||||||
impl Mergable for RemoteOp {
|
impl Mergable for RemoteOp {
|
||||||
fn is_mergable(&self, other: &Self, cfg: &()) -> bool {
|
fn is_mergable(&self, other: &Self, cfg: &()) -> bool {
|
||||||
self.id.is_connected_id(&other.id, self.content_len())
|
self.counter + self.content_len() as Counter == other.counter
|
||||||
&& self.content.is_mergable(&other.content, cfg)
|
&& self.content.is_mergable(&other.content, cfg)
|
||||||
&& self.container == other.container
|
&& self.container == other.container
|
||||||
}
|
}
|
||||||
|
@ -191,22 +187,13 @@ impl Sliceable for RemoteOp {
|
||||||
assert!(to > from);
|
assert!(to > from);
|
||||||
let content: OpContent = self.content.slice(from, to);
|
let content: OpContent = self.content.slice(from, to);
|
||||||
RemoteOp {
|
RemoteOp {
|
||||||
id: ID {
|
counter: (self.counter + from as Counter),
|
||||||
client_id: self.id.client_id,
|
|
||||||
counter: (self.id.counter + from as Counter),
|
|
||||||
},
|
|
||||||
content,
|
content,
|
||||||
container: self.container.clone(),
|
container: self.container.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasId for Op {
|
|
||||||
fn id_start(&self) -> ID {
|
|
||||||
self.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RichOp<'a> {
|
pub struct RichOp<'a> {
|
||||||
pub op: &'a Op,
|
pub op: &'a Op,
|
||||||
pub lamport: Lamport,
|
pub lamport: Lamport,
|
||||||
|
@ -217,7 +204,7 @@ impl HasIndex for Op {
|
||||||
type Int = Counter;
|
type Int = Counter;
|
||||||
|
|
||||||
fn get_start_index(&self) -> Self::Int {
|
fn get_start_index(&self) -> Self::Int {
|
||||||
self.id.counter
|
self.counter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +212,18 @@ impl HasIndex for RemoteOp {
|
||||||
type Int = Counter;
|
type Int = Counter;
|
||||||
|
|
||||||
fn get_start_index(&self) -> Self::Int {
|
fn get_start_index(&self) -> Self::Int {
|
||||||
self.id.counter
|
self.counter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasCounter for Op {
|
||||||
|
fn ctr_start(&self) -> Counter {
|
||||||
|
self.counter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasCounter for RemoteOp {
|
||||||
|
fn ctr_start(&self) -> Counter {
|
||||||
|
self.counter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,6 +218,36 @@ pub trait HasId {
|
||||||
fn id_start(&self) -> ID;
|
fn id_start(&self) -> ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HasCounter {
|
||||||
|
fn ctr_start(&self) -> Counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasCounterSpan: HasCounter + HasLength {
|
||||||
|
fn ctr_end(&self) -> Counter {
|
||||||
|
self.ctr_start() + self.atom_len() as Counter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ctr_last(&self) -> Counter {
|
||||||
|
self.ctr_start() + self.atom_len() as Counter - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ctr_span(&self) -> CounterSpan {
|
||||||
|
CounterSpan {
|
||||||
|
start: self.ctr_start(),
|
||||||
|
end: self.ctr_end(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HasCounter + HasLength> HasCounterSpan for T {}
|
||||||
|
|
||||||
|
impl<T: HasId> HasCounter for T {
|
||||||
|
#[inline]
|
||||||
|
fn ctr_start(&self) -> Counter {
|
||||||
|
self.id_start().counter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait HasIdSpan: HasId + HasLength {
|
pub trait HasIdSpan: HasId + HasLength {
|
||||||
fn intersect<T: HasIdSpan>(&self, other: &T) -> bool {
|
fn intersect<T: HasIdSpan>(&self, other: &T) -> bool {
|
||||||
let self_start = self.id_start();
|
let self_start = self.id_start();
|
||||||
|
@ -250,14 +280,6 @@ pub trait HasIdSpan: HasId + HasLength {
|
||||||
self.id_start().inc(self.content_len() as i32 - 1)
|
self.id_start().inc(self.content_len() as i32 - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ctr_last(&self) -> Counter {
|
|
||||||
self.id_start().counter + self.content_len() as i32 - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ctr_first(&self) -> Counter {
|
|
||||||
self.id_start().counter
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_id(&self, id: ID) -> bool {
|
fn contains_id(&self, id: ID) -> bool {
|
||||||
let id_start = self.id_start();
|
let id_start = self.id_start();
|
||||||
if id.client_id != id_start.client_id {
|
if id.client_id != id_start.client_id {
|
||||||
|
|
Loading…
Reference in a new issue