linuxにおけるbmsファイル管理

こんにちは。圧縮マニアです。
以下の記事は、

  • linuxでbmsを遊んでいる

  • 1GBでもディスクを節約したい

  • でもwavファイル等はそのままの形でとっておきたい

というこだわりがある人(おそらく地球上に100人いない?)向けの記事です。

summary

bmsファイルは"ほとんど"readonly
squashfsで圧縮とマウント
差分はoverlay
windowsでもいちおうできる?

注意・免責

ファイルを損失するとか何か損害があっても私は何も言えません…バックアップはちゃんととりましょう。

はじめに

私は圧縮マニアなので、普段はこんなことをしています。

$ xz -vv --lzma2=preset=9e,dict=1536MB,depth=16777216 largefile.tar &

lzma2アルゴリズムの最高設定depthマシマシの圧縮なので、
とんでもない時間がかかりますが、かなりの圧縮率を発揮してくれます。
(これ以上を目指すとなると、nncpやtensorflow-compressなど、ニューラルネットを使った実験的な実装を使うことになるでしょう)

バックアップ用途にはこれで良いのですが、日常的に使うファイルを毎回解凍してから使い、使い終わったら圧縮する、なんて当然やってられないわけです。

bmsファイルは"ほとんど"readonly

とはいえ、話をbmsに限れば、

  • イベント等での公開からしばらく経てば、差替えが発生することはほぼない

  • 差分の追加はありうるが、ファイル数・ファイル容量とも少量

  • ファイルの削除はまずない

つまり、"ほとんど"読み取り専用として良いことがわかります。
全くの読み取り専用であれば、fuse-zipなどで単一のアーカイブをファイルシステム扱いしても良いのですが、差分追加や差し替えがたとえ少量でも、更新があればアーカイブ自体を作り直さなければならなくなります。それは前述と同じで"やってられない"ということになります。

では諦めて通常のファイルシステムで扱うとして、透過的圧縮が十分に強力であればマニア的に満足なのですが、最近のディスクは十分に安いためそもそも透過的圧縮が流行りではありません。

  • ext4 透過的圧縮なし

  • zfs lz4/gzip

  • NTFS LZNT1(wikipediaによればLZ77の変種?)

  • erofs lz4/lz4hc

  • squashfs lz4/lzo/gzip/xz/zstd

圧縮率は高くてもlz4止まりの中、唯一squashfsだけがxzに対応しています。しかしsquashfs(とerofs)は"通常"のファイルシステムではなく、組み込みシステムやLiveCDで使われる"読み込み専用"のファイルシステムです。
じゃあどうするか…は後述。まずはsquashfsをセットアップしてみます。

squashfsのセットアップ

squashfsの紹介は参考にした記事に譲るとして、まずはインストール。
※debianを使っています。以下同じ。

# aptitude install squashfs-tools

インストールできたら、適当なディレクトリを選んでイメージファイルを作成。
(私の環境では120GBで2時間かかりました。まずは容量少なめのディレクトリでテストすることをおすすめします)

$ mksquashfs ~/bms/files/ ~/bms/bmsfiles.sqfs -comp xz -b 1048576 -Xdict-size 1MB -noappend
(中略)
Parallel mksquashfs: Using 8 processors
Creating 4.0 filesystem on (略)bmsfiles.sqfs, block size 1048576.
[=======================================================/] 1834649/1834649 100%

Exportable Squashfs 4.0 filesystem, xz compressed, data block size 1048576
	compressed data, compressed metadata, compressed fragments,
	compressed xattrs, compressed ids
	duplicates are removed
Filesystem size 67586209.82 Kbytes (66002.16 Mbytes)
	54.58% of uncompressed filesystem size (123818682.29 Kbytes)
Inode table size 12275768 bytes (11988.05 Kbytes)
	21.03% of uncompressed inode table size (58367941 bytes)
Directory table size 9110144 bytes (8896.62 Kbytes)
	23.48% of uncompressed directory table size (38803260 bytes)
Number of duplicate files found 254303
Number of inodes 1810977
Number of files 1803785
Number of fragments 82185
Number of symbolic links  0
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 7192
Number of ids (unique uids + gids) 1
Number of uids 1
	yst (1000)
Number of gids 1
	yst (1000)
$ ls -lh bmsfiles.sqfs 
-rw-r--r-- 1 yst yst 65G 123 01:28 bmsfiles.sqfs

半分くらいの容量になりました。
重複除去ができるの地味にうれしい。

マウントするためのディレクトリを作成。
(例としてホームディレクトリ下にtestという名前で。)

$ mkdir ~/test

マウント。

