Eine sichere, atomare Dateikopieroperation

8

Ich muss eine Datei von einem Ort zum anderen kopieren, und ich muss eine Ausnahme auslösen (oder zumindest irgendwie erkennen), wenn die Datei bereits am Ziel existiert (kein Überschreiben).

Ich kann zuerst mit os.path.exists () überprüfen, aber es ist extrem wichtig, dass die Datei nicht in der kurzen Zeit zwischen dem Überprüfen und dem Kopieren erstellt werden kann.

Gibt es einen eingebauten Weg, oder gibt es eine Möglichkeit, eine Aktion als atomar zu definieren?

    
Rory 23.07.2012, 14:43
quelle

2 Antworten

7

There ist in der Tat eine Möglichkeit, dies atomar und sicher zu tun, vorausgesetzt, dass alle Akteure es auf die gleiche Weise tun . Es ist eine Adaption des Lock-free-Whack-a-Mole-Algorithmus , und nicht ganz trivial, also fühlen Sie sich frei, mit "nein" als allgemeine Antwort zu gehen;)

Was tun?

  1. Überprüfen Sie, ob die Datei bereits existiert. Stoppen Sie, falls dies der Fall ist.
  2. Generieren Sie eine eindeutige ID
  3. Kopieren Sie die Quelldatei in den Zielordner mit einem temporären Namen, zB <target>.<UUID>.tmp .
  4. Benennen Sie die Kopie <target>-<UUID>.mole.tmp .
  5. um
  6. Suchen Sie nach anderen Dateien, die dem Muster entsprechen <target>-*.mole.tmp .
    • Wenn ihre UUID größer als Ihre ist, versuchen Sie, sie zu löschen . (Mach dir keine Sorgen, wenn es weg ist.)
    • Wenn ihre UUID weniger als Ihre vergleicht, versuchen Sie, Ihre eigenen zu löschen. (Wiederum, mach dir keine Sorgen, wenn es weg ist.) Behandle von nun an ihre UUID so, als wäre sie deine eigene.
  7. Überprüfen Sie erneut, ob die Zieldatei bereits existiert. Versuchen Sie in diesem Fall, Ihre temporäre Datei zu löschen. (Machen Sie sich keine Sorgen, wenn es weg ist. Denken Sie daran, dass sich Ihre UUID in Schritt 5 geändert haben könnte.)
  8. Falls Sie nicht bereits versucht haben, es in Schritt 6 zu löschen, versuchen Sie, Ihre temporäre Datei in den endgültigen Namen <target> umzubenennen. (Mach dir keine Sorgen, wenn es weg ist, springe einfach zurück zu Schritt 5.)

Du bist fertig!

Wie es funktioniert

Stellen Sie sich vor, dass jede mögliche Quelldatei ein Maulwurf ist, der aus seinem Loch kommt. Auf halbem Weg hält er inne und schlägt alle konkurrierenden Maulwürfe zurück in den Boden, bevor er feststellt, dass kein anderer Maulwurf vollständig aufgetaucht ist. Wenn du das in deinem Kopf durchläufst, solltest du sehen, dass nur ein Maulwurf es jemals ganz raus schaffen wird. Um zu verhindern, dass dieses System von Livelocking wird, fügen wir eine Gesamtbestellung hinzu, auf der Mole was whackern kann. Bam! Eine Doktorarbeit Lock-free-Algorithmus .

Schritt 4 sieht vielleicht unnötig aus - warum nicht einfach diesen Namen überhaupt verwenden? Ein anderer Prozess kann jedoch Ihre Maulwurf -Datei in Schritt 5 übernehmen und zum Gewinner in Schritt 7 machen. Daher ist es sehr wichtig, dass Sie den Inhalt nicht noch schreiben! Umbenennen auf demselben Dateisystem sind atomar, also Schritt 4 ist sicher.

    
Alice Purcell 22.01.2015, 14:13
quelle
11

Es gibt keine Möglichkeit, dies zu tun; Dateikopiervorgänge sind niemals atomar und es gibt keine Möglichkeit, sie zu erstellen.

Aber Sie können die Datei unter einem zufälligen, temporären Namen schreiben und umbenennen . Umbenennungsoperationen müssen atomar sein. Wenn die Datei bereits existiert, schlägt die Umbenennung fehl und Sie erhalten einen Fehler.

[EDIT2] rename() ist nur atomar, wenn Sie es im selben Dateisystem tun. Der sichere Weg besteht darin, die neue Datei im selben Ordner wie das Ziel zu erstellen.

[EDIT] Es gibt viele Diskussionen darüber, ob Umbenennen immer atomar ist oder nicht und über das Überschreibverhalten. Also habe ich einige Ressourcen ausgegraben.

Wenn unter Linux das Ziel existiert und Quell- und Zieldateien Dateien sind, wird das Ziel automatisch überschrieben ( man page <) / a>). Da habe ich mich geirrt.

Aber rename(2) garantiert immer noch, dass entweder die Originaldatei oder die neue Datei gültig bleibt, wenn etwas schief geht, also ist die Operation in dem Sinne atomar, dass Daten nicht korrumpiert werden können. Es ist nicht atomar in dem Sinne, dass es verhindert, dass zwei Prozesse die gleiche Umbenennung zur gleichen Zeit ausführen, und Sie können das Ergebnis vorhersagen. Man wird gewinnen, aber man kann nicht sagen, welches.

Wenn unter Windows ein anderer Prozess gerade die Datei schreibt, erhalten Sie eine Fehlermeldung, wenn Sie versuchen, sie zum Schreiben zu öffnen, also einen Vorteil für Windows, hier.

Wenn Ihr Computer abstürzt, während der Vorgang auf die Festplatte geschrieben wird, entscheidet die Implementierung des Dateisystems, wie viele Daten beschädigt werden. Es gibt nichts , was eine Anwendung dazu tun könnte. Also hör auf zu jammern: -)

Es gibt auch keinen anderen Ansatz, der besser oder sogar genauso gut funktioniert.

Sie können stattdessen die Datei sperren. Das würde aber alles komplizierter machen und keine zusätzlichen Vorteile bringen (abgesehen davon, dass es komplizierter ist, was einige Leute aus irgendeinem Grund als einen großen Vorteil betrachten). Und wenn Sie Ihre Datei auf einem Netzlaufwerk haben, fügen Sie viele schöne Ecken hinzu.

Sie könnten open(2) mit dem Modus O_CREAT verwenden, wodurch die Funktion fehlschlägt, wenn die Datei bereits existiert. Aber das würde einen zweiten Prozess nicht daran hindern, die Datei zu löschen und ihre eigene Kopie zu schreiben.

Oder Sie könnten ein Sperrverzeichnis erstellen, da das Erstellen von Verzeichnissen ebenfalls atomar sein muss. Aber das würde dich auch nicht viel kaufen. Sie müssten den Sperrcode selbst schreiben und absolut, 100% sicher sein, dass Sie das Sperrverzeichnis im Falle eines Desasters wirklich wirklich löschen - was nicht möglich ist.

    
Aaron Digulla 23.07.2012 14:46
quelle

Tags und Links