VMODSORT on ZFS
現行 Solaris のファイルシステムフレームワークでは、ファイル内容をキャッシュするためのメモリページ一覧を、vnode_t 毎に管理している。
但し、キャッシュページのデフォルトサイズが 8K(2^13) バイトであるため、例えば 1G(2^30) バイトのファイルの場合、2^(30-13) = 2^17 = 128K 個のエントリがぶら下がることになる。
そうなると、何らかの契機で「ファイル全体のダーティページ書き出し」の必要が出たりしようものなら、各ページ毎に書き出し要否を確認するためには線形探索が必要になり、恐ろしくコストが掛かる結末に。
そこで、このような事態を回避するために、Solaris のファイルシステムでは VMODSORT という仕組みを提供している。この仕組みは:
- MMU が機能提供している(多分、ページ改変時のイベント通知等) ⇒ この場合、pvn_vmodsort_supported 変数が非0に設定される
- vnode_t の v_flag フィールドに VMODSORT フラグが立っている
という場合に限り、そのファイル= vnode_t に関するキャッシュ内容保持リストは:
- 前半は、改変済みページの offset 昇順
- 後半は、未改変ページの offset 昇順
という感じに区分けされた状態に整列される、というもの。
こうすることで、未改変ページに行き当たったなら、改変済みページの確認を打ち切ることができるので、リスト全走査と比較すれば格段に効率化される。
当然「並べ替え」させるためのコストはゼロではないのだが:
- 大規模ファイルの場合は、並べ替えによる効率化メリットで相殺
- 小規模ファイルの場合は、そもそも並べ替えのコストが高くない
と考えれば、妥当なところだろう。
この VMODSORT 機構は、以前 OpenSolaris のソース調査をした際には:
という状況だったと記憶していたのだが、OpenSolaris 勉強会の最中に実際に ZFS が稼動しているマシン上で以下の要領により VMODSORT フラグを確認してみると:
- walk vn_cache | ::print vnode_t
みたいな感じで v_flag フィールドに VMODSORT フラグが立っていない。
時間も無かったので結局その場は保留として、この件に関する調査が宿題ということに。
で、早速ソースを確認してみたところ、ZFS 実装で vnode 構築を一手に引き受けている zfs_znode.c の zfs_znode_alloc() における処理は以下のようになっている:
switch (vp->v_type) { ..... case VREG: vp->v_flag |= VMODSORT; ....
うーむ、記憶通り、明らかに問答無用で VMODSORT を設定しているんだけどなぁ。
…………あ!わかった!VREG 以外には立てていない= VREG 以外を見てたんだ!
vn_cache から辿れる vnode_t の種別を確認すると:
> ::walk vn_cache | ::print vnode_t v_type ! sort | uniq v_type = 0 (VNON) v_type = 0t10 (VPORT) v_type = 1 (VREG) v_type = 2 (VDIR) v_type = 3 (VBLK) v_type = 4 (VCHR) v_type = 5 (VLNK) v_type = 6 (VFIFO) v_type = 7 (VDOOR) v_type = 8 (VPROC) v_type = 9 (VSOCK)
VREG 以外も相当紛れ込んでいる。集計してみたら、1/4 は VREG 以外のものだったので、たまたま選択したものが VREG 以外だったとしても無理は無い。あるいはリスト冒頭に非 VREG 以外が集まり易い=参照され易いものが VREG 以外になり易いのかもね。