przepisz istniejący plik, aby został zastąpiony nową wersją atomowo, tylko raz w pełni zapisany

18

Niejasno pamiętam gdzieś, gdzie kiedyś był, w niektórych Uniksach sposób otwierania istniejącego pliku do pisania, z flagą, która prosiła jądro o użycie starej wersji (dla innych procesów uzyskujących dostęp do niego do odczytu), aż do „nowego „wersja została w pełni zapisana (fd zamknięta), od tego momentu plik pojawił się jako nowa wersja.

Innymi słowy, inne procesy albo widziały starą wersję, albo nową, nigdy nie w pełni napisaną.

Czy ktoś kompetentny może wskazać mi odniesienie?

eudoksos
źródło
Brzmi jak to, co może zrobić Plan 9 , ale nie.
Gilles 'SO - przestań być zły'
2
Brzmi jak Files-11 w OpenVMS: „Za każdym razem, gdy plik jest zapisywany, zamiast zastępować istniejącą wersję, tworzony jest nowy plik o tej samej nazwie, ale z przyrostowym numerem wersji”.
Mat.
Dlaczego pytasz? Potrzebujesz tej funkcjonalności, czy może była to tylko ciekawość?
Nils
1
Z przyjemnością skorzystam z tej funkcjonalności i przypomniałem sobie, że gdzieś tam istniałem. Więc mieszanka zarówno potrzeby, jak i ciekawości.
eudoxos
Wszystkie systemy uniksowe pozwalają na to w inny sposób - utwórz nowy plik w tym samym katalogu, wypełnij zmienioną zawartość i dokonaj atomowej zmiany nazwy. Jest to znacznie droższe w przypadku drobnych zmian, ale działa.
Netch

Odpowiedzi:

14

To, co opisujesz, brzmi dokładnie jak podstawowa zmiana nazwy w celu zastąpienia pliku.

Po zmianie nazwy / przeniesieniu jednego pliku na inny stary plik jest rozłączany. Oznacza to, że plik nadal istnieje, ale nie ma go już w drzewie systemu plików. W ten sposób stare aplikacje będą mogły uzyskiwać dostęp do pliku, dopóki będą otwarte. Gdy wszystkie aplikacje zamkną stary plik, wówczas jest on faktycznie nieprzydzielony na dysku.

renameWywołanie systemowe jest operacją atomową. Aby to zrobić, należy utworzyć nowy plik pod inną nazwą, a następnie wywołać, renameaby zmienić nazwę pliku tymczasowego na ten, który chcesz zastąpić. Ponieważ operacja jest atomowa, absolutnie nie ma okresu, w którym brakuje pliku. Natychmiast przechodzi ze starego pliku do nowego pliku.
Należy jednak pamiętać, że plik tymczasowy i zastępowany plik muszą znajdować się w tym samym punkcie podłączenia.

Patrick
źródło
Możesz go użyć tylko wtedy, gdy Twój program jest napisany z myślą o funkcjonalności. W tym przypadku była to jednak funkcja systemu operacyjnego, dzięki której nawet zwykłe programy otrzymywały tę atomową semantykę automatycznie.
eudoxos
1
@eudoxos twój komentarz nie ma sensu. Mówisz, że programy muszą być napisane specjalnie, aby zrobić renamezamianę. Nawet jeśli istniała taka „funkcja systemu operacyjnego”, o której mówisz, program nadal musiałby zostać napisany, aby z niej skorzystać. Co za różnica?
Patrick,
Jest różnica, jeśli przekażesz (prawdopodobnie nieobsługiwaną) flagę do opensyscall lub jeśli musisz zrobić to, co opisujesz ręcznie.
eudoxos
Należy pamiętać, że aby zachować starą lub w pełni zapisaną nową wersję na wypadek awarii, należy dodatkowo zsynchronizować nowy plik z dyskiem za pomocą programu fsync lub podobnego
tekst
@tekstshell bez synchronizacji nadal dostajesz atomowość ... po prostu nie wytrzymałość ... prawda? W tym przypadku nie rozumiem argumentu z goo.gl/qfQQfy . W moim przypadku mam system pod ekstremalnym obciążeniem i chcę uniknąć opróżnienia systemu plików i nie obchodzi mnie, czy plik przetrwa awarię.
wcochran
6

Jak pisze Patrick , zwykłym sposobem na to jest zapisanie nowej wersji do osobnego pliku, a po zakończeniu zmień nazwę nowej wersji na starą nazwę pliku, zastępując ją atomowo. Ta druga operacja nosi nazwę nadpisywania według zmiany nazwy .

Teraz niektóre referencje:

Ślimak mechaniczny
źródło
man 3p renamemówi mi, że renameto rzeczywiście jest atomowe i myślę, że to jest przeznaczone dla wszystkich systemów plików Linux. A kiedy czytam pierwszy artykuł, który podłączyłeś, nadal myślę, że operacje zmiany nazwy Btrfs są atomowe.
hagello
1

To przypomina mi Allocate On Flush . Gdy system plików korzysta z tej funkcji, zamiast zapisywać dane bezpośrednio na dysku, odejmuje rozmiar danych do zapisania od licznika wolnego miejsca na dysku i przechowuje dane w pamięci, dopóki nie zostanie wykonane wywołanie systemowe synchronizacji lub jądro nie zdecyduje opróżnić zabrudzone bufory.

W takim przypadku, jeśli plik jest modyfikowany przez jeden proces i otwierany przez inny proces, ten drugi proces „zobaczy” niezmodyfikowaną ( lub „starą”, jeśli wolisz ) wersję pliku.

Oczywiście powyższe są teoretyczne i zależą od różnych czynników, i powiedziałbym trochę nieprzewidywalne - ponieważ nie wiesz dokładnie, kiedy jądro będzie spłukiwać brudne strony. Na przykład w Linuksie ( jak można również przeczytać w sekcji 15.3 Zrozumienia jądra Linuksa ), brudne strony są zapisywane na dysk pod następującymi warunkami:

  • Pamięć podręczna stron zapełnia się i potrzeba więcej stron lub liczba brudnych stron staje się zbyt duża.

  • Upłynęło zbyt wiele czasu, ponieważ strona pozostała brudna.

  • Proces żąda, aby wszystkie oczekujące zmiany urządzenia blokowego lub określonego pliku zostały usunięte; robi to przez wywołanie wywołania systemowego sync (), fsync () lub fdatasync ().

Ta funkcja jest znana z implementacji w systemach plików HFS +, XFS, Reiser4, ZFS, Btrfs i ext4.

dkaragasidis
źródło
2
To, co opisujesz, to technika systemu plików, która powinna być niewidoczna z przestrzeni użytkownika (a zatem nie robi tego, co wskazujesz) w systemach POSIX (plikowych) (patrz zapis : „Jeśli odczyt () danych pliku można udowodnić (w dowolny sposób) do wystąpienia po write () danych, musi odzwierciedlać to write (), nawet jeśli wywołania są wykonywane przez różne procesy . ”). Inne procesy nie zobaczą starych danych (w POSIX).
Mat.
Dziękuję za poprawienie mnie. Wydaje mi się, że moje rozumienie tej techniki systemu plików było błędne.
dkaragasidis
Racja, wygląda to na coś innego. Teraz niejasno przypominam sobie, że wspomniał o tej funkcji w wywiadzie dla RMS, być może był to jakiś stary tajemny system, który nigdy nie żył poza środowiskiem akademickim ... W każdym razie dzięki.
eudoxos