mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Remove local timestamps from CRDT operations
Use lamport timestamps for everything.
This commit is contained in:
parent
00aae5abee
commit
03f0365d4d
@ -2,70 +2,17 @@ use smallvec::SmallVec;
|
||||
use std::{
|
||||
cmp::{self, Ordering},
|
||||
fmt, iter,
|
||||
ops::{Add, AddAssign},
|
||||
};
|
||||
|
||||
pub type ReplicaId = u16;
|
||||
pub type Seq = u32;
|
||||
|
||||
#[derive(Clone, Copy, Default, Eq, Hash, PartialEq, Ord, PartialOrd)]
|
||||
pub struct Local {
|
||||
pub replica_id: ReplicaId,
|
||||
pub value: Seq,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)]
|
||||
pub struct Lamport {
|
||||
pub replica_id: ReplicaId,
|
||||
pub value: Seq,
|
||||
}
|
||||
|
||||
impl Local {
|
||||
pub const MIN: Self = Self {
|
||||
replica_id: ReplicaId::MIN,
|
||||
value: Seq::MIN,
|
||||
};
|
||||
pub const MAX: Self = Self {
|
||||
replica_id: ReplicaId::MAX,
|
||||
value: Seq::MAX,
|
||||
};
|
||||
|
||||
pub fn new(replica_id: ReplicaId) -> Self {
|
||||
Self {
|
||||
replica_id,
|
||||
value: 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(&mut self) -> Self {
|
||||
let timestamp = *self;
|
||||
self.value += 1;
|
||||
timestamp
|
||||
}
|
||||
|
||||
pub fn observe(&mut self, timestamp: Self) {
|
||||
if timestamp.replica_id == self.replica_id {
|
||||
self.value = cmp::max(self.value, timestamp.value + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<&'a Self> for Local {
|
||||
type Output = Local;
|
||||
|
||||
fn add(self, other: &'a Self) -> Self::Output {
|
||||
*cmp::max(&self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a Local> for Local {
|
||||
fn add_assign(&mut self, other: &Self) {
|
||||
if *self < *other {
|
||||
*self = *other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A vector clock
|
||||
#[derive(Clone, Default, Hash, Eq, PartialEq)]
|
||||
pub struct Global(SmallVec<[u32; 8]>);
|
||||
@ -79,7 +26,7 @@ impl Global {
|
||||
self.0.get(replica_id as usize).copied().unwrap_or(0) as Seq
|
||||
}
|
||||
|
||||
pub fn observe(&mut self, timestamp: Local) {
|
||||
pub fn observe(&mut self, timestamp: Lamport) {
|
||||
if timestamp.value > 0 {
|
||||
let new_len = timestamp.replica_id as usize + 1;
|
||||
if new_len > self.0.len() {
|
||||
@ -126,7 +73,7 @@ impl Global {
|
||||
self.0.resize(new_len, 0);
|
||||
}
|
||||
|
||||
pub fn observed(&self, timestamp: Local) -> bool {
|
||||
pub fn observed(&self, timestamp: Lamport) -> bool {
|
||||
self.get(timestamp.replica_id) >= timestamp.value
|
||||
}
|
||||
|
||||
@ -178,16 +125,16 @@ impl Global {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = Local> + '_ {
|
||||
self.0.iter().enumerate().map(|(replica_id, seq)| Local {
|
||||
pub fn iter(&self) -> impl Iterator<Item = Lamport> + '_ {
|
||||
self.0.iter().enumerate().map(|(replica_id, seq)| Lamport {
|
||||
replica_id: replica_id as ReplicaId,
|
||||
value: *seq,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<Local> for Global {
|
||||
fn from_iter<T: IntoIterator<Item = Local>>(locals: T) -> Self {
|
||||
impl FromIterator<Lamport> for Global {
|
||||
fn from_iter<T: IntoIterator<Item = Lamport>>(locals: T) -> Self {
|
||||
let mut result = Self::new();
|
||||
for local in locals {
|
||||
result.observe(local);
|
||||
@ -212,6 +159,16 @@ impl PartialOrd for Lamport {
|
||||
}
|
||||
|
||||
impl Lamport {
|
||||
pub const MIN: Self = Self {
|
||||
replica_id: ReplicaId::MIN,
|
||||
value: Seq::MIN,
|
||||
};
|
||||
|
||||
pub const MAX: Self = Self {
|
||||
replica_id: ReplicaId::MAX,
|
||||
value: Seq::MAX,
|
||||
};
|
||||
|
||||
pub fn new(replica_id: ReplicaId) -> Self {
|
||||
Self {
|
||||
value: 1,
|
||||
@ -230,12 +187,6 @@ impl Lamport {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Local {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Local {{{}: {}}}", self.replica_id, self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Lamport {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Lamport {{{}: {}}}", self.replica_id, self.value)
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
use prost::Message;
|
||||
use text::{EditOperation, InsertionTimestamp, UndoOperation};
|
||||
use text::{EditOperation, UndoOperation};
|
||||
|
||||
impl Database {
|
||||
pub async fn join_channel_buffer(
|
||||
@ -182,7 +182,6 @@ impl Database {
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub async fn get_channel_buffer_collaborators(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
@ -370,7 +369,6 @@ fn operation_to_storage(
|
||||
operation.replica_id,
|
||||
operation.lamport_timestamp,
|
||||
storage::Operation {
|
||||
local_timestamp: operation.local_timestamp,
|
||||
version: version_to_storage(&operation.version),
|
||||
is_undo: false,
|
||||
edit_ranges: operation
|
||||
@ -389,7 +387,6 @@ fn operation_to_storage(
|
||||
operation.replica_id,
|
||||
operation.lamport_timestamp,
|
||||
storage::Operation {
|
||||
local_timestamp: operation.local_timestamp,
|
||||
version: version_to_storage(&operation.version),
|
||||
is_undo: true,
|
||||
edit_ranges: Vec::new(),
|
||||
@ -399,7 +396,7 @@ fn operation_to_storage(
|
||||
.iter()
|
||||
.map(|entry| storage::UndoCount {
|
||||
replica_id: entry.replica_id,
|
||||
local_timestamp: entry.local_timestamp,
|
||||
lamport_timestamp: entry.lamport_timestamp,
|
||||
count: entry.count,
|
||||
})
|
||||
.collect(),
|
||||
@ -427,7 +424,6 @@ fn operation_from_storage(
|
||||
Ok(if operation.is_undo {
|
||||
proto::operation::Variant::Undo(proto::operation::Undo {
|
||||
replica_id: row.replica_id as u32,
|
||||
local_timestamp: operation.local_timestamp as u32,
|
||||
lamport_timestamp: row.lamport_timestamp as u32,
|
||||
version,
|
||||
counts: operation
|
||||
@ -435,7 +431,7 @@ fn operation_from_storage(
|
||||
.iter()
|
||||
.map(|entry| proto::UndoCount {
|
||||
replica_id: entry.replica_id,
|
||||
local_timestamp: entry.local_timestamp,
|
||||
lamport_timestamp: entry.lamport_timestamp,
|
||||
count: entry.count,
|
||||
})
|
||||
.collect(),
|
||||
@ -443,7 +439,6 @@ fn operation_from_storage(
|
||||
} else {
|
||||
proto::operation::Variant::Edit(proto::operation::Edit {
|
||||
replica_id: row.replica_id as u32,
|
||||
local_timestamp: operation.local_timestamp as u32,
|
||||
lamport_timestamp: row.lamport_timestamp as u32,
|
||||
version,
|
||||
ranges: operation
|
||||
@ -483,10 +478,9 @@ fn version_from_storage(version: &Vec<storage::VectorClockEntry>) -> Vec<proto::
|
||||
pub fn operation_from_wire(operation: proto::Operation) -> Option<text::Operation> {
|
||||
match operation.variant? {
|
||||
proto::operation::Variant::Edit(edit) => Some(text::Operation::Edit(EditOperation {
|
||||
timestamp: InsertionTimestamp {
|
||||
timestamp: clock::Lamport {
|
||||
replica_id: edit.replica_id as text::ReplicaId,
|
||||
local: edit.local_timestamp,
|
||||
lamport: edit.lamport_timestamp,
|
||||
value: edit.lamport_timestamp,
|
||||
},
|
||||
version: version_from_wire(&edit.version),
|
||||
ranges: edit
|
||||
@ -498,32 +492,26 @@ pub fn operation_from_wire(operation: proto::Operation) -> Option<text::Operatio
|
||||
.collect(),
|
||||
new_text: edit.new_text.into_iter().map(Arc::from).collect(),
|
||||
})),
|
||||
proto::operation::Variant::Undo(undo) => Some(text::Operation::Undo {
|
||||
lamport_timestamp: clock::Lamport {
|
||||
proto::operation::Variant::Undo(undo) => Some(text::Operation::Undo(UndoOperation {
|
||||
timestamp: clock::Lamport {
|
||||
replica_id: undo.replica_id as text::ReplicaId,
|
||||
value: undo.lamport_timestamp,
|
||||
},
|
||||
undo: UndoOperation {
|
||||
id: clock::Local {
|
||||
replica_id: undo.replica_id as text::ReplicaId,
|
||||
value: undo.local_timestamp,
|
||||
},
|
||||
version: version_from_wire(&undo.version),
|
||||
counts: undo
|
||||
.counts
|
||||
.into_iter()
|
||||
.map(|c| {
|
||||
(
|
||||
clock::Local {
|
||||
replica_id: c.replica_id as text::ReplicaId,
|
||||
value: c.local_timestamp,
|
||||
},
|
||||
c.count,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
}),
|
||||
version: version_from_wire(&undo.version),
|
||||
counts: undo
|
||||
.counts
|
||||
.into_iter()
|
||||
.map(|c| {
|
||||
(
|
||||
clock::Lamport {
|
||||
replica_id: c.replica_id as text::ReplicaId,
|
||||
value: c.lamport_timestamp,
|
||||
},
|
||||
c.count,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
})),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -531,7 +519,7 @@ pub fn operation_from_wire(operation: proto::Operation) -> Option<text::Operatio
|
||||
fn version_from_wire(message: &[proto::VectorClockEntry]) -> clock::Global {
|
||||
let mut version = clock::Global::new();
|
||||
for entry in message {
|
||||
version.observe(clock::Local {
|
||||
version.observe(clock::Lamport {
|
||||
replica_id: entry.replica_id as text::ReplicaId,
|
||||
value: entry.timestamp,
|
||||
});
|
||||
@ -546,8 +534,6 @@ mod storage {
|
||||
|
||||
#[derive(Message)]
|
||||
pub struct Operation {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub local_timestamp: u32,
|
||||
#[prost(message, repeated, tag = "2")]
|
||||
pub version: Vec<VectorClockEntry>,
|
||||
#[prost(bool, tag = "3")]
|
||||
@ -581,7 +567,7 @@ mod storage {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub replica_id: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub local_timestamp: u32,
|
||||
pub lamport_timestamp: u32,
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub count: u32,
|
||||
}
|
||||
|
@ -241,7 +241,6 @@ impl Database {
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub async fn create_user_flag(&self, flag: &str) -> Result<FlagId> {
|
||||
self.transaction(|tx| async move {
|
||||
let flag = feature_flag::Entity::insert(feature_flag::ActiveModel {
|
||||
@ -257,7 +256,6 @@ impl Database {
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub async fn add_user_flag(&self, user: UserId, flag: FlagId) -> Result<()> {
|
||||
self.transaction(|tx| async move {
|
||||
user_feature::Entity::insert(user_feature::ActiveModel {
|
||||
|
@ -439,7 +439,7 @@ impl Buffer {
|
||||
operations.extend(
|
||||
text_operations
|
||||
.iter()
|
||||
.filter(|(_, op)| !since.observed(op.local_timestamp()))
|
||||
.filter(|(_, op)| !since.observed(op.timestamp()))
|
||||
.map(|(_, op)| proto::serialize_operation(&Operation::Buffer(op.clone()))),
|
||||
);
|
||||
operations.sort_unstable_by_key(proto::lamport_timestamp_for_operation);
|
||||
@ -1304,7 +1304,7 @@ impl Buffer {
|
||||
|
||||
pub fn wait_for_edits(
|
||||
&mut self,
|
||||
edit_ids: impl IntoIterator<Item = clock::Local>,
|
||||
edit_ids: impl IntoIterator<Item = clock::Lamport>,
|
||||
) -> impl Future<Output = Result<()>> {
|
||||
self.text.wait_for_edits(edit_ids)
|
||||
}
|
||||
@ -1362,7 +1362,7 @@ impl Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_text<T>(&mut self, text: T, cx: &mut ModelContext<Self>) -> Option<clock::Local>
|
||||
pub fn set_text<T>(&mut self, text: T, cx: &mut ModelContext<Self>) -> Option<clock::Lamport>
|
||||
where
|
||||
T: Into<Arc<str>>,
|
||||
{
|
||||
@ -1375,7 +1375,7 @@ impl Buffer {
|
||||
edits_iter: I,
|
||||
autoindent_mode: Option<AutoindentMode>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Option<clock::Local>
|
||||
) -> Option<clock::Lamport>
|
||||
where
|
||||
I: IntoIterator<Item = (Range<S>, T)>,
|
||||
S: ToOffset,
|
||||
@ -1412,7 +1412,7 @@ impl Buffer {
|
||||
.and_then(|mode| self.language.as_ref().map(|_| (self.snapshot(), mode)));
|
||||
|
||||
let edit_operation = self.text.edit(edits.iter().cloned());
|
||||
let edit_id = edit_operation.local_timestamp();
|
||||
let edit_id = edit_operation.timestamp();
|
||||
|
||||
if let Some((before_edit, mode)) = autoindent_request {
|
||||
let mut delta = 0isize;
|
||||
|
@ -41,24 +41,22 @@ pub fn serialize_operation(operation: &crate::Operation) -> proto::Operation {
|
||||
proto::operation::Variant::Edit(serialize_edit_operation(edit))
|
||||
}
|
||||
|
||||
crate::Operation::Buffer(text::Operation::Undo {
|
||||
undo,
|
||||
lamport_timestamp,
|
||||
}) => proto::operation::Variant::Undo(proto::operation::Undo {
|
||||
replica_id: undo.id.replica_id as u32,
|
||||
local_timestamp: undo.id.value,
|
||||
lamport_timestamp: lamport_timestamp.value,
|
||||
version: serialize_version(&undo.version),
|
||||
counts: undo
|
||||
.counts
|
||||
.iter()
|
||||
.map(|(edit_id, count)| proto::UndoCount {
|
||||
replica_id: edit_id.replica_id as u32,
|
||||
local_timestamp: edit_id.value,
|
||||
count: *count,
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
crate::Operation::Buffer(text::Operation::Undo(undo)) => {
|
||||
proto::operation::Variant::Undo(proto::operation::Undo {
|
||||
replica_id: undo.timestamp.replica_id as u32,
|
||||
lamport_timestamp: undo.timestamp.value,
|
||||
version: serialize_version(&undo.version),
|
||||
counts: undo
|
||||
.counts
|
||||
.iter()
|
||||
.map(|(edit_id, count)| proto::UndoCount {
|
||||
replica_id: edit_id.replica_id as u32,
|
||||
lamport_timestamp: edit_id.value,
|
||||
count: *count,
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
crate::Operation::UpdateSelections {
|
||||
selections,
|
||||
@ -101,8 +99,7 @@ pub fn serialize_operation(operation: &crate::Operation) -> proto::Operation {
|
||||
pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
|
||||
proto::operation::Edit {
|
||||
replica_id: operation.timestamp.replica_id as u32,
|
||||
local_timestamp: operation.timestamp.local,
|
||||
lamport_timestamp: operation.timestamp.lamport,
|
||||
lamport_timestamp: operation.timestamp.value,
|
||||
version: serialize_version(&operation.version),
|
||||
ranges: operation.ranges.iter().map(serialize_range).collect(),
|
||||
new_text: operation
|
||||
@ -114,7 +111,7 @@ pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::
|
||||
}
|
||||
|
||||
pub fn serialize_undo_map_entry(
|
||||
(edit_id, counts): (&clock::Local, &[(clock::Local, u32)]),
|
||||
(edit_id, counts): (&clock::Lamport, &[(clock::Lamport, u32)]),
|
||||
) -> proto::UndoMapEntry {
|
||||
proto::UndoMapEntry {
|
||||
replica_id: edit_id.replica_id as u32,
|
||||
@ -123,7 +120,7 @@ pub fn serialize_undo_map_entry(
|
||||
.iter()
|
||||
.map(|(undo_id, count)| proto::UndoCount {
|
||||
replica_id: undo_id.replica_id as u32,
|
||||
local_timestamp: undo_id.value,
|
||||
lamport_timestamp: undo_id.value,
|
||||
count: *count,
|
||||
})
|
||||
.collect(),
|
||||
@ -197,7 +194,7 @@ pub fn serialize_diagnostics<'a>(
|
||||
pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
|
||||
proto::Anchor {
|
||||
replica_id: anchor.timestamp.replica_id as u32,
|
||||
local_timestamp: anchor.timestamp.value,
|
||||
timestamp: anchor.timestamp.value,
|
||||
offset: anchor.offset as u64,
|
||||
bias: match anchor.bias {
|
||||
Bias::Left => proto::Bias::Left as i32,
|
||||
@ -218,32 +215,26 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<crate::Operati
|
||||
crate::Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
|
||||
}
|
||||
proto::operation::Variant::Undo(undo) => {
|
||||
crate::Operation::Buffer(text::Operation::Undo {
|
||||
lamport_timestamp: clock::Lamport {
|
||||
crate::Operation::Buffer(text::Operation::Undo(UndoOperation {
|
||||
timestamp: clock::Lamport {
|
||||
replica_id: undo.replica_id as ReplicaId,
|
||||
value: undo.lamport_timestamp,
|
||||
},
|
||||
undo: UndoOperation {
|
||||
id: clock::Local {
|
||||
replica_id: undo.replica_id as ReplicaId,
|
||||
value: undo.local_timestamp,
|
||||
},
|
||||
version: deserialize_version(&undo.version),
|
||||
counts: undo
|
||||
.counts
|
||||
.into_iter()
|
||||
.map(|c| {
|
||||
(
|
||||
clock::Local {
|
||||
replica_id: c.replica_id as ReplicaId,
|
||||
value: c.local_timestamp,
|
||||
},
|
||||
c.count,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
})
|
||||
version: deserialize_version(&undo.version),
|
||||
counts: undo
|
||||
.counts
|
||||
.into_iter()
|
||||
.map(|c| {
|
||||
(
|
||||
clock::Lamport {
|
||||
replica_id: c.replica_id as ReplicaId,
|
||||
value: c.lamport_timestamp,
|
||||
},
|
||||
c.count,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
}))
|
||||
}
|
||||
proto::operation::Variant::UpdateSelections(message) => {
|
||||
let selections = message
|
||||
@ -298,10 +289,9 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<crate::Operati
|
||||
|
||||
pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
|
||||
EditOperation {
|
||||
timestamp: InsertionTimestamp {
|
||||
timestamp: clock::Lamport {
|
||||
replica_id: edit.replica_id as ReplicaId,
|
||||
local: edit.local_timestamp,
|
||||
lamport: edit.lamport_timestamp,
|
||||
value: edit.lamport_timestamp,
|
||||
},
|
||||
version: deserialize_version(&edit.version),
|
||||
ranges: edit.ranges.into_iter().map(deserialize_range).collect(),
|
||||
@ -311,9 +301,9 @@ pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation
|
||||
|
||||
pub fn deserialize_undo_map_entry(
|
||||
entry: proto::UndoMapEntry,
|
||||
) -> (clock::Local, Vec<(clock::Local, u32)>) {
|
||||
) -> (clock::Lamport, Vec<(clock::Lamport, u32)>) {
|
||||
(
|
||||
clock::Local {
|
||||
clock::Lamport {
|
||||
replica_id: entry.replica_id as u16,
|
||||
value: entry.local_timestamp,
|
||||
},
|
||||
@ -322,9 +312,9 @@ pub fn deserialize_undo_map_entry(
|
||||
.into_iter()
|
||||
.map(|undo_count| {
|
||||
(
|
||||
clock::Local {
|
||||
clock::Lamport {
|
||||
replica_id: undo_count.replica_id as u16,
|
||||
value: undo_count.local_timestamp,
|
||||
value: undo_count.lamport_timestamp,
|
||||
},
|
||||
undo_count.count,
|
||||
)
|
||||
@ -384,9 +374,9 @@ pub fn deserialize_diagnostics(
|
||||
|
||||
pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
|
||||
Some(Anchor {
|
||||
timestamp: clock::Local {
|
||||
timestamp: clock::Lamport {
|
||||
replica_id: anchor.replica_id as ReplicaId,
|
||||
value: anchor.local_timestamp,
|
||||
value: anchor.timestamp,
|
||||
},
|
||||
offset: anchor.offset as usize,
|
||||
bias: match proto::Bias::from_i32(anchor.bias)? {
|
||||
@ -500,12 +490,12 @@ pub fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction>
|
||||
|
||||
pub fn serialize_transaction(transaction: &Transaction) -> proto::Transaction {
|
||||
proto::Transaction {
|
||||
id: Some(serialize_local_timestamp(transaction.id)),
|
||||
id: Some(serialize_timestamp(transaction.id)),
|
||||
edit_ids: transaction
|
||||
.edit_ids
|
||||
.iter()
|
||||
.copied()
|
||||
.map(serialize_local_timestamp)
|
||||
.map(serialize_timestamp)
|
||||
.collect(),
|
||||
start: serialize_version(&transaction.start),
|
||||
}
|
||||
@ -513,7 +503,7 @@ pub fn serialize_transaction(transaction: &Transaction) -> proto::Transaction {
|
||||
|
||||
pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transaction> {
|
||||
Ok(Transaction {
|
||||
id: deserialize_local_timestamp(
|
||||
id: deserialize_timestamp(
|
||||
transaction
|
||||
.id
|
||||
.ok_or_else(|| anyhow!("missing transaction id"))?,
|
||||
@ -521,21 +511,21 @@ pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transa
|
||||
edit_ids: transaction
|
||||
.edit_ids
|
||||
.into_iter()
|
||||
.map(deserialize_local_timestamp)
|
||||
.map(deserialize_timestamp)
|
||||
.collect(),
|
||||
start: deserialize_version(&transaction.start),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn serialize_local_timestamp(timestamp: clock::Local) -> proto::LocalTimestamp {
|
||||
proto::LocalTimestamp {
|
||||
pub fn serialize_timestamp(timestamp: clock::Lamport) -> proto::LamportTimestamp {
|
||||
proto::LamportTimestamp {
|
||||
replica_id: timestamp.replica_id as u32,
|
||||
value: timestamp.value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_local_timestamp(timestamp: proto::LocalTimestamp) -> clock::Local {
|
||||
clock::Local {
|
||||
pub fn deserialize_timestamp(timestamp: proto::LamportTimestamp) -> clock::Lamport {
|
||||
clock::Lamport {
|
||||
replica_id: timestamp.replica_id as ReplicaId,
|
||||
value: timestamp.value,
|
||||
}
|
||||
@ -555,7 +545,7 @@ pub fn deserialize_range(range: proto::Range) -> Range<FullOffset> {
|
||||
pub fn deserialize_version(message: &[proto::VectorClockEntry]) -> clock::Global {
|
||||
let mut version = clock::Global::new();
|
||||
for entry in message {
|
||||
version.observe(clock::Local {
|
||||
version.observe(clock::Lamport {
|
||||
replica_id: entry.replica_id as ReplicaId,
|
||||
value: entry.timestamp,
|
||||
});
|
||||
|
@ -861,12 +861,12 @@ message ProjectTransaction {
|
||||
}
|
||||
|
||||
message Transaction {
|
||||
LocalTimestamp id = 1;
|
||||
repeated LocalTimestamp edit_ids = 2;
|
||||
LamportTimestamp id = 1;
|
||||
repeated LamportTimestamp edit_ids = 2;
|
||||
repeated VectorClockEntry start = 3;
|
||||
}
|
||||
|
||||
message LocalTimestamp {
|
||||
message LamportTimestamp {
|
||||
uint32 replica_id = 1;
|
||||
uint32 value = 2;
|
||||
}
|
||||
@ -1280,7 +1280,7 @@ message Excerpt {
|
||||
|
||||
message Anchor {
|
||||
uint32 replica_id = 1;
|
||||
uint32 local_timestamp = 2;
|
||||
uint32 timestamp = 2;
|
||||
uint64 offset = 3;
|
||||
Bias bias = 4;
|
||||
optional uint64 buffer_id = 5;
|
||||
@ -1324,7 +1324,6 @@ message Operation {
|
||||
|
||||
message Edit {
|
||||
uint32 replica_id = 1;
|
||||
uint32 local_timestamp = 2;
|
||||
uint32 lamport_timestamp = 3;
|
||||
repeated VectorClockEntry version = 4;
|
||||
repeated Range ranges = 5;
|
||||
@ -1333,7 +1332,6 @@ message Operation {
|
||||
|
||||
message Undo {
|
||||
uint32 replica_id = 1;
|
||||
uint32 local_timestamp = 2;
|
||||
uint32 lamport_timestamp = 3;
|
||||
repeated VectorClockEntry version = 4;
|
||||
repeated UndoCount counts = 5;
|
||||
@ -1362,7 +1360,7 @@ message UndoMapEntry {
|
||||
|
||||
message UndoCount {
|
||||
uint32 replica_id = 1;
|
||||
uint32 local_timestamp = 2;
|
||||
uint32 lamport_timestamp = 2;
|
||||
uint32 count = 3;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ regex.workspace = true
|
||||
[dev-dependencies]
|
||||
collections = { path = "../collections", features = ["test-support"] }
|
||||
gpui = { path = "../gpui", features = ["test-support"] }
|
||||
util = { path = "../util", features = ["test-support"] }
|
||||
ctor.workspace = true
|
||||
env_logger.workspace = true
|
||||
rand.workspace = true
|
||||
|
@ -8,7 +8,7 @@ use sum_tree::Bias;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)]
|
||||
pub struct Anchor {
|
||||
pub timestamp: clock::Local,
|
||||
pub timestamp: clock::Lamport,
|
||||
pub offset: usize,
|
||||
pub bias: Bias,
|
||||
pub buffer_id: Option<u64>,
|
||||
@ -16,14 +16,14 @@ pub struct Anchor {
|
||||
|
||||
impl Anchor {
|
||||
pub const MIN: Self = Self {
|
||||
timestamp: clock::Local::MIN,
|
||||
timestamp: clock::Lamport::MIN,
|
||||
offset: usize::MIN,
|
||||
bias: Bias::Left,
|
||||
buffer_id: None,
|
||||
};
|
||||
|
||||
pub const MAX: Self = Self {
|
||||
timestamp: clock::Local::MAX,
|
||||
timestamp: clock::Lamport::MAX,
|
||||
offset: usize::MAX,
|
||||
bias: Bias::Right,
|
||||
buffer_id: None,
|
||||
|
@ -46,18 +46,16 @@ lazy_static! {
|
||||
static ref LINE_SEPARATORS_REGEX: Regex = Regex::new("\r\n|\r|\u{2028}|\u{2029}").unwrap();
|
||||
}
|
||||
|
||||
pub type TransactionId = clock::Local;
|
||||
pub type TransactionId = clock::Lamport;
|
||||
|
||||
pub struct Buffer {
|
||||
snapshot: BufferSnapshot,
|
||||
history: History,
|
||||
deferred_ops: OperationQueue<Operation>,
|
||||
deferred_replicas: HashSet<ReplicaId>,
|
||||
replica_id: ReplicaId,
|
||||
local_clock: clock::Local,
|
||||
pub lamport_clock: clock::Lamport,
|
||||
subscriptions: Topic,
|
||||
edit_id_resolvers: HashMap<clock::Local, Vec<oneshot::Sender<()>>>,
|
||||
edit_id_resolvers: HashMap<clock::Lamport, Vec<oneshot::Sender<()>>>,
|
||||
wait_for_version_txs: Vec<(clock::Global, oneshot::Sender<()>)>,
|
||||
}
|
||||
|
||||
@ -85,7 +83,7 @@ pub struct HistoryEntry {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Transaction {
|
||||
pub id: TransactionId,
|
||||
pub edit_ids: Vec<clock::Local>,
|
||||
pub edit_ids: Vec<clock::Lamport>,
|
||||
pub start: clock::Global,
|
||||
}
|
||||
|
||||
@ -97,8 +95,8 @@ impl HistoryEntry {
|
||||
|
||||
struct History {
|
||||
base_text: Rope,
|
||||
operations: TreeMap<clock::Local, Operation>,
|
||||
insertion_slices: HashMap<clock::Local, Vec<InsertionSlice>>,
|
||||
operations: TreeMap<clock::Lamport, Operation>,
|
||||
insertion_slices: HashMap<clock::Lamport, Vec<InsertionSlice>>,
|
||||
undo_stack: Vec<HistoryEntry>,
|
||||
redo_stack: Vec<HistoryEntry>,
|
||||
transaction_depth: usize,
|
||||
@ -107,7 +105,7 @@ struct History {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct InsertionSlice {
|
||||
insertion_id: clock::Local,
|
||||
insertion_id: clock::Lamport,
|
||||
range: Range<usize>,
|
||||
}
|
||||
|
||||
@ -129,18 +127,18 @@ impl History {
|
||||
}
|
||||
|
||||
fn push(&mut self, op: Operation) {
|
||||
self.operations.insert(op.local_timestamp(), op);
|
||||
self.operations.insert(op.timestamp(), op);
|
||||
}
|
||||
|
||||
fn start_transaction(
|
||||
&mut self,
|
||||
start: clock::Global,
|
||||
now: Instant,
|
||||
local_clock: &mut clock::Local,
|
||||
clock: &mut clock::Lamport,
|
||||
) -> Option<TransactionId> {
|
||||
self.transaction_depth += 1;
|
||||
if self.transaction_depth == 1 {
|
||||
let id = local_clock.tick();
|
||||
let id = clock.tick();
|
||||
self.undo_stack.push(HistoryEntry {
|
||||
transaction: Transaction {
|
||||
id,
|
||||
@ -251,7 +249,7 @@ impl History {
|
||||
self.redo_stack.clear();
|
||||
}
|
||||
|
||||
fn push_undo(&mut self, op_id: clock::Local) {
|
||||
fn push_undo(&mut self, op_id: clock::Lamport) {
|
||||
assert_ne!(self.transaction_depth, 0);
|
||||
if let Some(Operation::Edit(_)) = self.operations.get(&op_id) {
|
||||
let last_transaction = self.undo_stack.last_mut().unwrap();
|
||||
@ -412,37 +410,14 @@ impl<D1, D2> Edit<(D1, D2)> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct InsertionTimestamp {
|
||||
pub replica_id: ReplicaId,
|
||||
pub local: clock::Seq,
|
||||
pub lamport: clock::Seq,
|
||||
}
|
||||
|
||||
impl InsertionTimestamp {
|
||||
pub fn local(&self) -> clock::Local {
|
||||
clock::Local {
|
||||
replica_id: self.replica_id,
|
||||
value: self.local,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lamport(&self) -> clock::Lamport {
|
||||
clock::Lamport {
|
||||
replica_id: self.replica_id,
|
||||
value: self.lamport,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||
pub struct Fragment {
|
||||
pub id: Locator,
|
||||
pub insertion_timestamp: InsertionTimestamp,
|
||||
pub timestamp: clock::Lamport,
|
||||
pub insertion_offset: usize,
|
||||
pub len: usize,
|
||||
pub visible: bool,
|
||||
pub deletions: HashSet<clock::Local>,
|
||||
pub deletions: HashSet<clock::Lamport>,
|
||||
pub max_undos: clock::Global,
|
||||
}
|
||||
|
||||
@ -470,29 +445,26 @@ impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentTextSummary {
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||
struct InsertionFragment {
|
||||
timestamp: clock::Local,
|
||||
timestamp: clock::Lamport,
|
||||
split_offset: usize,
|
||||
fragment_id: Locator,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct InsertionFragmentKey {
|
||||
timestamp: clock::Local,
|
||||
timestamp: clock::Lamport,
|
||||
split_offset: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Operation {
|
||||
Edit(EditOperation),
|
||||
Undo {
|
||||
undo: UndoOperation,
|
||||
lamport_timestamp: clock::Lamport,
|
||||
},
|
||||
Undo(UndoOperation),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct EditOperation {
|
||||
pub timestamp: InsertionTimestamp,
|
||||
pub timestamp: clock::Lamport,
|
||||
pub version: clock::Global,
|
||||
pub ranges: Vec<Range<FullOffset>>,
|
||||
pub new_text: Vec<Arc<str>>,
|
||||
@ -500,9 +472,9 @@ pub struct EditOperation {
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct UndoOperation {
|
||||
pub id: clock::Local,
|
||||
pub counts: HashMap<clock::Local, u32>,
|
||||
pub timestamp: clock::Lamport,
|
||||
pub version: clock::Global,
|
||||
pub counts: HashMap<clock::Lamport, u32>,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
@ -514,24 +486,21 @@ impl Buffer {
|
||||
let mut fragments = SumTree::new();
|
||||
let mut insertions = 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 = history.base_text.clone();
|
||||
if !visible_text.is_empty() {
|
||||
let insertion_timestamp = InsertionTimestamp {
|
||||
let insertion_timestamp = clock::Lamport {
|
||||
replica_id: 0,
|
||||
local: 1,
|
||||
lamport: 1,
|
||||
value: 1,
|
||||
};
|
||||
local_clock.observe(insertion_timestamp.local());
|
||||
lamport_clock.observe(insertion_timestamp.lamport());
|
||||
version.observe(insertion_timestamp.local());
|
||||
lamport_clock.observe(insertion_timestamp);
|
||||
version.observe(insertion_timestamp);
|
||||
let fragment_id = Locator::between(&Locator::min(), &Locator::max());
|
||||
let fragment = Fragment {
|
||||
id: fragment_id,
|
||||
insertion_timestamp,
|
||||
timestamp: insertion_timestamp,
|
||||
insertion_offset: 0,
|
||||
len: visible_text.len(),
|
||||
visible: true,
|
||||
@ -557,8 +526,6 @@ impl Buffer {
|
||||
history,
|
||||
deferred_ops: OperationQueue::new(),
|
||||
deferred_replicas: HashSet::default(),
|
||||
replica_id,
|
||||
local_clock,
|
||||
lamport_clock,
|
||||
subscriptions: Default::default(),
|
||||
edit_id_resolvers: Default::default(),
|
||||
@ -575,7 +542,7 @@ impl Buffer {
|
||||
}
|
||||
|
||||
pub fn replica_id(&self) -> ReplicaId {
|
||||
self.local_clock.replica_id
|
||||
self.lamport_clock.replica_id
|
||||
}
|
||||
|
||||
pub fn remote_id(&self) -> u64 {
|
||||
@ -602,16 +569,12 @@ impl Buffer {
|
||||
.map(|(range, new_text)| (range, new_text.into()));
|
||||
|
||||
self.start_transaction();
|
||||
let timestamp = InsertionTimestamp {
|
||||
replica_id: self.replica_id,
|
||||
local: self.local_clock.tick().value,
|
||||
lamport: self.lamport_clock.tick().value,
|
||||
};
|
||||
let timestamp = self.lamport_clock.tick();
|
||||
let operation = Operation::Edit(self.apply_local_edit(edits, timestamp));
|
||||
|
||||
self.history.push(operation.clone());
|
||||
self.history.push_undo(operation.local_timestamp());
|
||||
self.snapshot.version.observe(operation.local_timestamp());
|
||||
self.history.push_undo(operation.timestamp());
|
||||
self.snapshot.version.observe(operation.timestamp());
|
||||
self.end_transaction();
|
||||
operation
|
||||
}
|
||||
@ -619,7 +582,7 @@ impl Buffer {
|
||||
fn apply_local_edit<S: ToOffset, T: Into<Arc<str>>>(
|
||||
&mut self,
|
||||
edits: impl ExactSizeIterator<Item = (Range<S>, T)>,
|
||||
timestamp: InsertionTimestamp,
|
||||
timestamp: clock::Lamport,
|
||||
) -> EditOperation {
|
||||
let mut edits_patch = Patch::default();
|
||||
let mut edit_op = EditOperation {
|
||||
@ -696,7 +659,7 @@ impl Buffer {
|
||||
.item()
|
||||
.map_or(&Locator::max(), |old_fragment| &old_fragment.id),
|
||||
),
|
||||
insertion_timestamp: timestamp,
|
||||
timestamp,
|
||||
insertion_offset,
|
||||
len: new_text.len(),
|
||||
deletions: Default::default(),
|
||||
@ -726,7 +689,7 @@ impl Buffer {
|
||||
intersection.insertion_offset += fragment_start - old_fragments.start().visible;
|
||||
intersection.id =
|
||||
Locator::between(&new_fragments.summary().max_id, &intersection.id);
|
||||
intersection.deletions.insert(timestamp.local());
|
||||
intersection.deletions.insert(timestamp);
|
||||
intersection.visible = false;
|
||||
}
|
||||
if intersection.len > 0 {
|
||||
@ -781,7 +744,7 @@ impl Buffer {
|
||||
self.subscriptions.publish_mut(&edits_patch);
|
||||
self.history
|
||||
.insertion_slices
|
||||
.insert(timestamp.local(), insertion_slices);
|
||||
.insert(timestamp, insertion_slices);
|
||||
edit_op
|
||||
}
|
||||
|
||||
@ -808,28 +771,23 @@ impl Buffer {
|
||||
fn apply_op(&mut self, op: Operation) -> Result<()> {
|
||||
match op {
|
||||
Operation::Edit(edit) => {
|
||||
if !self.version.observed(edit.timestamp.local()) {
|
||||
if !self.version.observed(edit.timestamp) {
|
||||
self.apply_remote_edit(
|
||||
&edit.version,
|
||||
&edit.ranges,
|
||||
&edit.new_text,
|
||||
edit.timestamp,
|
||||
);
|
||||
self.snapshot.version.observe(edit.timestamp.local());
|
||||
self.local_clock.observe(edit.timestamp.local());
|
||||
self.lamport_clock.observe(edit.timestamp.lamport());
|
||||
self.resolve_edit(edit.timestamp.local());
|
||||
self.snapshot.version.observe(edit.timestamp);
|
||||
self.lamport_clock.observe(edit.timestamp);
|
||||
self.resolve_edit(edit.timestamp);
|
||||
}
|
||||
}
|
||||
Operation::Undo {
|
||||
undo,
|
||||
lamport_timestamp,
|
||||
} => {
|
||||
if !self.version.observed(undo.id) {
|
||||
Operation::Undo(undo) => {
|
||||
if !self.version.observed(undo.timestamp) {
|
||||
self.apply_undo(&undo)?;
|
||||
self.snapshot.version.observe(undo.id);
|
||||
self.local_clock.observe(undo.id);
|
||||
self.lamport_clock.observe(lamport_timestamp);
|
||||
self.snapshot.version.observe(undo.timestamp);
|
||||
self.lamport_clock.observe(undo.timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -849,7 +807,7 @@ impl Buffer {
|
||||
version: &clock::Global,
|
||||
ranges: &[Range<FullOffset>],
|
||||
new_text: &[Arc<str>],
|
||||
timestamp: InsertionTimestamp,
|
||||
timestamp: clock::Lamport,
|
||||
) {
|
||||
if ranges.is_empty() {
|
||||
return;
|
||||
@ -916,9 +874,7 @@ 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.insertion_timestamp.lamport() > timestamp.lamport()
|
||||
{
|
||||
if fragment_start == range.start && fragment.timestamp > timestamp {
|
||||
new_ropes.push_fragment(fragment, fragment.visible);
|
||||
new_fragments.push(fragment.clone(), &None);
|
||||
old_fragments.next(&cx);
|
||||
@ -955,7 +911,7 @@ impl Buffer {
|
||||
.item()
|
||||
.map_or(&Locator::max(), |old_fragment| &old_fragment.id),
|
||||
),
|
||||
insertion_timestamp: timestamp,
|
||||
timestamp,
|
||||
insertion_offset,
|
||||
len: new_text.len(),
|
||||
deletions: Default::default(),
|
||||
@ -986,7 +942,7 @@ impl Buffer {
|
||||
fragment_start - old_fragments.start().0.full_offset();
|
||||
intersection.id =
|
||||
Locator::between(&new_fragments.summary().max_id, &intersection.id);
|
||||
intersection.deletions.insert(timestamp.local());
|
||||
intersection.deletions.insert(timestamp);
|
||||
intersection.visible = false;
|
||||
insertion_slices.push(intersection.insertion_slice());
|
||||
}
|
||||
@ -1038,13 +994,13 @@ impl Buffer {
|
||||
self.snapshot.insertions.edit(new_insertions, &());
|
||||
self.history
|
||||
.insertion_slices
|
||||
.insert(timestamp.local(), insertion_slices);
|
||||
.insert(timestamp, insertion_slices);
|
||||
self.subscriptions.publish_mut(&edits_patch)
|
||||
}
|
||||
|
||||
fn fragment_ids_for_edits<'a>(
|
||||
&'a self,
|
||||
edit_ids: impl Iterator<Item = &'a clock::Local>,
|
||||
edit_ids: impl Iterator<Item = &'a clock::Lamport>,
|
||||
) -> Vec<&'a Locator> {
|
||||
// Get all of the insertion slices changed by the given edits.
|
||||
let mut insertion_slices = Vec::new();
|
||||
@ -1105,7 +1061,7 @@ impl Buffer {
|
||||
let fragment_was_visible = fragment.visible;
|
||||
|
||||
fragment.visible = fragment.is_visible(&self.undo_map);
|
||||
fragment.max_undos.observe(undo.id);
|
||||
fragment.max_undos.observe(undo.timestamp);
|
||||
|
||||
let old_start = old_fragments.start().1;
|
||||
let new_start = new_fragments.summary().text.visible;
|
||||
@ -1159,10 +1115,10 @@ impl Buffer {
|
||||
if self.deferred_replicas.contains(&op.replica_id()) {
|
||||
false
|
||||
} else {
|
||||
match op {
|
||||
Operation::Edit(edit) => self.version.observed_all(&edit.version),
|
||||
Operation::Undo { undo, .. } => self.version.observed_all(&undo.version),
|
||||
}
|
||||
self.version.observed_all(match op {
|
||||
Operation::Edit(edit) => &edit.version,
|
||||
Operation::Undo(undo) => &undo.version,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1180,7 +1136,7 @@ impl Buffer {
|
||||
|
||||
pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
|
||||
self.history
|
||||
.start_transaction(self.version.clone(), now, &mut self.local_clock)
|
||||
.start_transaction(self.version.clone(), now, &mut self.lamport_clock)
|
||||
}
|
||||
|
||||
pub fn end_transaction(&mut self) -> Option<(TransactionId, clock::Global)> {
|
||||
@ -1209,7 +1165,7 @@ impl Buffer {
|
||||
&self.history.base_text
|
||||
}
|
||||
|
||||
pub fn operations(&self) -> &TreeMap<clock::Local, Operation> {
|
||||
pub fn operations(&self) -> &TreeMap<clock::Lamport, Operation> {
|
||||
&self.history.operations
|
||||
}
|
||||
|
||||
@ -1289,16 +1245,13 @@ impl Buffer {
|
||||
}
|
||||
|
||||
let undo = UndoOperation {
|
||||
id: self.local_clock.tick(),
|
||||
timestamp: self.lamport_clock.tick(),
|
||||
version: self.version(),
|
||||
counts,
|
||||
};
|
||||
self.apply_undo(&undo)?;
|
||||
let operation = Operation::Undo {
|
||||
undo,
|
||||
lamport_timestamp: self.lamport_clock.tick(),
|
||||
};
|
||||
self.snapshot.version.observe(operation.local_timestamp());
|
||||
self.snapshot.version.observe(undo.timestamp);
|
||||
let operation = Operation::Undo(undo);
|
||||
self.history.push(operation.clone());
|
||||
Ok(operation)
|
||||
}
|
||||
@ -1363,7 +1316,7 @@ impl Buffer {
|
||||
|
||||
pub fn wait_for_edits(
|
||||
&mut self,
|
||||
edit_ids: impl IntoIterator<Item = clock::Local>,
|
||||
edit_ids: impl IntoIterator<Item = clock::Lamport>,
|
||||
) -> impl 'static + Future<Output = Result<()>> {
|
||||
let mut futures = Vec::new();
|
||||
for edit_id in edit_ids {
|
||||
@ -1435,7 +1388,7 @@ impl Buffer {
|
||||
self.wait_for_version_txs.clear();
|
||||
}
|
||||
|
||||
fn resolve_edit(&mut self, edit_id: clock::Local) {
|
||||
fn resolve_edit(&mut self, edit_id: clock::Lamport) {
|
||||
for mut tx in self
|
||||
.edit_id_resolvers
|
||||
.remove(&edit_id)
|
||||
@ -1513,7 +1466,7 @@ impl Buffer {
|
||||
.insertions
|
||||
.get(
|
||||
&InsertionFragmentKey {
|
||||
timestamp: fragment.insertion_timestamp.local(),
|
||||
timestamp: fragment.timestamp,
|
||||
split_offset: fragment.insertion_offset,
|
||||
},
|
||||
&(),
|
||||
@ -1996,7 +1949,7 @@ impl BufferSnapshot {
|
||||
let fragment = fragment_cursor.item().unwrap();
|
||||
let overshoot = offset - *fragment_cursor.start();
|
||||
Anchor {
|
||||
timestamp: fragment.insertion_timestamp.local(),
|
||||
timestamp: fragment.timestamp,
|
||||
offset: fragment.insertion_offset + overshoot,
|
||||
bias,
|
||||
buffer_id: Some(self.remote_id),
|
||||
@ -2188,15 +2141,14 @@ impl<'a, D: TextDimension + Ord, F: FnMut(&FragmentSummary) -> bool> Iterator fo
|
||||
break;
|
||||
}
|
||||
|
||||
let timestamp = fragment.insertion_timestamp.local();
|
||||
let start_anchor = Anchor {
|
||||
timestamp,
|
||||
timestamp: fragment.timestamp,
|
||||
offset: fragment.insertion_offset,
|
||||
bias: Bias::Right,
|
||||
buffer_id: Some(self.buffer_id),
|
||||
};
|
||||
let end_anchor = Anchor {
|
||||
timestamp,
|
||||
timestamp: fragment.timestamp,
|
||||
offset: fragment.insertion_offset + fragment.len,
|
||||
bias: Bias::Left,
|
||||
buffer_id: Some(self.buffer_id),
|
||||
@ -2269,19 +2221,17 @@ impl<'a, D: TextDimension + Ord, F: FnMut(&FragmentSummary) -> bool> Iterator fo
|
||||
impl Fragment {
|
||||
fn insertion_slice(&self) -> InsertionSlice {
|
||||
InsertionSlice {
|
||||
insertion_id: self.insertion_timestamp.local(),
|
||||
insertion_id: self.timestamp,
|
||||
range: self.insertion_offset..self.insertion_offset + self.len,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_visible(&self, undos: &UndoMap) -> bool {
|
||||
!undos.is_undone(self.insertion_timestamp.local())
|
||||
&& self.deletions.iter().all(|d| undos.is_undone(*d))
|
||||
!undos.is_undone(self.timestamp) && self.deletions.iter().all(|d| undos.is_undone(*d))
|
||||
}
|
||||
|
||||
fn was_visible(&self, version: &clock::Global, undos: &UndoMap) -> bool {
|
||||
(version.observed(self.insertion_timestamp.local())
|
||||
&& !undos.was_undone(self.insertion_timestamp.local(), version))
|
||||
(version.observed(self.timestamp) && !undos.was_undone(self.timestamp, version))
|
||||
&& self
|
||||
.deletions
|
||||
.iter()
|
||||
@ -2294,14 +2244,14 @@ impl sum_tree::Item for Fragment {
|
||||
|
||||
fn summary(&self) -> Self::Summary {
|
||||
let mut max_version = clock::Global::new();
|
||||
max_version.observe(self.insertion_timestamp.local());
|
||||
max_version.observe(self.timestamp);
|
||||
for deletion in &self.deletions {
|
||||
max_version.observe(*deletion);
|
||||
}
|
||||
max_version.join(&self.max_undos);
|
||||
|
||||
let mut min_insertion_version = clock::Global::new();
|
||||
min_insertion_version.observe(self.insertion_timestamp.local());
|
||||
min_insertion_version.observe(self.timestamp);
|
||||
let max_insertion_version = min_insertion_version.clone();
|
||||
if self.visible {
|
||||
FragmentSummary {
|
||||
@ -2378,7 +2328,7 @@ impl sum_tree::KeyedItem for InsertionFragment {
|
||||
impl InsertionFragment {
|
||||
fn new(fragment: &Fragment) -> Self {
|
||||
Self {
|
||||
timestamp: fragment.insertion_timestamp.local(),
|
||||
timestamp: fragment.timestamp,
|
||||
split_offset: fragment.insertion_offset,
|
||||
fragment_id: fragment.id.clone(),
|
||||
}
|
||||
@ -2501,10 +2451,10 @@ impl Operation {
|
||||
operation_queue::Operation::lamport_timestamp(self).replica_id
|
||||
}
|
||||
|
||||
pub fn local_timestamp(&self) -> clock::Local {
|
||||
pub fn timestamp(&self) -> clock::Lamport {
|
||||
match self {
|
||||
Operation::Edit(edit) => edit.timestamp.local(),
|
||||
Operation::Undo { undo, .. } => undo.id,
|
||||
Operation::Edit(edit) => edit.timestamp,
|
||||
Operation::Undo(undo) => undo.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2523,10 +2473,8 @@ impl Operation {
|
||||
impl operation_queue::Operation for Operation {
|
||||
fn lamport_timestamp(&self) -> clock::Lamport {
|
||||
match self {
|
||||
Operation::Edit(edit) => edit.timestamp.lamport(),
|
||||
Operation::Undo {
|
||||
lamport_timestamp, ..
|
||||
} => *lamport_timestamp,
|
||||
Operation::Edit(edit) => edit.timestamp,
|
||||
Operation::Undo(undo) => undo.timestamp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ impl sum_tree::KeyedItem for UndoMapEntry {
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct UndoMapKey {
|
||||
edit_id: clock::Local,
|
||||
undo_id: clock::Local,
|
||||
edit_id: clock::Lamport,
|
||||
undo_id: clock::Lamport,
|
||||
}
|
||||
|
||||
impl sum_tree::Summary for UndoMapKey {
|
||||
@ -50,7 +50,7 @@ impl UndoMap {
|
||||
sum_tree::Edit::Insert(UndoMapEntry {
|
||||
key: UndoMapKey {
|
||||
edit_id: *edit_id,
|
||||
undo_id: undo.id,
|
||||
undo_id: undo.timestamp,
|
||||
},
|
||||
undo_count: *count,
|
||||
})
|
||||
@ -59,11 +59,11 @@ impl UndoMap {
|
||||
self.0.edit(edits, &());
|
||||
}
|
||||
|
||||
pub fn is_undone(&self, edit_id: clock::Local) -> bool {
|
||||
pub fn is_undone(&self, edit_id: clock::Lamport) -> bool {
|
||||
self.undo_count(edit_id) % 2 == 1
|
||||
}
|
||||
|
||||
pub fn was_undone(&self, edit_id: clock::Local, version: &clock::Global) -> bool {
|
||||
pub fn was_undone(&self, edit_id: clock::Lamport, version: &clock::Global) -> bool {
|
||||
let mut cursor = self.0.cursor::<UndoMapKey>();
|
||||
cursor.seek(
|
||||
&UndoMapKey {
|
||||
@ -88,7 +88,7 @@ impl UndoMap {
|
||||
undo_count % 2 == 1
|
||||
}
|
||||
|
||||
pub fn undo_count(&self, edit_id: clock::Local) -> u32 {
|
||||
pub fn undo_count(&self, edit_id: clock::Lamport) -> u32 {
|
||||
let mut cursor = self.0.cursor::<UndoMapKey>();
|
||||
cursor.seek(
|
||||
&UndoMapKey {
|
||||
|
Loading…
Reference in New Issue
Block a user