1 个不稳定版本

0.1.0 2021年6月23日

#678并发

MIT/Apache

140KB
2K SLoC

并发节点复制

CNR(并发节点复制)库是在常规NR(节点复制)库上的扩展。

与NR不同,该库用于实现一个NUMA感知的并发版本的数据结构。它通过结合三种技术:基于交换的工作分区、操作日志和扁平化合并,将并发实现扩展到多个核心和NUMA节点。

它是如何工作的

为了复制一个并发数据结构,需要实现(来自cnr的)DispatchLogMapperLogMapper实现决定了并发执行中多个日志之间的工作分区。

LogMapper实现用于将操作映射到日志。两个交换操作可以映射到同一个或不同的日志;然而,两个冲突的操作必须映射到同一个日志。例如,我们为CHashMap实现Dispatch,并为支持的操作实现LogMapper

/// The replicated hashmap uses a concurrent hashmap internally.
pub struct CNRHashMap {
   storage: CHashMap<usize, usize>,
}

/// We support a mutable put operation on the hashmap.
#[derive(Debug, PartialEq, Clone)]
pub enum Modify {
   Put(usize, usize),
}

/// This `LogMapper` implementation distributes the keys amoung multiple logs
/// in a round-robin fashion. One can change the implementation to improve the
/// data locality based on the data sturucture layout in the memory.
impl LogMapper for Modify {
   fn hash(&self, _nlogs: usize, logs: &mut Vec<usize>) {
      logs.clear();
      match self {
         Modify::Put(key, _val) => log.push(*key % nlogs),
      }
   }
}

/// We support an immutable read operation to lookup a key from the hashmap.
#[derive(Debug, PartialEq, Clone)]
pub enum Access {
   Get(usize),
}

/// `Access` follows the same operation to log mapping as the `Modify`. This
/// ensures that the read and write operations for a particular key go to
/// the same log.
impl LogMapper for Access {
   fn hash(&self, nlogs: usize, logs: &mut Vec<usize>) {
      logs.clear();
      match self {
         Access::Get(key) => log.push(*key % nlogs),
      }
   }
}

/// The Dispatch traits executes `ReadOperation` (our Access enum)
/// and `WriteOperation` (our Modify enum) against the replicated
/// data-structure.
impl Dispatch for CNRHashMap {
   type ReadOperation = Access;
   type WriteOperation = Modify;
   type Response = Option<usize>;

   /// 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(&self, op: Self::WriteOperation) -> Self::Response {
       match op {
           Modify::Put(key, value) => self.storage.insert(key, value),
       }
   }
}

完整示例(使用HashMap作为底层数据结构)可以在这里找到。要运行,请执行:cargo run --example hashmap

编译库

由于使用了new_uninitget_mut_uncheckednegative_impls API,该库目前需要使用nightly rust编译器。库与no_std兼容。

rustup toolchain install nightly
rustup default nightly
cargo build

作为你的Cargo.toml中的依赖项

cnr = "*"

目前的代码应被视为早期版本,仍在开发中。在其当前形式下,该库仅在x86平台上已知可以工作(其他平台可能需要一些更改,且未经过测试)。

测试

实现中包含一系列单元测试和一些集成测试,这些测试使用堆栈检查实现的各个方面。

您可以通过执行以下命令来运行测试: cargo test

基准测试

基准测试(以及如何执行它们)在 benches 文件夹中解释得更加详细。

依赖项

~1.5MB
~38K SLoC