# mount -t squashfs ~/bms/bmsfiles.sqfs ~/test/

これで、ls ~/testして~/bms/files/と同じ中身が見れていればokです。

もし後で~/bms/files/の中身を間違って消しても、bmsfiles.sqfsの中にこの時点でのデータが残っていることになります。
通常のアーカイブのように圧縮できて、だけどmountすれば普通のファイルのようにアクセスできる、ということですから、この時点で要求の半分は満たせていることになります。(ただしこの時点では読み取り専用)。

アンマウントは以下。

# umount ~/test/


overlay(overlayfs)

"ほとんど"読み取り専用、しかし少量の更新はある、圧縮率は確保したい…
なら更新部分だけ別のレイヤーで管理できればいい、という発想がoverlayです。
なるほどdockerと相性がいいわけで…それはまた別のお話。

とりあえず以下のような構成で、ディレクトリを4つ作ることにします。

$ cd ~/bms
$ mkdir lower_sqfs    # 上記と同様に、squashfsをマウントする。読み取り専用
$ mkdir upper_sabun   # "少量の更新"を置くための場所
$ mkdir work          # 動作に必要らしい
$ mkdir merged_files  # upperとlowerが統合されて見える

さっきと同じように、squashfsをマウント。

# mount -t squashfs ~/bms/bmsfiles.sqfs ~/bms/lower_sqfs

overlayをマウント。

$ cd ~/bms
# mount -t overlay overjoy -o lowerdir=lower_sqfs,upperdir=upper_sabun,workdir=work merged_files

この時点では、merged_filesとlower_sqfsは同じ内容です。

merged_files内にファイルを追加してみます。

$ cd merged_files/
$ echo 12345 > abcde
$ ls -l abcde 
-rw-rw-r-- 1 yst yst 6 124 00:16 abcde
$ cat abcde 
12345

lower_sqfs内を見ても変更はありません。(内容は割愛)

upper_sabun内を直接操作していないのにファイルが1個追加されています。

$ cd ../upper_sabun
$ ls -l
合計 4
-rw-rw-r-- 1 yst yst 6 124 00:16 abcde
$ cat abcde 
12345

ファイルを追加でなく削除した場合には、upper_sabunにスペシャルファイルが追加され、削除したことがわかるようになっています。

これであとは特段意識せずに、~/bms/merged_files/をbms置き場として使うことができるようになりました。

ただ、再起動するとmountが外れてしまうと思うので、都度mountするか、/etc/fstabでの設定が必要です。個人的には/etc/fstabでの設定は怖いので↑のmountを2行書いただけのshellscriptを使っています。

あと気になるのは「圧縮して読み込みが遅くなるか?(あるいは早くなるか?)」ですが、wineでLR2.exeを動かす限り、体感できるほどの違いはありませんでした。

バックアップ代わりに

1年に1回くらいはバックアップ代わりにイメージを作り直すと良いかもしれません。
その時はmerged_filesを元に新しいイメージファイルを作ります。
作り終えたら、どこか別のディスクにでもバックアップしておきましょう。

$ mksquashfs ~/bms/merged_files/ ~/bms/bmsfiles.sqfs.2023 -comp xz -b 1048576 -Xdict-size 1MB -noappend

最新のイメージができたので、元のイメージはもう必要ありません。構成し直しましょう。
アンマウント。

# umount overjoy
# umount ~/bms/lower_sqfs

upper_sabunディレクトリには差分が残っていますが、それはすでに最新のイメージに含まれていますから、一旦どけておいて、折を見て削除しましょう。

$ tar cvfJ upper_sabun_2022.tar.xz ~/bms/upper_sabun/ --remove-files
$ mkdir ~/bms/upper_sabun/

再度マウント。

# mount -t squashfs ~/bms/bmsfiles.sqfs.2023 ~/bms/lower_sqfs
# mount -t overlay overjoy -o lowerdir=lower_sqfs,upperdir=upper_sabun,workdir=work merged_file

windowsの場合

windowsは、NTFSに透過的圧縮の機能があるので便利ですが、圧縮率はあまり高くありません。Microsoft Storeから好きなdistroをインストールすればこの記事の内容を同じように試せます(Windows Subsystem for Linux)。
windows側からlinux側を確認するには、エクスプローラーのアドレスバーに
 \\wsl$
と入力すれば、自分のインストールしたdistroの名前のネットワークフォルダが見えるはずです。
debianなら
 \\wsl$\Debian\home\[ユーザ名]
でホームディレクトリが見えます。
逆にlinux側からwindows側は/mnt/c以下です。

ではまた。おやすみなさい。

参考