如果我使用普通的IO API读写单个文件,则可以确保每个块的写入都是原子的。也就是说,如果我的写入仅修改单个块,则操作系统将保证写入整个块,或者完全不写入任何块。
如何在内存映射文件上实现相同的效果?
内存映射文件只是字节数组,因此,如果我修改字节数组,操作系统将无法得知何时考虑执行写入操作,因此(即使不太可能)它也可能会换出内存,在我的块写操作的中间,实际上我写了半个块。
我需要某种“输入/离开关键部分”,或在写入文件时将文件页面“固定”到内存中的某种方法。是否存在类似的东西?如果是这样,它是否可以在常见的POSIX系统和Windows上移植?
保持journal的技术似乎是唯一的方法。我不知道这对多个写入同一文件的应用程序如何起作用。 Cassandra项目的日记good article说明了如何获得绩效。关键是要确保日记只记录positive操作(我的第一种方法是将每次写入的前映像写入日记,以允许您回滚,但是过于复杂了)。
所以基本上,您的内存映射文件的标题中有一个transactionId
,如果您的标题适合一个块,则您知道它不会损坏,尽管许多人似乎用校验和写两次:[header[cksum]] [header[cksum]]
。如果第一个校验和失败,请使用第二个。
该日记看起来像这样:
[beginTxn[txnid]] [offset, length, data...] [commitTxn[txnid]]
您只需不断添加日记记录,直到记录变得太大,然后将其翻阅。启动程序时,请检查文件的事务ID是否在日志的最后一个事务ID中;否则,请回放日志中的所有事务以进行同步。
如果我使用普通的IO API读写单个文件,则可以确保每个块的写入都是原子的。也就是说,如果我的写入仅修改单个块,则操作系统将保证写入整个块,或者完全不写入任何块。
在一般情况下,操作系统不保证通过“普通IO API”完成的“块写入”是原子的:
[此外,您通常会担心多个扇区的持久性(例如,如果发生断电,我在该扇区之前发送的数据是否一定是稳定存储的?)。如果有任何正在进行的缓冲,除非您先使用另一个命令检查/用flags requesting cache bypass and said flags were actually honoured打开文件/设备,否则您的写操作可能仍只在RAM /磁盘缓存中。