(.gitディレクトリに)inotifyイベントがありません


11

私はinotifyイベントを使用してファイルの変更を監視しています(たまたま、Pythonからlibcを呼び出しています)。

中にいくつかのファイルについてはgit clone、私は奇妙な何かを参照してください。私が見IN_CREATEたイベントを、そして経て、私が見lsたファイルがコンテンツを持っていること、しかし、私は見ることはありませんIN_MODIFYIN_CLOSE_WRITE。私IN_CLOSE_WRITEはファイルに応答したいので、特に問題を引き起こしています。具体的には、ファイルのコンテンツのアップロードを開始することです。

異常な動作をするファイルは.git/objects/packディレクトリにあり、末尾が.packまたは.idxです。gitが作成する他のファイルには、より規則的なIN_CREATE-> IN_MODIFY-> IN_CLOSE_WRITEチェーンがあります(私はIN_OPENイベントを監視していません)。

これはMacOSのdockerの内部にありますが、リモートシステムのLinuxのdockerでも同じことを確認したため、MacOSの側面は関係ないのではないかと疑っています。見ていgit clone同じ Dockerコンテナーにいる場合、これが表示されます。

私の質問:

  • これらのファイルでこれらのイベントが欠落しているのはなぜですか?

  • それについて何ができますか?具体的には、これらのファイルへの書き込みの完了にどのように応答できますか?注:理想的には、「未完成」の文章を不必要に(誤って)アップロードしないように、「完成」したときに返信したいと思います。


編集:https ://developer.ibm.com/tutorials/l-inotify/を読むと、私が見ているものと一致しているように見えます

  • のような名前の個別の一時ファイル。tmp_pack_hBV4Alz作成、変更、および閉じられます。
  • ハードリンクは、最終的に、このファイルに作成された.pack名前。
  • 元のtmp_pack_hBV4Alz名前は削除されます。

私の問題は、inotifyをファイルのアップロードのトリガーとして使用しようとしていて、その.packファイルが別のファイルへのハードリンクであることを認識し、この場合はアップロードしていると思いますか?


答えはここのどこかにあるかもしれません...
チョロバ

@chorobaあなたは正しいかもしれません... mmapへの参照がたくさんあり、inotifyはファイルへのmmapアクセスを報告しません
Michal Charemza

1
ところであなたが(inotifyで)解決しようとしている元の問題は何ですか?Gitプロセスが何をしているのか、リポジトリに対して何をしたのかを推測するための、より堅牢なソリューションが存在するのでしょうか?
kostix

@kostixこれはgithub.com/uktrade/mobius3の一部であり、AWS FargateでJupyterLabまたはRStudioを実行しているコンテナーからユーザーのホームフォルダーをS3と同期します。これらのホームフォルダーには.gitフォルダーを含めることができます。私はinotifyソリューションが「ロバストロバスト」にならないことを知っています...しかし、「十分にロバスト」になることを望んでいます。
ミハルチャレムザ

1
@tink受け入れられた回答はLinuxカーネルのパッチのようですか?私は一般的にはそれでうまくいくと思いますが、私の場合、Fargateにはそのコントロールはありません。(そして、私がその能力を持っていたとしても、パッチを当てたカーネルに長期的に依存することの結果を少し恐れていることを認めます...)
Michal Charemza

回答:


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したところstracegitメモリマップされたファイルを使用していますが、ほとんどがコンテンツの読み取りに使用されています。常にのみで呼び出される使用法を参照してください。xmmapPROT_READ。したがって、以下の私の以前の答えは正しい答えではありません。それにもかかわらず、情報提供の目的で、私はそれをここに保持したいと思います:

  • はファイルアクセスに使用し、変更を報告しないため、IN_MODIFYイベントは表示されません。packfile.cmmapinotifymmap edファイルの。

    inotifyのマンページから:

    inotify APIは、mmap(2)、msync(2)、およびmunmap(2)が原因で発生する可能性があるファイルアクセスおよび変更を報告しません。


私の変更検出メカニズムはに依存しています。これは、IN_CLOSE_WRITEを使用して書き込まれたファイルを閉じるときにもトリガーされると思いmmapます。ファイルが書き込みモードで開かれている必要があるためです。
Michal Charemza

