Ist das Anhängen von Dateien unter UNIX atomar?

105

Was können wir im Allgemeinen als selbstverständlich betrachten, wenn wir aus mehreren Prozessen an eine Datei in UNIX anhängen? Ist es möglich, Daten zu verlieren (ein Prozess überschreibt die Änderungen des anderen)? Können Daten verstümmelt werden? (Beispielsweise hängt jeder Prozess eine Zeile pro Anhang an eine Protokolldatei an. Ist es möglich, dass zwei Zeilen beschädigt werden?) Wenn der Anhang nicht im obigen Sinne atomar ist, wie kann dann der gegenseitige Ausschluss am besten sichergestellt werden?

Lajos Nagy
quelle

Antworten:

64

Ein Schreibvorgang unter der Größe von 'PIPE_BUF' soll atomar sein. Das sollten mindestens 512 Bytes sein, obwohl es leicht größer sein könnte (Linux scheint es auf 4096 gesetzt zu haben).

Dies setzt voraus, dass Sie alle vollständig POSIX-kompatiblen Komponenten sprechen. Dies gilt beispielsweise nicht für NFS.

Angenommen, Sie schreiben in eine Protokolldatei, die Sie im Modus 'O_APPEND' geöffnet haben, und halten Ihre Zeilen (einschließlich Zeilenumbruch) unter 'PIPE_BUF'-Bytes lang, sollten Sie in der Lage sein, mehrere Schreiber in eine Protokolldatei ohne Beschädigungsprobleme zu haben. Alle Interrupts kommen vor oder nach dem Schreiben an, nicht in der Mitte. Wenn Sie möchten, dass die Dateiintegrität einen Neustart überlebt, müssen Sie auch fsync(2)nach jedem Schreibvorgang aufrufen , aber das ist für die Leistung schrecklich.

Klarstellung : Lesen Sie die Kommentare und die Antwort von Oz Solomon . Ich bin mir nicht sicher, ob das O_APPENDdiese PIPE_BUFGröße Atomizität haben soll. Es ist durchaus möglich, dass Linux genau so implementiert ist write(), oder es liegt an den Blockgrößen des zugrunde liegenden Dateisystems.

freiheit
quelle
11
Gibt bei vernünftigen Dateisystemen fsync(2)eine ebenso große Garantie wie dies der sync(2)Fall ist und hat weniger Auswirkungen auf die Leistung.
Ephemient
4
Bist du dir da sicher? Könnten Sie einen Link zu diesem Verhalten bereitstellen? Ich fand es bestätigt, wenn der Deskriptor eine Pipe ist, aber ich konnte keine Beweise dafür finden, dass es für jede Datei funktioniert . einschließlich normaler Nicht-NFS-Dateiobjekte.
Alan Franzoni
6
Wo genau in ... / write.html? Für O_APPEND sehe ich keine Erwähnung von PIPE_BUF und ich sehe das Versprechen, dass "keine zwischenzeitliche Änderung der Datei zwischen dem Ändern des Dateiversatzes und der Schreiboperation stattfinden soll" , aber ich bin mir nicht sicher, ob dies bedeutet, dass die Schreiboperation selbst ist ununterbrochen ...
akavel
6
Wie diese Antwort zeigt, gilt die Aussage PIPE_BUFauf dieser Seite nur für Pipes und FIFOs, nicht für reguläre Dateien.
Greg Inozemtsev
3
Wenn Signale eintreffen, kann dies noch schlimmer werden: bugzilla.kernel.org/show_bug.cgi?id=55651 . Warum ist dies überhaupt als Antwort markiert? PIPE_BUF hat nichts mit Dateien zu tun.
Dünn
35

Bearbeiten: Aktualisiert im August 2017 mit den neuesten Windows-Ergebnissen.

Ich werde Ihnen eine Antwort mit Links zu Testcode und Ergebnissen als Autor des Vorschlags geben Testcode Boost.AFIO geben, das ein asynchrones Dateisystem und eine Datei-I / O-C ++ - Bibliothek implementiert.

Erstens bedeutet O_APPEND oder das entsprechende FILE_APPEND_DATA unter Windows, dass Inkremente des maximalen Dateibereichs (Dateilänge) bei gleichzeitigen Writern atomar sind . Dies wird von POSIX garantiert und von Linux, FreeBSD, OS X und Windows korrekt implementiert. Samba implementiert es auch korrekt, NFS vor v5 nicht, da es nicht in der Lage ist, das Drahtformat atomar anzuhängen. Wenn Sie Ihre Datei also nur mit Anhängen öffnen, werden gleichzeitige Schreibvorgänge auf keinem größeren Betriebssystem in Bezug aufeinander gerissen, es sei denn, NFS ist beteiligt.

