J'observe les fichiers pour les changements en utilisant des événements inotify (en l'occurrence, depuis Python, en appelant dans libc).
Pour certains fichiers pendant un git clone
, je vois quelque chose d'étrange: je vois un IN_CREATE
événement, et je vois via ls
que le fichier a du contenu, cependant, je ne vois jamais IN_MODIFY
ou IN_CLOSE_WRITE
. Cela me pose des problèmes car j'aimerais répondre IN_CLOSE_WRITE
sur les fichiers: en particulier, pour lancer un téléchargement du contenu du fichier.
Les fichiers qui se comportent bizarrement se trouvent dans le .git/objects/pack
répertoire et se terminent par .pack
ou .idx
. Les autres fichiers créés par git ont une chaîne IN_CREATE
-> IN_MODIFY
-> plus régulière IN_CLOSE_WRITE
(je ne surveille pas les IN_OPEN
événements).
C'est à l'intérieur de Docker sur MacOS, mais j'ai vu des preuves de la même chose sur Docker sur Linux dans un système distant, donc je soupçonne que l'aspect MacOS n'est pas pertinent. Je vois cela si je regarde et je suis git clone
dans le même conteneur docker.
Mes questions:
Pourquoi ces événements manquent-ils dans ces fichiers?
Que peut-on y faire? Plus précisément, comment puis-je répondre à la fin des écritures dans ces fichiers? Remarque: idéalement, je voudrais répondre lorsque l'écriture est "terminée" pour éviter de télécharger inutilement / (incorrectement) une écriture "inachevée".
Edit: la lecture de https://developer.ibm.com/tutorials/l-inotify/ il ressemble à ce que je vois est cohérent avec
- un fichier temporaire distinct, avec un nom similaire
tmp_pack_hBV4Alz
, en cours de création, de modification et de fermeture; - un lien dur est créé vers ce fichier, avec le
.pack
nom final ; - le
tmp_pack_hBV4Alz
nom d' origine est supprimé.
Je pense que mon problème, qui essaie d'utiliser inotify comme déclencheur pour télécharger des fichiers, se réduit ensuite à remarquer que le .pack
fichier est un lien dur vers un autre fichier, et le téléchargement dans ce cas?
Réponses:
Pour répondre à votre question séparément pour
git
2.24.1 sous Linux 4.19.95:Vous ne voyez pas
IN_MODIFY
/IN_CLOSE_WRITE
events cargit clone
essaiera toujours d'utiliser des liens durs pour les fichiers sous le.git/objects
répertoire. Lors du clonage sur le réseau ou au-delà des limites du système de fichiers, ces événements réapparaissent.Afin de détecter la modification des liens matériels, vous devez configurer un gestionnaire pour l'
CREATE
événement inotify qui suit et conserve la trace de ces liens. Veuillez noter qu'un simpleCREATE
peut également signifier qu'un fichier non vide a été créé. Ensuite, surIN_MODIFY
/IN_CLOSE_WRITE
vers l'un des fichiers, vous devez également déclencher la même action sur tous les fichiers liés. Évidemment, vous devez également supprimer cette relation sur l'DELETE
événement.Une approche plus simple et plus robuste serait probablement de hacher périodiquement tous les fichiers et de vérifier si le contenu d'un fichier a changé.
Correction
Après avoir vérifié
git
attentivement le code source et exécutégit
avecstrace
, j'ai constaté qu'ilgit
utilise des fichiers mappés en mémoire, mais principalement pour lire le contenu. Voir l'utilisationxmmap
dont est toujours appelé avecPROT_READ
seulement. . Par conséquent, ma réponse précédente ci-dessous n'est PAS la bonne réponse. Néanmoins, à des fins d'information, je voudrais toujours le garder ici:Vous ne voyez pas les
IN_MODIFY
événements car ilpackfile.c
utilise l'mmap
accès aux fichiers etinotify
ne signale pas les modifications desmmap
fichiers ed.À partir de la page de manuel inotify :
la source
IN_CLOSE_WRITE
ce qui, selon moi, serait toujours déclenché lors de la fermeture d'un fichier écrit en utilisantmmap
, car le fichier aurait dû être ouvert en mode écriture?mmap
un fichier, les choses peuvent être un peu hors service. Par exemple, vous pouvez toujours écrire dans un descripteur de fichier fermé lorsque le fichier est mappé en mémoire.CLOSE_WRITE_CLOSE
même si je supprime leclose
etmunmap
à la fin. À creuser plus profondément dans la mise en œuvre git réelle alors ..inotifywait
etgit clone
(2.24.1), j'obtiens unOPEN
->CLOSE_NOWRITE,CLOSE
pour les*.idx
fichiers. Vous avez peut-être oublié de configurer un gestionnaire pourCLOSE_NOWRITE,CLOSE
? Remarque: vous obtiendrez un*NOWRITE*
car toutes les écritures effectuées via la mémoire mappée le sont.CLOSE_NOWRITE
: le problème est que je ne vois pasIN_CLOSE_WRITE
, et je voudrais répondre aux "modifications" du fichier pour déclencher un téléchargement, mais ignorer le fichier "lit". Remarque, je pense que la limitation mmap + inotify est en quelque sorte un redingue. Je pense que le problème est que les fichiers.pack
/.idx
sont initialement créés sous forme de liens durs vers un autre fichier, et donc ne se déclenchentIN_CREATE
(et leOPEN
->CLOSE_NOWRITE
se produit plus tard lorsque git lit réellement les fichiers).Je peux supposer que Git utilise la plupart du temps des mises à jour de fichiers atomiques qui se font comme ceci:
mktemp
-style).rename(2)
d -d sur le fichier d' origine; cette opération garantit que tout observateur essayant d'ouvrir le fichier en utilisant son nom obtiendra l'ancien contenu ou le nouveau.Ces mises à jour sont considérées
inotify(7)
comme desmoved_to
événements, puisqu'un fichier "réapparaît" dans un répertoire.la source
IN_MOVED_FROM
et lesIN_MOVED_TO
événements. Cependant, je ne vois pas cela se produire pour les fichiers.pack
et.idx
Sur la base de cette réponse acceptée, je suppose qu'il pourrait y avoir une différence dans les événements en fonction du protocole utilisé (c'est-à-dire ssh ou https).
Observez-vous le même comportement lors de la surveillance du clonage à partir du système de fichiers local avec l'
--no-hardlinks
option?Votre comportement observé lors de l'exécution de l'expérience à la fois sur un hôte Linux et Mac élimine probablement ce problème ouvert étant la cause https://github.com/docker/for-mac/issues/896 mais en ajoutant simplement au cas où.
la source
Il y a une autre possibilité (de l'homme inotify):
Et bien que cela
git clone
puisse générer un flux d'événements important, cela peut se produire.Comment éviter cela:
la source
Peut-être que vous avez fait la même erreur que moi il y a des années. Je n'ai utilisé inotify que deux fois. La première fois, mon code a simplement fonctionné. Plus tard, je n'avais plus cette source et j'ai recommencé, mais cette fois, je manquais des événements et je ne savais pas pourquoi.
Il s'avère que lorsque je lisais un événement, je lisais vraiment un petit lot d'événements. J'ai analysé celui que j'attendais, pensant que c'était tout, c'était tout. Finalement, j'ai découvert qu'il y avait plus que les données reçues, et quand j'ai ajouté un petit code pour analyser tous les événements reçus d'une seule lecture, plus aucun événement n'a été perdu.
la source