node_replication/
lib.rs

1// Copyright © 2019-2020 VMware, Inc. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! Node Replication (NR) is a library which can be used to implement a
5//! concurrent version of any single threaded data structure. It takes in a
6//! single threaded implementation of said data structure, and scales it out to
7//! multiple cores and NUMA nodes by combining three techniques: reader-writer
8//! locks, operation logging and flat combining.
9//!
10//! # How does it work
11//! To replicate a single-threaded data structure, one needs to implement the
12//! [Dispatch](trait.Dispatch.html) trait for it. The following snippet
13//! implements [Dispatch](trait.Dispatch.html) for
14//! [HashMap](https://doc.rust-lang.org/std/collections/struct.HashMap.html)
15//! as an example. A complete example
16//! (using [Replica](struct.Replica.html) and [Log](struct.Log.html)) can be found in the
17//! [examples](https://github.com/vmware/node-replication/tree/master/examples/hashmap.rs)
18//! folder.
19//!
20//! ```
21//! use node_replication::Dispatch;
22//! use std::collections::HashMap;
23//!
24//! /// The node-replicated hashmap uses a std hashmap internally.
25//! pub struct NrHashMap {
26//!    storage: HashMap<u64, u64>,
27//! }
28//!
29//! /// We support a mutable put operation on the hashmap.
30//! #[derive(Debug, PartialEq, Clone)]
31//! pub enum Modify {
32//!    Put(u64, u64),
33//! }
34//!
35//! /// We support an immutable read operation to lookup a key from the hashmap.
36//! #[derive(Debug, PartialEq, Clone)]
37//! pub enum Access {
38//!    Get(u64),
39//! }
40//!
41//! /// The Dispatch traits executes `ReadOperation` (our Access enum)
42//! /// and `WriteOperation` (our Modify enum) against the replicated
43//! /// data-structure.
44//! impl Dispatch for NrHashMap {
45//!    type ReadOperation = Access;
46//!    type WriteOperation = Modify;
47//!    type Response = Option<u64>;
48//!
49//!    /// The `dispatch` function applies the immutable operations.
50//!    fn dispatch(&self, op: Self::ReadOperation) -> Self::Response {
51//!        match op {
52//!            Access::Get(key) => self.storage.get(&key).map(|v| *v),
53//!        }
54//!    }
55//!
56//!    /// The `dispatch_mut` function applies the mutable operations.
57//!    fn dispatch_mut(
58//!        &mut self,
59//!        op: Self::WriteOperation,
60//!    ) -> Self::Response {
61//!        match op {
62//!            Modify::Put(key, value) => self.storage.insert(key, value),
63//!        }
64//!    }
65//! }
66//! ```
67#![no_std]
68#![cfg_attr(
69    feature = "unstable",
70    feature(new_uninit, get_mut_unchecked, negative_impls)
71)]
72
73#[cfg(test)]
74extern crate std;
75
76extern crate alloc;
77extern crate core;
78
79extern crate crossbeam_utils;
80
81#[macro_use]
82extern crate log as logging;
83
84#[macro_use]
85extern crate static_assertions;
86
87mod context;
88mod log;
89mod replica;
90
91#[cfg(not(loom))]
92#[path = "rwlock.rs"]
93pub mod rwlock;
94#[cfg(loom)]
95#[path = "loom_rwlock.rs"]
96pub mod rwlock;
97
98pub use crate::log::{Log, MAX_REPLICAS_PER_LOG};
99pub use replica::{Replica, ReplicaToken, MAX_THREADS_PER_REPLICA};
100
101use core::fmt::Debug;
102
103/// Trait that a data structure must implement to be usable with this library.
104///
105/// When this library executes a read-only operation against the data structure,
106/// it invokes the `dispatch()` method with the operation as an argument.
107///
108/// When this library executes a write operation against the data structure, it
109/// invokes the `dispatch_mut()` method with the operation as an argument.
110pub trait Dispatch {
111    /// A read-only operation. When executed against the data structure, an operation
112    /// of this type must not mutate the data structure in anyway. Otherwise, the
113    /// assumptions made by this library no longer hold.
114    type ReadOperation: Sized + Clone + PartialEq + Debug;
115
116    /// A write operation. When executed against the data structure, an operation of
117    /// this type is allowed to mutate state. The library ensures that this is done so
118    /// in a thread-safe manner.
119    type WriteOperation: Sized + Clone + PartialEq + Debug + Send;
120
121    /// The type on the value returned by the data structure when a `ReadOperation` or a
122    /// `WriteOperation` successfully executes against it.
123    type Response: Sized + Clone;
124
125    /// Method on the data structure that allows a read-only operation to be
126    /// executed against it.
127    fn dispatch(&self, op: Self::ReadOperation) -> Self::Response;
128
129    /// Method on the data structure that allows a write operation to be
130    /// executed against it.
131    fn dispatch_mut(&mut self, op: Self::WriteOperation) -> Self::Response;
132}
133
134#[cfg(doctest)]
135mod test_readme {
136    macro_rules! external_doc_test {
137        ($x:expr) => {
138            #[doc = $x]
139            extern "C" {}
140        };
141    }
142
143    external_doc_test!(include_str!("../README.md"));
144}