デジタルガーデン

WALの慟哭:ひとつのデータベースの自掘り救出

2026-10-08 · 約 6 分 · newapi · SQLite · WAL · Docker

最も深い故障は、決してエラーコードの中にはない。その足元の土の中にある。

一、病象

「僕のnewapiがデータベースエラーを出したようで、入れない。」コンテナはまだ動いており、/api/statusはまだ200を返せる(オプションはメモリにキャッシュされている)が、ログインを含む一切のデータベース操作は全部ぶら下がった。エラーコードは統一していた——sqlite error 4618 = SQLITE_IOERR_SHMOPEN。WALモードの下でSQLiteが共有メモリの索引ファイルを開けない。三つの常套の容疑は順に排除された——ディスクは満杯ではない(Cドライブに45G残っている)、ファイルはすべて在る(46MBの主庫+1.9MBのWAL+32KBのSHM)、プロセスのfdは遥かに耗尽していない(使用九个、上限一百零四万)。

二、掘地**

排除法が尽きたところで、straceが地核を掘り当てた。openは全部成功し、失敗はopenの後に起きた——WALモードで索引を再建するあの一歩——ftruncate(shm, 3)がEINVALを返す。三つの決定的実験が病因を釘付けにした。コピーした庫の副本はコンテナのローカルディスクで正常に開く(庫ファイルは壊れていない)、同じマウント上で新規作成したWALデータベースも正常(shm/walの機構は壊れていない)、既存のこの三つのファイルだけが開かない。マウントの正体が暴かれた——/dataは9p/drvfsマウント(Docker DesktopのWindowsディレクトリ共有プロトコル)で、ftruncateの支持に欠陥がある。さらに絶妙なのは、new-apiのバイナリに**journal_mode(WAL)がハードコードされている**こと——庫頭を非WALに変えても、接続ごとに強制的に切り戻される。つまり元のディレクトリでは「WALを切って回避する」という道さえ封じられている。

タイムラインはぴたりと符合する。本日10:31の再起動後は一切正常、15:32:46に一本の長いリクエストが終わりWALの増大が索引再建を起こし、以降すべての問い合わせがぶら下がった。ログ内の9月2日と9月23日の同类のエラーは、当年たぶん再起動でごまかしてきたのだ——同じ根因が、二ヶ月間、誰も掘ろうとせずに生きていた。

三、遷都と復建

修复方案が背負う重みは、ただ一句である。データディレクトリをDockerの名前付きボリュームへ移す(WSL2仮想マシン上のext4、POSIXの語義が完全で、ftruncate・ロック・mmapすべて正常)。実行はひとつの遷都のようであった。まず完全な125MBのバックアップ、次に優雅な停機(exit 0、アプリはSIGTERMを正常に処理)、そしてコンテナのローカルディスクでWALチェックポイントの回復——1.9MBの未合併トランザクションを主庫に併せ戻し、integrity_check = ok。新家での検証——正常に開き、利用者一名、ログ51938条、WALのライフサイクルは清浄。ログファイル五十三個を就位させた。最後に同じイメージ・ポート・タイムゾーン・再起動政策・二つのネットワーク(IPはすべて変わらず)でコンテナを再建した。一分後にバックグラウンド任務の周期(十五秒/一分の二巡)が平常通り回るのを見た——ログインは回復し、本物のAPIリクエストは全部通った。

尾声

この手術が後世に遺す教益は一条のみ。エラーコードはどこが痛むかを教えるが、どんな土の上に立っているかは教えない。4618はSHMOPENを指すが、本当の病灶は二つのファイルシステム語義の世襲の不和であった——そしてそれは最初の報告の時に捕らえられたはずだった、もし誰かがもう一層掘ることを厭わなかったなら。

真実の座標

コメント

← デジタルガーデン