内存映射文件和单个块的原子写入

时间:2010-09-21 10:17:19

标签: atomic mmap fwrite acid

如果我使用普通IO API读写单个文件,则保证每个块的写入是原子的。也就是说,如果我的write只修改了一个块,那么操作系统会保证写入整个块,或者根本不写入任何块。

如何在内存映射文件上实现相同的效果?

内存映射文件只是字节数组,所以如果我修改字节数组,操作系统就无法知道我何时考虑写“完成”,所以它可能(即使不太可能)换出内存就在我的块写操作的中间,实际上我写了半个块。

我需要某种“进入/离开关键部分”,或者在我写入时将文件页面“固定”到内存中的某种方法。这样的事情存在吗?如果是这样的话,可以通过普通的POSIX系统进行移植吗?视窗?

2 个答案:

答案 0 :(得分:5)

保持journal的技术似乎是唯一的方法。我不知道这对于写入同一文件的多个应用程序是如何工作的。 Cassandra项目有一个关于如何通过期刊获得表现的good article。关键是确保日志只记录正面动作(我的第一种方法是将每次写入的前映像写入日志,允许你回滚,但它过度了复杂)。

所以基本上你的内存映射文件在标题中有一个transactionId,如果你的标题适合一个块,你知道它不会被破坏,尽管很多人似乎用校验和写了两次:{ {1}}。如果第一个校验和失败,请使用第二个。

期刊看起来像这样:

[header[cksum]] [header[cksum]]

你只是继续附加日志记录,直到它变得太大,然后在某些时候翻过来。启动程序时,检查文件的事务ID是否在日志的最后一个事务ID中 - 如果不是,则回放日志中的所有事务以进行同步。

答案 1 :(得分:0)

如果我使用普通的IO API读写单个文件,则可以确保每个块的写入都是原子的。也就是说,如果我的写入仅修改单个块,则操作系统将保证整个块都被写入,或者根本不写入任何内容。

在一般情况下,操作系统不能保证使用“普通IO API”完成的“块写入”是原子的:

  • 块更多地是文件系统的概念-文件系统的块大小实际上可能映射到多个磁盘扇区...
  • 假设您是指扇区,您怎么知道您的写入仅映射到扇区?毫无疑问,通过文件系统间接访问后,I / O与扇区的I / O完全一致
  • There's nothing saying your disk HAS to implement sector atomicity。通常,“实际磁盘”是必需的,但不是必需的或有保证的属性。遗憾的是,除非程序具有NVMe磁盘并且您有权访问原始设备,或者您要向原始设备发送具有原子性保证的原始命令,否则程序将无法“检查”该属性。

此外,您通常会担心多个扇区的持久性(例如,如果发生断电,我在该扇区之前发送的数据是否一定是稳定存储的?)。如果正在进行任何缓冲,则除非您使用其他命令首先检查/用flags requesting cache bypass and said flags were actually honoured打开文件/设备,否则您的写操作可能仍只在RAM /磁盘缓存中。