在不知道文件描述符的情况下检测文件大小不为零的最快方法是什么?

What is the fastest way to detect file size is not zero without knowing the file descriptor?

为了简单解释一下我为什么需要这个, 我目前正在通过 stat(2) 进行检测。我无法控制文件描述符(可能会被其他线程用完,因为我的代码被注入以替换系统调用),所以我不能使用 fstat(2)(速度更快)。我需要多次进行此检查,那么有没有更快的方法来做同样的事情? 我在没有父子关系的不同进程中检查同一个文件。

您可能应该自己进行基准测试。

我测量过

//Real-time System-time
272.58 ns(R)    170.11 ns(S)  //lseek
366.44 ns(R)    366.28 ns(S)  //fstat
812.77 ns(R)    711.69 ns(S)  //stat("/etc/profile",&sb)

在我的 Linux 笔记本电脑上。它在运行之间略有波动,但 lseek 通常比 fstat 快一堆 ns,但你还需要一个 fd 并且 opening 在大约 1.6µs 时非常昂贵,所以stat 可能是您的最佳选择。


tom-karzes 所述,stat 应取决于路径中目录组件的数量。我在 PATH_MAX 长的“/foo/foo/.../foo”目录中尝试了它,我得到了 80µs.

了解您正在搜索的文件系统后,最有效的方法是打开关联的块设备并(逐块)搜索 inode table,并从那里的 inode 检查实际大小(打开块设备,这样你就可以从 in-memory 图像中获取索引节点,而不是从磁盘中获取)。这允许您以快速而肮脏的方式获取文件系统的所有零长度索引节点。缺点是你首先需要获取文件系统的信息,然后才能直接访问块设备,这通常是 non-root 进程所禁止的。之后,您必须搜索文件系统以获取所涉及文件的名称,以防万一您需要对这些文件执行某些操作。

顺便说一下,您假设 无法在与另一个线程共享的文件描述符上使用 fstat(2) 是错误的,因为 stat 系统调用在一个打开的文件描述符,并且不对文件执行任何操作---它是非阻塞的---,并且系统保证在访问 stat 结构时 inode 被锁定。

使用lseek(2)的方法在这种情况下无效,因为它实际上是将文件指针移动到文件末尾,然后又回到保存的地方,这需要执行和撤消移动 的两个系统调用,如果另一个线程使用另一个系统调用(在两者之间执行 write(2),而您拥有文件指针,则可能会发生许多竞争场景在另一个地方。

Unix(包括所有 posix 系统 linux、bsd 等)保证非阻塞系统调用(如 stat(2) 是)本质上是原子的,阻塞 inode在进程(或线程)执行系统调用时文件的。因此,当您的 stat(2) 系统调用正在获取数据时,没有其他线程可以使用该文件。即使在阻塞调用中,unix 也保证对同一描述符进行的不同系统调用将被链接起来执行,并且 process/thread 将不得不等到 stat(2) 系统调用结束。

fstat(2) 上的问题是它必须解决所有路径元素,直到到达文件的最终索引节点(这是存储文件长度的位置),这是在一个一个的基础。在它没有到达最终的 inode 之前,不会对最终的 inode 进行锁定(实际上,在我们到达它之前它是未知的,所以在我们完成 namei() 解析之前我们不能阻止它)然后它求解为原始 stat(2).

结论

stat(2) 其他线程 文件描述符一起使用而不用担心数据损坏,这是不可能发生的。请不要犹豫,因为在您收集 stat 信息时,文件的 inode 不会发生任何事情。