Gleichzeitige Lesevorgänge an atomaren Anhängen können jedoch möglich sein je nach Betriebssystem, Dateisystem und den Flags, mit denen Sie die Datei geöffnet haben, zerrissene Schreibvorgänge auftreten. Das Inkrement des maximalen Dateibereichs ist atomar, aber die Sichtbarkeit der Schreibvorgänge in Bezug auf Lesevorgänge kann oder kann nicht atomar sein. Hier ist eine kurze Zusammenfassung nach Flags, Betriebssystem und Dateisystem:


Nein O_DIRECT / FILE_FLAG_NO_BUFFERING:

Microsoft Windows 10 mit NTFS: Update Atomicity = 1 Byte bis einschließlich 10.0.10240, von 10.0.14393 mindestens 1 MB, wahrscheinlich unendlich (*).

Linux 4.2.6 mit ext4: Atomizität aktualisieren = 1 Byte

FreeBSD 10.2 mit ZFS: Atomizität aktualisieren = mindestens 1 MB, wahrscheinlich unendlich (*)

O_DIRECT / FILE_FLAG_NO_BUFFERING:

Microsoft Windows 10 mit NTFS: Aktualisieren Sie Atomicity = bis einschließlich 10.0.10240 bis zu 4096 Byte nur, wenn die Seite ausgerichtet ist, andernfalls 512 Byte, wenn FILE_FLAG_WRITE_THROUGH deaktiviert ist, andernfalls 64 Byte. Beachten Sie, dass diese Atomizität wahrscheinlich eher ein Merkmal von PCIe DMA ist als in. Seit 10.0.14393, mindestens 1 MB, wahrscheinlich unendlich (*).

Linux 4.2.6 mit ext4: Atomizität aktualisieren = mindestens 1 MB, wahrscheinlich unendlich (*). Beachten Sie, dass frühere Linuxes mit ext4 definitiv 4096 Bytes nicht überschritten haben. XFS hatte sicherlich benutzerdefinierte Sperren, aber es sieht so aus, als ob das aktuelle Linux dies endlich behoben hat.

FreeBSD 10.2 mit ZFS: Atomizität aktualisieren = mindestens 1 MB, wahrscheinlich unendlich (*)


Die rohen empirischen Testergebnisse finden Sie unter https://github.com/ned14/afio/tree/master/programs/fs-probe . Beachten Sie, dass wir nur bei 512-Byte-Vielfachen auf zerrissene Offsets testen. Daher kann ich nicht sagen, ob eine teilweise Aktualisierung eines 512-Byte-Sektors während des Lese-, Änderungs- und Schreibzyklus reißen würde.

Um die Frage des OP zu beantworten, stören sich O_APPEND-Schreibvorgänge nicht gegenseitig. Bei Lesevorgängen, die gleichzeitig mit O_APPEND-Schreibvorgängen ausgeführt werden, werden unter Linux mit ext4 wahrscheinlich zerrissene Schreibvorgänge angezeigt, es sei denn, O_DIRECT ist aktiviert, woraufhin Ihre O_APPEND-Schreibvorgänge ein Sektorgrößenmultiplikator sein müssten.


(*) "Wahrscheinlich unendlich" ergibt sich aus diesen Klauseln in der POSIX-Spezifikation:

Alle folgenden Funktionen müssen in den in POSIX.1-2008 angegebenen Effekten zueinander atomar sein, wenn sie mit regulären Dateien oder symbolischen Links arbeiten ... [viele Funktionen] ... read () ... write ( ) ... Wenn zwei Threads jeweils eine dieser Funktionen aufrufen, werden bei jedem Aufruf entweder alle angegebenen Effekte des anderen Aufrufs oder keine davon angezeigt. [Quelle]

und

Schreibvorgänge können in Bezug auf andere Lese- und Schreibvorgänge serialisiert werden. Wenn nachgewiesen werden kann, dass ein Lesen () von Dateidaten (auf irgendeine Weise) nach einem Schreiben () der Daten erfolgt, muss es dieses Schreiben () widerspiegeln, selbst wenn die Aufrufe von verschiedenen Prozessen ausgeführt werden. [Quelle]

aber umgekehrt:

Dieses Volume von POSIX.1-2008 gibt nicht das Verhalten gleichzeitiger Schreibvorgänge in eine Datei aus mehreren Prozessen an. Anwendungen sollten eine Form der Parallelitätskontrolle verwenden. [Quelle]

