Sie können den --link-dest=
verwenden Möglichkeit. Grundsätzlich würden Sie einen neuen Ordner erstellen, alle Dateien sind fest mit dem neuen verknüpft. Wenn alles fertig ist, können Sie einfach die Ordnernamen austauschen und den alten entfernen.
Es ist unmöglich, dies unter Linux zu 100 % atomar zu machen, da es dafür keine Kernel-/VFS-Unterstützung gibt. Das Austauschen der Namen ist jedoch tatsächlich nur 2 Systemaufrufe entfernt, sodass es weniger als 1 Sekunde dauern sollte, um es abzuschließen. Dies ist nur unter Darwin (MAC/OSX) mit dem Systemaufruf exchangedata auf HFS-Dateisystemen möglich.
Ich mache etwas Ähnliches mit rsync
Backups [auf Festplatte] und ich bin auf das gleiche Problem gestoßen, weil ein Daemon Dateien aktualisiert, während das Backup läuft.
Anders als viele Programme hat rsync viele verschiedene Fehlercodes [Siehe Manpage unten]. Interessant sind zwei:
23 -- teilweise Übertragung aufgrund eines Fehlers
24 -- teilweise Übertragung aufgrund verschwundener Quelldateien
Wenn rsync eine Übertragung durchführt und auf eine dieser Situationen stößt, stoppt es nicht einfach sofort. Es überspringt und fährt mit den Dateien fort, die es kann Transfer. Am Ende präsentiert es den Rückkehrcode.
Wenn Sie also den Fehler 23/24 erhalten, führen Sie einfach rsync erneut aus. Die nachfolgenden Läufe gehen viel schneller und übertragen normalerweise nur die fehlenden Dateien aus dem vorherigen Lauf. Irgendwann werden Sie einen sauberen Lauf bekommen [oder sollten].
Um atomar zu sein, verwende ich während der Übertragung ein "tmp"-Verzeichnis. Dann, wenn rsync run sauber ist, benenne ich es [atomar] in <date>
um
Ich verwende auch den --link-dest
Option, aber ich verwende das, um Delta-Backups zu behalten (z. B. --link-dest=yesterday
für täglich)
Obwohl ich es selbst nicht verwendet habe, ist die --partial-dir=DIR
kann verhindern, dass die versteckten Dateien das Backup-Verzeichnis überladen. Stellen Sie sicher, dass sich DIR auf demselben Dateisystem wie Ihr Backup-Verzeichnis befindet, damit Umbenennungen atomar sind
Während ich dies in Perl mache, habe ich ein Skript geschrieben, das das, was ich gesagt habe, mit etwas mehr Details/Präzision für Ihre spezielle Situation zusammenfasst. Es ist in tcsh-ähnlicher Syntax, [ungetestet und ein bisschen grob], aber behandeln Sie es als Pseudocode, um Ihren eigenen bash
zu schreiben , perl
, python
Skript, wie Sie wählen. Beachten Sie, dass es keine Begrenzung für Wiederholungsversuche gibt, aber Sie können dies ganz einfach nach Ihren Wünschen hinzufügen.
#!/bin/tcsh -f
# repo_backup -- backup repos even if they change
#
# use_tmp -- use temporary destination directory
# use_partial -- use partial directory
# use_delta -- make delta backup
# set remote server name ...
set remote_server="..."
# directory on server for backups
set backup_top="/path_to_backup_top"
set backup_backups="$backup_top/backups"
# set your rsync options ...
set rsync_opts=(...)
# keep partial files from cluttering backup
set server_partial=${remote_server}:$backup_top/partial
if ($use_partial) then
set rsync_opts=($rsync_opts --partial-dir=$server_partial)
endif
# do delta backups
if ($use_delta) then
set latest=(`ssh ${remote_server} ls $backup_backups | tail -1`)
# get latest
set delta_dir="$backup_backups/$latest"
if ($#latest > 0) then
set rsync_opts=($rsync_opts --link-dest=${remote_server}:$delta_dir)
endif
endif
while (1)
# get list of everything to backup
# set this to whatever you need
cd /local_top_directory
set transfer_list=(.)
# use whatever format you'd like
set date=`date +%Y%m%d_%H%M%S`
set server_tmp=${remote_server}:$backup_top/tmp
set server_final=${remote_server}:$backup_backups/$date
if ($use_tmp) then
set server_transfer=$server_tmp
else
set server_transfer=$server_final
endif
# do the transfer
rsync $rsync_opts $transfer_list $server_transfer
set code=$status
# run was clean
if ($code == 0) then
# atomically install backup
if ($use_tmp) then
ssh ${remote_server} mv $backup_top/tmp $backup_backups/$date
endif
break
endif
# partial -- some error
if ($code == 23) then
continue
endif
# partial -- some files disappeared
if ($code == 24) then
continue
endif
echo "fatal error ..."
exit(1)
end