watchman 可以发送文件更改的原因吗?

Can watchman send why a file changed?

watchman 是否能够发布到配置的命令,为什么它向该命令发送文件?

例如:

  1. 文件夹中的新文件可能是 FILE_CREATE 标志;
  2. 删除的文件会向命令发送 FILE_DELETE 标志;
  3. 修改后的文件会发送 FILE_MOD 标志等
  4. 也许即使文件夹被删除(因此文件夹下的文件)也会发送一个 FOLDER_DELETE 参数命名该文件夹,以及一个 FILE_DELETE 到文件夹下的文件 / FOLDER_DELETE 到下面的文件夹

有这种东西吗?

不,它不能那样做。原因对于它的设计来说是非​​常基础的。 TL;DR 是客户端正确处理这些单独的事件比您想象的要复杂得多,而且几乎在所有情况下您都不需要它们。

大多数文件监视系统都是抽象的,它们只是将系统特定的通知信息转换为某种通用形式。他们不会很好地处理或根本不会处理通知队列溢出的情况,也不会为他们的客户提供可靠地响应这种情况的方法。

除此之外,文件系统可能会在很短的时间内受到来自多个并发线程或进程的多种多样的更改。这使得该区域极易出现难以管理的 TOCTOU 问题。例如,创建和写入文件通常会导致一系列关于该文件及其包含目录的通知。如果文件在此序列后立即被删除(可能是构建步骤中的中间文件),当您看到有关文件创建的通知时,很可能它已经被删除了。

Watchman 接收通知的输入流,并将其输入文件系统的内部模型:观察到的文件的有序列表。每次收到通知时,watchman 都会将其视为一个信号,它应该去查看报告为已更改的文件,然后将该文件的条目移动到有序列表的最新末尾。

当您向 Watchman 询问有关文件系统的信息时,可能甚至可能有来自内核的未决通知。为了最小化 TOCTOU 并确保其状态是最新的,watchman 生成一个 synchronization cookie 并等待该通知可见,然后再响应您的查询。

以上两点的结合意味着守望者结果数据有两个重要的属性:

  1. 您保证已经观察到在您查询之前发生的所有通知
  2. 您在查询结果中仅收到一次任何给定文件的最新信息(更改结果合并在一起)

我们来谈谈溢出的情况。如果您的系统无法跟上文件更改的速度(例如:您有一个大项目并且正在快速创建和删除文件并且系统负载很重),则 OS 不适合分配给手表的缓冲区资源中的所有未决通知。发生这种情况时,它会破坏这些缓冲区并发送溢出信号。这意味着监视 API 的客户端错过了一些事件并且不再与文件系统的状态同步。如果该客户端维护有关文件系统的状态,则它不再有效。

Watchman 通过重新检查被监视的树并将所有文件综合标记为已更改来解决这种情况。这会导致来自客户端的下一个查询看到树中的所有内容。我们称其为 新实例 结果集,因为它与您第一次查询时获得的视图相同。我们在结果中设置一个标志,以便客户端知道这已经发生并且可以采取适当的步骤来修复自己的状态。您可以通过 query parameters.

配置此行为

在这些新鲜实例结果集中,我们不知道任何给定的文件是否真的改变了(有可能它改变的方式我们不能通过 lstat) 检测,即使我们可以看到它的元数据发生了变化,我们也不知道变化的原因。

可能有多个事件导致给定文件出现在 watchman 传送的结果中。我们不把他们单独记录下来,因为我们无法用无限的历史来追踪他们;想象一个文件整天每秒都被增量写入一次。我们是否每天保留 86400 个变更条目并将其交付给我们的客户?如果有几十万个这样的文件怎么办?我们必须截断该数据,此时数据的丢失会降低您对它的推理能力。

归根结底,客户除了尝试读取文件或查看其元数据之外很少做更多的事情,一般来说,他们只希望在文件具有时才这样做停止改变。对于这个用例,watchman-wait, watchman-make and trigger 都有一个稳定期的概念,它会导致更改通知延迟交付,直到文件系统停止更改之后。