Schreiben Sie die vorhandene Datei neu, sodass sie atomar durch eine neue Version ersetzt wird, und zwar nur einmal, wenn sie vollständig geschrieben wurde

18

Ich erinnere mich vage daran, irgendwo gelesen zu haben, dass es in einigen Unices eine Möglichkeit gab, eine vorhandene Datei zum Schreiben zu öffnen, mit einem Flag, das den Kernel aufforderte, die alte Version zu verwenden (für andere Prozesse, die zum Lesen darauf zugreifen), bis die "neue" msgstr "" "Version wurde vollständig geschrieben (fd geschlossen), ab diesem Zeitpunkt erschien die Datei als neue Version.

Mit anderen Worten, andere Prozesse sahen entweder die alte Version oder die neue, niemals eine unvollständig geschriebene.

Kann mich jemand mit Kenntnissen auf eine Referenz verweisen?

Eudoxos
quelle
Klingt nach Plan 9 , aber nein.
Gilles 'SO - hör auf böse zu sein'
2
Klingt wie Files-11 unter OpenVMS: "Jedes Mal, wenn eine Datei gespeichert wird, anstatt die vorhandene Version zu überschreiben, wird eine neue Datei mit demselben Namen, aber einer erhöhten Versionsnummer erstellt."
Mat
Warum hast du gefragt? Benötigen Sie diese Funktionalität oder war es nur Neugier?
Nils
1
Ich würde mich freuen, diese Funktionalität zu haben, und ich erinnerte mich, irgendwo gelesen zu haben, dass es sie gab. Eine Mischung aus Bedürfnis und Neugier.
Eudoxos
Alle Unix-Systeme erlauben dies auf andere Weise - erstelle eine neue Datei im selben Verzeichnis, fülle sie mit geänderten Inhalten und benenne sie atomar um. Dies ist viel teurer für kleine Änderungen, funktioniert aber.
Netch

Antworten:

14

Was Sie beschreiben, klingt genau wie eine grundlegende Umbenennung, um eine Datei zu überschreiben.

Wenn Sie eine Datei umbenennen / über eine andere verschieben, wird die Verknüpfung der alten Datei aufgehoben. Das heißt, die Datei ist noch vorhanden, befindet sich jedoch nicht mehr im Dateisystembaum. Daher können alte Anwendungen weiterhin auf die Datei zugreifen, solange sie geöffnet bleiben. Sobald alle Anwendungen die alte Datei geschlossen haben, ist sie tatsächlich nicht auf der Festplatte zugeordnet.

Der renameSystemaufruf ist eine atomare Operation. Dazu erstellen Sie eine neue Datei unter einem anderen Namen und rufen dann renameauf, um die temporäre Datei in die zu ersetzende Datei umzubenennen. Da die Operation atomar ist, gibt es absolut keinen Zeitraum, in dem die Datei fehlt. Es geht sofort von der alten zur neuen Datei über.
Beachten Sie jedoch, dass sich die temporäre Datei und die zu ersetzende Datei auf demselben Einhängepunkt befinden müssen.

Patrick
quelle
Sie können dies nur verwenden, wenn Ihr Programm speziell für die Funktionalität geschrieben wurde. In diesem Fall handelte es sich jedoch um eine OS-Funktion, bei der auch reguläre Programme diese atomare Semantik automatisch erhielten.
Eudoxos
1
@eudoxos dein Kommentar macht keinen Sinn. Sie sagen, Programme müssten speziell geschrieben werden, um die renameSwap-Sache zu tun . Selbst wenn es eine solche 'OS-Funktion' gäbe, von der Sie sprechen, müsste das Programm noch geschrieben werden, um auch davon zu profitieren. Was ist der Unterschied?
Patrick
Es ist ein Unterschied, ob Sie dem openSyscall ein (möglicherweise nicht unterstütztes) Flag übergeben oder das, was Sie beschreiben, von Hand ausführen müssen.
Eudoxos
Denken Sie daran, dass Sie im Falle eines Absturzes die neue Datei zusätzlich mit fsync oder ähnlichem synchronisieren müssen, um entweder die alte oder die vollständig geschriebene neue Version beizubehalten
textshell
@textshell ohne die Synchronisation bekommst du trotzdem Atomizität .... nur nicht Haltbarkeit ... richtig? Ich verstehe das Argument bei goo.gl/qfQQfy in diesem Fall nicht. In meinem Fall ist mein System extrem ausgelastet und ich möchte Dateisystem-Flushs vermeiden. Es ist mir egal, ob die Datei einen Absturz übersteht.
wcochran
6

