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"
serde = {version = "1.0.125", features = ["derive"]}
serde_json = "1.0.64"
smallvec = "1.6.1"
smallvec = {version = "1.6", features = ["union"]}
smol = "1.2"
tiny-skia = "0.5"
tree-sitter = "0.17"

View file

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

View file

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