在 ext4 文件系统下,通过一个 C 可执行文件最快地增加文件大小而无需在文件中创建空洞的方法是什么?

3

我所知道的增加文件大小最快的方法是使用ftruncate()或lseek()将文件指针移动到所需大小并写入一个字节。但在这种情况下,这种方法不符合我的需求,因为文件中的空洞并没有在文件系统中保留空间。

最好的替代方法是使用calloc()和write()吗?

int increase_file_size_(int fd, int pages) {
    int pagesize = 4096;
    void* data = calloc(pagesize, 1);
    for(int i = 0; i < pages; ++i) {
       // In a real world program this would handle partial writes and interruptions
       if (write(fd, data, pagesize) != pagesize) {
          return -1;
    }
    return 0;
}

也许可以通过使用writev来进一步加快速度。由于calloc需要初始化更少的内存,并且更多的数据适合于CPU缓存,因此下一个版本应该会更快。
int increase_file_size_(int fd, int pages) {
    int pagesize = 4096/16;
    void* data = calloc(pagesize, 1);
    struct iovec iov[16];
    for(int i = 0; i < 16; ++i) {
      iov[i].iov_base = data;
      iov[i].iov_len = pagesize ;
    }
    for(int i = 0; i < pages; ++i) {
       // In a real world program this would handle partial writes and interruptions
       if (writev(fd, data, pagesize) != pagesize * 16) {
          return -1;
    }
    return 0;
}

我可以进行实验,看看这些方法和页面大小哪个更快。但是,是否有另一种被认为是扩展文件的正常最佳实践的方法?还有其他方法需要进行性能测试吗?

谢谢。


为什么要动态分配固定大小的缓冲区?还是固定大小只是为了举例而已? - Carey Gregory
@CareyGregory,calloc有两个原因:1)因为可执行文件是使用-Wframe-larger-than=N编译的,其中N小于页面大小。2)它可以比在堆栈上清零数据更快。 - John Cashew
请查看fallocate的源代码。 - merlin2011
@merlin2011 谢谢!这正是我想要的。 - John Cashew
1个回答

2
看一下posix_fallocate()函数:它为文件保留空间,而不一定写入任何数据来占用该空间。分配的空间类似于稀疏文件,即使您没有显式地向其写入任何内容,也可以从中读取,但与稀疏文件不同的是,它实际上会减少文件系统中的可用空间。您可以确信稍后可以在文件的该区域写入内容而不会用尽空间。
请注意,如果在写入之前读取分配的空间,posix_fallocate()似乎不会对分配的空间的内容做出任何保证。我认为Linux实现将返回所有零字节,类似于稀疏文件,但您可能不应该依赖此行为。在写入真正的内容之前,请将其视为垃圾。
请注意,并非所有的文件系统驱动都支持posix_fallocate()利用的预分配功能,如果不支持预分配,我认为它会回退到实际写入文件的方式(正常方式)。像ext4和XFS这样的典型Linux文件系统是可以的,但如果你尝试在FAT或NTFS等文件系统上使用,你的程序可能会因I/O而阻塞一段时间。

有趣。只是为了确保所有的进程都有一些雨水,如果目标是一个稀疏分配的虚拟驱动器,比如VM或SAN,如果目标分配失败,文件写入仍然会失败。 - tdelaney
我认为可以依靠fallocate将零写入文件。手册上说它是这样工作的。 - John Cashew
但是fallocate是Linux特定的且不可移植的。 posix_fallocate是标准的,但它并不提供这样的保证。(但前者用于在Linux上实现后者。) - Wyzard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接