テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(dm-lc report) cache_idの指定方法に関する設計問題

現在のlc_ctrは, 以下のように3つの引数をとる. 最後は, cache_idである.

/*
 * <device-id> <path> <cache-id>
 */
static int lc_ctr(struct dm_target *ti, unsigned int argc, char **argv)

dm-lcでは, lc_cachesという配列のいずれかを指し示すポインタ(cache_id_ptr)があり, このポインタが「今対象としているキャッシュを示す」という設計をとっている. 従って, resume_cacheなどでは以下のように, switch_toでcache_id_ptrを変更してから実行することによって, 「そのスロットにresumeしたキャッシュを格納してください」という意味を持たせる. resume_cacheがcache_idを引数としてとるのではなく, グローバルなポインタを操りながら操作するということにする. 使い方が正しいかは分からないが, cache_id_ptrの値によってpolymorphicなのである. 例えば, id=0の場合はlc-mgr statusの出力が特殊になったりする.

cache_id_ptrの概念については, 以下を参考されたい.
https://github.com/akiradeveloper/dm-lc/blob/develop/dm-lc-admin.pdf

os.system("dmsetup message lc-mgr 0 switch_to %d" % (args.cache_id))
os.system("dmsetup message lc-mgr 0 resume_cache %s" % (args.path))

これは第一に, 引数を減らすためであるが, 想像のとおり, どのコマンドにおいても毎回毎回cache_idをパースしたりする処理を減らすためでもある. これはもちろんエラー処理も減らすことに繋がる. Don't Repeat Yourself(DRY)の精神がここにある. lc-mgrをオブジェクト指向的に設計しているとも言える.

lc_ctrもこれと同様に, switch_toでcache_id_ptrで, 使うキャッシュをポイントしてから実行することで, 第三引数はreduce出来るはずである. しかしそうはしていない.

それは, dmsetup tableの標準出力をdmsetup loadに食わせることによってデバイスをコピー出来ることが, DMターゲットが満たす暗黙的な仕様なのではないかと思うからである. 例えば以下のページではそのような仕様に依存している. http://user.xmission.com/~ddmayne/slackware/snapshot_origin.html

# dmsetup table origin | dmsetup load md2

これが, dm-snapにのみ期待した挙動なのか, あるいはDMターゲット一般に期待する挙動なのかが全く分からない. もし分かる人がいたら教えて欲しい. dm-develで議論すべきだろうか?

このような理由から, lc_ctrについては特別扱いしているわけである. しかし当然, DRYに反する. それに, 設計の一貫性を穢されるのがとてつもなく嫌だ. dm-lcの設計は他のDMターゲットにないものであり, 斬新である. Mikeがfirst lookでsurprisedと言った原因の一つはここにある.

もちろん, lc_ctrがcache_idを引数にとることによって得られるメリットは, 上記"Maybe仕様"を満たすためだけではない. 並行性の点からも優れる. 例えば, lc_ctrが並行的に呼ばれて, 複数のデバイスが同時に作られるとしたら?仮にcache_id_ptrというグローバルな状態を共有するのであれば, ロックが必要であるし性能はスケールしない. しかし一体どこの世の中に, そんなわけの分からない運用をしたい人間がいるだろうか?私は, 99%のユースケースでは, キャッシュは共有されないと考える. また, dm-lcがたかだか255個のbacking storeしかサポートしないことを抜きにして, 仮に1万個の仮想デバイスを作成するとしても, lc_ctrは, 逐次的に呼び出して十分である. 残りの極めてアブノーマルなユーザの方は, わがままを聞いてくれる有料ストレージベンダーと交渉を進めれば良い.

以上より, lc_ctrの第三引数を減らして設計をより良くするための論点は, Maybe仕様が本当に存在しているかどうかのみである. とはいえ, この設計判断は遅延出来る. そのためにAdminツールを開発したのである. カーネル空間からユーザランドへのインターフェイスは変わるかも知れないが, ユーザランドのインターフェイスは変更しない.

私の戦略はまず一旦, コミュニティのコメントを待って, それから決めるというものである. あまり頻繁に変更を繰り返すコードについてレビューする気は起きないだろうと思うので, 現在提出したv2で一旦打ち止めにしたい.

(追記) dmsetup tableの出力に関する議論をぐぐってみると, 以下のようなものが見つかる.
http://osdir.com/ml/linux.kernel.device-mapper.devel/2006-10/msg00148.html

The point of STATUSTYPE_TABLE is to return (readable) output to userspace in
a format that the crypt_ctr() function would accept back in.

dmsetup tableは, userspaceに, ctr()がback in出来るようなフォーマットで出力する必要があるとのことである. つまり, 私の現在の実装は正しい (ただし, デバイスの挙動は少し変わってしまう). とはいえ, 常にswitch_toさせる設計に変更したとしても, この仕様を裏切っていることにはならない. だって, ctr()をする時にも, その前にはswitch_toするはずだから. 外部の環境に一切依存してはならないなんて腐った話はないだろう.

(追記)
https://github.com/mathkid95/linux_samsung_jb/blob/master/Documentation/device-mapper/dm-raid.txt

この議論でも, 以下のように書かれている. DRYについてはcache_idのパースと妥当性に関するチェックを関数としてくくりだすことによって, コードが完全に死ぬことは避けられる. 「何の前準備もなしに, dmsetup tableの出力をCTRに突っ込んでも問題なくコピー出来ること」が条件であるとすれば, 直前にswitch_toの実行を必要とする設計は正しくない. やはりここはkeepだ. ユーザランドとの界面は難しい.

Performing a 'dmsetup table' should display the CTR table used to
construct the mapping (with possible reordering of optional
parameters).