inotify 이벤트 누락 (.git 디렉토리에서)


11

inotify 이벤트를 사용하여 변경 사항이있는 파일을보고 있습니다 (파이썬에서 libc로 호출).

동안 일부 파일의 경우 git cloneI는 다음을 참조하십시오, 나는 이상한 것을 볼 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파일이 다른 파일에 대한 하드 링크 임을 인식 하고이 경우 업로드하는 것으로 줄어 듭니다 .


대답은 여기 어딘가에있을 수 있습니다 ...
choroba

@choroba 당신이 옳을 수도 있습니다 ... mmap에 대한 많은 참조가 있고 inotify가 mmap 파일 액세스를보고하지 않습니다
Michal Charemza

1
BTW 해결하려는 원래 문제는 무엇입니까? Git 프로세스가 수행하는 작업을 저장소에 대해 추측하려고 시도하는 더 강력한 솔루션이있을 수 있습니까?
kostix

@kostix 이것은 github.com/uktrade/mobius3의 일부로 , AWS Fargate의 JupyterLab 또는 RStudio를 실행하는 컨테이너, S3과의 컨테이너에서 사용자의 홈 폴더를 동기화하며 해당 홈 폴더에는 .git 폴더가있을 수 있습니다. inotify 솔루션이 "강건한"것은 아니라는 것을 알고 있지만 "충분히 견고"할 수 있기를 바랍니다.
Michal Charemza

