Estoy mirando los archivos para ver los cambios usando eventos inotify (como sucede, desde Python, llamando a libc).
Para algunos archivos durante un git clone
, veo algo extraño: veo un IN_CREATE
evento, y veo ls
que el archivo tiene contenido, sin embargo, nunca veo IN_MODIFY
o IN_CLOSE_WRITE
. Esto me está causando problemas ya que me gustaría responder IN_CLOSE_WRITE
en los archivos: específicamente, para iniciar una carga del contenido del archivo.
Los archivos que se comportan de manera extraña están en el .git/objects/pack
directorio y terminan en .pack
o .idx
. Otros archivos que crea git tienen una cadena más regular IN_CREATE
-> IN_MODIFY
-> IN_CLOSE_WRITE
(no estoy buscando IN_OPEN
eventos).
Esto está dentro de Docker en MacOS, pero he visto evidencia de lo mismo en Docker en Linux en un sistema remoto, por lo que sospecho que el aspecto de MacOS no es relevante. Estoy viendo esto si estoy mirando y estoy git clone
en el mismo contenedor acoplable.
Mis preguntas:
¿Por qué faltan estos eventos en estos archivos?
¿Qué se puede hacer al respecto? Específicamente, ¿cómo puedo responder a la finalización de las escrituras en estos archivos? Nota: idealmente me gustaría responder cuando la escritura esté "terminada" para evitar la carga innecesaria / (incorrecta) de la escritura "sin terminar".
Editar: Lectura https://developer.ibm.com/tutorials/l-inotify/ parece que lo que estoy viendo es coherente con
- un archivo temporal separado, con nombre como
tmp_pack_hBV4Alz
, siendo creado, modificado y cerrado; - se crea un enlace duro a este archivo, con el
.pack
nombre final ; tmp_pack_hBV4Alz
Se borra el nombre original .
Creo que mi problema, que es tratar de usar inotify como un desencadenante para cargar archivos, luego se reduce a notar que el .pack
archivo es un enlace duro a otro archivo y cargarlo en este caso.
Respuestas:
Para responder a su pregunta por separado para
git
2.24.1 en Linux 4.19.95:No ves
IN_MODIFY
/IN_CLOSE_WRITE
eventos porquegit clone
siempre intentará usar enlaces duros para los archivos del.git/objects
directorio. Al clonar a través de la red o a través de los límites del sistema de archivos, estos eventos aparecerán nuevamente.Para detectar modificaciones de enlaces duros, debe configurar un controlador para el
CREATE
evento inotify que sigue y realiza un seguimiento de esos enlaces. Tenga en cuenta que un simpleCREATE
también puede significar que se creó un archivo no vacío. Luego, enIN_MODIFY
/IN_CLOSE_WRITE
a cualquiera de los archivos, también debe activar la misma acción en todos los archivos vinculados. Obviamente, también debes eliminar esa relación en elDELETE
evento.Probablemente, un enfoque más simple y robusto sería simplemente hacer hash periódicamente todos los archivos y verificar si el contenido de un archivo ha cambiado.
Corrección
Después de comprobar el
git
código fuente de cerca y funcionandogit
constrace
, encontré quegit
hace archivos de la memoria uso asignadas, pero sobre todo para la lectura de contenido. Vea el uso delxmmap
cual siempre se llama conPROT_READ
solo. . Por lo tanto, mi respuesta anterior a continuación NO es la respuesta correcta. Sin embargo, con fines informativos, todavía me gustaría mantenerlo aquí:No ve
IN_MODIFY
eventos porque sepackfile.c
usammap
para acceder a archivos yinotify
no informa modificaciones parammap
archivos ed.Desde la página de manual de inotify :
fuente
IN_CLOSE_WRITE
, lo que creo que todavía se activaría al cerrar un archivo que se escribió para usarmmap
, porque el archivo debería haber sido abierto en un modo de escritura.mmap
un archivo las cosas pueden salir un poco fuera de orden. Por ejemplo, aún puede escribir en un descriptor de archivo cerrado cuando tiene el archivo asignado en la memoria.CLOSE_WRITE_CLOSE
incluso si elimino elclose
ymunmap
al final. Tengo que profundizar en la implementación real de git entonces ...inotifywait
ygit clone
(2.24.1) obtengo unOPEN
->CLOSE_NOWRITE,CLOSE
para los*.idx
archivos. ¿Quizás olvidó configurar un controlador paraCLOSE_NOWRITE,CLOSE
? Nota: Obtendrá un*NOWRITE*
porque todas las escrituras ocurridas a través de la memoria asignada son.CLOSE_NOWRITE
: el problema es que no veoIN_CLOSE_WRITE
, y me gustaría responder a los "cambios" del archivo para activar una carga, pero ignorar las "lecturas" del archivo. Tenga en cuenta que realmente creo que en este momento la limitación mmap + inotify es un poco falsa. Creo que el problema es que los archivos.pack
/.idx
se crean inicialmente como enlaces duros a otro archivo, por lo que solo se disparanIN_CREATE
(y elOPEN
->CLOSE_NOWRITE
ocurre más tarde cuando git está leyendo los archivos).Puedo especular que Git usa la mayoría de las veces actualizaciones de archivos atómicos que se hacen así:
mktemp
estilo).rename(2)
d -d sobre el original; Esta operación garantiza que cada observador que intente abrir el archivo usando su nombre obtendrá el contenido anterior o el nuevo.Tales cambios son vistos por
inotify(7)
comomoved_to
eventos-desde un archivo "reaparece" en un directorio.fuente
IN_MOVED_FROM
yIN_MOVED_TO
eventos. Sin embargo, no veo que esto suceda para los archivos.pack
y.idx
Según esta respuesta aceptada , supongo que podría haber alguna diferencia en los eventos según el protocolo que se esté utilizando (es decir, ssh o https).
¿Observa el mismo comportamiento al monitorear la clonación desde el sistema de archivos local con la
--no-hardlinks
opción?Su comportamiento observado al ejecutar el experimento tanto en un host Linux como en Mac probablemente elimine este problema abierto que es la causa https://github.com/docker/for-mac/issues/896 pero agrega solo en caso.
fuente
Hay otra posibilidad (del hombre inotify):
Y si bien
git clone
puede generar un gran flujo de eventos, esto puede suceder.Cómo evitar esto:
fuente
Tal vez cometiste el mismo error que cometí hace años. Solo he usado inotify dos veces. La primera vez, mi código simplemente funcionó. Más tarde, ya no tenía esa fuente y comencé de nuevo, pero esta vez, me faltaban eventos y no sabía por qué.
Resulta que cuando estaba leyendo un evento, realmente estaba leyendo un pequeño lote de eventos. Analicé el que esperaba, pensando que era eso, eso era todo. Eventualmente, descubrí que hay más en los datos recibidos, y cuando agregué un pequeño código para analizar todos los eventos recibidos de una sola lectura, no se perdieron más eventos.
fuente