【问题标题】:File contents lost after power outage断电后文件内容丢失
【发布时间】:2023-03-15 06:43:01
【问题描述】:

我正在使用 C++ ofstream 在 Linux 上编写日志文件。当我使用 tail -f 命令监视文件内容时,我可以看到内容已正确填充。但是如果发生停电并且我在重启后再次检查文件,最后几行记录就消失了。使用 hexdump 我可以看到这些记录变成了空字符 '\0'。我尝试了 flush() 和 manipulator std::endl ,但它们无论如何都没有帮助。

tail 显示给我的内容是否真的没有写入磁盘,它们只是在缓冲区中?停电前inode表没有更新?我可以接受这个事实,但我不明白为什么如果没有写入文件,记录会变成空字符。

顺便说一句,我尝试了谷歌的 glog 并且得到了相同的结果(最后一堆空字符)。我还尝试了 zlog,一个 C 库。发现它只丢失了最后的记录,但没有用空字符替换它们。

【问题讨论】:

  • 使用同步而不是刷新。 stackoverflow.com/questions/14251873/… 的可能重复项
  • 纯属假设性解释:tail 显示的是操作系统缓存或磁盘控制器缓冲区的内容。文件已扩展(零),内容(可能)已写入磁盘控制器的缓冲区,但控制器尚未将其缓冲区写入磁盘。
  • @molbdnilo 我认为您建议立即更新文件系统以反映文件的新大小,但数据从未有机会被磁盘控制器写入磁盘。那么谁决定实际写入数据,操作系统?磁盘控制器固件?
  • @Donghui 我知道同步可以比刷新做得更好,但它会带来日志记录成本。我想这就是为什么不是每个日志库,例如glog,如果它更喜欢性能而不是一致性,则使用这种方式。
  • 是的,这是一个权衡

标签: linux stream


【解决方案1】:

好吧,当你断电,然后重新启动系统时,linux内核会尝试转发日志日志,以检测并纠正系统崩溃时从内存到磁盘的不一致。通常这意味着重做并提交所有可能的操作,直到系统崩溃,但撤消(并擦除)所有在崩溃时未提交的数据。

Linux(和其他 un*x 内核,如 freebsd)有一个称为有序数据写入的工具,它强制元数据(如来自 inode 的块指针或目录条目)在在实际操作之后更新他们指向的数据被有效地写入磁盘,因此不一致性减少到最低限度。我不知道实际的 linux 实现,但是例如,在 freebsd 中,你指向的内容(文件中的零块而不是实际写入的数据)对于 freebsd 内核是完全不可能的(好吧,你可以故意这样做,但不是偶然的)最可能的事情是linux可能只管理块信息而不是文件内容,或者它更新了文件大小指针而不是那里的数据。这不应该发生,因为这是一个已经解决的问题。

另一件事是您写入了多少数据,或者为什么您在屏幕上看到的内容在系统崩溃后没有出现。您可能听说过一种叫做延迟写入的东西,它允许内核在繁忙的系统上通过不立即将数据写入磁盘而将写入操作保存到磁盘,而是等待一段时间以便可以在核心内存缓冲区中解决更新在他们去磁盘之前。无论如何,磁盘写入是在一段时间延迟后强制执行的,这意味着 linux 中的 5 秒(我试着记住,上次我检查了很多时间,我怀疑在 5 到 30 秒之间)所以你可能会输最多最后五秒。

【讨论】:

  • 感谢您的提示。我将在freebsd上进行实验。是的,我的文件系统是 EXT4 有序数据模式。我的理解就像您解释的那样,元数据是在实际数据写入后更新的。但结果似乎相反。困扰我的是日志解析器必须处理这样的异常,即使它们只是一个块零)。
  • 这确实应该是不正确的,如果你修复文件系统,你有一个损坏的文件,这不可能是好的。如果在修复后打开填充并附加到它,它将显示一个零字节块,这不是一件好事。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多