我正在观察文件使用 inotify 事件的变化 (因为它发生,从 Python,调用 libc)。
对于一些文件在git clone
, I see something odd: I see an IN_CREATE
event, and I see via ls
that the file has content, however, I never see IN_MODIFY
or IN_CLOSE_WRITE
. This is causing me issues since I would like to respond to IN_CLOSE_WRITE
关于文件: 具体来说,要启动文件内容的上传。
行为古怪的文件在.git/objects/pack
directory, and they end in .pack
or .idx
. Other files that git creates have a more regular IN_CREATE
-> IN_MODIFY
-> IN_CLOSE_WRITE
chain (I'm not watching for IN_OPEN
事件)。
这是在 MacOS 上的 docker 内部,但是我在远程系统的 Linux 上的 docker 上看到了同样的证据,所以我怀疑 MacOS 方面无关紧要。我看到这个,如果看着git clone
都在_相同_Docker 容器。
我的问题:
为什么这些文件上缺少这些事件?
对此可以做些什么?具体来说,我如何应对这些文件的写入完成?注意: 理想情况下,我想在写作 “完成” 时做出回应,以避免不必要地/(错误地) 上传 “未完成” 的写作。
编辑: 阅读Https://developer.ibm.com/tutorials/ l-inotify/看起来我看到的是一致的
tmp_pack_hBV4Alz
,正在创建、修改和关闭;.pack
名称;tmp_pack_hBV4Alz
名称被删除。我认为我的问题是试图使用 inotify 作为上传文件的触发器,然后减少到注意到.pack
文件是到另一个文件的硬链接,在这种情况下上传?
To answer your question separately for git 2.24.1 on Linux 4.19.95:
- 为什么这些文件上缺少这些事件?
你看不到IN_MODIFY
/IN_CLOSE_WRITE
events because git clone
will always try to use hard links for files under the .git/objects
目录。当通过网络或跨文件系统边界进行克隆时,这些事件将再次出现。
- 对此可以做些什么?具体来说,我如何应对这些文件的写入完成?注意: 理想情况下,我想在写作 “完成” 时做出回应,以避免不必要地/(错误地) 上传 “未完成” 的写作。
为了捕捉硬链接的修改,你必须为 inotify 设置一个处理程序。CREATE
event which follows and keeps track of those links. Please note that a simple CREATE
can also mean that a nonempty file was created. Then, on IN_MODIFY
/IN_CLOSE_WRITE
to any of the files you have to trigger the same action on all linked files as well. Obviously you also have to remove that relationship on the DELETE
事件。
一个更简单、更健壮的方法可能是定期散列所有文件,并检查文件的内容是否发生了变化。
检查后git
source code closely and running git
with strace
, I found that git
does use memory mapped files, but mostly for reading content. See the usage of xmmap
which is always called with PROT_READ
只有。。因此,我之前的答案如下:非正确答案。然而,为了提供信息,我仍然想把它留在这里:
你看不到IN_MODIFY
events because packfile.c
uses mmap
for file access and inotify
does not report modifications for mmap
Ed 文件。
Inotify API 不报告由于 mmap (2) 、 msync (2) 和 munmap (2) 而可能发生的文件访问和修改。
I may speculate that Git most of the time uses atomic file updates which are done like this:
mktemp
-风格) 名称。rename(2)
D-d 超过原来的; 这个操作保证了每个试图用它的名字打开文件的观察者会得到旧的或新的内容。这样的更新被看到inotify(7)
as moved_to
事件-由于文件在目录中 “重新出现”。
Based on this accepted answer I'd assume there might be some difference in the events based on the protocol being used (i.e. ssh or https).
Do you observe the same behavior when monitoring cloning from the local filesystem with the --no-hardlinks
选项?
$ Git 克隆 git@github.com: user/repo.git
# 为新目录设置观察程序
$ Git 克隆-无硬链接回购新回购
您在 linux 和 Mac 主机上运行实验时观察到的行为可能消除了导致此开放性问题的原因Mac/issues/896 的 https://github.com/docker/但是只添加 incase。
There is another possibility (from man inotify):
请注意,事件队列可能会溢出。在这种情况下,事件是 迷路了。强大的应用程序应该处理丢失的可能性 事件优雅。例如,可能需要重建零件 或所有应用程序缓存。(一个简单,但可能 昂贵,方法是关闭 inotify 文件描述符,空 缓存,创建一个新的 inotify 文件描述符,然后重新创建 监视对象的监视和缓存条目。)
而git clone
会产生沉重的事件流,这可能会发生。
如何避免这种情况:
Maybe you made the same mistake I made years ago. I've only used inotify twice. The first time, my code simply worked. Later, I no longer had that source and started again, but this time, I was missing events and did not know why.
事实证明,当我阅读一个事件时,我真的是在阅读一小批事件。我解析了我所期望的那个,认为就是它,仅此而已。最终,我发现接收到的数据还有更多,当我添加一个小代码来解析从一次读取中接收到的所有事件时,没有更多的事件丢失。