一旦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