私はこれを調査する必要がありますが、メモリマップファイルがinotifyイベントをまったくトリガーしないと思います。ほとんどのintoifyイベントはファイル記述子の状態にリンクされていますが、ファイルの場合、状況が少し乱れるmmap可能性があります。たとえば、ファイルをメモリにマップした場合でも、閉じたファイル記述子に書き込むことができます。
Ente

そのスクラッチ、私はちょうどテストし、この実装例を、私は入手できますかCLOSE_WRITE_CLOSE私は削除しても、closeそしてmunmap終わり。その後、実際のGitの実装に深く掘る必要はあり...
エンテ

うーん、問題の再現に少し苦労しています。inotifywaitおよびgit clone(2.24.1)を使用したテストでは、ファイルのOPEN->が表示さCLOSE_NOWRITE,CLOSE*.idxます。多分あなたはのためのハンドラーを設定するのを忘れましたCLOSE_NOWRITE,CLOSEか?注:*NOWRITE*マップされたメモリを介して行われたすべての書き込みが原因で、a が表示されます。
Ente

はい、ありますCLOSE_NOWRITE。問題は「表示されない」でIN_CLOSE_WRITE、ファイルの「変更」に応答してアップロードをトリガーしますが、ファイルの「読み取り」は無視します。注意してください、私は実際にmmap + inotifyの制限は少し赤みを帯びているように思えます。問題は、.pack/ .idxファイルが最初に別のファイルへのハードリンクとして作成されるため、トリガーのみが発生することですIN_CREATE(そして、OPEN-> CLOSE_NOWRITEは後でgitが実際にファイルを読み取るときに発生します)。
Michal Charemza

2

Gitはほとんどの場合、次のように実行されるアトミックファイル更新を使用していると推測します。

  1. ファイルの内容がメモリに読み込まれます(変更されます)。
  2. 変更されたコンテンツは別のファイルに書き込まれます(通常、元のファイルと同じディレクトリにあり、ランダム化された(mktempスタイルの)名前が付けられています。
  3. 次に、新しいファイルはrename(2)元のファイルよりもd -dになります。この操作により、その名前を使用してファイルを開こうとするすべてのオブザーバーが古いコンテンツまたは新しいコンテンツを取得することが保証されます。

このような更新は、ファイルがディレクトリに「再表示」さinotify(7)れるmoved_toため、イベントとして認識されます。


ああ、いくつかのファイルのために、私はそれがこれを行うと思う:私は、様々な参照IN_MOVED_FROMIN_MOVED_TOイベント。しかし、私はこのために起こって表示されていない.pack.idx、ファイル
ミハル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ちょうど包みを加えます。


2

別の可能性があります(man inotifyから):

イベントキューがオーバーフローする可能性があることに注意してください。この場合、イベントは失われます。堅牢なアプリケーションは、失われたイベントの可能性を適切に処理する必要があります。たとえば、アプリケーションキャッシュの一部またはすべてを再構築する必要がある場合があります。(1つの単純ですがコストがかかる可能性があるアプローチは、inotifyファイル記述子を閉じ、キャッシュを空にし、新しいinotifyファイル記述子を作成してから、監視対象のオブジェクトの監視とキャッシュエントリを再作成します。)

また、git clone重いイベントフローを生成する可能性がありますが、これは発生する可能性があります。

これを回避する方法:

  1. 読み取りバッファーを増やして、fcntl(F_SETPIPE_SZ)を試してください(このアプローチは推測です、私は試したことはありません)。
  2. 専用スレッドの大きなバッファーにイベントを読み込み、別のスレッドでイベントを処理します。

2

たぶん、あなたは私が何年も前に犯したのと同じ間違いをしたでしょう。私はinotifyを2回しか使用していません。初めて、私のコードは単純に機能しました。後で、そのソースがなくなって再び開始しましたが、今回はイベントが欠落していて、その理由がわかりませんでした。

私がイベントを読んでいるとき、私は実際にイベントの小さなバッチを読んでいたことがわかりました。思っていたものを解析し、それだと思って、それがすべてでした。最終的に、受信したデータにはさらに多くのデータがあることを発見しました。1回の読み取りで受信したすべてのイベントを解析する小さなコードを追加したところ、イベントが失われることはありませんでした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.