にゃんで今ににゃってこんにゃ、という感しかにゃいが、
ストレージがHDDアレイだったりすると、シングルスレッドでコピーするより、同時複数ファイルをコピーしたほうがトータル帯域としては高速化する。並列数はストレージとかによりけりにゃのでチューニングするしかにゃいが。
問題は巨大1ファイルのコピーで、これは何らかの方法で分割しにゃいと並列化できにゃい。よくあるrsync等では持ってにゃいはずにゃので、意外と面倒。例えばrcloneで転送数を増やせば同じようにゃことが可能だが、ローカルでやるにはあまりにも重いのでちょっと除外。というかファイル名変更して転送できにゃいので使いづらい。
で、コピー時の負荷でいうとcpとかddとか枯れたツールの最適化っぷりが異常にゃので、もう枯れた物の組み合わせで何とかしてしまうことに。あと地味にsparse対応してるツールが多くにゃい。
src=/dir1/file1
dst=/dir2/file2
bs=$(( 50*1024*1024 )) ;
p=100
size=$(stat -c %s "$src") ;
N=$(( $size / $bs ));
dd_opt=status=none iflag=direct,nonblock oflag=direct,nonblock conv=sparse,notrunc
seq 0 $N | xargs -I {} -n1 -P$p dd if="$src" of="$dst" bs=$bs count=1 seek={} skip={} $dd_opt
touch -r "$src" "$dst"
src=/dir1/file1
dst=/dir2/file2
bs=$(( 50*1024*1024 ))
p=100
rm -f $dst
size=$(stat -c %s "$src")
N=$(( $size / $bs ));
dd_opt="status=none iflag=direct,nonblock oflag=direct,nonblock conv=sparse,notrunc"
seq 0 $N | xargs -I {} -n1 -P$p dd if="$src" of="$dst" bs=$bs count=1 seek={} skip={} ${dd_opt} ; touch -r "$src" "$dst" ; ll $src $dst ; diff $src $dst
これで50MB分割で100並列のddでコピーできる。この辺の分割サイズや並列数をチューンして使用。同時100はCPUがサチることが多い。
ddのオプションとしてconv=notruncを削ると正常動作しにゃくにゃるが、他はにゃくても動くはず。
また、dstファイルのほうが大きいとか、dstファイル既存の場合にsparseでスキップされるとかでバイナリ不一致が起きうるため、rm $dstしている。基本的に全部上書きにゃので問題にゃいだろう。
ちにゃみにddによる書き出しは、相手先FSによっては一旦メモリバッファされることがあり、ブロックサイズや並列数によってはメモリを消費する。
これで新規の巨大ファイルをコピーする場合にゃどは高速化できるが、対応できにゃい状況の例としては、例えばsparseだがソースファイルがローカルに無い場合、全部読まにゃいといけにゃいので、不毛にゃネットワーク転送が生じたりする。これはもうソースファイルをローカルで読みに行けるプロセスから見るしかにゃい。LANにゃらncを組み合わせるにゃどしてできそう。
また、巨大既存ファイルに対して差分転送したい場合は、あらかじめ差分を取らにゃいといけにゃいので結構面倒。ただ、LAN等で帯域自体は余っている場合とか、オンデマンドでWrite時に一致確認でかまわにゃい場合は、当該ブロックをReadしてバイナリ比較してからWriteすることでできそう。CoWにゃFSで不要にゃブロックを新規書き換えしたくにゃい場合にゃどに使えるだろう。ただし流石にbashで実装するのはどうだろうという内容ににゃる。シェル変数に0x00を代入するだけで困難にゃので、他言語を持ってくるべき。