Sie können mehr über die Bedeutung dieser in dieser Antwort lesen

Niall Douglas
quelle
29

Ich habe ein Skript geschrieben, um die maximale Größe der atomaren Anhänge empirisch zu testen. Das in bash geschriebene Skript erzeugt mehrere Arbeitsprozesse, die alle arbeiterspezifische Signaturen in dieselbe Datei schreiben. Anschließend wird die Datei gelesen und nach überlappenden oder beschädigten Signaturen gesucht. Sie können die Quelle für das Skript in diesem Blog-Beitrag sehen .

Die tatsächliche maximale Größe der atomaren Anhänge variiert nicht nur nach Betriebssystem, sondern auch nach Dateisystem.

Unter Linux + ext3 beträgt die Größe 4096 und unter Windows + NTFS 1024. Weitere Größen finden Sie in den Kommentaren unten.

Oz Solomon
quelle
Mit welchem ​​Dateisystem haben Sie unter Linux getestet? Ich frage mich, ob es vielleicht auf den Blockgrößen des Dateisystems basiert.
Freiheit
@freiheit Ich glaube zu der Zeit, als ich es auf ext3 getestet habe. Wenn Sie es auf einem anderen FS ausführen und ein anderes Ergebnis erhalten, schreiben Sie bitte einen Kommentar.
Oz Solomon
3
@OzSolomon, ich habe Ihr Skript unter Debian 7.8 verwendet und konnte nur atomare Schreibvorgänge bis einschließlich 1008 Byte (1024 - 16 Byte Overhead?) Auf meiner ext4-Partition und einem tmpfs-Mount abrufen. Alles darüber hinaus führte jedes Mal zu Korruption.
Eric Pruitt
6
Ihr Test scheint davon auszugehen, dass unabhängig von der Größe von zu echo $line >> $OUTPUT_FILEeinem einzigen Aufruf writevon führt $line.
Tomas
16

Der Standard sagt Folgendes: http://www.opengroup.org/onlinepubs/009695399/functions/pwrite.html .

Wenn das O_APPENDFlag der Dateistatusflags gesetzt ist, muss der Dateiversatz vor jedem Schreibvorgang auf das Ende der Datei gesetzt werden, und zwischen dem Ändern des Dateiversatzes und dem Schreibvorgang darf keine dazwischen liegende Dateiänderungsoperation auftreten.

Bastien Léonard
quelle
20
"zwischen" - aber was ist mit Interventionen während des Schreibens, die nach meinem Verständnis nach dem "zwischen" stattfinden? (Dh: <change_offset_action> ... "the_between_period" ... <write_action>) - soll ich verstehen, dass es dafür keine Garantien gibt?
akavel
@akavel stimmte zu; Es gibt keine Garantie dafür, dass das Schreiben selbst atomar ist. Aber ich bin verwirrt: Aufgrund der in Ihrem Angebot enthaltenen Garantie können wir den Schluss ziehen, dass eine Multithread-App, die dieselbe Datei anfügt, keine Teile verschiedener schriftlicher Aufzeichnungen vermischt. Aus Experimenten von OzSolomon geht jedoch hervor, dass auch diese Annahme verletzt wird. Warum?
Max
@Max sorry, ich fürchte , ich habe nicht Ihre Frage: Zum einen OzSolomon Experiment ist multi- Prozess , kein Mehrgewinde (single - Prozess) app; Zweitens verstehe ich nicht, wie Sie zu dem Schluss kommen, dass "eine Multithread-App [...] nicht gemischt wird" - genau das sehe ich nicht garantiert durch das Zitat von Bastien, wie ich in meinem Kommentar erwähne. Können Sie Ihre Frage klären?
akavel
2
Hmm, ich kann meine eigene Logik zum Zeitpunkt des Schreibens dieses Kommentars nicht rekonstruieren ... Ja, wenn Ihre Interpretation korrekt ist, können die verschiedenen Datensätze natürlich gemischt werden. Aber jetzt, wo ich Bastiens Zitat noch einmal lese, muss es bedeuten, dass niemand "während des Schreibens" unterbrechen kann - sonst wäre der gesamte Absatz im Standard nutzlos und würde buchstäblich überhaupt keine Garantie geben (nicht einmal, dass das Schreiben stattfinden wird am Ende, da sich jemand anderes möglicherweise versetzt bewegt, während der "Schreib" -Schritt ausgeführt wird.
Max