Я наблюдаю за изменениями в файлах, используя события inotify (как это происходит из Python, вызывая libc).
Для некоторых файлов во время a 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
событиями).
Это внутри докера на MacOS, но я видел доказательства того же на докере на Linux в удаленной системе, поэтому я подозреваю, что аспект MacOS не имеет значения. Я вижу это, если смотрю и git clone
в том же контейнере докера.
Мои вопросы:
Почему эти события отсутствуют в этих файлах?
Что с этим можно сделать? В частности, как я могу ответить на завершение записи в эти файлы? Примечание: в идеале я хотел бы ответить, когда запись «закончена», чтобы избежать ненужной / (неправильной) загрузки «незаконченной» записи.
Редактировать: чтение https://developer.ibm.com/tutorials/l-inotify/ похоже, что то, что я вижу, соответствует
- отдельный временный файл с именем, как
tmp_pack_hBV4Alz
, создается, изменяется и закрывается; - на этот файл создается жесткая ссылка с окончательным
.pack
именем; - оригинальное
tmp_pack_hBV4Alz
имя удалено.
Я думаю, что моя проблема, которая заключается в попытке использовать inotify в качестве триггера для загрузки файлов, сводится к тому, чтобы заметить, что .pack
файл представляет собой жесткую ссылку на другой файл, и к загрузке в этом случае?
Ответы:
Чтобы ответить на ваш вопрос отдельно для
git
2.24.1 в Linux 4.19.95:Вы не видите
IN_MODIFY
/IN_CLOSE_WRITE
events, потомуgit clone
что всегда будете пытаться использовать жесткие ссылки для файлов в.git/objects
каталоге. При клонировании по сети или через границы файловой системы эти события будут появляться снова.Чтобы поймать модификацию жестких ссылок, вы должны установить обработчик для
CREATE
события inotify, которое следует и отслеживает эти ссылки. Обратите внимание, что простойCREATE
может также означать, что был создан непустой файл. Затем вIN_MODIFY
/IN_CLOSE_WRITE
к любому из файлов вы должны запустить одно и то же действие для всех связанных файлов. Очевидно, вы также должны удалить эти отношения наDELETE
мероприятии.Возможно, более простым и надежным подходом будет просто периодически хэшировать все файлы и проверять, изменилось ли содержимое файла.
коррекция
После
git
тщательной проверки исходного кода и работыgit
с нимstrace
я обнаружил, чтоgit
файлы, отображаемые в память , действительно используются, но в основном для чтения содержимого. Смотрите использованиеxmmap
которого всегда вызываетсяPROT_READ
только с. , Поэтому мой предыдущий ответ ниже НЕ является правильным ответом. Тем не менее, в информационных целях я все еще хотел бы сохранить это здесь:Вы не видите
IN_MODIFY
события, потому чтоpackfile.c
используетmmap
для доступа к файлу иinotify
не сообщает об изменениях дляmmap
файлов ed.Из справочной страницы inotify :
источник
IN_CLOSE_WRITE
, что, я думаю, будет по-прежнему срабатывать при закрытии файла, который был записан для использованияmmap
, поскольку файл должен был быть открыт в режиме записи?mmap
файл, все может выйти из строя. Например, вы все равно можете записывать в закрытый файловый дескриптор, когда файл отображается в памяти.CLOSE_WRITE_CLOSE
даже, если я удаляюclose
иmunmap
в конце. Приходится копать глубже в фактическую реализацию git ..inotifywait
иgit clone
(2.24.1) я получаюOPEN
->CLOSE_NOWRITE,CLOSE
для*.idx
файлов. Может быть, вы забыли настроить обработчик дляCLOSE_NOWRITE,CLOSE
? Примечание: вы получите,*NOWRITE*
потому что все записи происходили через отображенную память.CLOSE_NOWRITE
: проблема в том, что я не вижуIN_CLOSE_WRITE
, и я хотел бы ответить на «изменения» файла, чтобы инициировать загрузку, но проигнорировать «чтение» файла. Обратите внимание, я на самом деле думаю, что сейчас ограничение mmap + inotify является чем-то вроде красной селедки. Я думаю, проблема заключается в том, что файлы.pack
/.idx
изначально создавались как жесткие ссылки на другой файл, и поэтому запускаются толькоIN_CREATE
(аOPEN
->CLOSE_NOWRITE
происходит позже, когда git фактически читает файлы).Я могу предположить, что Git большую часть времени использует атомарные обновления файлов, которые выполняются следующим образом:
mktemp
-стиль) имя.rename(2)
d -d по сравнению с оригинальным; эта операция гарантирует, что каждый наблюдатель, пытающийся открыть файл, используя его имя, получит либо старое содержимое, либо новое.Такие обновления рассматриваются
inotify(7)
какmoved_to
события - поскольку файл «появляется» в каталоге.источник
IN_MOVED_FROM
иIN_MOVED_TO
события. Тем не менее, я не вижу это происходит за.pack
и.idx
файлыОсновываясь на этом принятом ответе, я предположил бы, что могут быть некоторые различия в событиях, основанных на используемом протоколе (то есть ssh или https).
Наблюдаете ли вы то же поведение при мониторинге клонирования из локальной файловой системы с помощью
--no-hardlinks
опции?Наблюдаемое вами поведение при запуске эксперимента на хостах Linux и Mac, вероятно, устраняет эту открытую проблему, являющуюся причиной https://github.com/docker/for-mac/issues/896, но добавляя просто incase.
источник
Есть еще одна возможность (от man inotify):
И хотя он
git clone
может генерировать большой поток событий, это может произойти.Как этого избежать:
источник
Может быть, вы сделали ту же ошибку, которую я сделал несколько лет назад. Я использовал inotify только дважды. В первый раз мой код просто работал. Позже у меня больше не было этого источника, и я начал заново, но на этот раз я пропустил события и не знал, почему.
Оказывается, когда я читал событие, я действительно читал небольшую серию событий. Я проанализировал тот, который ожидал, думая, что это все, вот и все. В конце концов, я обнаружил, что есть еще что-то для полученных данных, и когда я добавил небольшой код для анализа всех событий, полученных от одного чтения, больше никаких событий не было потеряно.
источник