ファイルへのアトミックなライト

アトミックというのは, ざっくりいうと, いかなるタイミングでサーバのHDDがぶっ壊れたとしても, ストレージから読み取れる状態は,

  1. 処理をする前
  2. 処理が完了した後

のいずれかであって, 中間的な状態ではないということです. 例えば, みなさんがファイルをオープンしてライトしている間にサーバが落ちた時, ストレージの状態は何も保証されない. 運が良ければ何のライトも残らないし, 大抵の場合は新しいライトと古いデータが混在して, 破滅する.

既存の議論

ファイルシステムの上でこれを行うにはどうするか?ということを気になってる人は山ほどいるらしく, Apache Transactionのようなものもある.

ただし, このプロジェクトは, ファイルシステムの上でトランザクション(複数の処理をアトミックに行うこと)を実現することは不可能だと分かったのでおねんね状態となった. ロックとか, 有用なパーツは提供出来るけど, ユーザがもっとも期待してるのはトランザクションだから, それが実現出来ない以上, 辞めた方がいいという理由のようである. 技術的なこともあるかも知れないが, 真の理由は飽きたからだと思う.

We have decided to move the project to dormant as we are convinced that the main advertised feature transactional file access can not be implemented reliably. We are convinced that no such implementation can be possible on top of an ordinary file system. Although there are other useful parts (as multi level locking including deadlock detection) the transactional file system is the main reason people use this library for. As it simply can not be made fully transactional, it does not work as advertised.

基本的な考え方は,

The transactionality is achieved by first writing to temporary files and upon commit moving or copying them to the primary location. Locks and a delicate commit mechanism will assure that no data corruption occurs.

に書いてあるように,

  1. tmpファイルに書く(a.tmp)
  2. mv a.tmp a

である. 私が調べたところ, この方針でアトミックライトを実装しようとしている人は山ほどいるし, 山ほどスレッドが立っている. ライブラリもちょこちょこ存在する. atomic-write: Atomically write to a file. すべてのライブラリに目を通したわけではないし, すべてのスレッドを完全に理解したわけではないが, 考察に穴があることが多かったので, 私なりの考えをまとめておこうと思う. (それが正しいともまた限らないけど)

私の考え

アトミックなライトは可能

まず明らかに, 拠り所としなければいけないのは, mv(or rename)が本当にアトミックか?である. これは実はPOSIXのrenameはatomicである.

Rename (computing) - Wikipedia

In POSIX, a successful call to rename is guaranteed to have been atomic from the point of view of the current host

従って, 以下のような考え方でアトミックライトを実現することが出来る.

ライター:

  1. tmpファイルに書く
  2. renameする

リーダー:

  • 1の途中で落ちたら, tmpファイルが残っているかも知れないから, リーダーは「ライトは失敗した」とみなす
  • 2の途中で落ちることはあり得ない. つまり, tmpが残っているか, renameに成功してtmpが消えるか
  • tmpが残っている場合はやはり, リーダーは「ライトは失敗した」とみなす
  • tmpが存在しない場合は, リーダーは「ライトは成功した」(あるいはライトはなかった)とみなす

トランザクションは条件つき

ここでトランザクションは, aとbとcをアトミックに更新するという意味とする.

  • 仮に, aとbとcがライターの都合で決められるとすると, トランザクションは不可能だと思う. なぜならば, 複数のrenameはアトミックでないから. 参考: C++ atomic write to multiple files. : cpp
  • 仮に, aとbとcに常にまとまりがあるならば, これらを1つのディレクトリに置いて, symlinkの切替というアトミック操作を利用してトランザクションを実現出来る.
  • 仮に, 上書きがないとする(常に新規書き込み)と, トランザクション自体は実現出来ないが, アプリケーションの性質によってはそうみなせる可能性がある. rename前にデータを参照しようとしたらファイルが存在しないことが保証されるため.

と色々考えてみたのだが, 異常に難しいということだけ分かった. この分野で詳しい人がいたらお食事でもごちそうするので, 色々話を聞かせてください.

comments powered by Disqus
Built with Hugo
テーマ StackJimmy によって設計されています。