Eksik inotify olayları (.git dizininde)


11

İnotify olaylarını kullanarak değişiklikleri izlemek için dosyaları izliyorum (olduğu gibi, Python'dan libc'ye çağırıyor).

A sırasında bazı dosyalar için git clone, garip bir şey görüyorum: bir IN_CREATEolay görüyorum ve görüyorum lski dosya içeriğe sahip, ancak, asla görmüyorum IN_MODIFYveya IN_CLOSE_WRITE. IN_CLOSE_WRITEDosyalara yanıt vermek istediğim için bu bana sorun yaratıyor : özellikle, dosya içeriğinin yüklenmesini başlatmak için.

Garip davranan dosyalar .git/objects/packdizinde bulunur ve .packveya ile biter .idx. Git'in oluşturduğu diğer dosyalar daha düzenli IN_CREATE-> IN_MODIFY-> bir IN_CLOSE_WRITEzincire sahiptir ( IN_OPENolayları izlemiyorum ).

Bu, MacOS'taki docker'ın içinde, ancak uzak bir sistemde Linux'ta docker'da da aynı şeyin kanıtını gördüm, bu yüzden şüphem MacOS yönünün alakalı olmadığıdır. İzliyor ve eğer bunu görüyorum git cloneiçindedir aynı liman işçisi kap.

Sorularım:

  • Bu olaylar bu dosyalarda neden eksik?

  • Bu konuda ne yapılabilir? Özellikle, bu dosyalara yazma işlemlerinin tamamlanmasına nasıl yanıt verebilirim? Not: İdeal olarak "bitmemiş" yazmayı yüklemeden gereksiz / (yanlış) yüklemeyi önlemek için yazma "bittiğinde" yanıt vermek istiyorum.


Düzenleme: https://developer.ibm.com/tutorials/l-inotify/ okumak, gördüğüm şeyle tutarlı görünüyor

  • adı tmp_pack_hBV4Alzoluşturulmuş, değiştirilmiş ve kapatılmış ayrı bir geçici dosya ;
  • bu dosyaya son adla bir sabit bağlantı oluşturulur .pack;
  • orijinal tmp_pack_hBV4Alzad silinir.

Bence dosyaları yüklemek için bir tetikleyici olarak inotify kullanmaya çalışan sorunum daha sonra .packdosyanın başka bir dosyaya sabit bir bağlantı olduğunu ve bu durumda karşıya yükleme farkını azaltır azalır ?


Cevap burada bir yerde olabilir ...
choroba

@choroba Haklı olabilirsiniz ... mmap'e birçok referans görüyorum ve
inotify

1
BTW (inotify ile) çözmeye çalıştığınız orijinal sorun nedir? Git sürecinin bir depoya ne yaptığını / yaptığını tahmin etmeye çalışan daha sağlam bir çözüm olabilir mi?
kostix

@kostix Bu parçasıdır github.com/uktrade/mobius3 ve S3, AWS Fargate içinde JupyterLab veya RStudio çalışan kaplardan kullanıcıların klasörlerine senkronize, ve bu ev klasörlerinde .git klasörler olabilir. İnotify çözümünün “sağlam-sağlam” olmayacağını biliyorum ... ama umarım “yeterince sağlam” olabilir.
Michal Charemza

1
@tink Kabul edilen cevap Linux çekirdeğinde bir yama gibi mi görünüyor? Genel olarak şüphelendiğim işe yarayacaktır, ancak Fargate'teki benim durumumda bu kontrole sahip değilim. (Ve bu güce sahip olsam bile uzun vadede yamalı bir çekirdeğe bağlı
olmanın

Yanıtlar:


5

Sorunuzu gitLinux 4.19.95'te 2.24.1 için ayrı ayrı cevaplamak için :

  • Bu olaylar bu dosyalarda neden eksik?

