From 5d1afaf484c2abf532ccab5d50d6639494256752 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Jun 2021 18:03:44 +0200 Subject: [PATCH] Reduce `Fragment` size by not storing `ReplicaId` twice --- zed/src/editor/buffer.rs | 119 +++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 54 deletions(-) diff --git a/zed/src/editor/buffer.rs b/zed/src/editor/buffer.rs index f455709ce5b086495b9496be7c346e0eaec63d11..68ddb22b5acb8b4c7a177a1375a4fb28f19847d4 100644 --- a/zed/src/editor/buffer.rs +++ b/zed/src/editor/buffer.rs @@ -169,7 +169,7 @@ impl History { } fn push(&mut self, op: EditOperation) { - self.ops.insert(op.id, op); + self.ops.insert(op.timestamp.local(), op); } fn start_transaction( @@ -326,12 +326,34 @@ struct Diff { changes: Vec<(ChangeTag, usize)>, } +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +struct InsertionTimestamp { + replica_id: ReplicaId, + local: time::Seq, + lamport: time::Seq, +} + +impl InsertionTimestamp { + fn local(&self) -> time::Local { + time::Local { + replica_id: self.replica_id, + value: self.local, + } + } + + fn lamport(&self) -> time::Lamport { + time::Lamport { + replica_id: self.replica_id, + value: self.lamport, + } + } +} + #[derive(Eq, PartialEq, Clone, Debug)] struct Fragment { + timestamp: InsertionTimestamp, len: usize, visible: bool, - insertion_id: time::Local, - lamport_timestamp: time::Lamport, deletions: HashSet, max_undos: time::Global, } @@ -359,10 +381,7 @@ impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentTextSummary { #[derive(Clone, Debug, Eq, PartialEq)] pub enum Operation { - Edit { - edit: EditOperation, - lamport_timestamp: time::Lamport, - }, + Edit(EditOperation), Undo { undo: UndoOperation, lamport_timestamp: time::Lamport, @@ -376,7 +395,7 @@ pub enum Operation { #[derive(Clone, Debug, Eq, PartialEq)] pub struct EditOperation { - id: time::Local, + timestamp: InsertionTimestamp, version: time::Global, ranges: Vec>, new_text: Option, @@ -457,12 +476,11 @@ impl Buffer { if visible_text.len() > 0 { fragments.push( Fragment { - insertion_id: Default::default(), - lamport_timestamp: Default::default(), + timestamp: Default::default(), len: visible_text.len(), + visible: true, deletions: Default::default(), max_undos: Default::default(), - visible: true, }, &None, ); @@ -932,21 +950,21 @@ impl Buffer { None } else { self.start_transaction_at(None, Instant::now()).unwrap(); - let edit_id = self.local_clock.tick(); - let lamport_timestamp = self.lamport_clock.tick(); - let edit = self.apply_local_edit(&ranges, new_text, edit_id, lamport_timestamp); + let timestamp = InsertionTimestamp { + replica_id: self.replica_id, + local: self.local_clock.tick().value, + lamport: self.lamport_clock.tick().value, + }; + let edit = self.apply_local_edit(&ranges, new_text, timestamp); self.history.push(edit.clone()); - self.history.push_undo(edit.id); - self.last_edit = edit.id; - self.version.observe(edit.id); + self.history.push_undo(edit.timestamp.local()); + self.last_edit = edit.timestamp.local(); + self.version.observe(edit.timestamp.local()); self.end_transaction_at(None, Instant::now(), cx).unwrap(); - Some(Operation::Edit { - edit, - lamport_timestamp, - }) + Some(Operation::Edit(edit)) } } @@ -1067,20 +1085,15 @@ impl Buffer { fn apply_op(&mut self, op: Operation) -> Result<()> { match op { - Operation::Edit { - edit, - lamport_timestamp, - .. - } => { - if !self.version.observed(edit.id) { + Operation::Edit(edit) => { + if !self.version.observed(edit.timestamp.local()) { self.apply_remote_edit( &edit.version, &edit.ranges, edit.new_text.as_deref(), - edit.id, - lamport_timestamp, + edit.timestamp, ); - self.version.observe(edit.id); + self.version.observe(edit.timestamp.local()); self.history.push(edit); } } @@ -1116,8 +1129,7 @@ impl Buffer { version: &time::Global, ranges: &[Range], new_text: Option<&str>, - local_timestamp: time::Local, - lamport_timestamp: time::Lamport, + timestamp: InsertionTimestamp, ) { if ranges.is_empty() { return; @@ -1171,7 +1183,9 @@ impl Buffer { // Skip over insertions that are concurrent to this edit, but have a lower lamport // timestamp. while let Some(fragment) = old_fragments.item() { - if fragment_start == range.start && fragment.lamport_timestamp > lamport_timestamp { + if fragment_start == range.start + && fragment.timestamp.lamport() > timestamp.lamport() + { new_ropes.push_fragment(fragment, fragment.visible); new_fragments.push(fragment.clone(), &None); old_fragments.next(&cx); @@ -1196,8 +1210,7 @@ impl Buffer { new_ropes.push_str(new_text); new_fragments.push( Fragment { - insertion_id: local_timestamp, - lamport_timestamp, + timestamp, len: new_text.len(), deletions: Default::default(), max_undos: Default::default(), @@ -1216,7 +1229,7 @@ impl Buffer { let intersection_end = cmp::min(range.end, fragment_end); if fragment.was_visible(version, &self.undo_map) { intersection.len = intersection_end - fragment_start; - intersection.deletions.insert(local_timestamp); + intersection.deletions.insert(timestamp.local()); intersection.visible = false; } if intersection.len > 0 { @@ -1252,8 +1265,8 @@ impl Buffer { self.fragments = new_fragments; self.visible_text = visible_text; self.deleted_text = deleted_text; - self.local_clock.observe(local_timestamp); - self.lamport_clock.observe(lamport_timestamp); + self.local_clock.observe(timestamp.local()); + self.lamport_clock.observe(timestamp.lamport()); } pub fn undo(&mut self, mut cx: Option<&mut ModelContext>) -> Vec { @@ -1355,7 +1368,7 @@ impl Buffer { let mut fragment = fragment.clone(); let fragment_was_visible = fragment.visible; if fragment.was_visible(&edit.version, &self.undo_map) - || fragment.insertion_id == edit.id + || fragment.timestamp.local() == edit.timestamp.local() { fragment.visible = fragment.is_visible(&self.undo_map); fragment.max_undos.observe(undo.id); @@ -1403,7 +1416,7 @@ impl Buffer { false } else { match op { - Operation::Edit { edit, .. } => self.version >= edit.version, + Operation::Edit(edit) => self.version >= edit.version, Operation::Undo { undo, .. } => self.version.observed(undo.edit_id), Operation::UpdateSelections { selections, .. } => { if let Some(selections) = selections { @@ -1430,11 +1443,10 @@ impl Buffer { &mut self, ranges: &[Range], new_text: Option, - local_timestamp: time::Local, - lamport_timestamp: time::Lamport, + timestamp: InsertionTimestamp, ) -> EditOperation { let mut edit = EditOperation { - id: local_timestamp, + timestamp, version: self.version(), ranges: Vec::with_capacity(ranges.len()), new_text: None, @@ -1487,8 +1499,7 @@ impl Buffer { new_ropes.push_str(new_text); new_fragments.push( Fragment { - insertion_id: local_timestamp, - lamport_timestamp, + timestamp, len: new_text.len(), deletions: Default::default(), max_undos: Default::default(), @@ -1507,7 +1518,7 @@ impl Buffer { let intersection_end = cmp::min(range.end, fragment_end); if fragment.visible { intersection.len = intersection_end - fragment_start; - intersection.deletions.insert(local_timestamp); + intersection.deletions.insert(timestamp.local()); intersection.visible = false; } if intersection.len > 0 { @@ -1987,11 +1998,13 @@ impl<'a> Iterator for HighlightedChunks<'a> { impl Fragment { fn is_visible(&self, undos: &UndoMap) -> bool { - !undos.is_undone(self.insertion_id) && self.deletions.iter().all(|d| undos.is_undone(*d)) + !undos.is_undone(self.timestamp.local()) + && self.deletions.iter().all(|d| undos.is_undone(*d)) } fn was_visible(&self, version: &time::Global, undos: &UndoMap) -> bool { - (version.observed(self.insertion_id) && !undos.was_undone(self.insertion_id, version)) + (version.observed(self.timestamp.local()) + && !undos.was_undone(self.timestamp.local(), version)) && self .deletions .iter() @@ -2004,14 +2017,14 @@ impl sum_tree::Item for Fragment { fn summary(&self) -> Self::Summary { let mut max_version = time::Global::new(); - max_version.observe(self.insertion_id); + max_version.observe(self.timestamp.local()); for deletion in &self.deletions { max_version.observe(*deletion); } max_version.join(&self.max_undos); let mut min_insertion_version = time::Global::new(); - min_insertion_version.observe(self.insertion_id); + min_insertion_version.observe(self.timestamp.local()); let max_insertion_version = min_insertion_version.clone(); if self.visible { FragmentSummary { @@ -2124,9 +2137,7 @@ impl Operation { fn lamport_timestamp(&self) -> time::Lamport { match self { - Operation::Edit { - lamport_timestamp, .. - } => *lamport_timestamp, + Operation::Edit(edit) => edit.timestamp.lamport(), Operation::Undo { lamport_timestamp, .. } => *lamport_timestamp, @@ -3474,7 +3485,7 @@ mod tests { impl Operation { fn edit_id(&self) -> Option { match self { - Operation::Edit { edit, .. } => Some(edit.id), + Operation::Edit(edit) => Some(edit.timestamp.local()), Operation::Undo { undo, .. } => Some(undo.edit_id), Operation::UpdateSelections { .. } => None, }