基本のキじゃないですかね。
ヒミツが書いてあるファイルがあるとします。
/anywhere/somewhere/secret.txt
読み出してから内容を変更して書き戻す場合、以下のような手順が基本だと思うのです。
1. メモリに読み出す
2. 内容をメモリ上で変更する
3. テンポラリファイルに書き出す。hogehoge.txt
4. secret.txtを削除する
5. hogehoge.txtをコピーしてsecret.txtにする
6. hogehogeを削除する
何を心配しているかというと、書き込み中に電源がばちっと落ちたり、OSがpanicを起こしたりしたときに困るからです。
そんなことはファイルシステムに任せておけばよい。
ext4なら、ジャーナルがあるから復旧できる。fsckすりゃいいだけじゃないか。
などと言われてもここは譲れません。
ext4のジャーナルは、メタ情報だけしか保護されないと聞きます。つまりファイルの中身はあてにならないというのです。
ファイルが消えてしまったりサイズが変わってしまっている場合は、初期状態に戻すなどの対処を作りこむことができます。困るのは、ファイルは残っていて、サイズも正しいのに中身だけおかしくなるような場合です。*1
先に挙げた手順では、6が完了するまで、旧ファイルか新ファイルの内容の両方または片方が常に存在します。したがって、異常終了したあとの起動時やファイルアクセス時に、前回書き込みがどこで終わったか簡単に判定することができます。
例えば、テンポラリhogehoge.txtが残っていれば、3~6のどこかで何かが起きたと分かります。そのテンポラリは中身が信用できないわけでもなく、secret.txtが存在しない場合は、hogehoge.txtは新ファイルとしてほぼ信用することができます。
もちろんすべての手順が、順序どおりファイルシステム上に反映されているかあるいはストレージデバイスに書き込みが完了しているかといえば、バッファの存在を考えれば信用できないかもしれません。できるだけflush()同等の操作をしてファイルシステムの同期化をするのが望ましいのは言うまでもありません。
マッチ箱の中なら、ここに書いたことは基本に過ぎず、レアケースを拾うためにはもっと工夫が必要です。ファイルにCRCをつけておくことはもちろん*2、2重3重バックアップも考慮が必要です。
なんでもかんでもSQLiteのデータベースに押し込んでしまえというどこぞのニセOSも、多少は参考になるのかもしれません。めんどうなことはSQLiteに任せればかなり気が楽になることは確かです。
そもそもややこしいディレクトリ構成のあちこちに断片的なファイルを押し込んで、あ~でもないこ~でもないといじくり回すくらいなら、SQLiteのデータベースに任せてしまうのも悪くない考えだということです。
SQLiteのアトミックコミット(アトミック性を高めたデータ保存技術)については、以下のページが参考になると思います。
Atomic Commit In SQLite
http://www.sqlite.org/atomiccommit.html
SQLiteはフツウのファイルにDBを格納しても、それなりに動作する点が売りなワケでして、ここで書いたような話は当然クリアできる技術が含まれているだろうということです。
SQLiteのサイトにはこんなことも書かれています。
About SQLite
http://www.sqlite.org/about.html
・・・Think of SQLite not as a replacement for Oracle but as a replacement for fopen()
SQLiteをオラクルの代用品としてではなく、fopen()の代用品だとみなしてください。
どうにもならないバイナリファイルを作り散らかしてメンテ不能に陥るくらいなら、SQLiteという押入れを導入した方が良い場合がほとんどでしょう。
コメント