2017年12月15日金曜日

圧縮データをランダムアクセスしよう

CFカードやSDカードのイメージならば、圧縮イメージをマウントするを応用して、loopデバイスをアクセスすれば、ランダムアクセスができる(もちろんreadonlyだけど)。

元がストレージメディアのイメージなら、それでも良いだろう。しかし、ダラダラと続くストリームデータ(個人的には地震データ)を圧縮していることも多い。これらをアクセスするときでも、nbdkitとnbd-clientを使ってloopデバイスを作るのは、なんか手間が多い。
もっと手軽に、圧縮データ内の任意の位置を、高速にランダムアクセスしたい。

しかしながら、xz utilsには、その機能が無い。ファイルフォーマット自体はランダムアクセスを提供できる構造になっているのだが、それを利用するためのアプリケーションは提供されていないのだ。

個人的にはどうしても欲しかったので、数年前に自分で作ってしまった。
本日、コメントやヘルプメッセージを少し整理して、ソースコードを以下に置いた。

xzrd-20171215.tar.xz
xzrd-20171219.tar.xz

実は、「圧縮イメージをマウントする」をブログに書く前に実験的にそのアプリを実装しており、そのアプリを元に自分でnbdデバイスを作ろうとして、すでに存在しているのを発見し、ブログの記事になったのだった。
自分で作ったアプリは、簡単な動作確認をしていたものの、実験的に作ったものだ。充分に検証されたわけではない。
そのため、その時はブログでは紹介しなかった。

最初に「圧縮イメージをマウントする」を書いた頃は、マウントできれば充分だと思っていたのだが、ちょっと見るだけでも複数のコマンドを発行しなければならないのは手間が多いので、ストレージメディアイメージではない圧縮データのランダムアクセスでは、実験的に作ったそのアプリを使っていた。
2年半にわたって使用してきたが、特に問題が見られないので、公開することにした。
(先週、Lubuntu1604用のマウント方法をブログに書いたついでに。)
作った後で、liblzmaはマルチスレッドでも動作するのではないかと思い、マルチスレッド化した。
プロセッサ数や圧縮レートにもよるが、マルチスレッド展開はとても速く、ランダムアクセス以外でも便利に使える
ただし、パイプでは使えない。元々ランダムアクセス用に作ったため、indexテーブルを必要とするためだ

また、圧縮イメージをマウントすると同様、ランダムアクセス(およびマルチスレッド展開)のためには、小さなブロック単位で圧縮されていないと意味がない

マルチスレッド化に関しては、本家xz-utilsでも着々と開発が進んでいる。
xzの5.2以降では、Block header 内に、Compressed Size と、Uncompressed Size が入っている。
私がxzrdを実装した頃は、これら情報がなかったためIndexテーブルを使ったが、将来本家からマルチスレッド展開機能が出てくるときは、これらのフィールドを使用したものになるだろう。パイプで処理したい人はもう少し待つ必要がある。

xz utilsのソースは、ソースファイル毎にライセンスが違っている。
(tarの中の COPYING か、Debian系なら、/usr/share/doc/xz-utils/copyright を参照)
本ソフトウエアは、xzのソースをベースに、一部コードを流用して作製した。そして、xzのソースのライセンスは、public domain なので、公開の義務は無いと言える。しかし、私はxz圧縮の恩恵をたくさん受けているので、同じように公開する事にした。

ビルド方法
liblzmaを使うので、例えばDebian系であれば、liblzma-devパッケージをインストールしておく。
$ sudo apt-get install liblzma-dev
その後、ダウンロードしたソースを展開し、作成されたサブディレクトリ xzrd-20171219 の中で、makeを実行する。
$ tar -xf xzrd-20171219.tar.xz
  (サブディレクトリ xzrd-20171219 ができる)
$ cd xzrd-20171219
$ make
これで、サブディレクトリ xzrd-20171219 内に、実行ファイル xzrd ができる。
パスの通った任意のディレクトリにコピーして使え。


使い方
SYNOPSIS
xzrd [-h] [-b<blkSz>] [-o<blk#>] [-c<#OfBlk>] [-v<#>] [-T<#ofThread>] <fileName>

DESCRIPTION
指定されたファイル名の.xzファイルの非圧縮時のデータを、指定されたブロックサイズ、先頭ブロック番号、ブロック数で読み取る。 読み取られたブロックは標準出力に出力される。
.xzファイルは1つしか使えない。また、複数のストリームを持つxzファイルを正しく扱えない。

OPTIONS
-h ヘルプメッセージの表示
-b<blkSz> ブロックサイズをバイト数で指定する。デフォルトは512だ。
ここでいうブロックは、.xzファイルのストリーム内にあるブロックとは関係ない。ブロックデバイスのイメージを扱うときに、ブロック単位でアクセスしたいので、アクセスサイズが指定できるようにした。
任意の値を指定できる。バイト単位でアクセスしたいなら、1を指定しても良い。
-o<blk#> 読み取る先頭ブロック番号を指定する。
デフォルト=0。
-c<#OfBlk> 読み取るブロック数を指定する。0を指定すると、最後まで読む。
デフォルト=1。
-v<#> うるさいレベル。
0: 表示なし。
1: うるさい。
2: もっとうるさい。
3: もっともうるさい。
デフォルト=1。 (と言いつつ、0と0以外ぐらいしか違いがない)
-T<#ofThread> スレッド数を指定する。
省略時、または1よりも小さな値を指定すると、実装されているプロセッサ数が指定されたものと仮定される。
<fileName> .xz ファイルのファイル名を指定する。

おまけとして、xzrd-20171215.tar.xz内に、xz-file-format.txt の日本語訳途中の文書も入れておいた。xzファイルの構造がわかる程度の訳になっていると思う。 まだ途中なので、英文も併記されている。

公開したソースも、訳した文書も、Public domainのものとする。勝手に使っていいが、再利用の際は、
This software includes code from XZ Utils <http://tukaani.org/xz/>
を見えるようにしなければならない。また、引用元のxz-utilsのライセンスについての記述にしたがうこと。
私の名前は、見えなくても良い。再利用は、自己責任で行え。

履歴
日付 変更内容
2017/12/19 ソースコードをダウンロードするのに、GoogleDriveのアカウントが必要なようだったので、共有のリンクを作りなおした。
ヘルプメッセージの表示方法を「使い方」に書いていなかった。
さらにそのヘルプメッセージで、
"This software includes code from XZ Utils <http://tukaani.org/xz/>"
を表示するように、2017/12/15に改造したのに、改行文字を間違えて見えなくなっていた。
そして、xz-file-format.jp.txtの訳を少し直した。
リンクを貼り直したが、前のやつも残しておく。xzrd-20171215.tar.xz
修正内容が細かくたくさんあった。他にもありそうなので、履歴欄を作った。
どうにもこうにも、おっちょこちょいだな…
2017/12/20 各オプションのデフォルト値(省略時の値)を書き加えた。

0 件のコメント:

コメントを投稿