文件空洞

来源:互联网 发布:软件项目立项 编辑:程序博客网 时间:2024/05/17 01:49

这里首先解释一下什么是文件空洞。

在UNIX文件操作中,文件位移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,这一点是允许的。位于文件中但没有写过的字节都被填充为0。

如果 offset 比文件的当前长度更大,下一个写操作就会把文件“撑大(extend)”。这就是所谓的在文件里创造“空洞(hole)”。没有被实际写入文件的所有字节由重复的 0 表示。

比较常见的就是lseek,lseek用于在读写文件时移动读/写指针,但是lseek的位置可以超出文件范围,并且不会返回错误,在下一次写文件时会对文件造成‘空洞’。

在自己组织构建文件系统时,比如监控领域的私有文件系统,是要非常注意文件空洞的。由于linux的调度策略,在更新文件索引和数据时要特别小心,即使你是先写数据再更新索引,也有可能会发生文件空洞。为什么呢?

在你写数据码流时,由于数据一般比较大,比如128k,由于数据量比较大,此时linux不会立刻写入硬盘中,而会先放入内存中。但是你更新文件索引时,数据量非常小,一般都在字节级,系统可能会立刻就将数据写入硬盘而不会放入到队列排队。表面上我们是没有错的,但是如果这个时候断电了,系统设计又没有断电保护,我们想一下会发生什么。索引已经写到硬盘了,但是数据呢,数据已经丢了,也就是说索引记录的文件长度和实际的文件长度不一致,可能会相差几十M,当你再次开机进行下次写文件的时候就会出现文件空洞了,并且从文件来看丢失的数据好像是‘存在’的,实际上当你去获取数据时,会发现数据全是0。

当然你可以在系统内创建一个线程负责定时向硬盘刷数据,保证异常情况下不会丢失太多的数据。也可以每次写数据都采用fsync的方式,这样就可以保证不会有差错。但是要同时考虑到系统性能。

因此,我们在是使用lseek接口时,一定要注意防止文件空洞的产生。