IN_MODIFY/ IN_CLOSE_WRITEOlaylarını görmezsiniz, çünkü git cloneher zaman .git/objectsdizin altındaki dosyalar için sabit bağlantılar kullanmaya çalışır . Ağ üzerinden veya dosya sistemi sınırları boyunca klonlama yaparken, bu olaylar tekrar görünecektir.

  • Bu konuda ne yapılabilir? Özellikle, bu dosyalara yazma işlemlerinin tamamlanmasına nasıl yanıt verebilirim? Not: İdeal olarak "bitmemiş" yazmayı yüklemeden gereksiz / (yanlış) yüklemeyi önlemek için yazma "bittiğinde" yanıt vermek istiyorum.

Sabit bağlantılarda değişiklik yakalamak için inotify CREATEolayı için bu bağlantıları takip eden ve takip eden bir işleyici ayarlamanız gerekir . Basit CREATEbir öğenin de boş olmayan bir dosya oluşturulduğu anlamına gelebileceğini lütfen unutmayın . Daha sonra, herhangi bir dosyada IN_MODIFY/ üzerinde IN_CLOSE_WRITE, aynı işlemi tüm bağlı dosyalarda tetiklemeniz gerekir. Açıkçası DELETEolaydaki bu ilişkiyi de ortadan kaldırmalısınız .

Daha basit ve daha sağlam bir yaklaşım, muhtemelen tüm dosyaları periyodik olarak karmak ve bir dosyanın içeriğinin değişip değişmediğini kontrol etmek olacaktır.


Düzeltme

gitKaynak kodunu yakından kontrol ettikten ve çalıştıktan gitsonra strace, gitbellek eşlemeli dosyaları kullandığını, ancak çoğunlukla içerik okumak için kullandığını gördüm . Kullanımının xmmapher zaman PROT_READsadece ile çağrıldığını görün . . Bu nedenle aşağıdaki benim önceki cevabım doğru cevap DEĞİLDİR . Yine de bilgilendirme amacıyla hala burada tutmak istiyorum:

  • IN_MODIFYOlayları görmüyorsunuz çünkü dosya erişimi için packfile.ckullanımlar mmapve inotifyiçin değişiklikler bildirmiyormmap ed dosyaları .

    Gönderen Inotify man :

    İnotify API, mmap (2), msync (2) ve munmap (2) nedeniyle meydana gelebilecek dosya erişimlerini ve değişiklikleri bildirmez.


Benim değişiklik algılama mekanizması bağlıdır IN_CLOSE_WRITE, hangi kullanarak yazmak için bir dosya kapatılırken hala tetiklenir düşünüyorum mmap, çünkü dosya bir yazma modunda açılmış olması gerekirdi?
Michal Charemza

Bunu araştırmak zorundayım, ancak bellek eşlemeli bir dosyanın herhangi bir inotify olayını tetiklemediğinden şüpheleniyorum. İntoify olaylarının çoğu dosya tanımlayıcı durumuyla bağlantılıdır, ancak mmapbir dosya yaptığınızda işler biraz bozulabilir . Örneğin, dosyayı belleğe eşledikten sonra kapalı bir dosya tanımlayıcıya yazabilirsiniz.
Ente

Karalayın, sadece test bu örnek uygulama ve ben alırım CLOSE_WRITE_CLOSEben kaldırmak yapmak bile closeve munmapsonunda. O zaman gerçek git uygulamasının derinliklerine inmelisin ..
Ente

Hmm sorununuzu yeniden oluşturmak için biraz uğraşıyorum. inotifywaitVe git clone(2.24.1) ile yaptığım testlerde dosyalar için bir OPEN-> alıyorum . Belki bir işleyici kurmayı unuttun ? Not: Alacaksınız çünkü eşlenen bellekte gerçekleşen tüm yazılar. CLOSE_NOWRITE,CLOSE*.idxCLOSE_NOWRITE,CLOSE*NOWRITE*
Ente

Evet, var CLOSE_NOWRITE: sorun görmüyorum IN_CLOSE_WRITEve bir yüklemeyi tetiklemek için "değişiklikler" dosyasına yanıt vermek, ancak "okumalar" dosyasını yoksaymak istiyorum. Not, aslında şu anda mmap + inotify sınırlamasının biraz kırmızı ringa balığı olduğunu düşünüyorum. Bence sorun .pack/ .idxdosyaları başlangıçta başka bir dosyaya sabit bağlantılar olarak oluşturulur ve bu yüzden sadece tetik IN_CREATE(ve git aslında dosyaları okurken OPEN-> CLOSE_NOWRITEsonra olur).
Michal Charemza

