一旦write
或writev
返回(即OS已經接受它),操作系統負責將數據寫入到磁盤。這不再是你的問題,而且不管你的程序崩潰,它都會發生。請注意,對於一次接受或實際寫入的數據的確切數量,您是否有無控制,也不知道它是否發生在多個文件系統塊中,或者它是否是任何特定大小。您發送一個請求到write
,它告訴你它實際接受了多少,它會自行決定將它寫入磁盤。
可能這會發生在塊大小的倍數上,因爲這對於操作系統來說是有意義的,但這是不能以任何方式保證(在許多系統上,包括Linux,讀取和寫入都是通過或緊密耦合與文件映射)。
同樣的「不必關心」保證適用於文件映射(理論上的例外是,崩潰的應用程序原則上仍然可以寫入仍然映射的區域,但是一旦您已經取消映射區域,則不能即使在理論上也是如此)。除非你拔掉插頭(或內核崩潰),否則數據將被寫入並且一致。
由於內存頁面是設備塊的倍數,並且文件映射不知道其他任何內容,因此數據將只能以多個文件系統塊寫入,它只是以這種方式工作。
您可以類型(忽略任何可能的無緩衝的磁盤上寫入緩存)得到一些控制與fdatasync
磁盤上的內容。當該函數返回時,之前緩衝區中的內容已發送到磁盤。
但是,這仍然不會阻止您的進程同時在另一個線程中崩潰,並且不會阻止某人拔出插件。 fdatasync
優於fsync
,因爲它不會觸及inode附近的任何東西,這意味着它更快更安全(由於長度尚未更新,您可能會丟失後續崩潰中寫入的最後一個數據,但是您絕對不應該破壞/損壞整個文件)。使用C庫函數(fwrite
)自己進行緩衝並控制您寫入的數據量,但只有「已寫入」數據意味着它存儲在C庫擁有的緩衝區中(在您的過程中) 。如果進程死亡,數據就消失了。無法控制數據如何擊中磁盤,或者如果有的話。 (Nb:你可以控制的一些,只要你可以fflush
,這會在返回之前立即將緩衝區的內容傳遞給底層的寫入函數,最有可能的是writev
,這樣你就回到了第一段。 )
異步IO(內核 aio)將繞過內核緩衝區,並通常直接從您的進程中提取數據。您的流程死亡,您的數據消失了。 Glibc aio使用在write
上阻塞的線程,與第1段中的相同。
如果您隨時拔出插頭或打開「關閉」開關,會發生什麼情況?沒人知道。
通常一些數據會丟失,操作系統可以給很多保證,但是它不能做魔術。儘管在理論上,您可能有一個系統可以緩衝內存與電池或系統,並擁有龐大的專用磁盤緩存,這也是電池供電。沒人能說。無論如何,計劃丟失數據。
也就是說,什麼是寫一次應該不會,如果你繼續追加到一個文件通常會損壞(雖然,真的什麼都可能發生,而「不應該」,並不意味着很多)。總之,在追加模式下使用write
或者使用文件映射應該足夠好,它們就像你可以得到的一樣好。除突然斷電之外,它們可靠且高效。
如果電源故障是一個問題,UPS將提供比任何軟件解決方案所能提供的更好的保證。
至於文件大小,我看不出有任何理由人爲地限制文件大小(假設爲合理的新的文件系統)。 「標準」Linux文件系統的普通文件大小限制(如果有的話)在TB級範圍內。
無論哪種方式,如果你感到不安與破壞一個文件,不管是什麼原因可能會破壞有價值的數據30天的想法,開始每天都有新的文件一次。它不需要額外的費用。
至少在Linux系統中,你可以結合使用'fflush'用'fsync'或'sync',以確保所有的數據被寫入到磁盤當然違反這個保證... – jofel 2012-04-18 10:25:23
@jofel:的確,我在編寫這個時編輯了它。 :-)但是還有更多。首先它阻塞,除非你有多個線程,否則每秒鐘到達1000條消息。對於多個線程,同步不會產生任何影響,因爲另一個線程可能在同步過程中結束您的進程。另外,在磁盤上有未知的電源故障行爲寫入緩存(希望是一個好的,但誰知道)。現在當然也有非阻塞同步,但是...... – Damon 2012-04-18 10:35:23