1
@tink 허용되는 답변이 Linux 커널의 패치 인 것 같습니다. 그것은 일반적으로 의심되는 작동하지만 Fargate의 경우에는 그 통제권이 없습니다. (그리고 나는 그 힘이 있더라도 장기적으로 패치 된 커널에 의존 한 결과에 대해 약간의 두려움을
느낀다

답변:


5

gitLinux 4.19.95 에서 2.24.1에 대해 별도로 질문에 대답하려면 다음을 수행하십시오 .

  • 이러한 파일에서 이러한 이벤트가 누락 된 이유는 무엇입니까?

디렉토리 아래의 파일에 대해 항상 하드 링크를 사용하려고하기 때문에 IN_MODIFY/ IN_CLOSE_WRITE이벤트 가 표시되지 않습니다 . 네트워크 또는 파일 시스템 경계를 통해 복제하면 이러한 이벤트가 다시 나타납니다.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에드 파일.

    로부터 inotify를 맨 :

    inotify API는 mmap (2), msync (2) 및 munmap (2)로 인해 발생할 수있는 파일 액세스 및 수정을보고하지 않습니다.


내 변경 감지 메커니즘은에 의존 IN_CLOSE_WRITE합니다. 파일을 mmap쓰기 모드로 열었어야했기 때문에 를 사용하여 작성된 파일을 닫을 때 여전히 트리거 될 것이라고 생각 합니까?
Michal Charemza

이것을 조사해야하지만 메모리 매핑 파일이 inotify 이벤트를 전혀 트리거하지 않는다고 생각합니다. 대부분의 inify 이벤트는 파일 디스크립터의 상태에 연결되어 있지만 mmap파일을 작성할 때 약간 순서 가 잘못 될 수 있습니다. 예를 들어, 파일을 메모리에 매핑 한 경우에도 닫힌 파일 설명자에 쓸 수 있습니다.
엔테

스크래치, 방금 이 예제 구현을 테스트 CLOSE_WRITE_CLOSE했으며 closeand munmap를 제거해도 짝수를 얻습니다 . 실제 git 구현에 대해 더 깊이 파고 들어야합니다.
Ente

흠 문제를 재현하기 위해 조금 고심하고 있습니다. inotifywaitgit clone(2.24.1) 테스트 에서 파일에 대해 OPEN-> CLOSE_NOWRITE,CLOSE를 얻습니다 *.idx. 에 대한 핸들러 설정을 잊었을 수 CLOSE_NOWRITE,CLOSE있습니까? 참고 : *NOWRITE*모든 쓰기는 매핑 된 메모리를 통해 발생했기 때문에 얻을 수 있습니다.
엔테

예, 있습니다 CLOSE_NOWRITE. 문제가 보이지 않습니다. IN_CLOSE_WRITE"변경"파일에 응답하여 업로드를 트리거하고 있지만 "읽기"파일은 무시하고 싶습니다. 실제로 mmap + inotify 제한은 약간의 청어입니다. 문제는 .pack/ .idx파일이 처음에 다른 파일에 대한 하드 링크로 생성되므로 트리거 만 발생 IN_CREATE한다는 것입니다 ( git이 실제로 파일을 읽을 때 OPEN-> CLOSE_NOWRITE가 나중에 발생 함).
Michal Charemza

2

Git은 대부분 다음과 같이 수행되는 원자 파일 업데이트를 사용한다고 추측 할 수 있습니다 .

  1. 파일의 내용은 메모리로 읽히고 수정됩니다.
  2. 수정 된 내용은 별도의 파일 (일반적으로 원래 파일과 동일한 디렉토리에 있으며 무작위 ( mktemp-스타일) 이름)로 작성됩니다.
  3. 새 파일은 rename(2)원래 파일 보다 d -d입니다. 이 작업을 통해 이름을 사용하여 파일을 열려고하는 모든 관찰자가 이전 내용이나 새 내용을 얻을 수 있습니다.

이러한 업데이트로 볼 수 있습니다 inotify(7)와 같은 moved_to디렉토리에있는 이벤트-이후 파일 "다시 나타납니다."


아 내가 생각하는 일부 파일을 위해이 작업을 수행합니다 : 나는 여러 참조 IN_MOVED_FROMIN_MOVED_TO이벤트를. 그러나이 파일 .pack.idx파일에 대해서는 이런 일이 발생하지 않습니다.
Michal Charemza

팩 파일은 매우 클 수 있습니다 (최소 2GiB, 몇 기가 바이트). 원자 업데이트를 사용하여 저장하면 스토리지 공간에서 금지 될 수 있으므로 다른 전략을 사용하여 업데이트 될 수 있습니다.
kostix

2

을 바탕으로 이 허용 대답 내가 사용되는 프로토콜을 기반으로 이벤트에 약간의 차이가있을 수 있습니다 가정 것 (즉, SSH 또는 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 및 Mac 호스트 모두에서 실험을 실행하는 것으로 관찰 된 행동은 아마도 https://github.com/docker/for-mac/issues/896 의 원인이되는이 열린 문제를 제거 하지만 아마도 incase를 추가합니다.


2

또 다른 가능성이 있습니다 (man inotify에서).

이벤트 큐가 오버 플로우 될 수 있습니다. 이 경우 이벤트가 손실됩니다. 강력한 응용 프로그램은 이벤트 손실 가능성을 정상적으로 처리해야합니다. 예를 들어, 응용 프로그램 캐시의 일부 또는 전부를 다시 작성해야 할 수도 있습니다. (단순하지만 비용이 많이 드는 방법 중 하나는 inotify 파일 디스크립터를 닫고 캐시를 비우고 새로운 inotify 파일 디스크립터를 작성한 다음 모니터 할 오브젝트의 시계 및 캐시 항목을 다시 작성하는 것입니다.)

그리고 git clone많은 이벤트 흐름을 생성 할 수 있지만 이런 일이 발생할 수 있습니다.

이것을 피하는 방법 :

  1. 읽기 버퍼를 늘리고 fcntl (F_SETPIPE_SZ)을 시도하십시오 (이 접근 방식은 추측 한 적이 없습니다).
  2. 전용 스레드에서 큰 버퍼로 이벤트를 읽고 다른 스레드에서 이벤트를 처리하십시오.

2

내가 몇 년 전에했던 실수를 나는 inotify를 두 번만 사용했습니다. 처음으로 내 코드는 간단하게 작동했습니다. 나중에 더 이상 해당 소스를 가지고 다시 시작하지 않았지만 이번에는 이벤트가 누락되어 이유를 알지 못했습니다.

이벤트를 읽을 때 실제로는 작은 이벤트를 읽는 것으로 나타났습니다. 나는 내가 생각한 것을 파싱했다. 그것이 전부라고 생각했다. 결국, 나는 수신 된 데이터에 더 많은 것이 있음을 발견했으며 단일 읽기에서 수신 된 모든 이벤트를 구문 분석하기 위해 작은 코드를 추가하면 더 이상 이벤트가 손실되지 않았습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.