2

Git'in çoğu zaman bu şekilde yapılan atomik dosya güncellemelerini kullandığını düşünebilirim :

  1. Bir dosyanın içeriği belleğe okunur (ve değiştirilir).
  2. Değiştirilen içerik ayrı bir dosyaya yazılır (genellikle orijinaliyle aynı dizinde bulunur ve rastgele (mktemp stil) bir ada sahiptir.
  3. Daha sonra yeni dosya rename(2)orijinal dosyanın üzerine d-d olur; bu işlem, adını kullanarak dosyayı açmaya çalışan her gözlemcinin eski içeriği veya yenisini alacağını garanti eder.

Bu tür güncellemeler tarafından görülmektedir inotify(7)olarak moved_tobir dizinde olaylar-yana bir dosya "yeniden görünür".


Ah bazı dosyalar için bence bunu yapar: Çeşitli IN_MOVED_FROMve IN_MOVED_TOolayları görüyorum . Ancak, bunun .packve .idxdosyalar için olduğunu görmüyorum
Michal Charemza

Paket dosyaları büyük olabilir (birkaç gigabayt, en az 2GiB'ye kadar, inanıyorum); atomik güncellemeler kullanarak bunları kullanmak depolama alanında yasak olabilir, bu nedenle başka bir strateji kullanılarak güncellenebilir.
kostix

2

Bu kabul edilen cevaba dayanarak kullanılan protokole (yani ssh veya https) bağlı olarak olaylarda bazı farklılıklar olabileceğini varsayıyorum.

Bu --no-hardlinksseçenekle yerel dosya sisteminden klonlamayı izlerken aynı davranışı gözlemliyor musunuz ?

$ git clone git@github.com:user/repo.git
# set up watcher for new dir
$ git clone --no-hardlinks repo new-repo

Hem linux hem de Mac ana bilgisayarında denemeyi çalıştırırken gözlemlediğiniz davranış muhtemelen bu açık sorunun nedeni ortadan kaldırıyor https://github.com/docker/for-mac/issues/896 ancak sadece bir ekler.


2

Başka bir olasılık daha var (insandan inotify):

Olay kuyruğunun taşabileceğini unutmayın. Bu durumda olaylar kaybolur. Sağlam uygulamalar, kayıp olay olasılığını nazikçe ele almalıdır. Örneğin, uygulama önbelleğinin bir kısmını veya tamamını yeniden oluşturmak gerekebilir. (Basit ama muhtemelen pahalı bir yaklaşım, inotify dosya tanımlayıcısını kapatmak, önbelleği boşaltmak, yeni bir inotify dosya tanımlayıcısı oluşturmak ve ardından izlenecek nesneler için saatler ve önbellek girdilerini yeniden oluşturmaktır.)

Ve süre git clone ağır olay akışı üretebilirken, bu olabilir.

Bundan nasıl kaçınılır:

  1. Okuma arabelleğini artırın, fcntl (F_SETPIPE_SZ) deneyin (bu yaklaşım bir tahmin, hiç denemedim).
  2. Olayları özel bir iş parçacığında büyük bir arabellekte okuyun, başka bir iş parçacığında olayları işleyin.

2

Belki de yıllar önce yaptığım aynı hatayı yaptınız. Sadece iki kez inotify kullandım. İlk defa, kodum işe yaradı. Daha sonra, artık bu kaynağa sahip değildim ve tekrar başladım, ancak bu sefer olayları kaçırdım ve nedenini bilmiyordum.

Bir olayı okurken gerçekten küçük bir olay grubunu okuduğum anlaşılıyor. Beklediğimden ayrıldım, öyle olduğunu düşündüm, hepsi bu. Sonunda, alınan verilerden daha fazlası olduğunu keşfettim ve tek bir okumadan alınan tüm olayları ayrıştırmak için küçük bir kod eklediğimde, başka olay kaybedilmedi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.