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