mirror of
https://github.com/loro-dev/loro.git
synced 2025-02-08 21:47:41 +00:00
feat: get vv from dag
This commit is contained in:
parent
ed145367e0
commit
16395a4fa2
3 changed files with 152 additions and 3 deletions
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
change::Lamport,
|
change::Lamport,
|
||||||
id::{ClientID, Counter, ID},
|
id::{ClientID, Counter, ID},
|
||||||
span::{CounterSpan, IdSpan},
|
span::{CounterSpan, IdSpan},
|
||||||
|
version::VersionVector,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait DagNode {
|
pub trait DagNode {
|
||||||
|
@ -92,11 +93,16 @@ pub(crate) trait Dag {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: we probably need cache to speedup this
|
||||||
|
#[inline]
|
||||||
|
fn get_vv(&self, id: ID) -> VersionVector {
|
||||||
|
get_version_vector(&|id| self.get(id).map(|x| x as &dyn DagNode), id)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn find_path(&self, from: ID, to: ID) -> Option<Path> {
|
fn find_path(&self, from: ID, to: ID) -> Option<Path> {
|
||||||
let mut ans: Option<Path> = None;
|
let mut ans: Option<Path> = None;
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_rev_path(target: ID, from: ID, to_from_map: &FxHashMap<ID, ID>) -> Vec<IdSpan> {
|
fn get_rev_path(target: ID, from: ID, to_from_map: &FxHashMap<ID, ID>) -> Vec<IdSpan> {
|
||||||
let mut last_visited: Option<ID> = None;
|
let mut last_visited: Option<ID> = None;
|
||||||
let mut a_rev_path = vec![];
|
let mut a_rev_path = vec![];
|
||||||
|
@ -158,6 +164,43 @@ pub(crate) trait Dag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_version_vector<'a, Get>(get: &'a Get, id: ID) -> VersionVector
|
||||||
|
where
|
||||||
|
Get: Fn(ID) -> Option<&'a dyn DagNode>,
|
||||||
|
{
|
||||||
|
let mut vv = VersionVector::new();
|
||||||
|
let mut visited: FxHashSet<ID> = FxHashSet::default();
|
||||||
|
vv.insert(id.client_id, id.counter + 1);
|
||||||
|
let node = get(id).unwrap();
|
||||||
|
|
||||||
|
if node.deps().is_empty() {
|
||||||
|
return vv;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
for dep in node.deps() {
|
||||||
|
stack.push(dep);
|
||||||
|
}
|
||||||
|
|
||||||
|
while !stack.is_empty() {
|
||||||
|
let node_id = *stack.pop().unwrap();
|
||||||
|
let node = get(node_id).unwrap();
|
||||||
|
let node_id_start = node.dag_id_start();
|
||||||
|
if !visited.contains(&node_id_start) {
|
||||||
|
vv.try_update_end(node_id);
|
||||||
|
for dep in node.deps() {
|
||||||
|
if !visited.contains(dep) {
|
||||||
|
stack.push(dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visited.insert(node_id_start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vv
|
||||||
|
}
|
||||||
|
|
||||||
fn find_common_ancestor<'a, F, G>(get: &'a F, a_id: ID, b_id: ID, mut on_found: G) -> Option<ID>
|
fn find_common_ancestor<'a, F, G>(get: &'a F, a_id: ID, b_id: ID, mut on_found: G) -> Option<ID>
|
||||||
where
|
where
|
||||||
F: Fn(ID) -> Option<&'a dyn DagNode>,
|
F: Fn(ID) -> Option<&'a dyn DagNode>,
|
||||||
|
|
|
@ -216,6 +216,35 @@ struct Interaction {
|
||||||
len: usize,
|
len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod get_version_vector {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vv() {
|
||||||
|
let mut a = TestDag::new(0);
|
||||||
|
let mut b = TestDag::new(1);
|
||||||
|
a.push(1);
|
||||||
|
b.push(1);
|
||||||
|
a.merge(&b);
|
||||||
|
a.push(1);
|
||||||
|
let actual = a.get_vv(ID::new(0, 0));
|
||||||
|
assert_eq!(actual, vec![ID::new(0, 0)].into());
|
||||||
|
let actual = a.get_vv(ID::new(0, 1));
|
||||||
|
assert_eq!(actual, vec![ID::new(0, 1), ID::new(1, 0)].into());
|
||||||
|
|
||||||
|
let mut c = TestDag::new(2);
|
||||||
|
c.merge(&a);
|
||||||
|
b.push(1);
|
||||||
|
c.merge(&b);
|
||||||
|
c.push(1);
|
||||||
|
let actual = c.get_vv(ID::new(2, 0));
|
||||||
|
assert_eq!(
|
||||||
|
actual,
|
||||||
|
vec![ID::new(0, 1), ID::new(1, 1), ID::new(2, 0)].into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod find_path {
|
mod find_path {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,85 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
|
|
||||||
use crate::{change::Lamport, ClientID};
|
use crate::{
|
||||||
|
change::Lamport,
|
||||||
|
id::{Counter, ID},
|
||||||
|
ClientID,
|
||||||
|
};
|
||||||
|
|
||||||
pub type VersionVector = FxHashMap<ClientID, u32>;
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub struct VersionVector(FxHashMap<ClientID, Counter>);
|
||||||
|
|
||||||
|
impl Deref for VersionVector {
|
||||||
|
type Target = FxHashMap<ClientID, Counter>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for VersionVector {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VersionVector {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(FxHashMap::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_end(&mut self, id: ID) {
|
||||||
|
self.0.insert(id.client_id, id.counter + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// update the end counter of the given client, if the end is greater
|
||||||
|
/// return whether updated
|
||||||
|
#[inline]
|
||||||
|
pub fn try_update_end(&mut self, id: ID) -> bool {
|
||||||
|
if let Some(end) = self.0.get_mut(&id.client_id) {
|
||||||
|
if *end < id.counter {
|
||||||
|
*end = id.counter + 1;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.0.insert(id.client_id, id.counter + 1);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VersionVector {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FxHashMap<ClientID, Counter>> for VersionVector {
|
||||||
|
fn from(map: FxHashMap<ClientID, Counter>) -> Self {
|
||||||
|
Self(map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<ID>> for VersionVector {
|
||||||
|
fn from(vec: Vec<ID>) -> Self {
|
||||||
|
let mut vv = VersionVector::new();
|
||||||
|
for id in vec {
|
||||||
|
vv.set_end(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
vv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
|
||||||
pub(crate) struct TotalOrderStamp {
|
pub(crate) struct TotalOrderStamp {
|
||||||
|
|
Loading…
Reference in a new issue