GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie kopiere ich eine Datei transaktional?

rsync macht diese Arbeit. Eine temporäre Datei ist O_EXCL standardmäßig erstellt (nur deaktiviert, wenn Sie --inplace verwenden ) und dann renamed über die Zieldatei. Verwenden Sie --ignore-existing um B nicht zu überschreiben, falls es existiert.

In der Praxis hatte ich nie Probleme damit auf ext4-, zfs- oder sogar NFS-Mounts.


Keine Sorge, noclobber ist eine Standardfunktion.


Du hast nach NFS gefragt. Diese Art von Code bricht wahrscheinlich unter NFS, da die Prüfung auf noclobber beinhaltet zwei separate NFS-Operationen (überprüfen Sie, ob eine Datei existiert, erstellen Sie eine neue Datei) und zwei Prozesse von zwei separaten NFS-Clients können in eine Race-Bedingung geraten, bei der beide erfolgreich sind (beide überprüfen, ob B.part noch nicht existiert, dann fahren beide fort, sie erfolgreich zu erstellen, wodurch sie sich gegenseitig überschreiben.)

Es ist nicht wirklich notwendig, allgemein zu prüfen, ob das Dateisystem, in das Sie schreiben, so etwas wie noclobber unterstützt atomar oder nicht. Sie könnten den Dateisystemtyp überprüfen, ob es NFS ist, aber das wäre eine Heuristik und nicht unbedingt eine Garantie. Dateisysteme wie SMB/CIFS (Samba) leiden wahrscheinlich unter den gleichen Problemen. Dateisysteme, die durch FUSE verfügbar gemacht werden, können sich korrekt verhalten oder auch nicht, aber das hängt hauptsächlich von der Implementierung ab.

Ein möglicherweise besserer Ansatz besteht darin, die Kollision in B.part zu vermeiden Schritt, indem Sie (durch Zusammenarbeit mit anderen Agenten) einen eindeutigen Dateinamen verwenden, sodass Sie sich nicht auf noclobber verlassen müssen . Beispielsweise könnten Sie als Teil des Dateinamens Ihren Hostnamen, Ihre PID und einen Zeitstempel (+ möglicherweise eine Zufallszahl) angeben. Da auf einem Host zu jedem Zeitpunkt ein einzelner Prozess unter einer bestimmten PID ausgeführt werden sollte, sollte dies der Fall sein Eindeutigkeit garantieren.

Also entweder:

test -f B && continue  # skip already existing
unique=$(hostname).$$.$(date +%s).$RANDOM
cp A B.part."$unique"
# Maybe check for existance of B again, remove
# the temporary file and bail out in that case.
mv B.part."$unique" B
# mv (rename) should always succeed, overwrite a
# previously copied B if one exists.

Oder:

test -f B && continue  # skip already existing
unique=$(hostname).$$.$(date +%s).$RANDOM
cp A B.part."$unique"
if ln B.part."$unique" B ; then
    echo "Success creating B"
else
    echo "Failed creating B, already existed"
fi
# Both cases require cleanup.
rm B.part."$unique"

Wenn also zwischen zwei Agenten eine Wettlaufbedingung besteht, fahren beide mit der Operation fort, aber die letzte Operation ist atomar, sodass entweder B mit einer vollständigen Kopie von A existiert oder B nicht existiert.

Sie können die Größe des Rennens verringern, indem Sie nach dem Kopieren und vor dem mv erneut prüfen oder ln Betrieb, aber es gibt immer noch eine kleine Rennbedingung. Aber unabhängig von der Racebedingung sollte der Inhalt von B konsistent sein, vorausgesetzt, beide Prozesse versuchen, ihn aus A (oder einer Kopie einer gültigen Datei als Ursprung) zu erstellen.

Beachten Sie das in der ersten Situation mit mv , wenn ein Rennen existiert, ist der letzte Prozess derjenige, der gewinnt, da rename(2) eine vorhandene Datei atomar ersetzen wird:

