Post

unix data sync

leveldb的file io中,有些io是要同步磁盘的,这里集中看一下。

传统的UNIX实现的内核中都设置有缓冲区或者页面高速缓存,大多数磁盘IO都是通过缓冲写的。

当你想将数据write进文件时,内核通常会将该数据复制到其中一个缓冲区中,如果该缓冲没被写满的话,内核就不会把它放入到输出队列中。

当这个缓冲区被写满或者内核想重用这个缓冲区时,才会将其排到输出队列中。等它到达等待队列首部时才会进行实际的IO操作。

所以,针对某个fd,如果你想保证磁盘上的实际文件和缓冲区中的内容保持一致,这里其实也有几个方法

  1. fcntl(F_FULLFSYNC)

    1
    2
    3
    
     #include <fcntl.h>
    
     int fcntl(int fd, int cmd, ... /* arg */ );
    

    对于 F_FULLFSYNC,实际使用时是这样的:

    1
    
     int result = fcntl(fd, F_FULLFSYNC);
    
  2. fdatasync

    1
    2
    3
    
     #include <unistd.h>
    
     int fdatasync(int fd);
    
  3. fsync

    1
    2
    3
    
     #include <unistd.h>
    
     int fsync(int fd);
    

所有这些函数的参数和返回值说明:

  • fd: 文件描述符,指向要同步的文件。
  • 返回值:
    • 成功时返回 0
    • 失败时返回 -1,并设置 errno 来指示错误

注意事项:

  1. fcntl 是一个更通用的函数,可以执行多种文件控制操作。F_FULLFSYNC 是其中的一个特定命令,仅在 macOS 系统上可用。

  2. fdatasync 和 fsync 在大多数 UNIX-like 系统上都可用,它们是 POSIX 标准的一部分。

  3. 使用这些函数时,需要包含相应的头文件,并且在某些系统上可能需要链接特定的库。

  4. 错误处理通常涉及检查返回值并在失败时检查 errno。例如:

1
2
3
4
if (fsync(fd) == -1) {
    perror("fsync failed");
    // 处理错误...
}

具体来讲,这三个调用都用于确保数据持久化,但它们在不同的操作系统和文件系统上有不同的行为和保证。让我们逐一比较:

  1. fcntl(fd, F_FULLFSYNC)

    • 这是 macOS 特有的系统调用。
    • 提供最强的持久化保证。
    • 确保所有数据和元数据都被写入到物理存储介质。
    • 会等待存储设备完成所有待处理的写操作。
    • 在某些情况下可以绕过硬件缓存。
    • 性能开销最大,但提供最强的数据安全保证。
  2. fdatasync(fd)

    • POSIX 标准的一部分,在大多数 UNIX-like 系统上可用。
    • 同。步文件的数据部分到磁盘
    • 不一定同步文件的元数据(除非元数据对读取文件内容必要)。
    • 通常比 fsync 快,因为它可能不需要更新某些元数据。
    • 在某些文件系统上,可能和 fsync 的行为相同。
  3. fsync(fd)

    • POSIX 标准的一部分,在大多数 UNIX-like 系统上可用。
    • 同步文件的所有数据和元数据到磁盘。
    • 确保文件的所有方面(包括修改时间、大小等)都被更新。
    • 通常比 fdatasync 慢,因为它需要更新所有相关的元数据。

性能和保证强度比较:

fcntl(F_FULLFSYNC) > fsync > fdatasync

  • fcntl(F_FULLFSYNC) 提供最强的保证,但性能开销最大。
  • fsync 提供全面的文件同步,包括所有元数据。
  • fdatasync 专注于数据同步,可能会在某些情况下性能更好。

使用建议:

  1. 如果你在 macOS 上开发,并且需要最强的持久化保证,使用 fcntl(F_FULLFSYNC)。
  2. 如果你需要确保文件的所有方面都被同步,包括元数据,使用 fsync。
  3. 如果你主要关心文件的数据内容,而不太在意元数据(如访问时间),使用 fdatasync 可能会有更好的性能。
  4. 在跨平台应用中,fsync 通常是最安全和最通用的选择。

需要注意的是,实际行为可能因操作系统和文件系统而异。在某些系统上,这些调用的实际实现可能没有显著区别。始终建议在目标系统上进行测试,以确保达到所需的持久化级别。

This post is licensed under CC BY 4.0 by the author.

Trending Tags