State

Struct State 

Source
pub struct State<ID: TreeId, TM: TreeMeta, A: Actor> { /* private fields */ }
Expand description

Holds Tree CRDT state and implements the core algorithm.

State is not tied to any actor/peer and should be equal on any two replicas where each has applied the same operations.

State may be instantiated to manipulate a CRDT Tree or alternatively the higher level TreeReplica may be used.

For usage/examples, see: tests/tree.rs

This code aims to be an accurate implementation of the tree crdt algorithm described in:

“A highly-available move operation for replicated trees and distributed filesystems” [1] by Martin Klepmann, et al.

[1] https://martin.kleppmann.com/papers/move-op.pdf

Implementations§

Source§

impl<ID: TreeId, TM: TreeMeta, A: Actor> State<ID, TM, A>

Source

pub fn new() -> Self

create a new State

Source

pub fn tree(&self) -> &Tree<ID, TM>

returns tree reference

Source

pub fn tree_mut(&mut self) -> &mut Tree<ID, TM>

returns mutable Tree reference

Warning: this is dangerous. Normally the Tree should not be mutated directly.

See the demo_move_to_trash in examples/demo.rs for a use-case, only after log truncation has been performed.

Source

pub fn log(&self) -> &Vec<LogOpMove<ID, TM, A>>

returns log reference

Examples found in repository?
examples/demo.rs (line 260)
211fn demo_truncate_log() {
212    let mut replicas: Vec<TreeReplica<TypeId, TypeMeta, TypeActor>> = Vec::new();
213    let num_replicas = 5;
214
215    // start some replicas.
216    for _i in 0..num_replicas {
217        // pass true flag to enable causally stable threshold tracking
218        let r: TreeReplica<TypeId, TypeMeta, TypeActor> = TreeReplica::new(new_id());
219        replicas.push(r);
220    }
221
222    let root_id = new_id();
223
224    // Generate initial tree state.
225    let mut opmoves = vec![replicas[0].opmove(0, "root", root_id)];
226
227    println!("generating move operations...");
228
229    // generate some initial ops from all replicas.
230    for r in replicas.iter_mut() {
231        let finaldepth = rand::thread_rng().gen_range(3, 6);
232        let mut ops = vec![];
233        mktree_ops(&mut ops, r, root_id, 2, finaldepth);
234        opmoves.extend(r.opmoves(ops));
235    }
236
237    // apply all ops to all replicas
238    println!(
239        "applying {} operations to all {} replicas...\n",
240        opmoves.len(),
241        replicas.len()
242    );
243    apply_ops_to_replicas(&mut replicas, &opmoves);
244
245    #[derive(Debug)]
246    #[allow(dead_code)]
247    struct Stat {
248        pub replica: TypeActor,
249        pub ops_before_truncate: usize,
250        pub ops_after_truncate: usize,
251    }
252
253    let mut stats: Vec<Stat> = Vec::new();
254    for r in replicas.iter_mut() {
255        println!("truncating log of replica {}...", r.id());
256        println!(
257            "causally stable threshold: {:?}\n",
258            r.causally_stable_threshold()
259        );
260        let ops_b4 = r.state().log().len();
261        r.truncate_log();
262        let ops_after = r.state().log().len();
263        stats.push(Stat {
264            replica: *r.id(),
265            ops_before_truncate: ops_b4,
266            ops_after_truncate: ops_after,
267        });
268    }
269
270    println!("-- Stats -- ");
271    println!("\n{:#?}", stats);
272}
Source

pub fn add_log_entry(&mut self, entry: LogOpMove<ID, TM, A>)

add_log_entry

Source

pub fn truncate_log_before(&mut self, timestamp: &Clock<A>) -> bool

removes log entries before a given timestamp. not part of crdt-tree algo.

Source

pub fn do_op(&mut self, op: OpMove<ID, TM, A>) -> LogOpMove<ID, TM, A>

The do_op function performs the actual work of applying a move operation.

This function takes as argument a pair consisting of a Move operation and the current tree and it returns a pair consisting of a LogMove operation (which will be added to the log) and an updated tree.

Source

pub fn undo_op(&mut self, log: &LogOpMove<ID, TM, A>)

undo_op

Source