Wie Patrick schreibt , besteht die übliche Methode darin, die neue Version in eine separate Datei zu schreiben und die neue Version nach Beendigung in den alten Dateinamen umzubenennen und diese atomar zu überschreiben. Diese zweite Operation wird als Überschreiben durch Umbenennen bezeichnet .

Nun einige Referenzen:

Mechanische Schnecke
quelle
man 3p renamesagt mir, das renameist in der Tat atomar, und ich denke, das ist für alle Linux-Dateisysteme gedacht. Und wenn ich den ersten Artikel lese, den Sie verlinkt haben, denke ich immer noch, dass Btrfs-Umbenennungsoperationen atomar sind.
Hagello
1

Das erinnert mich an Allocate On Flush . Wenn ein Dateisystem diese Funktion verwendet, subtrahiert es, anstatt Daten direkt auf die Festplatte zu schreiben, die Größe der zu schreibenden Daten vom Zähler für den freien Speicherplatz der Festplatte und speichert die Daten im Speicher, bis ein Synchronisationssystemaufruf ausgeführt wird oder der Kernel entscheidet die schmutzigen Puffer zu spülen.

Wenn in diesem Fall die Datei von einem Prozess geändert und von einem anderen Prozess geöffnet wird, wird für den letzteren Prozess die nicht geänderte ( oder "alte" ) Version der Datei "angezeigt " .

Die obigen Angaben sind natürlich theoretisch und hängen von verschiedenen Faktoren ab, und ich würde sagen, dass sie etwas unvorhersehbar sind, da Sie nicht genau wissen, wann der Kernel die schmutzigen Seiten leeren wird. Unter Linux ( wie Sie auch in Abschnitt 15.3 unter Grundlegendes zum Linux-Kernel nachlesen können ) werden die fehlerhaften Seiten unter den folgenden Bedingungen auf die Festplatte geschrieben:

  • Der Seiten-Cache wird zu voll und es werden mehr Seiten benötigt oder die Anzahl der verschmutzten Seiten wird zu groß.

  • Es ist zu viel Zeit vergangen, seit eine Seite schmutzig geblieben ist.

  • Ein Prozess fordert an, dass alle ausstehenden Änderungen eines Blockgeräts oder einer bestimmten Datei gelöscht werden. Dazu wird ein Systemaufruf sync (), fsync () oder fdatasync () aufgerufen.

Es ist bekannt, dass diese Funktion in den Dateisystemen HFS +, XFS, Reiser4, ZFS, Btrfs und ext4 implementiert ist.

dkaragasidis
quelle
2
Was Sie beschreiben, ist eine Dateisystemtechnik, die für den Benutzerbereich unsichtbar sein sollte (und daher nicht das tut, was Sie angeben), auf POSIX- (Datei-) Systemen (siehe " Schreiben "). Um nach einem write () der Daten aufzutreten, muss write () angegeben werden, auch wenn die Aufrufe von unterschiedlichen Prozessen stammen . "). Andere Prozesse werden nicht die alten Daten sehen (auf POSIX).
Mat
Danke für die Korrektur. Ich denke, mein Verständnis dieser Dateisystemtechnik war falsch.
dkaragasidis
Richtig, das sieht nach etwas anderem aus. Ich erinnere mich jetzt vage, dass er diese Funktion in einem Interview mit RMS erwähnte, vielleicht war es ein altes arkanes System, das nie außerhalb der akademischen Welt gelebt hat ... Trotzdem vielen Dank.
Eudoxos