【问题标题】:Does posix write ensure file offset unchanged on failure?posix write 是否确保文件偏移在失败时保持不变?
【发布时间】:2022-08-31 19:34:14
【问题描述】:

我正在学习 LevelDB 和 RocksDB,并且对它们如何在不截断的情况下保持 WAL 数据完整性感到困惑。

我发现了什么:

  1. 始终在块边界(即 8 KiB)处查找日志文件。猜猜这意味着两个街区之间没有垃圾。
  2. 日志写入器(和底层的 WriteableFile)永远不会在写入失败时截断文件。它只是继续写。猜猜这意味着失败的写入不会改变文件偏移量,因此下一次写入仍然位于它应该在的位置。

    但是来自Posix spec 它说:

    本卷POSIX.1-2017没有指定返回错误后文件偏移量的值;案例太多了。对于编程错误,例如 [EBADF],这个概念没有意义,因为不涉及文件。对于立即检测到的错误,例如[EAGAIN],显然指针不应该改变。然而,在中断或硬件错误之后,更新的值将非常有用,并且是许多实现的行为。

    那么,这是一种不应该依赖于实际系统或实际上由实际系统确保并且可以安全使用的非特定行为吗?

  • 数据库通常使用直接 IO,这比普通的write() 系统调用提供了更多的控制权。
  • @Barmar DIO 需要对齐的写入,而 IMO 不适合这种情况。

标签: linux filesystems posix rocksdb leveldb


【解决方案1】:

我正在学习 LevelDB 和 RocksDB 并且对他们如何保持 WAL 感到困惑 没有截断的数据完整性。

RocksDB 首先将日志文件拆分为固定长度的“块”(即 32KiB)。固定长度的块可以在读取时轻松验证每个块的校验和。

在固定长度的块上,有序列化的“记录”。每个“记录”的长度可以存储在多个“块”中。 Rocksdb中每个WriteBatch的原子性是通过我们可以读取“记录”的全部内容来确保的,块确保校验和的完整性。

如果发生写入失败,下次我们打开同一个日志文件进行读取时,将忽略上次未完成的写入,从而不提交遇到 I/O 错误的未完成 WriteBatch。

日志写入器(和底层的 WriteableFile)永远不会在写入失败时截断文件。它只是继续写。猜猜这意味着失败的写入不会更改文件偏移量,因此下一次写入仍然位于它应该在的位置。

如果发生 I/O 错误,我认为 RocksDB 不会重用相同的日志文件进行写入。 (还不确定)

我尝试在发生 I/O 错误时截断日志文件,并在下次程序重新启动时重用它。但它最终会出现许多极端情况问题,我认为这不是一个好习惯。

【讨论】:

    猜你喜欢
    • 2016-05-04
    • 1970-01-01
    • 2015-01-22
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 2019-12-22
    • 1970-01-01
    • 2011-10-04
    相关资源
    最近更新 更多