mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-22 21:07:43 +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,
|
||||
id::{ClientID, Counter, ID},
|
||||
span::{CounterSpan, IdSpan},
|
||||
version::VersionVector,
|
||||
};
|
||||
|
||||
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]
|
||||
fn find_path(&self, from: ID, to: ID) -> Option<Path> {
|
||||
let mut ans: Option<Path> = None;
|
||||
|
||||
#[inline]
|
||||
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 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>
|
||||
where
|
||||
F: Fn(ID) -> Option<&'a dyn DagNode>,
|
||||
|
|
|
@ -216,6 +216,35 @@ struct Interaction {
|
|||
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 {
|
||||
use super::*;
|
||||
|
||||
|
|
|
@ -1,8 +1,85 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
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)]
|
||||
pub(crate) struct TotalOrderStamp {
|
||||
|
|
Loading…
Reference in a new issue