hogeとはワイルドカードのようなものです。日々起こった、さまざまなこと −すなわちワイルドカード− を取り上げて日記を書く、という意味で名付けたのかというとそうでもありません。適当に決めたらこんな理由が浮かんできました。
05/28/2017 ふむ [長年日記]
■ [Py][小ネタ] llesync
exFAT なパーティションにディレクトリツリーを同期したいことがあるのだが,
- 10 年以上前からデスクトップのファイルシステムが EUC-JP で,convert するのも面倒なので放置している
- しかし exFAT はファイル名が UTF-8 じゃないと書き込みを拒否するくさい
といったようなことがあって,面倒臭いなあと思っていた.
ファイルの同期といえば rsync(1) 大先生なのだが,単に -a オプションを使うと chown(2) でエラーを吐くとかまあ色々あって,概ね下記のようなオプションを指定することになる.
# rsync -rpt --iconv eucjp,utf8 SRC DST
とはいえ覚えられないし打つのも面倒だし,alias するとか wrapper 書くとかすることになると思うのだが,どうせ rsync(1) ほど高機能/高性能なものを求めているわけでもなし,せっかくなのでフルスクラッチで書いてみた. それが llesync.
とはいえどうせなら zero-copy でいっちょやってみるかと,データ本体を user space にメモリコピーすることはないようにした. その結果が下記.
$ sudo bash -c 'echo 1 > /proc/sys/vm/drop_caches' $ time sudo llesync -S hoge /mnt/card/tmp/. real 0m3.328s user 0m0.467s sys 0m0.347s $ rm -rf /mnt/card/tmp/hoge $ sudo bash -c 'echo 1 > /proc/sys/vm/drop_caches' $ time sudo rsync -rpt --iconv eucjp,utf8 hoge /mnt/card/tmp/. real 0m3.633s user 0m1.296s sys 0m0.304s
rsync(1) はデータを user space に持ってきてから kernel space に送る (read(2) したデータを write(2) する) という動作をするので,zero-copy にすることで user 時間に差が現れる. まあ,real は大差ないので大した意味はないけれど.
llesync はデフォルトでは差分をチェックせず cp -r のような動作をするので,更新されたファイルだけコピーしたい場合は上記のように -S オプションを指定する. 差分のチェックはデフォルトでサイズ,mtime,ファイル名の比較だけど,プラットフォームが Linux Kernel Crypto API をサポートしていれば md5 等のハッシュ値を比較することもできる. 例えば sha1 ハッシュ値を比較したい場合は下記のようにする.
$ sudo llesync -S -a sha1 hoge /mnt/card/tmp/.
hashlib を使わなかったのは,言わずもがな zero-copy を堅持するため. とはいえ如何に zero-copy と言えど,ハッシュ値の比較を使うとめちゃくちゃ遅くなるので,使いどころはあまりないのだけれど.
ちなみにハッシュ値を算出する部分は独立したモジュールに分けておいたので,下記のようにハッシュ値を求めることができる.
$ sudo bash -c 'echo 1 > /proc/sys/vm/drop_caches' $ time python3 -m llehash -a sha1 data 440a94499f1862fab752280ab7c4470b7d859a69 data real 0m4.592s user 0m0.071s sys 0m2.279s $ sudo bash -c 'echo 1 > /proc/sys/vm/drop_caches' $ time sha1sum data 440a94499f1862fab752280ab7c4470b7d859a69 data real 0m4.393s user 0m2.332s sys 0m0.272s
zero-copy のため user 時間と sys 時間に差が生まれているのが見て取れるけど,こちらもまあ real は大差ないので大した意味はない.