概要
- SQLiteのWALモードでは チェックサム が利用されているが、エラー時はエラーを投げずにフレームを破棄
- チェックサム不一致が発生すると、そのフレーム以降すべて破棄される仕様
- この挙動は バグではなく仕様 として設計されている
- チェックサム検証はWAL Index構築時に行われる
- データ損失やエラー通知方法に課題があり、より柔軟な回復手段が求められる
SQLiteのWALモードにおけるチェックサムの動作
- WAL(Write-Ahead Logging)モード は、2010年に導入された高書き込み性能向けのオプション
- 書き込みはまず WALファイル に記録され、チェックポイント時にメインDBファイルへ反映
- WAL内の各ページは フレーム と呼ばれ、各フレームにはヘッダーとチェックサムが付与
- チェックサムは ローリング方式 で、n+1フレームのチェックサムはnフレームに依存
- フレームの整合性確認時、チェックサム不一致があれば、そのフレーム以降の全フレームを破棄
- この動作は 公式ドキュメント にも明記されている
チェックサム検証のタイミングとWAL Index
- SQLiteは デフォルトではチェックサム検証を行わない ため、ページ破損に気付かない場合がある
- WALファイルには同一ページ番号のフレームが複数存在する場合がある
- 参照高速化のため WAL Index(.db-shmファイル) を構築
- WAL Index構築時にフレームごとに チェックサム検証 を実施
- コード上では walIndexRecover 内で walDecodeFrame を呼び出し、チェックサムを照合
チェックサムエラー発生時の挙動
- .dbと.db-walファイルのみ存在し、.db-shmファイルがない場合に問題発生しやすい
- WAL書き込み中に 異常終了 し、WAL Indexが未更新の場合、次回起動時に再構築が発生
- フレームのチェックサム不一致時、そのフレーム以降が 全て破棄 され、たとえ実際には破損していなくてもデータ損失
- SQLiteは 最後の接続終了時に必ずチェックポイントとWAL切り詰め を行う
デモ例と課題
- 旧バージョンのページに属するフレームを破損させても、以降の全フレームが破棄されるため 不要なデータ損失
- インデックスや重要でないテーブルのページ破損でも 全データ損失 のリスク
- より高度な回復手法があれば 一部データの回復 も可能
振り返りと考察
- 破損検出時にエラーを投げず、自動的にWALを切り詰める 仕様は好ましくない
- ユーザー側で破損検出時の挙動を選択できる オプション提供 が望ましい
- SQLiteは 組み込み環境 や モバイルデバイス (安価なSDカード利用)での利用が多く、破損検出の重要性が高い
- 他のデータベースも同様の挙動をとる可能性があるが、未検証
他者の視点
- Pekka Enbergは「組み込み用途では クラッシュより継続動作 が望ましい」と指摘
- Alex Millerは「 モバイル端末のSDカード では破損が頻発するため、SQLiteには破損検出機能が重要」とコメント
要望
- 破損検出時にエラー発生→ユーザー側で対処 できる仕組みの導入
- デフォルトでの 自動切り詰め動作の見直し や、挙動選択オプションの追加
- より柔軟な 回復・データ保全機構 の実装