Czy inotify uruchamia powiadomienie, gdy zapis zostanie rozpoczęty lub gdy zostanie zakończony?


12

Wyobraź sobie dwa procesy, czytnik i pisarz, komunikujące się za pomocą zwykłego pliku na ext3 fs. Czytnik ma IN_MODIFYzegarek inotify na pliku. Program Writer zapisuje do pliku 1000 bajtów w jednym write()wywołaniu. Czytnik pobiera zdarzenie inotify i wywołuje fstatplik. Co widzi Reader?

  1. Czy istnieje jakakolwiek gwarancja, że ​​program Reader odzyska co najmniej 1000 st_sizez pliku? Z moich eksperymentów wydaje się, że nie.

  2. Czy jest jakaś gwarancja, że ​​Reader może faktycznie read()1000 bajtów?

Dzieje się tak na poważnie powiązanym polu we / wy. Na przykład sarpokazuje czasy oczekiwania około 1 sekundy. W moim przypadku czytnik faktycznie czeka 10 sekund PO odebraniu zdarzenia inotify przed wywołaniem stati uzyskuje zbyt małe wyniki.

Miałem nadzieję, że zdarzenie inotify nie zostanie dostarczone, dopóki plik nie będzie gotowy. Podejrzewam, że tak naprawdę dzieje się to, że zdarzenie inotify jest uruchamiane PODCZAS write()połączenia w programie Writer, a dane są w rzeczywistości dostępne dla innych procesów w systemie, ilekroć jest gotowy. W tym przypadku 10 s to za mało czasu.

Chyba szukam tylko potwierdzenia, że ​​jądro faktycznie implementuje inotify w sposób, w jaki zgaduję. Ponadto, czy są jakieś opcje, które mogą zmienić to zachowanie?

Wreszcie - jaki jest sens inotify, biorąc pod uwagę to zachowanie? Po otrzymaniu zdarzenia i tak sprowadzasz się do odpytywania pliku / katalogu, dopóki dane nie będą faktycznie dostępne. Równie dobrze może to robić cały czas i zapomnieć o niedotyczeniu.

*** EDYTOWAĆ ** * * Dobra, jak to często bywa, zachowanie, które widzę, ma sens, teraz, gdy rozumiem, co naprawdę robię. ^ _ ^

Właściwie odpowiadam na zdarzenie IN_CREATE w katalogu, w którym plik się znajduje. Tak więc faktycznie rejestruję plik w odpowiedzi na utworzenie pliku, niekoniecznie zdarzenie IN_MODIFY, które może nadejść później.

Zamierzam zmienić swój kod, aby po otrzymaniu zdarzenia IN_CREATE subskrybować IN_MODIFY na samym pliku i nie będę próbował czytać pliku, dopóki nie otrzymam zdarzenia IN_MODIFY. Zdaję sobie sprawę, że jest tam małe okno, w którym mogę pominąć zapis do pliku, ale jest to dopuszczalne w mojej aplikacji, ponieważ w najgorszym przypadku plik zostanie zamknięty po maksymalnej liczbie sekund.


Możesz użyć potoku zamiast pliku. Zobacz man mknod
Daniel Kullmann

Musimy użyć zwykłego pliku, aby między dwoma procesami był bufor wielu terabajtów. Również w celu zachowania danych w buforze podczas ponownego uruchamiania.
Todd Freed

Odpowiedzi:


5

Z tego, co widzę w źródle jądra , inotify uruchamia się dopiero po zakończeniu zapisu (tzn. Twoje przypuszczenia są błędne). Po wyzwoleniu powiadomienia zdarzają się tylko dwie kolejne rzeczy sys_write, funkcja implementująca writesyscall: ustawienie niektórych parametrów harmonogramu i aktualizacja pozycji w deskryptorze pliku. Kod ten był podobny już w wersji 2.6.14 . Do czasu uruchomienia powiadomienia plik ma już nowy rozmiar.

Sprawdź, co może pójść nie tak:

  • Może czytelnik otrzymuje stare powiadomienia z poprzedniego zapisu.
  • Jeśli czytelnik zadzwoni, stata następnie zadzwoni readlub na odwrót, coś może się zdarzyć pomiędzy. Jeśli nadal dołączasz się do pliku, wywoływanie w statpierwszej kolejności gwarantuje, że będziesz w stanie przeczytać tak daleko, ale możliwe jest, że do czasu, gdy czytnik zadzwoni read, zostanie zapisanych więcej danych , nawet jeśli nie otrzymało jeszcze powiadomienia powiadamiającego.
  • Tylko dlatego, że wywołania programu piszącego writenie oznaczają, że jądro zapisze żądaną liczbę znaków. Istnieje bardzo niewiele okoliczności, w których zapisy atomowe są gwarantowane do dowolnego rozmiaru. Każde writepołączenie ma jednak atomowy charakter: w pewnym momencie dane nie są jeszcze zapisywane, a następnie nagle zapisano n bajtów, gdzie n jest wartością zwracaną writewywołania. Jeśli zauważysz częściowo zapisany plik, oznacza to, że writezwrócił argument mniejszy niż jego rozmiar.

Przydatne narzędzia do badania tego, co się dzieje, to:

  • strace -tt
  • kontrolowany podsystem

Dziękuję za pomysły. Właśnie przejrzałem kod i faktycznie sprawdzam tylko -1 jako wartość zwracaną z zapisu dla przypadku błędu. Być może więc nie otrzymuję zwracanej wartości z zapisu, która wskazuje, że wszystkie dane zostały zapisane. Niemniej jednak, kiedy patrzę na plik po fakcie, wiem, że wszystkie „1000” bajtów zostały zapisane, ponieważ plik jest w dobrej formie, tzn. Składa się z całych, spójnych zapisów. Więc pierwszy zapis nie jest częściowo zapisany.
Todd Freed
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.