clock: Cleanup ReplicaId, Lamport and Global (#40600)
- Notable change is the use of a newtype for `ReplicaId` - Fixes `WorktreeStore::create_remote_worktree` creating a remote worktree with the local replica id, though this is not currently used - Fixes observing the `Agent` (that is following the agent) causing global clocks to allocate 65535 elements - Shrinks the size of `Global` a bit. In a local or non-collab remote session it won't ever allocate still. Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
@@ -6,7 +6,7 @@ use std::{cmp::Ordering, fmt::Debug, ops::Range};
|
||||
use sum_tree::{Bias, Dimensions};
|
||||
|
||||
/// A timestamped position in a buffer
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
|
||||
pub struct Anchor {
|
||||
pub timestamp: clock::Lamport,
|
||||
/// The byte offset in the buffer
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use clock::Lamport;
|
||||
use std::{fmt::Debug, ops::Add};
|
||||
use sum_tree::{ContextLessSummary, Dimension, Edit, Item, KeyedItem, SumTree};
|
||||
|
||||
@@ -11,10 +12,10 @@ struct OperationItem<T>(T);
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OperationQueue<T: Operation>(SumTree<OperationItem<T>>);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct OperationKey(clock::Lamport);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct OperationSummary {
|
||||
pub key: OperationKey,
|
||||
pub len: usize,
|
||||
@@ -69,7 +70,10 @@ impl<T: Operation> OperationQueue<T> {
|
||||
|
||||
impl ContextLessSummary for OperationSummary {
|
||||
fn zero() -> Self {
|
||||
Default::default()
|
||||
OperationSummary {
|
||||
key: OperationKey::new(Lamport::MIN),
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, other: &Self) {
|
||||
@@ -93,7 +97,7 @@ impl Add<&Self> for OperationSummary {
|
||||
|
||||
impl Dimension<'_, OperationSummary> for OperationKey {
|
||||
fn zero(_cx: ()) -> Self {
|
||||
Default::default()
|
||||
OperationKey::new(Lamport::MIN)
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, summary: &OperationSummary, _: ()) {
|
||||
@@ -123,11 +127,13 @@ impl<T: Operation> KeyedItem for OperationItem<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use clock::ReplicaId;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_len() {
|
||||
let mut clock = clock::Lamport::new(0);
|
||||
let mut clock = clock::Lamport::new(ReplicaId::LOCAL);
|
||||
|
||||
let mut queue = OperationQueue::new();
|
||||
assert_eq!(queue.len(), 0);
|
||||
|
||||
+35
-23
@@ -16,7 +16,7 @@ fn init_logger() {
|
||||
|
||||
#[test]
|
||||
fn test_edit() {
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "abc");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "abc");
|
||||
assert_eq!(buffer.text(), "abc");
|
||||
buffer.edit([(3..3, "def")]);
|
||||
assert_eq!(buffer.text(), "abcdef");
|
||||
@@ -40,7 +40,11 @@ fn test_random_edits(mut rng: StdRng) {
|
||||
let mut reference_string = RandomCharIter::new(&mut rng)
|
||||
.take(reference_string_len)
|
||||
.collect::<String>();
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), reference_string.clone());
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
reference_string.clone(),
|
||||
);
|
||||
LineEnding::normalize(&mut reference_string);
|
||||
|
||||
buffer.set_group_interval(Duration::from_millis(rng.random_range(0..=200)));
|
||||
@@ -176,7 +180,11 @@ fn test_line_endings() {
|
||||
LineEnding::Windows
|
||||
);
|
||||
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "one\r\ntwo\rthree");
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"one\r\ntwo\rthree",
|
||||
);
|
||||
assert_eq!(buffer.text(), "one\ntwo\nthree");
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Windows);
|
||||
buffer.check_invariants();
|
||||
@@ -190,7 +198,7 @@ fn test_line_endings() {
|
||||
|
||||
#[test]
|
||||
fn test_line_len() {
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
buffer.edit([(0..0, "abcd\nefg\nhij")]);
|
||||
buffer.edit([(12..12, "kl\nmno")]);
|
||||
buffer.edit([(18..18, "\npqrs\n")]);
|
||||
@@ -207,7 +215,7 @@ fn test_line_len() {
|
||||
#[test]
|
||||
fn test_common_prefix_at_position() {
|
||||
let text = "a = str; b = δα";
|
||||
let buffer = Buffer::new(0, BufferId::new(1).unwrap(), text);
|
||||
let buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), text);
|
||||
|
||||
let offset1 = offset_after(text, "str");
|
||||
let offset2 = offset_after(text, "δα");
|
||||
@@ -256,7 +264,7 @@ fn test_common_prefix_at_position() {
|
||||
#[test]
|
||||
fn test_text_summary_for_range() {
|
||||
let buffer = Buffer::new(
|
||||
0,
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"ab\nefg\nhklm\nnopqrs\ntuvwxyz",
|
||||
);
|
||||
@@ -348,7 +356,7 @@ fn test_text_summary_for_range() {
|
||||
|
||||
#[test]
|
||||
fn test_chars_at() {
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
buffer.edit([(0..0, "abcd\nefgh\nij")]);
|
||||
buffer.edit([(12..12, "kl\nmno")]);
|
||||
buffer.edit([(18..18, "\npqrs")]);
|
||||
@@ -370,7 +378,7 @@ fn test_chars_at() {
|
||||
assert_eq!(chars.collect::<String>(), "PQrs");
|
||||
|
||||
// Regression test:
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
buffer.edit([(0..0, "[workspace]\nmembers = [\n \"xray_core\",\n \"xray_server\",\n \"xray_cli\",\n \"xray_wasm\",\n]\n")]);
|
||||
buffer.edit([(60..60, "\n")]);
|
||||
|
||||
@@ -380,7 +388,7 @@ fn test_chars_at() {
|
||||
|
||||
#[test]
|
||||
fn test_anchors() {
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
buffer.edit([(0..0, "abc")]);
|
||||
let left_anchor = buffer.anchor_before(2);
|
||||
let right_anchor = buffer.anchor_after(2);
|
||||
@@ -498,7 +506,7 @@ fn test_anchors() {
|
||||
|
||||
#[test]
|
||||
fn test_anchors_at_start_and_end() {
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
let before_start_anchor = buffer.anchor_before(0);
|
||||
let after_end_anchor = buffer.anchor_after(0);
|
||||
|
||||
@@ -521,7 +529,7 @@ fn test_anchors_at_start_and_end() {
|
||||
|
||||
#[test]
|
||||
fn test_undo_redo() {
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "1234");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "1234");
|
||||
// Set group interval to zero so as to not group edits in the undo stack.
|
||||
buffer.set_group_interval(Duration::from_secs(0));
|
||||
|
||||
@@ -558,7 +566,7 @@ fn test_undo_redo() {
|
||||
#[test]
|
||||
fn test_history() {
|
||||
let mut now = Instant::now();
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "123456");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "123456");
|
||||
buffer.set_group_interval(Duration::from_millis(300));
|
||||
|
||||
let transaction_1 = buffer.start_transaction_at(now).unwrap();
|
||||
@@ -625,7 +633,7 @@ fn test_history() {
|
||||
#[test]
|
||||
fn test_finalize_last_transaction() {
|
||||
let now = Instant::now();
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "123456");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "123456");
|
||||
buffer.history.group_interval = Duration::from_millis(1);
|
||||
|
||||
buffer.start_transaction_at(now);
|
||||
@@ -661,7 +669,7 @@ fn test_finalize_last_transaction() {
|
||||
#[test]
|
||||
fn test_edited_ranges_for_transaction() {
|
||||
let now = Instant::now();
|
||||
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "1234567");
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "1234567");
|
||||
|
||||
buffer.start_transaction_at(now);
|
||||
buffer.edit([(2..4, "cd")]);
|
||||
@@ -700,9 +708,9 @@ fn test_edited_ranges_for_transaction() {
|
||||
fn test_concurrent_edits() {
|
||||
let text = "abcdef";
|
||||
|
||||
let mut buffer1 = Buffer::new(1, BufferId::new(1).unwrap(), text);
|
||||
let mut buffer2 = Buffer::new(2, BufferId::new(1).unwrap(), text);
|
||||
let mut buffer3 = Buffer::new(3, BufferId::new(1).unwrap(), text);
|
||||
let mut buffer1 = Buffer::new(ReplicaId::new(1), BufferId::new(1).unwrap(), text);
|
||||
let mut buffer2 = Buffer::new(ReplicaId::new(2), BufferId::new(1).unwrap(), text);
|
||||
let mut buffer3 = Buffer::new(ReplicaId::new(3), BufferId::new(1).unwrap(), text);
|
||||
|
||||
let buf1_op = buffer1.edit([(1..2, "12")]);
|
||||
assert_eq!(buffer1.text(), "a12cdef");
|
||||
@@ -741,11 +749,15 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
|
||||
let mut network = Network::new(rng.clone());
|
||||
|
||||
for i in 0..peers {
|
||||
let mut buffer = Buffer::new(i as ReplicaId, BufferId::new(1).unwrap(), base_text.clone());
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::new(i as u16),
|
||||
BufferId::new(1).unwrap(),
|
||||
base_text.clone(),
|
||||
);
|
||||
buffer.history.group_interval = Duration::from_millis(rng.random_range(0..=200));
|
||||
buffers.push(buffer);
|
||||
replica_ids.push(i as u16);
|
||||
network.add_peer(i as u16);
|
||||
replica_ids.push(ReplicaId::new(i as u16));
|
||||
network.add_peer(ReplicaId::new(i as u16));
|
||||
}
|
||||
|
||||
log::info!("initial text: {:?}", base_text);
|
||||
@@ -759,7 +771,7 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
|
||||
0..=50 if mutation_count != 0 => {
|
||||
let op = buffer.randomly_edit(&mut rng, 5).1;
|
||||
network.broadcast(buffer.replica_id, vec![op]);
|
||||
log::info!("buffer {} text: {:?}", buffer.replica_id, buffer.text());
|
||||
log::info!("buffer {:?} text: {:?}", buffer.replica_id, buffer.text());
|
||||
mutation_count -= 1;
|
||||
}
|
||||
51..=70 if mutation_count != 0 => {
|
||||
@@ -771,7 +783,7 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
|
||||
let ops = network.receive(replica_id);
|
||||
if !ops.is_empty() {
|
||||
log::info!(
|
||||
"peer {} applying {} ops from the network.",
|
||||
"peer {:?} applying {} ops from the network.",
|
||||
replica_id,
|
||||
ops.len()
|
||||
);
|
||||
@@ -792,7 +804,7 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
first_buffer.text(),
|
||||
"Replica {} text != Replica 0 text",
|
||||
"Replica {:?} text != Replica 0 text",
|
||||
buffer.replica_id
|
||||
);
|
||||
buffer.check_invariants();
|
||||
|
||||
+13
-13
@@ -12,7 +12,7 @@ mod undo_map;
|
||||
|
||||
pub use anchor::*;
|
||||
use anyhow::{Context as _, Result};
|
||||
use clock::LOCAL_BRANCH_REPLICA_ID;
|
||||
use clock::Lamport;
|
||||
pub use clock::ReplicaId;
|
||||
use collections::{HashMap, HashSet};
|
||||
use locator::Locator;
|
||||
@@ -573,7 +573,7 @@ struct InsertionFragment {
|
||||
fragment_id: Locator,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct InsertionFragmentKey {
|
||||
timestamp: clock::Lamport,
|
||||
split_offset: usize,
|
||||
@@ -709,7 +709,7 @@ impl FromIterator<char> for LineIndent {
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn new(replica_id: u16, remote_id: BufferId, base_text: impl Into<String>) -> Buffer {
|
||||
pub fn new(replica_id: ReplicaId, remote_id: BufferId, base_text: impl Into<String>) -> Buffer {
|
||||
let mut base_text = base_text.into();
|
||||
let line_ending = LineEnding::detect(&base_text);
|
||||
LineEnding::normalize(&mut base_text);
|
||||
@@ -717,7 +717,7 @@ impl Buffer {
|
||||
}
|
||||
|
||||
pub fn new_normalized(
|
||||
replica_id: u16,
|
||||
replica_id: ReplicaId,
|
||||
remote_id: BufferId,
|
||||
line_ending: LineEnding,
|
||||
normalized: Rope,
|
||||
@@ -731,10 +731,7 @@ impl Buffer {
|
||||
|
||||
let visible_text = history.base_text.clone();
|
||||
if !visible_text.is_empty() {
|
||||
let insertion_timestamp = clock::Lamport {
|
||||
replica_id: 0,
|
||||
value: 1,
|
||||
};
|
||||
let insertion_timestamp = clock::Lamport::new(ReplicaId::LOCAL);
|
||||
lamport_clock.observe(insertion_timestamp);
|
||||
version.observe(insertion_timestamp);
|
||||
let fragment_id = Locator::between(&Locator::min(), &Locator::max());
|
||||
@@ -788,7 +785,7 @@ impl Buffer {
|
||||
history: History::new(self.base_text().clone()),
|
||||
deferred_ops: OperationQueue::new(),
|
||||
deferred_replicas: HashSet::default(),
|
||||
lamport_clock: clock::Lamport::new(LOCAL_BRANCH_REPLICA_ID),
|
||||
lamport_clock: clock::Lamport::new(ReplicaId::LOCAL_BRANCH),
|
||||
subscriptions: Default::default(),
|
||||
edit_id_resolvers: Default::default(),
|
||||
wait_for_version_txs: Default::default(),
|
||||
@@ -1254,7 +1251,7 @@ impl Buffer {
|
||||
for edit_id in edit_ids {
|
||||
let insertion_slice = InsertionSlice {
|
||||
edit_id: *edit_id,
|
||||
insertion_id: clock::Lamport::default(),
|
||||
insertion_id: clock::Lamport::MIN,
|
||||
range: 0..0,
|
||||
};
|
||||
let slices = self
|
||||
@@ -1858,7 +1855,7 @@ impl Buffer {
|
||||
T: rand::Rng,
|
||||
{
|
||||
let mut edits = self.get_random_edits(rng, edit_count);
|
||||
log::info!("mutating buffer {} with {:?}", self.replica_id, edits);
|
||||
log::info!("mutating buffer {:?} with {:?}", self.replica_id, edits);
|
||||
|
||||
let op = self.edit(edits.iter().cloned());
|
||||
if let Operation::Edit(edit) = &op {
|
||||
@@ -1881,7 +1878,7 @@ impl Buffer {
|
||||
if let Some(entry) = self.history.undo_stack.choose(rng) {
|
||||
let transaction = entry.transaction.clone();
|
||||
log::info!(
|
||||
"undoing buffer {} transaction {:?}",
|
||||
"undoing buffer {:?} transaction {:?}",
|
||||
self.replica_id,
|
||||
transaction
|
||||
);
|
||||
@@ -2918,7 +2915,10 @@ impl InsertionFragment {
|
||||
|
||||
impl sum_tree::ContextLessSummary for InsertionFragmentKey {
|
||||
fn zero() -> Self {
|
||||
Default::default()
|
||||
InsertionFragmentKey {
|
||||
timestamp: Lamport::MIN,
|
||||
split_offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, summary: &Self) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::UndoOperation;
|
||||
use clock::Lamport;
|
||||
use std::cmp;
|
||||
use sum_tree::{Bias, SumTree};
|
||||
|
||||
@@ -24,7 +25,7 @@ impl sum_tree::KeyedItem for UndoMapEntry {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct UndoMapKey {
|
||||
edit_id: clock::Lamport,
|
||||
undo_id: clock::Lamport,
|
||||
@@ -32,7 +33,10 @@ struct UndoMapKey {
|
||||
|
||||
impl sum_tree::ContextLessSummary for UndoMapKey {
|
||||
fn zero() -> Self {
|
||||
Default::default()
|
||||
UndoMapKey {
|
||||
edit_id: Lamport::MIN,
|
||||
undo_id: Lamport::MIN,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, summary: &Self) {
|
||||
@@ -69,7 +73,7 @@ impl UndoMap {
|
||||
cursor.seek(
|
||||
&UndoMapKey {
|
||||
edit_id,
|
||||
undo_id: Default::default(),
|
||||
undo_id: Lamport::MIN,
|
||||
},
|
||||
Bias::Left,
|
||||
);
|
||||
@@ -93,7 +97,7 @@ impl UndoMap {
|
||||
cursor.seek(
|
||||
&UndoMapKey {
|
||||
edit_id,
|
||||
undo_id: Default::default(),
|
||||
undo_id: Lamport::MIN,
|
||||
},
|
||||
Bias::Left,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user