feat: get vv from dag

This commit is contained in:
Zixuan Chen 2022-08-03 21:56:06 +08:00
parent ed145367e0
commit 16395a4fa2
3 changed files with 152 additions and 3 deletions

View file

@ -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>,

View file

@ -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::*;

View file

@ -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 {