mirror of
https://github.com/loro-dev/loro.git
synced 2025-02-06 04:19:34 +00:00
refactor: reduce tracker mem usage by using nonmax id (#282)
This commit is contained in:
parent
cadde3cb55
commit
06e3a5420d
5 changed files with 72 additions and 22 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -778,6 +778,7 @@ dependencies = [
|
|||
"fxhash",
|
||||
"js-sys",
|
||||
"loro-rle",
|
||||
"nonmax",
|
||||
"serde",
|
||||
"serde_columnar",
|
||||
"string_cache",
|
||||
|
@ -939,6 +940,12 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "nonmax"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51"
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.1"
|
||||
|
|
|
@ -23,6 +23,7 @@ string_cache = "0.8"
|
|||
arbitrary = { version = "1.3.0", features = ["derive"] }
|
||||
js-sys = { version = "0.3.60", optional = true }
|
||||
serde_columnar = "0.3.3"
|
||||
nonmax = "0.5.5"
|
||||
|
||||
[features]
|
||||
wasm = ["wasm-bindgen", "js-sys"]
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::{fmt::Display, sync::Arc};
|
|||
use arbitrary::Arbitrary;
|
||||
use enum_as_inner::EnumAsInner;
|
||||
|
||||
use nonmax::NonMaxI32;
|
||||
use serde::{Deserialize, Serialize};
|
||||
mod error;
|
||||
mod id;
|
||||
|
@ -32,6 +33,41 @@ pub struct ID {
|
|||
pub counter: Counter,
|
||||
}
|
||||
|
||||
/// It's the unique ID of an Op represented by [PeerID] and [Counter].
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct CompactId {
|
||||
pub peer: PeerID,
|
||||
pub counter: NonMaxI32,
|
||||
}
|
||||
|
||||
impl CompactId {
|
||||
pub fn new(peer: PeerID, counter: Counter) -> Self {
|
||||
Self {
|
||||
peer,
|
||||
counter: NonMaxI32::new(counter).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_id(&self) -> ID {
|
||||
ID {
|
||||
peer: self.peer,
|
||||
counter: self.counter.get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ID> for CompactId {
|
||||
type Error = ID;
|
||||
|
||||
fn try_from(id: ID) -> Result<Self, ID> {
|
||||
if id.counter == i32::MAX {
|
||||
return Err(id);
|
||||
}
|
||||
|
||||
Ok(Self::new(id.peer, id.counter))
|
||||
}
|
||||
}
|
||||
|
||||
/// It's the unique ID of an Op represented by [PeerID] and [Lamport] clock.
|
||||
/// It's used to define the total order of Ops.
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use generic_btree::rle::{HasLength, Mergeable, Sliceable};
|
||||
use loro_common::{Counter, HasId, IdFull, IdSpan, Lamport, ID};
|
||||
use loro_common::{CompactId, Counter, HasId, IdFull, IdSpan, Lamport, ID};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::AnchorType;
|
||||
|
@ -176,8 +176,8 @@ pub(super) struct FugueSpan {
|
|||
/// The status at the `new` version.
|
||||
/// It's used when calculating diff.
|
||||
pub diff_status: Option<Status>,
|
||||
pub origin_left: Option<ID>,
|
||||
pub origin_right: Option<ID>,
|
||||
pub origin_left: Option<CompactId>,
|
||||
pub origin_right: Option<CompactId>,
|
||||
pub content: RichtextChunk,
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,13 @@ impl Sliceable for FugueSpan {
|
|||
origin_left: if range.start == 0 {
|
||||
self.origin_left
|
||||
} else {
|
||||
Some(self.id.inc((range.start - 1) as Counter).id())
|
||||
Some(
|
||||
self.id
|
||||
.inc((range.start - 1) as Counter)
|
||||
.id()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
)
|
||||
},
|
||||
origin_right: self.origin_right,
|
||||
content: self.content._slice(range),
|
||||
|
@ -247,7 +253,7 @@ impl Mergeable for FugueSpan {
|
|||
&& self.id.lamport + self.content.len() as Lamport == rhs.id.lamport
|
||||
&& rhs.origin_left.is_some()
|
||||
&& rhs.origin_left.unwrap().peer == self.id.peer
|
||||
&& rhs.origin_left.unwrap().counter
|
||||
&& rhs.origin_left.unwrap().counter.get()
|
||||
== self.id.counter + self.content.len() as Counter - 1
|
||||
&& self.origin_right == rhs.origin_right
|
||||
&& self.content.can_merge(&rhs.content)
|
||||
|
|
|
@ -109,7 +109,7 @@ impl CrdtRope {
|
|||
}
|
||||
_ => {
|
||||
// Otherwise, we need to test whether origin_right's origin_left == this.origin_left
|
||||
if iter.elem.origin_left == origin_left {
|
||||
if iter.elem.origin_left.map(|x| x.to_id()) == origin_left {
|
||||
Some(origin_right)
|
||||
} else {
|
||||
None
|
||||
|
@ -127,8 +127,8 @@ impl CrdtRope {
|
|||
(origin_right, parent_right_idx, in_between)
|
||||
};
|
||||
|
||||
content.origin_left = origin_left;
|
||||
content.origin_right = origin_right;
|
||||
content.origin_left = origin_left.map(|x| x.try_into().unwrap());
|
||||
content.origin_right = origin_right.map(|x| x.try_into().unwrap());
|
||||
(parent_right_leaf, in_between)
|
||||
};
|
||||
|
||||
|
@ -144,7 +144,7 @@ impl CrdtRope {
|
|||
let other_origin_left = other_elem.origin_left;
|
||||
if other_origin_left != content.origin_left
|
||||
&& other_origin_left
|
||||
.map(|left| visited.iter().all(|x| !x.contains_id(left)))
|
||||
.map(|left| visited.iter().all(|x| !x.contains_id(left.to_id())))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
// The other_elem's origin_left must be at the left side of content's origin_left.
|
||||
|
@ -176,10 +176,10 @@ impl CrdtRope {
|
|||
|
||||
let other_parent_right_idx =
|
||||
if let Some(other_origin_right) = other_elem.origin_right {
|
||||
let elem_idx = find_elem(other_origin_right);
|
||||
let elem_idx = find_elem(other_origin_right.to_id());
|
||||
let elem = self.tree.get_elem(elem_idx).unwrap();
|
||||
// It must be the start of the elem
|
||||
assert_eq!(elem.id.id(), other_origin_right);
|
||||
assert_eq!(elem.id.id(), other_origin_right.to_id());
|
||||
if elem.origin_left == content.origin_left {
|
||||
Some(elem_idx)
|
||||
} else {
|
||||
|
@ -621,7 +621,7 @@ impl LeafUpdate {
|
|||
mod test {
|
||||
use std::ops::Range;
|
||||
|
||||
use loro_common::{Counter, PeerID, ID};
|
||||
use loro_common::{CompactId, Counter, PeerID, ID};
|
||||
|
||||
use crate::container::richtext::RichtextChunk;
|
||||
|
||||
|
@ -726,8 +726,8 @@ mod test {
|
|||
let mut rope = CrdtRope::new();
|
||||
rope.insert(0, span(0, 0..10), |_| panic!());
|
||||
let fugue = rope.insert(5, span(1, 10..20), |_| panic!()).content;
|
||||
assert_eq!(fugue.origin_left, Some(ID::new(0, 4)));
|
||||
assert_eq!(fugue.origin_right, Some(ID::new(0, 5)));
|
||||
assert_eq!(fugue.origin_left, Some(CompactId::new(0, 4)));
|
||||
assert_eq!(fugue.origin_right, Some(CompactId::new(0, 5)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -738,11 +738,11 @@ mod test {
|
|||
rope.delete(5, 2, |_| {});
|
||||
assert_eq!(rope.len(), 8);
|
||||
let fugue = rope.insert(6, span(1, 10..20), |_| panic!()).content;
|
||||
assert_eq!(fugue.origin_left, Some(ID::new(0, 7)));
|
||||
assert_eq!(fugue.origin_right, Some(ID::new(0, 8)));
|
||||
assert_eq!(fugue.origin_left, Some(CompactId::new(0, 7)));
|
||||
assert_eq!(fugue.origin_right, Some(CompactId::new(0, 8)));
|
||||
let fugue = rope.insert(5, span(1, 10..11), |_| panic!()).content;
|
||||
assert_eq!(fugue.origin_left, Some(ID::new(0, 4)));
|
||||
assert_eq!(fugue.origin_right, Some(ID::new(0, 5)));
|
||||
assert_eq!(fugue.origin_left, Some(CompactId::new(0, 4)));
|
||||
assert_eq!(fugue.origin_right, Some(CompactId::new(0, 5)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -753,8 +753,8 @@ mod test {
|
|||
rope.insert(0, span(0, 0..10), |_| panic!());
|
||||
rope.insert(5, future_span(1, 10..20), |_| panic!());
|
||||
let fugue = rope.insert(5, span(1, 10..20), |_| panic!()).content;
|
||||
assert_eq!(fugue.origin_left, Some(ID::new(0, 4)));
|
||||
assert_eq!(fugue.origin_right, Some(ID::new(0, 5)));
|
||||
assert_eq!(fugue.origin_left, Some(CompactId::new(0, 4)));
|
||||
assert_eq!(fugue.origin_right, Some(CompactId::new(0, 5)));
|
||||
}
|
||||
{
|
||||
// insert deleted
|
||||
|
@ -762,8 +762,8 @@ mod test {
|
|||
rope.insert(0, span(0, 0..10), |_| panic!());
|
||||
rope.insert(5, dead_span(1, 10..20), |_| panic!());
|
||||
let fugue = rope.insert(5, span(1, 10..20), |_| panic!()).content;
|
||||
assert_eq!(fugue.origin_left, Some(ID::new(0, 4)));
|
||||
assert_eq!(fugue.origin_right, Some(ID::new(1, 0)));
|
||||
assert_eq!(fugue.origin_left, Some(CompactId::new(0, 4)));
|
||||
assert_eq!(fugue.origin_right, Some(CompactId::new(1, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue