2010-09-21 75 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