Wenn neuerPfad bereits existiert, wird es atomar ersetzt, sodass es keinen Punkt gibt, an dem ein anderer Prozess versucht, auf newpath zuzugreifen wird feststellen, dass es fehlt. [...]

Wenn neuerPfad existiert, aber der Vorgang schlägt aus irgendeinem Grund fehl, rename() garantiert, eine Instanz von newpath zu hinterlassen vorhanden.

Es ist also durchaus möglich, dass Prozesse, die B zu diesem Zeitpunkt verbrauchen, während dieses Prozesses unterschiedliche Versionen davon (unterschiedliche Inodes) sehen. Wenn die Autoren nur alle versuchen, denselben Inhalt zu kopieren, und die Leser einfach den Inhalt der Datei konsumieren, ist das möglicherweise in Ordnung, wenn sie unterschiedliche Inodes für Dateien mit demselben Inhalt erhalten, werden sie genauso glücklich sein.

Der zweite Ansatz mit einem harten Link sieht aus besser, aber ich erinnere mich, dass ich Experimente mit Hardlinks in einer engen Schleife auf NFS von vielen gleichzeitigen Clients gemacht und Erfolge gezählt habe, und es schien immer noch einige Race Conditions zu geben, bei denen es so aussah, als ob zwei Clients gleichzeitig eine Hardlink-Operation ausgaben gleiches Ziel, beide schienen erfolgreich zu sein. (Es ist möglich, dass dieses Verhalten mit der speziellen NFS-Serverimplementierung YMMV zusammenhängt.) In jedem Fall handelt es sich wahrscheinlich um die gleiche Art von Race-Condition, bei der Sie möglicherweise zwei separate Inodes für dieselbe Datei erhalten, wenn es zu viele gibt Gleichzeitigkeit zwischen Autoren, um diese Race-Bedingungen auszulösen. Wenn Ihre Autoren konsistent sind (beide kopieren A nach B) und Ihre Leser nur den Inhalt konsumieren, könnte das ausreichen.

Schließlich haben Sie das Sperren erwähnt. Leider fehlt es zumindest in NFSv3 stark an Locking (bei NFSv4 bin ich mir nicht sicher, aber ich wette, es ist auch nicht gut). tatsächliche Dateikopien, aber das ist störend, komplex und anfällig für Probleme wie Deadlocks, also würde ich sagen, dass es besser ist, es zu vermeiden.

Für weitere Hintergrundinformationen zum Thema Atomarität bei NFS lesen Sie vielleicht das Maildir-Postfachformat, das erstellt wurde, um Sperren zu vermeiden und sogar auf NFS zuverlässig zu funktionieren. Dies geschieht, indem überall eindeutige Dateinamen beibehalten werden (so dass Sie nicht einmal ein abschließendes B am Ende erhalten.)

Vielleicht etwas interessanter für Ihren speziellen Fall, das Maildir++-Format erweitert Maildir, um Unterstützung für Postfachkontingente hinzuzufügen, und tut dies, indem es eine Datei mit einem festen Namen innerhalb des Postfachs atomar aktualisiert (damit es Ihrem B näher kommen könnte). Ich denke, Maildir++ versucht es anhängen, was auf NFS nicht wirklich sicher ist, aber es gibt einen Neuberechnungsansatz, der ein ähnliches Verfahren wie dieses verwendet und als atomares Ersetzen gültig ist.

Hoffentlich sind all diese Hinweise nützlich!


Linux
  1. Wie kopiert man rekursiv Dateien nach Dateierweiterung?

  2. Wie benenne ich eine Datei unter Linux um?

  3. Wie macht man eine Datei spärlich?

  4. So sortieren Sie eine Datei an Ort und Stelle

  5. Wie kopiere ich eine Datei, die mit einem Punkt beginnt?

So verknüpfen Sie eine Datei unter Linux per Symlink

So kopieren Sie Dateien mit einer bestimmten Dateierweiterung rekursiv

So kopieren Sie Dateien und Verzeichnisse im Linux-Terminal

So kopieren Sie das Verzeichnis unter Linux

Wie Echo in Datei

So kopieren Sie eine Datei im Dateimanager