11个版本

0.4.1 2022年4月28日
0.4.0 2021年7月28日
0.3.5 2021年6月9日
0.3.2 2021年3月15日
0.2.1 2020年12月30日

#132 in 内存管理

MIT 许可证

1MB
17K SLoC

Rust 12K SLoC // 0.1% comments C++ 2K SLoC // 0.1% comments C 1.5K SLoC // 0.2% comments Go 666 SLoC // 0.2% comments Shell 533 SLoC // 0.0% comments Scons 24 SLoC

DOI crates.io GHA build status Build Status

刚玉:Rust中的持久性内存编程库

刚玉为Rust应用程序提供持久性内存支持。这对于开发无需担心崩溃一致性和数据丢失的安全持久性内存应用程序非常有用。关于其设计和实现的更多详细信息,请参阅我们ASPLOS 2021学术论文论文(访问此视频观看演示)。

通过仔细使用Rust的严格类型检查规则和借用机制,刚玉保证了实现中不存在常见的持久性内存相关错误。刚玉使软件实现不包含以下类型的持久性内存相关问题

  • 野指针,
  • 对数据的不可恢复修改,
  • 由于电源故障引起的数据不一致,
  • 以及Rust处理的全部内存相关问题。

开发者将在设计时看到这些问题。因此,它降低了出错的风险。刚玉的编程模型由使用安全的持久性指针和软件事务内存组成。

三个指针包装器位于刚玉接口的核心。开发者可以使用它们来安全地分配持久性内存。

  • Pbox<T>:最简单的动态分配形式,
  • Prc<T>:用于共享持久对象的单线程引用计数指针,
  • Parc<T>:用于共享持久对象的线程安全引用计数指针。

用法

使用以下任意一条指令在 Cargo.toml 的依赖项部分添加 Corundum:

[dependencies]
corundum = "0.4.1"

或者

[dependencies]
corundum = { git = "https://github.com/NVSL/Corundum.git" }

如果您想启用像 pin_journals 这样的功能,请将其添加到 features 属性中。例如

[dependencies]
corundum = { version="0.4.1", features=["pin_journals", "no_pthread"] }

内存池

内存池是一种实现了与持久内存一起工作的所有必要接口的类型。您可以使用默认的内存池,也可以定义一个新的内存池类型。后者要求您的类型实现 MemPool 特性。请以 pass-through 分配器为例。为了自动实现新的池类型,提供了一个 pool!() 宏。给定一个参数,它创建一个以参数命名的新的模块,并在其中创建一个名为 Allocator 的默认分配器。如果提供两个参数,它将创建一个使用第一个参数命名的模块,并使用第二个参数创建分配器类型。

// Custom name for the allocator (my_mod::MyAllocator)
corundum::pool!(my_mod, MyAllocator);

// Standard name for the allocator (my_mod::Allocator)
corundum::pool!(my_mod);

打开内存池文件

在使用之前,首先要打开内存池文件。您可以通过使用 open()open_no_root() 方法来完成此操作。第一个返回给定根对象类型的 root 对象。第二个返回一个 guard 对象;只要 root/guard 对象在作用域内,池就会保持打开状态。打开函数接受池文件路径和一个标志来创建池文件。

if let Ok(_) = my_pool::Allocator::open_no_root("image", O_F) {
    println!("Image file is formatted and ready to use");
} else {
    println!("No image file found");
}
if let Ok(root) = my_pool::Allocator::open::<Root>("image", O_F) {
    println!("Image file is formatted and the root object is created ({:?})", root);
} else {
    println!("No image file");
}

PM 安全数据结构

您可以使用给定的指针定义任何数据结构,而不需要任何原始指针或引用。Corundum 帮助您编写正确的代码。

use corundum::rc::Prc;
use corundum::cell::LogCell;

type A = corundum::default::Allocator;

struct MyData {
    id: i32,
    link: Option<Prc<LogRefCell<MyData, A>, A>>
}

在每种类型中指定池可能会让您感到困扰。Corundum 使用类型别名和过程宏来提供定义新数据结构的一种更简单的方法。pool!() 宏将所有与内部池类型关联的持久类型别名化。例如

pool!(my_pool);
use my_pool::*;

struct MyData {
    id: i32,
    link: Option<Prc<PRefCell<MyData>>>
}

PCloneRoot 过程宏也可以用于自动生成类型的对应特质的实现。

use corundum::default::*;

#[derive(PClone, Root)]
struct MyData {
    id: i32,
    link: Option<Prc<PRefCell<MyData>>>
}

事务性内存

Corundum 不允许在事务之外对受保护的数据进行任何修改。为了允许可变借用受保护的数据,您可以将它包装在 PCellPMutex 等,并使用它们相应的内部可变接口,这需要一个对日志对象的引用。要获取日志,您可以使用 transaction

transaction(|j| {
    let my_data = Prc::new(LogRefCell::new(
        MyData {
            id: 1,
            link: None
        }), j);
    let mut my_data = my_data.borrow_mut(j);
    my_data.id = 2;
})

文档

请访问 Documentation 页面获取更多信息。

问题和贡献

请随时通过 GitHub 问题报告任何错误。

如果您有其他问题或建议,您可以通过 [email protected] 联系我们。

免责声明

所展示的库未经工业用途测试。

许可

刚玉存储库采用Apache许可证2.0版本,(http://www.apache.org/licenses/LICENSE2.0).

除非您明确声明,否则您提交给许可方的任何贡献,若旨在包含在作品中的,均应遵守本许可协议的条款和条件,不得附加任何其他条款或条件。

依赖项

~4.5–6MB
~113K SLoC