Implement time::Global using a SmallVec

Version vectors are going to be small most of the time, especially
as soon as we introduce an optimization that will let us only
track concurrent versions, thus preventing the version vector from
growing indefinitely over time in the tree.
This commit is contained in:
Antonio Scandurra 2021-05-18 11:31:40 +02:00
parent 84e0efe5df
commit a8ece757e4
3 changed files with 26 additions and 42 deletions

View file

@ -23,7 +23,7 @@ scoped-pool = {path = "../scoped_pool"}
seahash = "4.1" seahash = "4.1"
serde = {version = "1.0.125", features = ["derive"]} serde = {version = "1.0.125", features = ["derive"]}
serde_json = "1.0.64" serde_json = "1.0.64"
smallvec = "1.6.1" smallvec = {version = "1.6", features = ["union"]}
smol = "1.2" smol = "1.2"
tiny-skia = "0.5" tiny-skia = "0.5"
tree-sitter = "0.17" tree-sitter = "0.17"

View file

@ -36,7 +36,7 @@ seahash = "4.1"
serde = {version = "1", features = ["derive"]} serde = {version = "1", features = ["derive"]}
similar = "1.3" similar = "1.3"
simplelog = "0.9" simplelog = "0.9"
smallvec = "1.6.1" smallvec = {version = "1.6", features = ["union"]}
smol = "1.2.5" smol = "1.2.5"
[dev-dependencies] [dev-dependencies]

View file

@ -1,13 +1,9 @@
use smallvec::SmallVec;
use std::cmp::{self, Ordering}; use std::cmp::{self, Ordering};
use std::collections::HashMap;
use std::mem;
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
use std::sync::Arc;
use lazy_static::lazy_static;
pub type ReplicaId = u16; pub type ReplicaId = u16;
pub type Seq = u64; pub type Seq = u32;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Ord, PartialOrd)] #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub struct Local { pub struct Local {
@ -58,18 +54,8 @@ impl<'a> AddAssign<&'a Local> for Local {
} }
} }
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Global(Arc<HashMap<ReplicaId, u64>>); pub struct Global(SmallVec<[Local; 3]>);
lazy_static! {
static ref DEFAULT_GLOBAL: Global = Global(Arc::new(HashMap::new()));
}
impl Default for Global {
fn default() -> Self {
DEFAULT_GLOBAL.clone()
}
}
impl Global { impl Global {
pub fn new() -> Self { pub fn new() -> Self {
@ -77,21 +63,27 @@ impl Global {
} }
pub fn get(&self, replica_id: ReplicaId) -> Seq { pub fn get(&self, replica_id: ReplicaId) -> Seq {
*self.0.get(&replica_id).unwrap_or(&0) self.0
.iter()
.find(|t| t.replica_id == replica_id)
.map_or(0, |t| t.value)
} }
pub fn observe(&mut self, timestamp: Local) { pub fn observe(&mut self, timestamp: Local) {
let map = Arc::make_mut(&mut self.0); if let Some(entry) = self
let value = map.entry(timestamp.replica_id).or_insert(0); .0
*value = cmp::max(*value, timestamp.value); .iter_mut()
.find(|t| t.replica_id == timestamp.replica_id)
{
entry.value = cmp::max(entry.value, timestamp.value);
} else {
self.0.push(timestamp);
}
} }
pub fn observe_all(&mut self, other: &Self) { pub fn observe_all(&mut self, other: &Self) {
for (replica_id, value) in other.0.as_ref() { for timestamp in other.0.iter() {
self.observe(Local { self.observe(*timestamp);
replica_id: *replica_id,
value: *value,
});
} }
} }
@ -100,9 +92,7 @@ impl Global {
} }
pub fn changed_since(&self, other: &Self) -> bool { pub fn changed_since(&self, other: &Self) -> bool {
self.0 self.0.iter().any(|t| t.value > other.get(t.replica_id))
.iter()
.any(|(replica_id, value)| *value > other.get(*replica_id))
} }
} }
@ -110,8 +100,10 @@ impl PartialOrd for Global {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let mut global_ordering = Ordering::Equal; let mut global_ordering = Ordering::Equal;
for replica_id in self.0.keys().chain(other.0.keys()) { for timestamp in self.0.iter().chain(other.0.iter()) {
let ordering = self.get(*replica_id).cmp(&other.get(*replica_id)); let ordering = self
.get(timestamp.replica_id)
.cmp(&other.get(timestamp.replica_id));
if ordering != Ordering::Equal { if ordering != Ordering::Equal {
if global_ordering == Ordering::Equal { if global_ordering == Ordering::Equal {
global_ordering = ordering; global_ordering = ordering;
@ -142,12 +134,4 @@ impl Lamport {
pub fn observe(&mut self, timestamp: Self) { pub fn observe(&mut self, timestamp: Self) {
self.value = cmp::max(self.value, timestamp.value) + 1; self.value = cmp::max(self.value, timestamp.value) + 1;
} }
pub fn to_bytes(&self) -> [u8; 24] {
let mut bytes = [0; 24];
bytes[0..8].copy_from_slice(unsafe { &mem::transmute::<u64, [u8; 8]>(self.value.to_be()) });
bytes[8..10]
.copy_from_slice(unsafe { &mem::transmute::<u16, [u8; 2]>(self.replica_id.to_be()) });
bytes
}
} }