Switch to a dense representation for clock::Global
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
447f710570
commit
b25c3eb740
3 changed files with 124 additions and 74 deletions
|
@ -438,11 +438,22 @@ impl Buffer {
|
||||||
pub fn new(replica_id: u16, remote_id: u64, history: History) -> Buffer {
|
pub fn new(replica_id: u16, remote_id: u64, history: History) -> Buffer {
|
||||||
let mut fragments = SumTree::new();
|
let mut fragments = SumTree::new();
|
||||||
|
|
||||||
|
let mut local_clock = clock::Local::new(replica_id);
|
||||||
|
let mut lamport_clock = clock::Lamport::new(replica_id);
|
||||||
|
let mut version = clock::Global::new();
|
||||||
let visible_text = Rope::from(history.base_text.as_ref());
|
let visible_text = Rope::from(history.base_text.as_ref());
|
||||||
if visible_text.len() > 0 {
|
if visible_text.len() > 0 {
|
||||||
|
let timestamp = InsertionTimestamp {
|
||||||
|
replica_id: 0,
|
||||||
|
local: 1,
|
||||||
|
lamport: 1,
|
||||||
|
};
|
||||||
|
local_clock.observe(timestamp.local());
|
||||||
|
lamport_clock.observe(timestamp.lamport());
|
||||||
|
version.observe(timestamp.local());
|
||||||
fragments.push(
|
fragments.push(
|
||||||
Fragment {
|
Fragment {
|
||||||
timestamp: Default::default(),
|
timestamp,
|
||||||
len: visible_text.len(),
|
len: visible_text.len(),
|
||||||
visible: true,
|
visible: true,
|
||||||
deletions: Default::default(),
|
deletions: Default::default(),
|
||||||
|
@ -456,7 +467,7 @@ impl Buffer {
|
||||||
visible_text,
|
visible_text,
|
||||||
deleted_text: Rope::new(),
|
deleted_text: Rope::new(),
|
||||||
fragments,
|
fragments,
|
||||||
version: clock::Global::new(),
|
version,
|
||||||
last_edit: clock::Local::default(),
|
last_edit: clock::Local::default(),
|
||||||
undo_map: Default::default(),
|
undo_map: Default::default(),
|
||||||
history,
|
history,
|
||||||
|
@ -465,8 +476,8 @@ impl Buffer {
|
||||||
deferred_replicas: HashSet::default(),
|
deferred_replicas: HashSet::default(),
|
||||||
replica_id,
|
replica_id,
|
||||||
remote_id,
|
remote_id,
|
||||||
local_clock: clock::Local::new(replica_id),
|
local_clock,
|
||||||
lamport_clock: clock::Lamport::new(replica_id),
|
lamport_clock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1093,10 +1104,10 @@ impl Buffer {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
match op {
|
match op {
|
||||||
Operation::Edit(edit) => self.version >= edit.version,
|
Operation::Edit(edit) => self.version.ge(&edit.version),
|
||||||
Operation::Undo { undo, .. } => self.version >= undo.version,
|
Operation::Undo { undo, .. } => self.version.ge(&undo.version),
|
||||||
Operation::UpdateSelections { selections, .. } => {
|
Operation::UpdateSelections { selections, .. } => {
|
||||||
self.version >= *selections.version()
|
self.version.ge(selections.version())
|
||||||
}
|
}
|
||||||
Operation::RemoveSelections { .. } => true,
|
Operation::RemoveSelections { .. } => true,
|
||||||
Operation::SetActiveSelections { set_id, .. } => {
|
Operation::SetActiveSelections { set_id, .. } => {
|
||||||
|
@ -1947,10 +1958,10 @@ impl<'a> Content<'a> {
|
||||||
let fragments_cursor = if since == self.version {
|
let fragments_cursor = if since == self.version {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.fragments.filter(
|
Some(
|
||||||
move |summary| summary.max_version.changed_since(since),
|
self.fragments
|
||||||
&None,
|
.filter(move |summary| !since.ge(&summary.max_version), &None),
|
||||||
))
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
Edits {
|
Edits {
|
||||||
|
@ -2233,13 +2244,9 @@ impl<'a> sum_tree::Dimension<'a, FragmentSummary> for VersionedFullOffset {
|
||||||
fn add_summary(&mut self, summary: &'a FragmentSummary, cx: &Option<clock::Global>) {
|
fn add_summary(&mut self, summary: &'a FragmentSummary, cx: &Option<clock::Global>) {
|
||||||
if let Self::Offset(offset) = self {
|
if let Self::Offset(offset) = self {
|
||||||
let version = cx.as_ref().unwrap();
|
let version = cx.as_ref().unwrap();
|
||||||
if *version >= summary.max_insertion_version {
|
if version.ge(&summary.max_insertion_version) {
|
||||||
*offset += summary.text.visible + summary.text.deleted;
|
*offset += summary.text.visible + summary.text.deleted;
|
||||||
} else if !summary
|
} else if version.observed_any(&summary.min_insertion_version) {
|
||||||
.min_insertion_version
|
|
||||||
.iter()
|
|
||||||
.all(|t| !version.observed(*t))
|
|
||||||
{
|
|
||||||
*self = Self::Invalid;
|
*self = Self::Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{self, Ordering},
|
cmp::{self, Ordering},
|
||||||
fmt,
|
fmt, iter,
|
||||||
ops::{Add, AddAssign},
|
ops::{Add, AddAssign},
|
||||||
slice,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ReplicaId = u16;
|
pub type ReplicaId = u16;
|
||||||
|
@ -59,7 +58,7 @@ impl<'a> AddAssign<&'a Local> for Local {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Hash, Eq, PartialEq)]
|
#[derive(Clone, Default, Hash, Eq, PartialEq)]
|
||||||
pub struct Global(SmallVec<[Local; 3]>);
|
pub struct Global(SmallVec<[u32; 8]>);
|
||||||
|
|
||||||
impl From<Vec<rpc::proto::VectorClockEntry>> for Global {
|
impl From<Vec<rpc::proto::VectorClockEntry>> for Global {
|
||||||
fn from(message: Vec<rpc::proto::VectorClockEntry>) -> Self {
|
fn from(message: Vec<rpc::proto::VectorClockEntry>) -> Self {
|
||||||
|
@ -98,75 +97,119 @@ impl Global {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, replica_id: ReplicaId) -> Seq {
|
pub fn get(&self, replica_id: ReplicaId) -> Seq {
|
||||||
self.0
|
self.0.get(replica_id as usize).copied().unwrap_or(0) as Seq
|
||||||
.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) {
|
||||||
if let Some(entry) = self
|
if timestamp.value > 0 {
|
||||||
.0
|
let new_len = timestamp.replica_id as usize + 1;
|
||||||
.iter_mut()
|
if new_len > self.0.len() {
|
||||||
.find(|t| t.replica_id == timestamp.replica_id)
|
self.0.resize(new_len, 0);
|
||||||
{
|
}
|
||||||
entry.value = cmp::max(entry.value, timestamp.value);
|
|
||||||
} else {
|
let entry = &mut self.0[timestamp.replica_id as usize];
|
||||||
self.0.push(timestamp);
|
*entry = cmp::max(*entry, timestamp.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join(&mut self, other: &Self) {
|
pub fn join(&mut self, other: &Self) {
|
||||||
for timestamp in other.0.iter() {
|
if other.0.len() > self.0.len() {
|
||||||
self.observe(*timestamp);
|
self.0.resize(other.0.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (left, right) in self.0.iter_mut().zip(&other.0) {
|
||||||
|
*left = cmp::max(*left, *right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn meet(&mut self, other: &Self) {
|
pub fn meet(&mut self, other: &Self) {
|
||||||
for timestamp in other.0.iter() {
|
if other.0.len() > self.0.len() {
|
||||||
if let Some(entry) = self
|
self.0.resize(other.0.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_len = 0;
|
||||||
|
for (ix, (left, right)) in self
|
||||||
.0
|
.0
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.find(|t| t.replica_id == timestamp.replica_id)
|
.zip(other.0.iter().chain(iter::repeat(&0)))
|
||||||
|
.enumerate()
|
||||||
{
|
{
|
||||||
entry.value = cmp::min(entry.value, timestamp.value);
|
if *left == 0 {
|
||||||
} else {
|
*left = *right;
|
||||||
self.0.push(*timestamp);
|
} else if *right > 0 {
|
||||||
|
*left = cmp::min(*left, *right);
|
||||||
|
}
|
||||||
|
|
||||||
|
if *left != 0 {
|
||||||
|
new_len = ix + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.0.resize(new_len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn observed(&self, timestamp: Local) -> bool {
|
pub fn observed(&self, timestamp: Local) -> bool {
|
||||||
self.get(timestamp.replica_id) >= timestamp.value
|
self.get(timestamp.replica_id) >= timestamp.value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn changed_since(&self, other: &Self) -> bool {
|
pub fn observed_any(&self, other: &Self) -> bool {
|
||||||
self.0.iter().any(|t| t.value > other.get(t.replica_id))
|
let mut lhs = self.0.iter();
|
||||||
|
let mut rhs = other.0.iter();
|
||||||
|
loop {
|
||||||
|
if let Some(left) = lhs.next() {
|
||||||
|
if let Some(right) = rhs.next() {
|
||||||
|
if *right > 0 && left >= right {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
pub fn iter(&self) -> slice::Iter<Local> {
|
return false;
|
||||||
self.0.iter()
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
return false;
|
||||||
impl PartialOrd for Global {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
let mut global_ordering = Ordering::Equal;
|
|
||||||
|
|
||||||
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;
|
|
||||||
} else if ordering != global_ordering {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(global_ordering)
|
pub fn ge(&self, other: &Self) -> bool {
|
||||||
|
let mut lhs = self.0.iter();
|
||||||
|
let mut rhs = other.0.iter();
|
||||||
|
loop {
|
||||||
|
if let Some(left) = lhs.next() {
|
||||||
|
if let Some(right) = rhs.next() {
|
||||||
|
if left < right {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return rhs.next().is_none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gt(&self, other: &Self) -> bool {
|
||||||
|
let mut lhs = self.0.iter();
|
||||||
|
let mut rhs = other.0.iter();
|
||||||
|
loop {
|
||||||
|
if let Some(left) = lhs.next() {
|
||||||
|
if let Some(right) = rhs.next() {
|
||||||
|
if left <= right {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return rhs.next().is_none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter<'a>(&'a self) -> impl 'a + Iterator<Item = Local> {
|
||||||
|
self.0.iter().enumerate().map(|(replica_id, seq)| Local {
|
||||||
|
replica_id: replica_id as ReplicaId,
|
||||||
|
value: *seq,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,11 +262,11 @@ impl fmt::Debug for Lamport {
|
||||||
impl fmt::Debug for Global {
|
impl fmt::Debug for Global {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "Global {{")?;
|
write!(f, "Global {{")?;
|
||||||
for (i, element) in self.0.iter().enumerate() {
|
for timestamp in self.iter() {
|
||||||
if i > 0 {
|
if timestamp.replica_id > 0 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
write!(f, "{}: {}", element.replica_id, element.value)?;
|
write!(f, "{}: {}", timestamp.replica_id, timestamp.value)?;
|
||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,9 +319,9 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
text: buffer,
|
|
||||||
saved_mtime,
|
saved_mtime,
|
||||||
saved_version: clock::Global::new(),
|
saved_version: buffer.version(),
|
||||||
|
text: buffer,
|
||||||
file,
|
file,
|
||||||
syntax_tree: Mutex::new(None),
|
syntax_tree: Mutex::new(None),
|
||||||
parsing_in_background: false,
|
parsing_in_background: false,
|
||||||
|
@ -620,7 +620,7 @@ impl Buffer {
|
||||||
this.language.as_ref().map_or(true, |curr_language| {
|
this.language.as_ref().map_or(true, |curr_language| {
|
||||||
!Arc::ptr_eq(curr_language, &language)
|
!Arc::ptr_eq(curr_language, &language)
|
||||||
});
|
});
|
||||||
let parse_again = this.version > parsed_version || language_changed;
|
let parse_again = this.version.gt(&parsed_version) || language_changed;
|
||||||
this.parsing_in_background = false;
|
this.parsing_in_background = false;
|
||||||
this.did_finish_parsing(new_tree, parsed_version, cx);
|
this.did_finish_parsing(new_tree, parsed_version, cx);
|
||||||
|
|
||||||
|
@ -1132,12 +1132,12 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_dirty(&self) -> bool {
|
pub fn is_dirty(&self) -> bool {
|
||||||
self.version > self.saved_version
|
!self.saved_version.ge(&self.version)
|
||||||
|| self.file.as_ref().map_or(false, |file| file.is_deleted())
|
|| self.file.as_ref().map_or(false, |file| file.is_deleted())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_conflict(&self) -> bool {
|
pub fn has_conflict(&self) -> bool {
|
||||||
self.version > self.saved_version
|
!self.saved_version.ge(&self.version)
|
||||||
&& self
|
&& self
|
||||||
.file
|
.file
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue