Wyobraź sobie dwa procesy, czytnik i pisarz, komunikujące się za pomocą zwykłego pliku na ext3 fs. Czytnik ma IN_MODIFY
zegarek inotify na pliku. Program Writer zapisuje do pliku 1000 bajtów w jednym write()
wywołaniu. Czytnik pobiera zdarzenie inotify i wywołuje fstat
plik. Co widzi Reader?
Czy istnieje jakakolwiek gwarancja, że program Reader odzyska co najmniej 1000
st_size
z pliku? Z moich eksperymentów wydaje się, że nie.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 sar
pokazuje czasy oczekiwania około 1 sekundy. W moim przypadku czytnik faktycznie czeka 10 sekund PO odebraniu zdarzenia inotify przed wywołaniem stat
i 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.
Odpowiedzi:
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ącawrite
syscall: 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:
stat
a następnie zadzwoniread
lub na odwrót, coś może się zdarzyć pomiędzy. Jeśli nadal dołączasz się do pliku, wywoływanie wstat
pierwszej kolejności gwarantuje, że będziesz w stanie przeczytać tak daleko, ale możliwe jest, że do czasu, gdy czytnik zadzwoniread
, zostanie zapisanych więcej danych , nawet jeśli nie otrzymało jeszcze powiadomienia powiadamiającego.write
nie 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żdewrite
połą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ąwrite
wywołania. Jeśli zauważysz częściowo zapisany plik, oznacza to, żewrite
zwrócił argument mniejszy niż jego rozmiar.Przydatne narzędzia do badania tego, co się dzieje, to:
strace -tt
źródło