cob: Have clock value for empty COB state
By using `0` as the clock value for an empty state (without operations), we simplify transaction code. Previously, there was no clock value for empty states, which meant that we had to sometimes use an `Option`.
This commit is contained in:
parent
c568feb700
commit
5ee1f42b6a
|
|
@ -48,8 +48,8 @@ pub fn evaluate(root: Oid, graph: &Dag<Oid, Change>, rng: fastrand::Rng) -> hist
|
|||
clock + entry.contents().len() as Clock - 1
|
||||
})
|
||||
.max()
|
||||
.map(|n| n + 1)
|
||||
.unwrap_or_default();
|
||||
.unwrap_or_default() // When there are no operations, the clock is zero.
|
||||
+ 1;
|
||||
log::trace!("change '{}' accepted", c.change.id());
|
||||
|
||||
entries.insert(*entry.id(), EntryWithClock { entry, clock });
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ impl History {
|
|||
timestamp,
|
||||
};
|
||||
let mut entries = HashMap::new();
|
||||
entries.insert(id, EntryWithClock::from(root_entry));
|
||||
entries.insert(id, EntryWithClock::root(root_entry));
|
||||
|
||||
create_dag(&id, &entries)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,11 +131,11 @@ pub struct EntryWithClock {
|
|||
pub clock: Clock,
|
||||
}
|
||||
|
||||
impl From<Entry> for EntryWithClock {
|
||||
fn from(entry: Entry) -> Self {
|
||||
impl EntryWithClock {
|
||||
pub fn root(entry: Entry) -> Self {
|
||||
Self {
|
||||
entry,
|
||||
clock: Clock::default(),
|
||||
clock: 1 as Clock, // The root entry has a clock value of `1`.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ impl<'a> Issues<'a> {
|
|||
tx.tag(tags.to_owned(), []);
|
||||
})?;
|
||||
// Just a sanity check that our clock is advancing as expected.
|
||||
debug_assert_eq!(clock.get(), 2);
|
||||
debug_assert_eq!(clock.get(), 3);
|
||||
|
||||
Ok(IssueMut {
|
||||
id,
|
||||
|
|
@ -549,6 +549,8 @@ mod test {
|
|||
let created = issues
|
||||
.create("My first issue", "Blah blah blah.", &[], &signer)
|
||||
.unwrap();
|
||||
assert_eq!(created.clock().get(), 3);
|
||||
|
||||
let (id, created) = (created.id, created.issue);
|
||||
let issue = issues.get(&id).unwrap().unwrap();
|
||||
|
||||
|
|
@ -645,7 +647,7 @@ mod test {
|
|||
let mut issue = issues
|
||||
.create("My first issue", "Blah blah blah.", &[], &signer)
|
||||
.unwrap();
|
||||
let root = OpId::initial(author);
|
||||
let root = OpId::root(author);
|
||||
|
||||
let c1 = issue.comment("Hi hi hi.", root, &signer).unwrap();
|
||||
let c2 = issue.comment("Ha ha ha.", root, &signer).unwrap();
|
||||
|
|
@ -706,8 +708,8 @@ mod test {
|
|||
.create("My first issue", "Blah blah blah.", &[], &signer)
|
||||
.unwrap();
|
||||
|
||||
// The initial thread op id is always the same.
|
||||
let c0 = OpId::initial(author);
|
||||
// The root thread op id is always the same.
|
||||
let c0 = OpId::root(author);
|
||||
|
||||
issue.comment("Ho ho ho.", c0, &signer).unwrap();
|
||||
issue.comment("Ha ha ha.", c0, &signer).unwrap();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ impl OpId {
|
|||
Self(Lamport::initial(), actor)
|
||||
}
|
||||
|
||||
pub fn root(actor: ActorId) -> Self {
|
||||
Self(Lamport::initial().tick(), actor)
|
||||
}
|
||||
|
||||
/// Get operation id clock.
|
||||
pub fn clock(&self) -> Lamport {
|
||||
self.0
|
||||
|
|
@ -153,7 +157,7 @@ impl<G: Signer, A: Clone> Actor<G, A> {
|
|||
/// Create a new operation.
|
||||
pub fn op(&mut self, action: A) -> Op<A> {
|
||||
let author = *self.signer.public_key();
|
||||
let clock = self.clock;
|
||||
let clock = self.clock.tick();
|
||||
let timestamp = clock::Physical::now();
|
||||
let op = Op {
|
||||
action,
|
||||
|
|
@ -162,7 +166,6 @@ impl<G: Signer, A: Clone> Actor<G, A> {
|
|||
timestamp,
|
||||
};
|
||||
self.ops.insert((self.clock, author), op.clone());
|
||||
self.clock.tick();
|
||||
|
||||
op
|
||||
}
|
||||
|
|
|
|||
|
|
@ -787,7 +787,7 @@ impl<'a> Patches<'a> {
|
|||
tx.tag(tags.to_owned(), []);
|
||||
})?;
|
||||
// Just a sanity check that our clock is advancing as expected.
|
||||
debug_assert_eq!(clock.get(), 2);
|
||||
debug_assert_eq!(clock.get(), 3);
|
||||
|
||||
Ok(PatchMut::new(id, patch, clock, self))
|
||||
}
|
||||
|
|
@ -1023,7 +1023,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(patch.clock, clock::Lamport::from(2));
|
||||
assert_eq!(patch.clock.get(), 3);
|
||||
|
||||
let id = patch.id;
|
||||
let patch = patches.get(&id).unwrap().unwrap();
|
||||
|
|
@ -1238,15 +1238,15 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(patch.clock.get(), 2);
|
||||
assert_eq!(patch.clock.get(), 3);
|
||||
assert_eq!(patch.description(), Some("Blah blah blah."));
|
||||
assert_eq!(patch.version(), 0);
|
||||
|
||||
let (r1, t1) = patch
|
||||
.update("I've made changes.", base, rev1_oid, &signer)
|
||||
.unwrap();
|
||||
assert_eq!(r1.clock().get(), 3);
|
||||
assert_eq!(t1.clock().get(), 4);
|
||||
assert_eq!(r1.clock().get(), 4);
|
||||
assert_eq!(t1.clock().get(), 5);
|
||||
|
||||
let id = patch.id;
|
||||
let patch = patches.get(&id).unwrap().unwrap();
|
||||
|
|
|
|||
|
|
@ -194,17 +194,19 @@ where
|
|||
pub struct Transaction<T: FromHistory> {
|
||||
actor: ActorId,
|
||||
start: Lamport,
|
||||
clock: Option<Lamport>,
|
||||
clock: Lamport,
|
||||
actions: Vec<T::Action>,
|
||||
}
|
||||
|
||||
impl<T: FromHistory> Transaction<T> {
|
||||
/// Create a new transaction.
|
||||
pub fn new(actor: ActorId, clock: Lamport) -> Self {
|
||||
let start = clock;
|
||||
|
||||
Self {
|
||||
actor,
|
||||
start: clock,
|
||||
clock: Some(clock),
|
||||
start,
|
||||
clock,
|
||||
actions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -225,7 +227,7 @@ impl<T: FromHistory> Transaction<T> {
|
|||
let mut tx = Transaction {
|
||||
actor,
|
||||
start: Lamport::initial(),
|
||||
clock: None,
|
||||
clock: Lamport::initial(),
|
||||
actions: Vec::new(),
|
||||
};
|
||||
operations(&mut tx);
|
||||
|
|
@ -235,7 +237,7 @@ impl<T: FromHistory> Transaction<T> {
|
|||
let (id, cob, clock) = store.create(message, actions, signer)?;
|
||||
|
||||
// The history clock should be in sync with the tx clock.
|
||||
assert_eq!(Some(clock), tx.clock);
|
||||
assert_eq!(clock, tx.clock);
|
||||
|
||||
Ok((id, cob, clock))
|
||||
}
|
||||
|
|
@ -243,20 +245,7 @@ impl<T: FromHistory> Transaction<T> {
|
|||
/// Add an operation to this transaction.
|
||||
pub fn push(&mut self, action: T::Action) -> cob::OpId {
|
||||
self.actions.push(action);
|
||||
|
||||
// If our clock already had a value, it means this isn't the first operation
|
||||
// of this COB. In that case we 'tick' the clock and return the new clock
|
||||
// value.
|
||||
//
|
||||
// Otherwise, it means it was the first operation of our COB. In that case
|
||||
// we set our clock to the initial clock value (0), and return that.
|
||||
if let Some(ref mut clock) = self.clock {
|
||||
OpId::new(clock.tick(), self.actor)
|
||||
} else {
|
||||
self.clock = Some(Lamport::initial());
|
||||
|
||||
OpId::initial(self.actor)
|
||||
}
|
||||
OpId::new(self.clock.tick(), self.actor)
|
||||
}
|
||||
|
||||
/// Commit transaction.
|
||||
|
|
@ -279,7 +268,7 @@ impl<T: FromHistory> Transaction<T> {
|
|||
let timestamp = cob.history().timestamp().into();
|
||||
|
||||
// The history clock should be in sync with the tx clock.
|
||||
assert_eq!(Some(cob.history().clock()), self.clock.map(|c| c.get()));
|
||||
assert_eq!(cob.history().clock(), self.clock.get());
|
||||
|
||||
// Start the clock from where the transcation clock started.
|
||||
let mut clock = self.start;
|
||||
|
|
|
|||
Loading…
Reference in New Issue