2010-09-21 30 views
10

如果我使用普通的IO API读取和写入单个文件,写入将保证每个块都是原子性的。也就是说,如果我的写操作只修改一个块,那么操作系统会保证写入整个块,或者完全不写。内存映射文件和单个块的原子写入

如何在内存映射文件上实现相同效果?内存映射文件只是字节数组,所以如果我修改字节数组,操作系统无法知道什么时候我认为写入“完成”,所以它可能(即使这不太可能)换出内存就在我写块操作的中间,实际上我写了半块。

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

+0

有多少应用程序正在与您的映射文件进行交互? – Justin 2010-10-25 17:01:52

+0

只有一个进程,即数据库服务器。 – 2010-10-26 08:23:27

回答

4

保持journal似乎是唯一的方法。我不知道这是如何与多个应用程序写入同一个文件。卡桑德拉项目有一个good article关于如何获得期刊的表现。关键是要确保,日记只记录积极行动(我的第一个方法是写每个写日志允许您回滚,但它过于复杂)的前映像。

因此,基本上你的内存映射文件在头部有一个transactionId,如果你的头部适合一个块,你知道它不会被破坏,尽管很多人似乎用一个校验和写了两次:[header[cksum]] [header[cksum]]。如果第一个校验和失败,请使用第二个校验和。

该杂志看起来是这样的:

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

你只是不停地追加日志记录,直到它变得太大,那么在某些时候滚动它。启动程序时,检查文件的事务ID是否位于日志的最后一个事务ID - 如果不是,则回放日志中的所有事务以进行同步。

+0

是的,日记是要走的路,我知道这些算法。但问题在于,即使在使用日志时,也必须保证数据文件的单独页面只写入完整页面,否则会冒着“半写”页面的风险,并且无法检测它是否会已损坏或没有。这就是为什么我正在寻找一种方法来对映射文件中的页面进行原子写入。 – 2010-10-26 08:25:22

+1

为什么不能这样工作:partialWrite =(file.transaction-id Justin 2010-10-26 13:02:19

+0

@MartinProbst:你根本无法做原子写入页面。我相信这对Windows内核是一个基本的异步操作。你可能会想看看FlushFileBuffers的Win API函数。 – Noldorin 2012-02-23 03:04:42