5 个版本
0.2.3 | 2024年6月1日 |
---|---|
0.2.2 | 2024年5月14日 |
0.2.1 | 2024年1月20日 |
0.2.0 | 2024年1月20日 |
0.1.0 | 2024年1月16日 |
#143 在 Unix API 中
每月293次下载
61KB
1K SLoC
可以快照的内存区域。
试用
cargo build --release \
-p shm-snapshot --features="shm-restore shm-restore-tracing" --bin shm-restore \
-p primes-snapshot
RUST_LOG=info ./target/release/shm-restore \
--snapshot=restore-v1 ./target/prime-snapshot \
./target/release/primes-snapshot
这里的独特之处在于能够完全杀死(SIGKILL
)和重启进程树,这将保留大部分信息,同时保证恢复状态的连续性。以下列出了快照模式,默认不使用任何模式的结果是在子进程终止后执行快照,因此信息保留最弱。
问题陈述
该库实现了一些基本的进程间策略,用于同步内存映射文件中的数据。有一个主机和客户端,它们位于从环境传递的相同文件描述符上,并由主机推送到客户端。主机的任务是创建内存映射文件中数据的快照,并将此类状态持久化到磁盘,以便在后续客户端执行之前自动恢复最新的快照。
客户端应该几乎不需要关注主机的操作,特别是该机制至少应该是无阻塞的,最好是等待-free(在锁-free和无阻塞之间没有额外的价值,因为只运行快照制作线程/进程很少有用,但是一种允许的“解决方案”)。
这里实际快照的主要问题是,对于整个文件任意大的区域没有这样的原始设备。此外,系统调用(如 copy_file_range
,write
等)的读取不能可靠地说是与任何一方做的任何操作有关联的。没有有效的实现,例如,承诺只读取文件“正向”/循环通过文件,例如,从大量复制中页可以以实际上任何顺序落在磁盘上。
总体设计
主机和客户端将文件分成两个区域:一组包含协调结构的内存页和一个用户数据尾。然后某种机制保证可以以原子语义保存协调数据的单元。
客户端库通常提供一种机制,将协调结构的写操作与用户结构的写操作进行排序,使得某个协调单元的原子复制意味着用户内存中适当访问区域的原子快照。通过这种方式,可以将任意辅助数据附加到任何快照上。请注意,在主机持久化快照所需的时间内,有必要冻结相应的协调单元。这种需求扩展到辅助数据(API帮助确保这一属性)。通常,您应该优先考虑将辅助数据保留在不可变数据结构中,以便正在进行的快照可以共享尽可能多的宝贵内存资源,即尽可能多的内存可变部分仍然可用。
详细信息
队列策略
一种简单的无阻塞策略,使用连续数据流中的描述符作为一致性标记。如果主机与客户端创建状态相比复制较慢,它可能会被饿死。
此策略不需要主机以可写模式映射数据。
客户端可以通过运行自己的例行检查成功快照文件来可选地检测此条件,并根据速度减慢做出相应反应。这不建议这样做,因为它可能会威胁到主要的好处,即风险前进或等待,取决于文件系统。
三缓冲区策略
此策略尚未实现。一种CAS / hazard-pointer策略,其中客户端创建并提供具有状态增量缓冲区。当这些缓冲区成功包含在某个持久快照中时,主机返回这些缓冲区。
此策略要求主机以可写模式映射数据。该策略与客户端进行协调。
作者并不完全清楚这种策略如何有效地实现。在Linux中我们有futex等待,但可能有关于阻塞自由性的未知问题?
关于未实现策略的思考,基于重映射的快照
依赖于一个内存区域以这种方式映射,以便可以使用 MREMAP_DONTUNMAP
进行重映射,并安装了一个 userfaultfd
来通过写时复制语义恢复区域。
这里有一点细节,不清楚硬件缓存是否已刷新到该区域。实际上,除了执行快照的处理器之外的其他处理器可能还有残余的存储指令,或者存储结果晚于重映射后的系统调用/进程间通信。不清楚是否需要在快照之后建立所有“后续”写入的附加happens-before关系,以确保不存在此类挂起的更改。因此,库必须跟踪其写入者,并从他们那里等待完成标志。
依赖项
~0.1–9.5MB
~99K SLoC