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

问题描述 投票:13回答:2

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

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

内存映射文件只是字节数组,因此,如果我修改字节数组,操作系统将无法得知何时考虑执行写入操作,因此(即使不太可能)它也可能会换出内存,在我的块写操作的中间,实际上我写了半个块。

我需要某种“输入/离开关键部分”,或在写入文件时将文件页面“固定”到内存中的某种方法。是否存在类似的东西?如果是这样,它是否可以在常见的POSIX系统和Windows上移植?

atomic mmap fwrite acid
2个回答
5
投票

保持journal的技术似乎是唯一的方法。我不知道这对多个写入同一文件的应用程序如何起作用。 Cassandra项目的日记good article说明了如何获得绩效。关键是要确保日记只记录positive操作(我的第一种方法是将每次写入的前映像写入日记,以允许您回滚,但是过于复杂了)。

所以基本上,您的内存映射文件的标题中有一个transactionId,如果您的标题适合一个块,则您知道它不会损坏,尽管许多人似乎用校验和写两次:[header[cksum]] [header[cksum]]。如果第一个校验和失败,请使用第二个。

该日记看起来像这样:

[beginTxn[txnid]] [offset, length, data...] [commitTxn[txnid]]

您只需不断添加日记记录,直到记录变得太大,然后将其翻阅。启动程序时,请检查文件的事务ID是否在日志的最后一个事务ID中;否则,请回放日志中的所有事务以进行同步。


0
投票

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

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

  • 块更多是文件系统的概念-文件系统的块大小实际上可能映射到多个磁盘扇区...
  • 假设您是指扇区,您怎么知道您的写入仅映射到一个扇区?当通过文件系统间接访问时,没有什么可以说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 /磁盘缓存中。

© www.soinside.com 2019 - 2024. All rights reserved.