rsyncの罠
rsyncの -u オプションには注意が必要というお話。どういうオプションかというと、
-u, --update This forces rsync to skip any files which exist on the destina- tion and have a modified time that is newer than the source file. (If an existing destination file has a modify time equal to the source file's, it will be updated if the sizes are dif- ferent.)
訳すと
-u, --update このオプションはrsyncに、転送先に存在し、かつ変更時刻が転送元より 新しいファイルをスキップさせます。もし変更時刻が同じでサイズが違う 場合には、転送されます。
つまり、-u をつけると、ソース元のタイムスタンプが転送先より古いと更新されない。注意が必要なのは、比較に使われるタイムスタンプは、変更時刻(modification time; mtime)で、これは「当該ファイルの属性」で変更できる。
言い換えるとソース元のファイルのタイムスタンプ(mtime)が若返ったとき、それは転送されない。mtimeが若返ることがあるのか?と思いがちだが、バックアップから書き戻すと容易に発生する。たとえばsrcディレクトリからdstディレクトリへrsyncでコピーすることを考える。
> find . . ./src ./src/abc.txt ./dst ./dst/abc.txt
こういう状態で、以下のようなことをしたとしよう。
実際にやってみると、こうなる。バックアップを取っていじって、rsyncを行う(バックアップしたファイルまで転送されているが、別ディレクトリに取っても本質は同じこと)。
> cp src/abc.txt src/abc2.txt > jvim src/abc.txt > rsync -auv src/ dst/ building file list ... done ./ abc.txt abc2.txt sent 333 bytes received 92 bytes 850.00 bytes/sec total size is 63 speedup is 0.15
バックアップから書き戻して、再度rsyncしてみる。
-u オプション付きのものはファイルリストから漏れており転送自体が予定されていない。(もっともファイルリストに入っても、-nオプションを指定しているから、転送されないけど)
> mv src/abc2.txt src/abc.txt > rsync -n -auv src/ dst/ building file list ... done ./ sent 112 bytes received 26 bytes 276.00 bytes/sec total size is 42 speedup is 0.30
-uオプションを外すと、転送リストに追加されていることがわかる。
> rsync -n -av src/ dst/ building file list ... done ./ abc.txt sent 118 bytes received 32 bytes 300.00 bytes/sec total size is 42 speedup is 0.28
これは、ファイルの移動の場合では、Modify Time(mtime)が保存されるため。そのため、バックアップを取ったあと、編集し、書き戻すと、こういうことが発生する。
mvする前(バックアップから書き戻す前)
> stat -x src/abc*.txt File: "src/abc.txt" Size: 21 FileType: Regular File Mode: (0700/-rwx------) Uid: ( 1001/ user0) Gid: ( 1001/ user0) Device: 0,110 Inode: 7136817 Links: 1 Access: Sat Oct 25 00:07:35 2008 Modify: Sat Oct 25 00:07:35 2008 Change: Sat Oct 25 00:07:35 2008
mvした後(バックアップから書き戻した後)
> stat -x src/abc.txt File: "src/abc.txt" Size: 21 FileType: Regular File Mode: (0700/-rwx------) Uid: ( 1001/ user0) Gid: ( 1001/ user0) Device: 0,110 Inode: 7136811 Links: 1 Access: Sat Oct 25 00:08:03 2008 Modify: Sat Oct 25 00:07:22 2008 Change: Sat Oct 25 00:08:20 2008
mv後に、Modifyの時刻が、00:07:35 → 00:07:22 と若返っていることに注意。
ここでは、シェルベースで操作したが、Samba経由での操作でも同じことが発生する。他のファイルシステム(NTFS)へバックアップし、書き戻した場合でも同じことが発生する。うっかりすると、ファイルの一部だけ転送されて、バージョンが異なるファイルが混在してしまうので要注意。
単純にトラフィックが少ないcpとして、rsyncを使う場合には、-uオプションをつけてはダメ。-uオプションは、以下に示すように相互にデータのやりとりをするような場合に使う。つまり、データ転送を素早く行う為のオプションではなく、タイムスタンプを記帳し同期を行うためのオプションなのだろうね。
To synchronize my samba source trees I use the following Makefile targets: get: rsync -avuzb --exclude '*~' samba:samba/ . put: rsync -Cavuzb . samba:samba/ sync: get put
もっとも、この場合でもファイルのタイムスタンプが書き戻る問題には対応できないわけだが、*NIX上でファイルを普通にエディタでファイルをいじっているだけなら問題はおきない*1。
コマンドのオプションは、奥が深い(奥が深い症候群...)と思ったそんな日のこと。
*1:もっともこういう用途ならバージョン管理システムを使った方が幸せになれると思うんだけど...