はじめに
仕事で同じプロジェクトのリポジトリを複数扱っていたりする場合、ファイルの重複は避けられません。
9割がた同じファイル構成のディレクトリが複数ある場合に、その分だけ容量を食われるのってイライラしますよね。
同じファイルがあった場合には容量を割かないようにしたいなぁ と思い、色々調べたところ、FreeDup というアプリケーションを見つけたので試してみました。
同じファイルシステム上に同じファイルがあった場合にハードリンク化したり、複数のファイルシステム間の場合にはシンボリックリンクに差し替えることでディスク容量を削減くれる素敵なソフトウェアです。
FreeDup のダウンロード
FreeDup の「Download」より、以下のソースをダウンロードし展開しました。
$ wget http://freedup.org/freedup-1.6-3-src.tar.bz2
$ tar xf freedup-1.6-3-src.tar.bz2
$ cd freedup-1.6-3
$ ls
COPYING Makefile.AIX Makefile.Linux README.html config.c demo freedup.h html mp3.h mpc.h ogg.c sha1.c symharden web.c
COPYING.SHA Makefile.BSD Makefile.tests TODO config.h freedup freedup.spec jpg.c mp4.c my.c ogg.h sha1.h symharden.1 web.h
ChangeLog Makefile.CYGWIN_NT-5.1 README auto.c copyright freedup.1 freedup.xinetd jpg.h mp4.h my.h pad.xml socket.c symharden.c
Makefile Makefile.Darwin README.SHA auto.h debian freedup.c helper.h mp3.c mpc.c nethelp.h rules socket.h verify
$ file freedup
freedup: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=600c144926945f4675f424dd682e65081d8f86e9, stripped
$ ./freedup -h
USAGE: ./freedup [options] [<tree> ...]
-a --freedups provide compatibility to freedups by William Stearns.[=-upg]
-b --basedir <path> sets the current working directory to <path>.
-c --countsave count file space savings per linked file.
-d --sametime requires the modification time stamps to be equal.
-D --timediff <seconds> allow the modification time stamps to differ by maximum #.
-e --environment <env> load or store command line as an environment. There exist:
-f --samename requires the path-stripped file names to be equal.
-g --samegroup requires groups of the files to be equal before linking.
-h --help shows this help. [other option are ignored]
-H --showhard do treat hardlink files as duplicates and show them on -in
-i --interact Decide in interactive mode individually, what to do with them.
-k --globalkey <key> Decide linking direction by key. Valid are @,#,<,>,+ and -.
-l --hardlink only allow hardlinks. No symlinks are established.
-m --minbytes <bytes> only consider larger files. (preferred: -o "-size +#")
-n --noaction do not really perform links [no action].
-o --findoptions <opts> pass an option string to the initially called find command.
-p --sameperm requires file permissions to be equal.
-P --permmask <mask> sets the octal mask for file permissions comparison.
-q --quietrun produces no output during the run (toggles -c and -v to off).
-s --symlinks generate symlinks although some given paths are relative.
-t --hashmethod <type> select hash method: sha512,sha384,sha256,sha224,sha1,md5,sum
-T --dirmtime restore the time stamp of the directory after linking.
-u --sameuser requires users of the files to be equal before linking.
-v --verbose display shell commands to perform linking [verbose mode].
-V --version display current version.
-w --weaklinks only weak symbolic links allthough hardlinks might be possible.
-x --extra <style> select comparison style: auto, jpg, mp3, mp4, mpc, ogg
-# --hash disable fast comparison using hash strings [0=no,1=classic,2=fast].
-0 --nonzero disable linking of empty files i.e. files of size 0.
<tree> any directory to scan for duplicate files recursively.
Options are toggle switches. Their final state applies.
Later <tree> entries are linked to the earlier ones.
If no <tree> is given, filenames are expected from standard input.
When standard input is used the option -o has no effect.
freedup: Version 1.6-3d ?2007-2008 by AN@freedup.org.
sha1.c/h of sha-1.0.4 ?2001-2003 by Allan Saddi.
$ export PATH=$PWD:$PATH
ということで、特にコンパイルなどは必要なく動くものが手に入りました。
MacOS で試す場合は、
$ make
で Darwin 用のバイナリを生成しましょう。
MSG_NOSIGNAL で怒られるので、適当に MSG_FREEDUP に置換しておくと通るようになりました。
Qtの1つのバージョンで動作確認
まず試したのは qt-everywhere-src-5.12.3.tar.xz です。
$ wget https://download.qt.io/archive/qt/5.12/5.12.3/single/qt-everywhere-src-5.12.3.tar.xz
$ mkdir src
$ tar xf qt-everywhere-src-5.12.3.tar.xz -C src
$ find src/qt-everywhere-src-5.12.3 | wc -l
249853
$ du -s src/qt-everywhere-src-5.12.3
2814198 src/qt-everywhere-src-5.12.3
24万ファイル(ディレクトリを含む)、2.8GB の巨大な構成になっています。
ではこれに対して freedup
を実行して重複がどのくらいあるのか確認してみましょう。
$ freedup -l -T -t sha512 src/qt-everywhere-src-5.12.3
Reading directory tree -
228016 files to investigate
12468 files of 228016 replaced by links.
The total size of replaced files was 66755038 bytes.
$ du -s qt-everywhere-src-5.12.3
2712267 qt-everywhere-src-5.12.3
228016 個のファイルを操作し、12468の重複を検知し、ハードリンクに置き換えることで 667MB の容量の削減を実現できました。
MacOS の場合は /usr/bin/sha512sum
コマンドが存在しないので、-t sum
を指定するといいでしょう。
Qt の2つのバージョンのソースコードで確認
次に、5.12.3 と 5.12.0 の2つに対して実行してみましょう。
$ rm -rf src/qt-everywhere-src-5.12.3
$ tar xf qt-everywhere-src-5.12.3.tar.xz -C src
$ wget https://download.qt.io/archive/qt/5.12/5.12.0/single/qt-everywhere-src-5.12.0.tar.xz
$ tar xf qt-everywhere-src-5.12.0.tar.xz -C src
$ du -s src/
11231880 src/
$ freedup -l -T -t sha512 src
Reading directory tree |
456256 files to investigate
236160 files of 456256 replaced by links.
The total size of replaced files was 2218745857 bytes.
22GBほど削減できたようです。
$ du -sh *
2.6G qt-everywhere-src-5.12.0
141M qt-everywhere-src-5.12.3
ファイルの構成は中身は一切変わっていないですが、重複ファイルをハードリンク化したことにより、ディスク領域の大幅な節約となりました。
TODO: git のリポジトリで試してみる
git 内部のデータファイルがほぼ重複しているのでこちらも大幅な削減が見込めるのではないかと思います。
TODO: ビルドディレクトリでも試してみる
バージョンやコンパイルのオプションに依存しますが、コンパイル済みのバイナリも内容が重複しているものがあるような気がしています。
おわりに
仕事や趣味で同じプロジェクトのソースコードがディスク上に複数存在している場合に容量を削減する方法が見つかりました。
ただ、ハードリンクを使っている性質上、 ファイルを修正する可能性がある場合は注意が必要 です。
開発ブランチとリリースアーカイブ間でハードリンク化されている場合、開発ブランチのファイルを編集するとリリースアーカイブのファイルも更新されてしまうと思います。