--link-dest=
を使用できます オプション。基本的に、新しいフォルダーを作成すると、すべてのファイルが新しいフォルダーにハードリンクされます。すべてが完了したら、フォルダ名を入れ替えて古いものを削除するだけです。
カーネル/VFS のサポートがないため、Linux でこの 100% アトミックを行うことは不可能です。ただし、名前の交換は実際には 2 syscall しかかからないため、完了するのに 1 秒もかからないはずです。 HFS ファイルシステムで exchangedata システム コールを使用する Darwin (MAC/OSX) でのみ可能です。
rsync
で同様のことを行います [ディスクへの] バックアップを行っていましたが、バックアップの実行中にデーモンがファイルを更新するために、同じ問題に遭遇しました。
多くのプログラムとは異なり、rsync には 多くの さまざまなエラー コード [man ページの下部を参照]。興味深いのは次の 2 つです:
<ブロック引用>
23 -- エラーによる部分転送
24 -- ソースファイルが消失したため部分転送
rsync が転送を行っているときに、これらの状況のいずれかに遭遇した場合、ただちに停止するわけではありません。スキップして、できるファイルを続行します 移行。最後に、リターン コードを示します。
したがって、エラー 23/24 が発生した場合は、rsync を再実行してください。後続の実行ははるかに速くなり、通常は前回の実行で不足しているファイルを転送するだけです。最終的には、問題なく実行できる [または取得する必要がある] でしょう。
アトミックであるため、転送中に「tmp」ディレクトリを使用します。次に、rsync の実行がクリーンになったら、[アトミックに] 名前を <date>
に変更します
--link-dest
も使用しています オプションですが、私はそれを使用して差分バックアップを保持しています (例:--link-dest=yesterday
毎日)
私自身は使っていませんが、--partial-dir=DIR
隠しファイルがバックアップ ディレクトリを乱雑にするのを防ぐことができます。名前の変更がアトミックになるように、DIR がバックアップ ディレクトリと同じファイル システム上にあることを確認してください
私はこれを perl で行っていますが、あなたの特定の状況に合わせて、私が言ってきたことをもう少し詳細/正確に要約するスクリプトを書きました。これは tcsh に似た構文 [テストされておらず、少しラフ] ですが、独自の bash
を作成するための疑似コードとして扱ってください。 、 perl
、 python
選択したスクリプト。再試行に制限はありませんが、必要に応じて簡単に追加できます。
#!/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