Отсутствуют события inotify (в каталоге. git) - PullRequest
11 голосов
/ 22 января 2020

Я наблюдаю за изменениями файлов, используя события inotify (как это происходит с Python, вызывая lib c).

Для некоторых файлов во время git clone я вижу что-то странное : Я вижу событие IN_CREATE и через ls вижу, что в файле есть содержимое, однако я никогда не вижу IN_MODIFY или IN_CLOSE_WRITE. Это вызывает у меня проблемы, поскольку я хотел бы ответить на IN_CLOSE_WRITE в файлах: в частности, чтобы начать загрузку содержимого файла.

Файлы, которые ведут себя странно, находятся в каталоге .git/objects/pack, и они заканчиваются на .pack или .idx. Другие файлы, которые git создает, имеют более регулярную цепочку IN_CREATE -> IN_MODIFY -> IN_CLOSE_WRITE (я не наблюдаю за IN_OPEN событиями).

Это внутри docker на MacOS, но я видел доказательства того же на docker на Linux в удаленной системе, поэтому я подозреваю, что аспект MacOS не имеет значения. Я вижу это, если смотреть и git clone находятся в том же docker контейнере.

Мои вопросы:

  • Почему эти события отсутствует в этих файлах?

  • Что с этим можно сделать? В частности, как я могу ответить на завершение записи в эти файлы? Примечание: в идеале я хотел бы ответить, когда запись «закончена», чтобы избежать ненужной / (неправильной) загрузки «незаконченной» записи.


Редактировать: Чтение https://developer.ibm.com/tutorials/l-inotify/ похоже, что то, что я вижу, соответствует

  • отдельному временному файлу с именем вроде tmp_pack_hBV4Alz, который создается, изменяется и закрывается;
  • hard ссылка создается для этого файла с окончательным .pack именем;
  • оригинальное tmp_pack_hBV4Alz имя удалено.

Я думаю, что мой проблема, которая пытается использовать inotify в качестве триггера для загрузки файлов, а затем сводится к тому, чтобы заметить, что файл .pack является жесткой ссылкой на другой файл, и к загрузке в этом случае?

Ответы [ 5 ]

5 голосов
/ 26 января 2020

Чтобы ответить на ваш вопрос отдельно для git 2.24.1 на Linux 4.19.95:

  • Почему эти события отсутствуют в этих файлах?

Вы не видите IN_MODIFY / IN_CLOSE_WRITE событий, потому что git clone всегда будет пытаться использовать жесткие ссылки для файлов в каталоге .git/objects. При клонировании по сети или через границы файловой системы эти события будут появляться снова.

  • Что с этим можно сделать? В частности, как я могу ответить на завершение записи в эти файлы? Примечание: в идеале я хотел бы ответить, когда запись «закончена», чтобы избежать ненужной / (неправильной) загрузки «незаконченной» записи.

Чтобы отследить изменение жестких ссылок, вы должны установить обработчик для события inotify CREATE, которое следует и отслеживает эти ссылки. Обратите внимание, что простой CREATE также может означать, что был создан непустой файл. Затем на IN_MODIFY / IN_CLOSE_WRITE для любого из файлов вы должны запустить то же действие для всех связанных файлов. Очевидно, что вы также должны удалить эту связь в событии DELETE.

Более простой и надежный подход, вероятно, состоит в том, чтобы просто периодически sh иметь все файлы и проверять, изменилось ли содержимое файла. .


Исправление

После тщательной проверки исходного кода git и запуска git с strace я обнаружил, что git использует файлы с отображением в памяти, но в основном для чтения контента. См. Использование xmmap, которое всегда вызывается только с PROT_READ. . Поэтому мой предыдущий ответ ниже НЕ правильный ответ. Тем не менее, в информационных целях я все еще хотел бы сохранить это здесь:

  • Вы не видите IN_MODIFY событий, потому что packfile.c использует mmap для файла access и inotify не сообщает об изменениях для mmap ed файлов.

    На странице управления inotify :

    API inotify не сообщает о доступе к файлам и изменения, которые могут произойти из-за mmap (2), msyn c (2) и munmap (2).

2 голосов
/ 29 января 2020

Может быть, вы сделали ту же ошибку, которую я совершил годы go. Я использовал inotify только дважды. В первый раз мой код просто работал. Позже у меня больше не было этого источника, и я начал заново, но на этот раз я пропустил события и не знал, почему.

Оказывается, когда я читал событие, я действительно читал небольшую партию событий. Я проанализировал тот, который ожидал, думая, что это все, вот и все. В конце концов, я обнаружил, что есть еще что-то для полученных данных, и когда я добавил небольшой код для разбора всех событий, полученных от одного чтения, больше никаких событий не было потеряно.

2 голосов
/ 28 января 2020

Существует еще одна возможность (от man inotify):

Обратите внимание, что очередь событий может переполниться. В этом случае события теряются. Надежные приложения должны корректно обрабатывать возможность потерянных событий. Например, может потребоваться перестроить часть или весь кэш приложения. (Один простой, но, возможно, дорогой подход - закрыть дескриптор файла inotify, очистить кэш, создать новый дескриптор файла inotify, а затем заново создать наблюдения и записи в кеше для объектов, подлежащих мониторингу.)

И хотя git clone может генерировать поток тяжелых событий, это может произойти.

Как этого избежать:

  1. Увеличьте буфер чтения, попробуйте fcntl (F_SETPIPE_SZ) (это Подход - это предположение, я никогда не пробовал).
  2. Считывание событий в большой буфер в выделенном потоке, обработка событий в другом потоке.
2 голосов
/ 26 января 2020

На основании этого принятого ответа Я бы предположил, что могут быть некоторые различия в событиях, основанных на используемом протоколе (т. Е. S sh или https).

Делаете ли вы наблюдать такое же поведение при мониторинге клонирования из локальной файловой системы с параметром --no-hardlinks?

$ git clone git@github.com:user/repo.git
# set up watcher for new dir
$ git clone --no-hardlinks repo new-repo

Ваше наблюдаемое поведение при запуске эксперимента на хосте linux и Ma c, вероятно, устраняет это открытое проблема является причиной https://github.com/docker/for-mac/issues/896, но добавляется только случай

2 голосов
/ 22 января 2020

Я могу предположить, что Git большую часть времени использует atomi c обновления файла, которые выполняются следующим образом:

  1. Содержимое файла считывается в память ( и изменены).
  2. Измененное содержимое записывается в отдельный файл (обычно расположенный в том же каталоге, что и исходный) и имеет рандомизированное (mktemp -стиль) имя.
  3. В этом случае новый файл rename(2) d -d превосходит исходный, и эта операция гарантирует, что каждый наблюдатель, пытающийся открыть файл с использованием его имени, получит либо старое содержимое, либо новое.

Такие обновления воспринимаются inotify(7) как moved_to события, поскольку файл «появляется» в каталоге.

...