在Linux下编程,我们可以有很多种方式操作文件?
1、system call
Open、write、Sync、close,这部分就是vfs的system call会陷入内核态。
其中write, 只保证数据从应用地址空间拷贝到内核地址空间,即page cache。只有fsync才保证数据和元数据都实实在在地落盘了。
2、Library
这部分是C library的IO流式读写,对底层系统调用进行了封装
3、Mmap
Mmap将外存的文件块映射到内存中,可以利用OS的页面管理(虚拟空间映射,页面缓存与自动刷出,页面对齐等)
Mmap会有TLB miss的代价。
4、Zero-copy零拷贝
上述的文件读写方式,适合对单个文件的多次频繁IO。当我们需要将一个大文件传输到另一个大文件时,如果采用read+write的方式,需要频繁的在用户态和内核态之间拷贝数据。这时候可以考虑用sendfile。 senfile不需要内核态和用户态之间的数据拷贝。但是DMA需要在内核中需要维护一个连续的buffer用来传输数据。
注意:
DMA: DMA负责将数据从一个地址空间复制到另外一个地址空间。当CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。它的作用就是解放了CPU的工作。通过DMA的机制写盘,不占用系统CPU资源。
扩展问题:将普通应用中的数据写入到磁盘文件中,要经历什么?
要经历几层缓存。
IO就是内存和外存之间的数据传输。
在内存中,就是用户态和内核态;个人应用位于用户态,在进行读写的时候,通过system call,将数据拷贝到内核态;另外,也有可能是上面我提到的另外几种写文件的方式。
在内核态中,这里只考虑两层结构:VFS和BLOCKIO层。当我们调用write将数据写出时,首先会写入到page cache中。最后,操作系统会周期性的清理Page cache就是将Kernel Buffer中的数据写到磁盘中,或者我们对文件调用fsync,那么才最终落盘。
参考: http://liuyangming.tech/10-2019/INNODB-vs-PgSQL-buffer.html