watchman 是否能够发布到配置的命令,为什么它将文件发送到该命令?
例如:
- 文件夹中的新文件可能是 FILE_CREATE 标志;
- 被删除的文件将向命令发送 FILE_DELETE 标志;
- 修改的文件将发送 FILE_MOD 标志等。
- 甚至当一个文件夹被删除(因此其中的文件)会发送一个 FOLDER_DELETE 参数命名该文件夹,以及一个 FILE_DELETE 到其下的文件/ FOLDER_DELETE 到其下的文件夹
有这样的事吗?
watchman 是否能够发布到配置的命令,为什么它将文件发送到该命令?
例如:
有这样的事吗?
不,它不能那样做。原因对于它的设计来说是非常基础的。TL;DR 是,要让客户正确处理这些单独的事件,并且在几乎所有情况下您并不真正想要它们,它比您想象的要复杂得多。
大多数文件监视系统都是抽象的,它们简单地将系统特定的通知信息转换为某种通用形式。他们不能很好地或根本不能处理通知队列溢出的问题,也不能为他们的客户提供可靠地响应这种情况的方法。
除此之外,文件系统可能会在很短的时间内受到多个并发线程或进程的变化。这使得该区域极易出现难以管理的TOCTOU问题。例如,创建和写入文件通常会导致一系列关于文件及其包含目录的通知。如果在此序列之后立即删除文件(可能它是构建步骤中的中间文件),那么当您看到有关文件创建的通知时,很有可能它已被删除。
Watchman 接收通知的输入流并将其输入文件系统的内部模型:观察到的文件的有序列表。每次收到通知时,守望者都将其视为一个信号,它应该去查看报告为已更改的文件,然后将该文件的条目移动到有序列表的最新末尾。
当您向 Watchman 询问有关文件系统的信息时,可能甚至可能还有来自内核的未决通知。为了最小化 TOCTOU 并确保其状态是最新的,watchman 会生成一个同步 cookie并等待该通知可见,然后再响应您的查询。
上述两件事的结合意味着 watchman 结果数据有两个重要的属性:
我们来谈谈溢出的情况。如果您的系统无法跟上文件更改的速度(例如:您有一个大项目并且正在非常快速地创建和删除文件并且系统负载很重),则操作系统无法适应所有待处理的分配给手表的缓冲区资源中的通知。发生这种情况时,它会破坏这些缓冲区并发送溢出信号。这意味着监视 API 的客户端已经错过了一些事件,并且不再与文件系统的状态同步。如果该客户端维护有关文件系统的状态,则它不再有效。
Watchman 通过重新检查被监视的树并将所有文件综合标记为被更改来解决这种情况。这会导致来自客户端的下一个查询看到树中的所有内容。我们称其为新实例结果集,因为它与您第一次查询时获得的视图相同。我们在结果中设置了一个标志,以便客户端知道这已经发生并且可以采取适当的步骤来修复自己的状态。您可以通过查询参数配置此行为。
在这些新的实例结果集中,我们不知道任何给定的文件是否真的改变了(它可能以我们无法检测到的方式改变 via lstat
),即使我们可以看到它的元数据发生了变化,我们不知道这种变化的原因。
可能有多个事件导致给定文件出现在 watchman 提供的结果中。我们不会单独记录它们,因为我们无法用无限的历史来跟踪它们;想象一个文件一整天每秒增量写入一次。我们是否每天为它保留 86400 个更改条目并将其交付给我们的客户?如果有数十万个这样的文件怎么办?我们必须截断该数据,此时数据中的丢失会降低您对它的推理能力。
在所有这一切结束时,客户端很少会尝试读取文件或查看其元数据之外的更多操作,一般来说,他们只想在文件停止更改时才这样做。对于这个用例,watchman-wait、watchman-make和trigger都具有结算期的概念,这会导致更改通知延迟交付,直到文件系统停止更改之后。