open 的同步标记

#+SETUPFILE: ~/Dropbox/Doc/Org_Templates/level-1.org
#+ATTR_HTML: border="2" rules="all" frame="all"

open 是 Linux 下打开文件的标准 API, 这个 API 同时定义了很多文件操作的参数, 不同的参数对性能影响很大. 事实上, 对同步的参数来讲(O_SYNC 系列), 默认的参数 很快, 但是会损失一些功能, 比如 cache 的存在并没有真正的把修改的内容写入文件, 如果是异常关机可能导致磁盘数据和内存没有同步, 对某些应用(如虚拟机)意味着磁盘 可能损坏.

O_SYNC

同步 I/O 的标记, 执行 write 时, 保证数据被写入硬件才返回, 也就是说调用 write 写数据的时候, write 将被阻塞, 直到所有数据(包括文件内容和文件属性) 都写入了底层硬件.

O_DSYNC

和 O_SYNC 类似, 只不过这个标记保证的只是文件的内容被写入底层硬件, 并不保证 文件属性的同步.

O_DIRECT

POSIX 并没有包含这个标志, 在 Linux 上使用的时候必须要定义 _GNU_SOURCE 这个宏.

如果使用这个标志, 数据的传输将不会通过内核空间, 而是使用 DMA 直接在用户空间 到存储设备之间传送, 不保证数据是否同步. 所以 O_DIRECT 常和 O_SYNC 一起 保证数据的同步和效率.

测试

我写了一个简单的测试程序来测试以上参数对数据读写的影响.

Flags Used Time
Default 3ms
O_SYNC 90000ms
O_DSYNC 30000ms
O_DIRECT 1ms
O_SYNC and O_DIRECT 1ms

测试结果

测试代码:

#define _GNU_SOURCE

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

/* #define USE_SYNC 1 */
/* #define USE_DSYNC 1 */
/* #define USE_DIRECT 1 */

void test()
{
    int fd;
    int i;
    int offset = 0;
    unsigned char buf[512] = "1234567890";
    int flags = 0;

#ifdef USE_DIRECT
    void *align_buf = NULL;
    if (posix_memalign(&align_buf, 512, sizeof(buf)) != 0) {
        perror("memalign failed");
        return;
    }
#endif

    flags = O_WRONLY | O_CREAT | O_TRUNC;
#ifdef USE_SYNC
    printf("USE O_SYNC flag\n");
    flags |= O_SYNC;
#endif
#ifdef USE_DSYNC
    printf("USE O_DSYNC flag\n");
    flags |= O_DSYNC;
#endif
#ifdef USE_DIRECT
    printf("USE O_DIRECT flag\n");
    flags |= O_DIRECT;
#endif
    fd = open("/tmp/test.bin", flags, 0644);

    if (fd == -1) {
        perror("Create file failed");
        return;
    }
    if (ftruncate(fd, 10 * 1024 * 1024)) {
        goto cleanup;
    }

    for (i = 0; i < 2048; ++i) {
#ifdef USE_DIRECT
        int len = pwrite(fd, align_buf, sizeof(buf), offset);
#else
        int len = pwrite(fd, buf, sizeof(buf), offset);
#endif
    if (len < 0) {
            perror("failed to write");
            break;
    } else if (len == 0) {
            break;
            /* ? */
        }
        offset += len;
    }

cleanup:
    if (fd != -1) {
        close(fd);
    }
#ifdef USE_DIRECT
    if (align_buf) {
        free(align_buf);
    }
#endif
}

int main(int argc, char *argv[])
{
    test();
    return 0;
}

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