Skip to content

Commit

Permalink
Merge 9fc8579 into 9d63596
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-da committed Jan 27, 2021
2 parents 9d63596 + 9fc8579 commit aca47d0
Show file tree
Hide file tree
Showing 11 changed files with 457 additions and 479 deletions.
493 changes: 206 additions & 287 deletions examples/tree.rs → examples/demo.rs

Large diffs are not rendered by default.

21 changes: 1 addition & 20 deletions src/clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,14 @@
// specific language governing permissions and limitations relating to use of the SAFE Network
// Software.

//! Implements Lamport Clock
//!
//! For usage/examples, see:
//! examples/tree.rs
//! test/tree.rs
//!
//! This code aims to be an accurate implementation of the
//! tree crdt 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
//!
//! For clarity, data structures in this implementation are named
//! the same as in the paper (State, Tree) or close to
//! (OpMove --> Move, LogOpMove --> LogOp). Some are not explicitly
//! named in the paper, such as TreeId, TreeMeta, TreeNode, Clock.

use crdts::quickcheck::{Arbitrary, Gen};
use serde::{Deserialize, Serialize};
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};

use crdts::Actor;
use std::hash::{Hash, Hasher};

/// lamport clock + actor
/// Implements a `Lamport Clock` consisting of an `Actor` and an integer counter.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Clock<A: Actor> {
actor_id: A,
Expand Down
38 changes: 18 additions & 20 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,29 @@
//! named in the paper, such as TreeId, TreeMeta, TreeNode, Clock.
#![deny(missing_docs)]

/// This module contains a Tree.
pub mod tree;
mod tree;
pub use self::tree::Tree;

/// This module contains State.
pub mod state;
mod state;
pub use self::state::State;

/// This module contains a Clock.
pub mod clock;
mod clock;
pub use self::clock::Clock;

/// This module contains OpMove.
pub mod opmove;
mod opmove;
pub use self::opmove::OpMove;

/// This module contains `LogOpMove`.
pub mod logopmove;
mod logopmove;
pub use self::logopmove::LogOpMove;

/// This module contains `TreeId`.
pub mod treeid;
mod treeid;
pub use self::treeid::TreeId;

/// This module contains `TreeMeta`.
pub mod treemeta;
mod treemeta;
pub use self::treemeta::TreeMeta;

/// This module contains `TreeNode`.
pub mod treenode;
mod treenode;
pub use self::treenode::TreeNode;

pub use self::{
clock::Clock, logopmove::LogOpMove, opmove::OpMove, state::State, tree::Tree, treeid::TreeId,
treemeta::TreeMeta, treenode::TreeNode,
};
mod treereplica;
pub use self::treereplica::TreeReplica;
24 changes: 4 additions & 20 deletions src/logopmove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,15 @@
// specific language governing permissions and limitations relating to use of the SAFE Network
// Software.

//! Implements `LogOpMove`, a log entry used by `State`
//!
//! For usage/examples, see:
//! examples/tree.rs
//! test/tree.rs
//!
//! This code aims to be an accurate implementation of the
//! tree crdt 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>
//!
//! For clarity, data structures in this implementation are named
//! the same as in the paper (`State`, `Tree`) or close to
//! (`OpMove` --> `Move`, `LogOpMove` --> `LogOp`). Some are not explicitly
//! named in the paper, such as TreeId, TreeMeta, TreeNode, Clock.

use serde::{Deserialize, Serialize};
use std::cmp::{Eq, PartialEq};

use super::{Clock, OpMove, TreeId, TreeMeta, TreeNode};
use crdts::Actor;

