首页 > linux open系统调用的O_DIRECT标记

linux open系统调用的O_DIRECT标记

前言

open系统调用中针对打开的文件描述符,可以增加一个O_DIRECT标记,该标记能够使得针对该文件描述符的写操作绕过操作系统page cache,直接进入通用块设备层,从而减少页缓存对IO效率的影响。

但是针对O_DIRECT标记有一个问题,数据及其元数据尝试落盘但是无法保证完整落盘,如果保证落盘,则需要O_SYNC的标记支持,即IO到达块设备才会返回,来确保用户态的数据安全性。

代码测试

测试代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include /*打印当前时间*/
void printDatetime()
{ while(1) { time_t now;struct tm *tm_now;time(&now);tm_now = localtime(&now);printf("now datetime: %d-%d-%d %d:%d:%d
", tm_now->tm_year, tm_now->tm_mon, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);fflush(stdout);sleep(1);}
}int main(int argc, char* argv[])
{ char *file_path;char *file_path_new;if ((argc > 1 && argv[1]) || argv[2] ) { file_path = argv[1];file_path_new = argv[2];} else { printf("no file path
");_exit(1);}printf("%s
",argv[1]);pthread_t t1;int err = pthread_create(&t1,NULL,printDatetime,NULL);if (err) { printf("create thread error 
");_exit(-1);}int fd;fd = open(file_path,O_WRONLY |O_CREAT |O_APPEND | O_DIRECT);if (fd == -1) { printf("open failed
");_exit(-1);}int fd2;fd2 = open(file_path_new,O_RDWR |O_CREAT |O_APPEND | O_DIRECT);if (fd2 == -1) { printf("open failed
");_exit(-1);}while(1) { int len = write(fd,"something
",sizeof("something
"));if (len == -1) { printf("write failed
");}printf("write_old success
");int len_new = write(fd2,"write to new file something
",sizeof("write to new file something
"));if (len_new == -1) { printf("write failed
");}printf("write_new success
");sleep(1);}close(fd);close(fd2);return 0;
}

注意,关于O_DIRECT系统调用除了包含头文件fcntl.h之外,编译时需加入-D_GNU_SOURCE参数

以上代码编译如下:gcc test_write.c -o write -lpthread -D_GNU_SOURCE

  • 用于传递数据的缓冲区,其内存边界必须对齐为逻辑块大小的整数倍

    man 2 open原文描述如下

    Under Linux 2.4, transfer sizes, and the alignment of the user buffer and the file offset must all be multiples of the logical block size of the file system. Under Linux 2.6, alignment to 512-byte boundaries suffices

    在2.4版本及以下 4096B对齐,而2.6以后都是512B

    关于查看逻辑块大小使用如下命令

    [root@node1 ~]# dumpe2fs /dev/hda5|grep -i "block size"
    dumpe2fs 1.42.9 (28-Dec-2013)
    Block size:               4096
    

    如果要写入裸盘文件可以使用如下命令查看逻辑块大小,

    [root@node1 ~]# parted /dev/sdb
    GNU Parted 3.1
    Using /dev/sdb
    Welcome to GNU Parted! Type 'help' to view a list of commands.
    (parted) p                                                                
    Model: ATA WDC WD121PURX-78 (scsi)
    Disk /dev/sdb: 12.0TB
    Sector size (logical/physical): 512B/4096B
    Partition Table: gpt
    Disk Flags: 
    
  • 数据传输的开始点,即文件和设备的偏移量,必须是逻辑块大小的整数倍

  • 待传递数据的长度必须是逻辑块大小的整数倍。

以上代码写入的数据存储引擎已经封装好了4K的边界对齐和块对齐,所以未设置4k边界对齐和写入数据块对齐

dd测试

使用dd对direct标记进行测试

[root@node1 ~]# dd if=/dev/zero of=/nas/cephfs/n1/test_dd bs=1M count=512
512+0 records in
512+0 records out
536870912 bytes (537 MB) copied, 0.284967 s, 1.9 GB/s
[root@node1 ~]# dd if=/dev/zero of=/nas/cephfs/n1/test_dd bs=1M count=512 oflag=direct
512+0 records in
512+0 records out
536870912 bytes (537 MB) copied, 11.519 s, 46.6 MB/s

以上数据可见,如果不加direct标记,则数据会经过页缓存cat /proc/meminfo |grep -i dirty来检测是否写入,因为操作系统页缓存处理速度肯定快,所以dd消耗的时间就少

而使用direct标记之后,会绕过操作系统缓存,数据直接交由磁盘处理,此时磁盘数据速度肯定会慢,所以耗费的时间就久

更多相关:

  • 获取linux时间  并计算时间偏移 void getSystemTimer(void){#if 0 char *wdate[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"} ; time_t timep; struct tm *p; time(&timep); p=gmtime(&timep...

  • 对于大多数程序员来说,代码风格直接反映了他的水平和逻辑能力。下面这段是我发现的比较好的代码风格,来自微软。Code  1 /***  2 *loctim64.c - Convert __time64_t value to time structure  3 *  4 *       Copyright (c) Microsoft Co...

  • 本例的初始文件是4位数字 (e.g. 0001.png),想在前面补1个0 (00001.png) import numpy as np import cv2 from ptsemseg.utils import recursive_glob import osroot = "./src/" root1 = "./dst/" fil...

  • 方法一: QString file("sample.jpg"); if (file.contains(".jpg") ||      file.contains(".bmp") ||      file.contains(".png")) {     qDebug()<<"这是图片。"; } 方法二: QString file_...

  • shell中可能经常能看到:>/dev/null 2>&1 命令的结果可以通过%>的形式来定义输出 分解这个组合:“>/dev/null 2>&1” 为五部分。 1:> 代表重定向到哪里,例如:echo "123" > /home/123.txt 2:/dev/null 代表空设备文件 3:2> 表示stderr标准错误...

  • 第三步,使用JODConverter将office文档转换为pdf       JODConverter是一个java的OpenDucument文件转换器,可以进行许多文件格式的转换,它利用 OpenOffice来进行转换工作,它能进行以下的转换工作:      1.Microsoft Office格式转换为OpenDucument...

  • 本文是西门子开放式TCP通信的第2篇,上一篇我们讲了使用西门子1200PLC作为TCP服务器的程序编写,可以点击下方链接阅读:【公众号dotNet工控上位机:thinger_swj】基于Socket访问西门子PLC系列教程(一)在完成上述步骤后,接下来就是编写上位机软件与PLC之间进行通信。上位机UI界面设计如下图所示:从上图可以看出...

  • 我有一个大型数据集,列出了在全国不同地区销售的竞争对手产品。我希望通过使用这些新数据帧名称中的列值的迭代过程,根据区域将该数据帧分成几个其他区域,以便我可以分别处理每个数据帧-例如根据价格对每个地区的信息进行排序,以了解每个地区的市场情况。我给出了以下数据的简化版本:Competitor Region ProductA Product...

  • 作为一名IT从业者,我来回答一下这个问题。首先,对于具有Java编程基础的人来说,学习Python的初期并不会遇到太大的障碍,但是要结合自己的发展规划来制定学习规划,尤其要重视学习方向的选择。Java与Python都是比较典型的全场景编程语言,相比于Java语言来说,当前Python语言在大数据、人工智能领域的应用更为广泛一些,而且大...

  • 这段时间通过学习相关的知识,最大的变化就是看待事物更加喜欢去了解事物后面的本质,碰到问题后解决问题思路也发生了改变。举个具体的例子,我在学习数据分析,将来会考虑从事这方面的工作,需要掌握的相关专业知识这个问题暂且按下不表,那哪些具体的问题是我需要了解的呢,以下简单罗列:1、了解数据分析师这个岗位在各个地区的需求情况?2、数据分析师的薪...

  • 这一节将开始学习python的一个核心数据分析支持库---pandas,它是python数据分析实践与实战的必备高级工具。对于使用 Python 进行数据分析来说,pandas 几乎是无人不知,无人不晓的。今天,我们就来认识认识数据分析界鼎鼎大名的 pandas。目录一. pandas主要数据结构 SeriesDataFrame二...