Můžete použít --link-dest=
volba. V podstatě byste vytvořili novou složku, všechny soubory jsou pevně propojeny s novou. Když je vše hotovo, můžete pouze zaměnit názvy složek a odstranit starý.
V Linuxu to není možné udělat 100% atomic, protože pro to neexistuje žádná podpora jádra/VFS. Záměna jmen je však ve skutečnosti vzdálena pouze 2 systémová volání, takže její dokončení by mělo trvat méně než 1 sekundu. Je to možné pouze na Darwinu (MAC/OSX) se systémovým voláním exchangedata na souborových systémech HFS.
Dělám něco podobného s rsync
zálohuje [na disk] a narazil jsem na stejný problém kvůli démonu, který aktualizuje soubory, zatímco záloha běží.
Na rozdíl od mnoha programů má rsync mnoho různé chybové kódy [Viz manuálová stránka dole]. Zajímavé jsou dva:
23 -- částečný přenos z důvodu chyby
24 -- částečný přenos kvůli zmizelým zdrojovým souborům
Když rsync provádí přenos a narazí na jednu z těchto situací, nezastaví se okamžitě. Přeskočí a pokračuje se soubory, které může převod. Na konci představuje návratový kód.
Pokud se tedy zobrazí chyba 23/24, spusťte znovu rsync. Následné běhy půjdou mnohem rychleji, obvykle se pouze přenesou chybějící soubory z předchozího běhu. Nakonec získáte [nebo byste měli získat] čistý běh.
Pokud jde o atomovou, používám při přenosu adresář "tmp". Poté, když je běh rsync čistý, přejmenuji jej [atomicky] na <date>
Také používám --link-dest
možnost, ale já ji používám k udržování delta záloh (např. --link-dest=yesterday
denně)
I když jsem to sám nepoužíval, --partial-dir=DIR
může zabránit tomu, aby skryté soubory zaplnily záložní adresář. Ujistěte se, že DIR je na stejném souborovém systému jako váš záložní adresář, takže přejmenování bude atomické
Zatímco to dělám v perlu, napsal jsem skript, který shrnuje to, co jsem řekl, s trochu podrobnějším/přesnějším pro vaši konkrétní situaci. Je to v syntaxi podobné tcsh, [netestované a trochu drsné], ale zacházejte s ním jako s pseudokódem pro psaní vlastního bash
, perl
, python
skript, jak si vyberete. Všimněte si, že nemá žádný limit na opakování, ale můžete jej přidat snadno, podle svého přání.
#!/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