pub fn redo_op(&mut self, log: LogOpMove<ID, TM, A>)

redo_op uses do_op to perform an operation again and recomputes the LogMove record (which might have changed due to the effect of the new operation)

Source

pub fn apply_op(&mut self, op1: OpMove<ID, TM, A>)

See general description of apply/undo/redo above.

The apply_op func takes two arguments: a Move operation to apply and the current replica state; and it returns the new replica state. The constrains t::{linorder} in the type signature indicates that timestamps t are instance if linorder type class, and they can therefore be compared with the < operator during a linear (or total) order.

Source

pub fn apply_ops_into(&mut self, ops: Vec<OpMove<ID, TM, A>>)

applies a list of operations and consume them. (no cloning)

Source

pub fn apply_ops(&mut self, ops: &[OpMove<ID, TM, A>])

applies a list of operations reference, cloning each op.

Trait Implementations§

Source§

impl<ID: Clone + TreeId, TM: Clone + TreeMeta, A: Clone + Actor> Clone for State<ID, TM, A>

Source§

fn clone(&self) -> State<ID, TM, A>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<ID: TreeId, TM: TreeMeta, A: Actor> CmRDT for State<ID, TM, A>

Source§

fn apply(&mut self, op: Self::Op)

Apply an operation to a State instance.

Source§

type Op = OpMove<ID, TM, A>

Op defines a mutation to the CRDT. As long as Op’s from one actor are replayed in exactly the same order they were generated by that actor, the CRDT will converge. In other words, we must have a total ordering on each actors operations, while requiring only a partial order over all ops. E.g. Read more
Source§

impl<ID: Debug + TreeId, TM: Debug + TreeMeta, A: Debug + Actor> Debug for State<ID, TM, A>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<ID: TreeId, A: Actor, TM: TreeMeta> Default for State<ID, TM, A>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de, ID, TM, A> Deserialize<'de> for State<ID, TM, A>
where ID: Deserialize<'de> + TreeId, TM: Deserialize<'de> + TreeMeta, A: Deserialize<'de> + Actor,

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<ID: TreeId, A: Actor, TM: TreeMeta> From<(Vec<LogOpMove<ID, TM, A>>, Tree<ID, TM>)> for State<ID, TM, A>

Source§

fn from(e: (Vec<LogOpMove<ID, TM, A>>, Tree<ID, TM>)) -> Self

creates State from tuple (Vec<LogOpMove>, Tree)

Source§

impl<ID: TreeId, TM: TreeMeta, A: Actor> IntoIterator for State<ID, TM, A>

Implement IntoIterator for State. This is useful for walking all Nodes in a tree without knowing a starting point.

Source§

type Item = (ID, TreeNode<ID, TM>)

The type of the elements being iterated over.
Source§

type IntoIter = IntoIter<ID, TreeNode<ID, TM>>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<ID: PartialEq + TreeId, TM: PartialEq + TreeMeta, A: PartialEq + Actor> PartialEq for State<ID, TM, A>

Source§

fn eq(&self, other: &State<ID, TM, A>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<ID, TM, A> Serialize for State<ID, TM, A>
where ID: Serialize + TreeId, TM: Serialize + TreeMeta, A: Serialize + Actor,

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<ID: Eq + TreeId, TM: Eq + TreeMeta, A: Eq + Actor> Eq for State<ID, TM, A>

Source§

impl<ID: TreeId, TM: TreeMeta, A: Actor> StructuralPartialEq for State<ID, TM, A>

Auto Trait Implementations§

§

impl<ID, TM, A> Freeze for State<ID, TM, A>

§

impl<ID, TM, A> RefUnwindSafe for State<ID, TM, A>

§

impl<ID, TM, A> Send for State<ID, TM, A>
where ID: Send, TM: Send, A: Send,

§

impl<ID, TM, A> Sync for State<ID, TM, A>
where ID: Sync, TM: Sync, A: Sync,

§

impl<ID, TM, A> Unpin for State<ID, TM, A>
where ID: Unpin, TM: Unpin, A: Unpin,

§

impl<ID, TM, A> UnwindSafe for State<ID, TM, A>
where ID: UnwindSafe, TM: UnwindSafe, A: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<TM> TreeMeta for TM
where TM: Clone,