/// From the paper:
/// Implements `LogOpMove`, a log entry used by `State`
///
/// From the paper[1]:
/// ----
/// In order to correctly apply move operations, a replica needs
/// to maintain not only the current state of the tree, but also
Expand All @@ -53,6 +36,7 @@ use crdts::Actor;
/// such that (p', m', c') E tree, then `oldp` is set to `Some(p', m')`.
/// The `get_parent()` function implements this.
/// ----
/// [1] <https://martin.kleppmann.com/papers/move-op.pdf>
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LogOpMove<ID: TreeId, TM: TreeMeta, A: Actor> {
// an operation that is being logged.
Expand Down
29 changes: 7 additions & 22 deletions src/opmove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,6 @@
// specific language governing permissions and limitations relating to use of the SAFE Network
// Software.

//! Implements OpMove, the only way to manipulate Tree data.
//!
//! OpMove are applied via State::apply_op()
//!
//! For usage/examples, see:
//! examples/tree.rs
//! test/tree.rs
//!
//! This code aims to be an accurate implementation of the
//! tree crdt 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
//!
//! For clarity, data structures in this implementation are named
//! the same as in the paper (State, Tree) or close to
//! (OpMove --> Move, LogOpMove --> LogOp). Some are not explicitly
//! named in the paper, such as TreeId, TreeMeta, TreeNode, Clock.

use serde::{Deserialize, Serialize};
use std::cmp::{Eq, PartialEq};

Expand All @@ -36,7 +15,12 @@ use crdts::quickcheck::{Arbitrary, Gen};
use crdts::Actor;
use std::hash::Hash;

/// From the paper:
/// Implements `OpMove`, the only way to manipulate tree data.
///
/// `OpMove` are applied via `State`::apply_op() or at a higher
/// level via `TreeReplica`::apply_op()
///
/// From the paper[1]:
/// ----
/// We allow the tree to be updated in three ways: by creating
/// a new child of any parent node, by deleting a node, or by
Expand Down Expand Up @@ -80,6 +64,7 @@ use std::hash::Hash;
/// changes, and apply these operations using the algorithm
/// described...
/// ----
/// [1] https://martin.kleppmann.com/papers/move-op.pdf
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct OpMove<ID: TreeId, TM: TreeMeta, A: Actor> {
/// lamport clock + actor
Expand Down
50 changes: 25 additions & 25 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,31 @@
// specific language governing permissions and limitations relating to use of the SAFE Network
// Software.

//! Holds Tree CRDT state and implements the core algorithm.
//!
//! `State` is the primary object to instantiate that represents
//! a CRDT Tree.
//!
//! For usage/examples, see:
//! examples/tree.rs
//! test/tree.rs
//!
//! This code aims to be an accurate implementation of the
//! tree crdt 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
//!
//! For clarity, data structures in this implementation are named
//! the same as in the paper (State, Tree) or close to
//! (`OpMove` --> `Move`, `LogOpMove` --> `LogOp`). Some are not explicitly
//! named in the paper, such as `TreeId`, `TreeMeta`, `TreeNode`, `Clock`.

use serde::{Deserialize, Serialize};
use std::cmp::{Eq, Ordering, PartialEq};

use super::{Clock, LogOpMove, OpMove, Tree, TreeId, TreeMeta, TreeNode};
use crdts::{Actor, CmRDT};
use log::warn;

/// `State`. This is the primary interface for working with a
/// Tree CRDT.
/// 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:
/// test/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
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct State<ID: TreeId, TM: TreeMeta, A: Actor> {
// a list of `LogMove` in descending timestamp order.
Expand All @@ -63,7 +57,13 @@ impl<ID: TreeId, TM: TreeMeta, A: Actor> State<ID, TM, A> {
&self.tree
}

/// returns mutable tree reference
/// returns mutable Tree reference
///
/// Warning: this is dangerous. Normally the `Tree` should
/// not be mutated directly.
///
/// See the demo_move_to_trash in examples/tree.rs for a
/// use-case, only after log truncation has been performed.
#[inline]
pub fn tree_mut(&mut self) -> &mut Tree<ID, TM> {
&mut self.tree
Expand Down
35 changes: 11 additions & 24 deletions src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,19 @@
// specific language governing permissions and limitations relating to use of the SAFE Network
// Software.

//! Implements Tree, a set of triples representing current tree structure.
//!
//! For usage/examples, see:
//! examples/tree.rs
//! test/tree.rs
//!
//! This code aims to be an accurate implementation of the
//! tree crdt 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
//!
//! For clarity, data structures in this implementation are named
//! the same as in the paper (State, Tree) or close to
//! (OpMove --> Move, LogOpMove --> LogOp). Some are not explicitly
//! named in the paper, such as TreeId, TreeMeta, TreeNode, Clock.

use serde::{Deserialize, Serialize};
use std::cmp::{Eq, PartialEq};
use std::collections::HashMap;

use super::{TreeId, TreeMeta, TreeNode};

/// From the paper:
/// Implements `Tree`, a set of triples representing current tree structure.
///
/// Normally this `Tree` struct should not be instantiated directly.
/// Instead instantiate `State` (lower-level) or `TreeReplica` (higher-level)
/// and invoke operations on them.
///
/// From the paper[1]:
/// ----
/// We can represent the tree as a set of (parent, meta, child)
/// triples, denoted in Isabelle/HOL as (’n × ’m × ’n) set. When
Expand All @@ -47,6 +34,7 @@ use super::{TreeId, TreeMeta, TreeNode};
/// for c from the set tree, and then add {(p, m, c)} to represent
/// the new parent-child relationship.
/// ----
/// [1] https://martin.kleppmann.com/papers/move-op.pdf
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Tree<ID: TreeId, TM: TreeMeta> {
triples: HashMap<ID, TreeNode<ID, TM>>, // tree_nodes, indexed by child_id.
Expand Down Expand Up @@ -138,24 +126,23 @@ impl<ID: TreeId, TM: TreeMeta> Tree<ID, TM> {
}
}

/// returns true if ancestor_id is an ancestor of child_id in tree.
///
/// parent | child
/// --------------
/// 1 2
/// 1 3
/// 3 5
/// 2 6
/// 6 8

///
/// 1
/// 2 3
/// 6 5
/// 8
///
/// is 2 ancestor of 8? yes.
/// is 2 ancestor of 5? no.

/// determines if ancestor_id is an ancestor of node_id in tree.
/// returns bool
pub fn is_ancestor(&self, child_id: &ID, ancestor_id: &ID) -> bool {
let mut target_id = child_id;
while let Some(n) = self.find(&target_id) {
Expand Down
19 changes: 0 additions & 19 deletions src/treeid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,6 @@
// specific language governing permissions and limitations relating to use of the SAFE Network
// Software.

//! Implements `TreeId`, a trait for representing `Tree` (Node) Identifiers
//!
//! For usage/examples, see:
//! examples/tree.rs
//! test/tree.rs
//!
//! This code aims to be an accurate implementation of the
//! tree crdt 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>
//!
//! For clarity, data structures in this implementation are named
//! the same as in the paper (State, Tree) or close to
//! (`OpMove` --> `Move`, `LogOpMove` --> `LogOp`). Some are not explicitly
//! named in the paper, such as `TreeId`, `TreeMeta`, `TreeNode`, `Clock`.

use std::hash::Hash;

/// `TreeId` trait. `TreeId` are unique identifiers for each node in a tree.
Expand Down
23 changes: 2 additions & 21 deletions src/treemeta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,7 @@
// specific language governing permissions and limitations relating to use of the SAFE Network
// Software.

//! Implements `TreeMeta`, a trait for representing `Tree` (`Node`) metadata
//!
//! For usage/examples, see:
//! examples/tree.rs
//! test/tree.rs
//!
//! This code aims to be an accurate implementation of the
//! tree crdt 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>
//!
//! For clarity, data structures in this implementation are named
//! the same as in the paper (State, Tree) or close to
//! (`OpMove` --> `Move`, `LogOpMove` --> `LogOp`). Some are not explicitly
//! named in the paper, such as `TreeId`, `TreeMeta`, `TreeNode`, `Clock`.

/// `TreeMeta` trait. `TreeMeta` are application-defined pieces of data that are stored
/// with each node in the Tree.
/// `TreeMeta` represent the app-defined data that an application stores in each node
/// of the tree.
pub trait TreeMeta: Clone {}
impl<TM: Clone> TreeMeta for TM {}

0 comments on commit aca47d0

Please sign in to comment.