我正在通过 JVM 程序中的 socket/bser 接口集成 watchman。
我看到奇怪的时机:
- 构建系统写入一个文件(一个小文本文件)
- 我在 bser 界面上收到守望通知
- 线程 A 监听 bser 订阅通知将更新放到一个单独线程的队列中
- 线程 B 读取队列,读取更改的文件,然后将文件的数据放到网络上
但是,不知何故,线程 B 正在读取一个空文件。
我假设在某些时候它是有效的空,例如 IO/系统调用可能是:
- 清除文件内容
- 写入块 1
- 写入块 2
- 关闭文件
我假设我的线程 B 正在步骤 1 和 2 之间读取文件。或者可能是 1 和 4,如果 4 是刷新结果的时间。
我的困惑有两个方面:
1)我认为守望者的默认 20 毫秒等待会解释这样的事情,而且我只会在我的线程 A 上看到更新,更不用说当我的线程 B 在第 4 步之后进行读取并且数据完成写入时文件。
2)即使守望者确实“过早地”告诉我第一个系统调用(比如步骤 1),并且我在它是一个空文件时读取了结果,应该还有另一个系统调用/守望者通知“顺便说一句,文件有一些现在的内容”。
FWIW/奇怪的是,我在使用 Java WatchService API 时看到了同样的行为,在那里我会得到一个 inotify 事件,但是“太快”读取一个文件,所以得到空的或部分的结果,然后没有跟进当其余数据可用时通知事件。
我认为这是WatchService的侥幸/细微差别,所以我当时通过在读取文件之前检查文件修改时间来解决它,并在假设文件“完成”写入之前等待确保修改时间> 2秒.
(请注意,这也处理了大约 100mb+ 的文件正在写入,其中构建过程可能每 100ms+ 写入一大块数据,但是使用 WatchService 我看到了 100 条 inotify 通知,这些通知基本上是一次连续的写入。)
当我将我的 WatchService 代码移植到 watchman 时,我放弃了这个“ensureSettled”黑客,因为我假设 watchman 的 20 毫秒稳定期(这比我使用的 2 秒低得多,但嘿,这是默认值)+ 与有点beta WatchService 意味着它不会是一个问题。
但是在使用 watchman-ported 代码的大约一天内,我看到了空文件读取,就像我使用 WatchService 一样。
关于我所缺少的任何想法?
我可以添加回 ensureSettled hack,但此时我很好奇发生了什么。