差分保持

差分保持について備忘録メモ。


今のVIVER(version 0.2)では、データの書き込みを疑似的に再現するために、読み取り専用の元データに対して、ブロックデバイスレベルの差分を保存することで対応している。
ブロックデバイスレベルというところは諸刃であり、ファイルシステムレベルの差分と比較すると、以下のような表ができる。

レイヤー 差分の効率 元データが変化したときに差分データは 差分保持用のディスクが一杯になったことの検出(通知)
ブロックデバイス 良い まったく使えなくなる できない
ファイルシステム 悪い ある程度使える できる

ブロックデバイスレベルであれば、その上にext3などのファイルシステムを作ることになる。従ってファイルの作成や削除、ロック処理などのファイルシステムが行う仕事は、成熟したレベルのものを利用できる。
一方、差分保持をファイルシステムレベルで行う場合、ファイルの作成や削除がうまく働かない場合がある。ファイルシステムレベルの差分では、たとえばあるファイルを削除するとき、「ファイルXを削除したという情報を持つファイルを作成する」ことでファイルの削除を実現する。では、この特殊ファイルを削除したらどうなるか?元のデータが現れるのか?カーネルパニックか?
他にもこの方法であれば、「ディレクトリAにはファイルBが入っている。ディレクトリAを削除。同名のディレクトリAを作成。ディレクトリAの中にファイルBが入っている」ということが起こる。
これらの現象は、実際にunionfsを利用して確かめた。しかし頻繁にバージョンアップが繰り返されているので、今では解決しているのかもしれない。
また、ファイルシステムレベルの場合、ファイル単位で差分を作成するため、たとえば1GBのファイルを少し変更するだけで、1GBの差分データが必要になるため、効率が良くない。(今のunionfsはうまくやっているかもしれない)


ブロックデバイスレベルの差分にも問題がある。
まず、元データが1ビットでも変化したら、差分データが使い物にならなくなる。上に載っているファイルシステムが壊れることになる。ファイルシステムレベルであっても完全に追従できるわけではないので、安全上、元データを作り直したら、差分データは破棄しましょう、で良いのではないかと思っている。ただ/homeディレクトリの場合はそうもいかないと思うので、これはUSBメモリなどのストレージを直に(差分ではなく)使うことになる。


差分保持用のディスクが一杯になったことの検出(通知)というのは難しい問題で、これは何とかしないといけないと思う。
ブロックデバイスレベルでは、そもそも差分を完全に保持するためには、元データと同じ容量の差分保持用ディスクが必要になる。ただこれだけでは書き換えはできても追記ができないので、さらにもう少し大きめの差分保持用ディスクが必要ということになる。
しかしこのサイズのディスクが用意できれば、そもそも差分を保持する必要など無くて、元データをコピーしてくれば良い。これができないので、スパースファイルを使って、3GB分の大きさ差分ファイルを128MBの差分保持用ディスクに載せる、ということをする。元データが2GBで、追記分が1GBなら、ファイルシステムからは「1GB分の空きがある」と見える。もちろん1GBも書き込めない。「書き込みまたは書き換え」が128MBを超えたところで、実際にディスクには書き込めなくなる。「書き込みまたは書き換え」が128MBを超えたときなので、追記分を128MBにすれば良いというわけでは無い。このときファイルシステムはそんなことを知らないのが問題で、カーネルのバッファが持ちこたえられる分は、ファイルシステムには書き込めてしまう。たとえばメモリを512MB搭載しているマシンでは、512MB - アプリケーションで使用しているメモリまではあふれた分も持ちこたえられるが、それを超えると、いつまでたっても書き込みが終わらない、ということになる(凍る)
このとき「書き込めないよ」と言っているのは、「差分を保持しているディスクのファイルシステム」になる(たぶん)。実際に使用するファイルシステム → 差分を適用した書き込み可能ブロックデバイス → 差分ブロックファイル → 差分を保持しているディスクのファイルシステム → 差分を保持しているディスクのブロックデバイス となっているので、「書き込み可能ブロックデバイス」を作るドライバでは、実際に書き込めなくなったかどうかを検出できない(たぶん)
差分を保持しているディスクを監視するデーモンを走らせて、一杯になったらユーザーに「もうヤバいよ!」と通知するか…。



ということで、困った。
NILFSというものを発見。書き込みを追記だけで行うファイルシステム。データを読み込むときは、最初から変更履歴をおっていき、最終的なデータを割り出す。いわゆるログファイルシステムというもの?
以前に、LinLogFSを差分保持に使おうと思ったことがあって、いろいろ考えていた。差分とは言わないかもしれない。追記しかしないので、読み取り専用領域の後ろに適当な大きさの書き込み可能な部分を接続しておけば、書き込みができることになる。追記ブロックレベルで行うので効率は良いが(たぶん…)、ファイルシステムなので、ディスクが一杯になったこともおそらく検出できる。(使ったこと無いので…)
ただ問題は、ガーベジコレクション(「GC」と書いたほうがかっこいい(笑 )を実装されてしまうと困るという点。追記だけしていると、当然ながらそのうちディスク容量が無くなる。そのころには「前の方」のデータはほとんど使わなくなるだろうから、ここを再構築して、ディスク容量を確保する。また、追記だけしていると、一つの現在のデータを読み取るだけに、読み込まなければならないデータが増えていく。つまり読み取り速度が低下していく。なので適宜再構築(GC)が必要になる。
と、ログ構造化ファイルシステムの本来の用途としてはGCは必要なのだけど、疑似的書き込み可能を実現する方法としては、GCは困る。再構築なんてできない。
で、どうやらNILFSにはGCが"まだ"実装されていない模様。今実装している最中のようで…。


さらに、ログ構造化ファイルシステムの利点は、ほとんどVIVERには意味がない。

  • 追記だけなので、シークが減って書き込みが速い … 書き込み先はRAMであることが多い。もとよりシークしない。
  • いつでも以前の状態のデータを取り出せる(連続したスナップショット) … 差分を適用せずに読み出せば、最初のデータは取り出せる。作業途中のデータが読み出せるのは良いかもしれないけど、せいぜいRAMの容量分だけ。
  • クラッシュしてもすぐに復帰できる … クラッシュしたらRAM上の差分は消える。

そして「一つの現在のデータを読み取るのに、たくさんのデータを読み取らないといけない」という欠点だけが残る。




あーどうする。