2013年8月23日

ファイルシステムを跨いでのファイルの移動にはmvを使ってはいけない

mv(1)は賢い。同じファイルシステム内のファイルの移動ならrename(2)を使ってディレクトリエントリだけを変更し、ファイルシステムを跨いだ移動ならまずcp(1)と同じ動作でファイルをコピーしてからrm(1)と同じ動作で元のファイルを削除する。便利だ。

しかし便利さに甘えてはいけない。

失敗例は、btrfsの一つのサブボリュームから別のサブボリュームにファイルを移動させようとしたとき。mvで移動を開始したがどうも遅い。簡単な計測をしてみると5MB/s程度の速度しか出ていない。SOHO向けのNASで、だ。

straceで調べてみると、ファイルをコピーする前に必ずrenameを実行して本来の移動だけですまないかどうか試して、ダメならコピーを実行する、と言うことを全てのファイルの移動に毎回行っている。一回にかかる時間は僅かかも知れないが、移動したいファイルは50万個ぐらいあるから無視できない。おまけに、コピーの実行には32KBという小さなバッファで毎回read(2)write(2)を呼んでいる。遅いわけだ。多分cpとかtar(1)で実際にファイルをコピーして元のファイルを削除した方が速かったと思う。

今回はbtrfsのサブボリューム間の移動だった。btrfsのサブボリュームはストレージプールは共有するが個別のファイルシステムとして動作する。だから、コピーによる移動は同じストレージプールにコピーして削除と言うバカ臭いことになる。

おまけにmvのコピーによるファイルの移動は、個々のファイルのアトリビュートは全ファイルをコピーし終わるまで確定しないようだ。

今回はストレージの空き容量容量が十分あったので全ファイルを一旦コピーしてからコピー元の全ファイルを削除と言う方法も取れたはずだが、空き容量に余裕がないときはファイルをスキャンしながら一つづつコピーしては削除と言う動作をするスクリプトでも書くか。

0 件のコメント:

コメントを投稿