#+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;
}