🍑

ALTER TABLEするとアプリが起動しなくなった!の原因判明

2024/05/16に公開

10年以上個人開発アプリとして運用しているiOSのメモアプリが、ここ最近、alter tableを掛ける変更を追加するとアプリが起動しなくなる人がチラホラ。

1家1人3つずつ、どうぞ
https://apps.apple.com/jp/app/id513272765

sqliteも長く運用していると老朽化するのか...などと思いつつ、機能追加のためにsqliteにカラムを追加するのが怖くなってきた。

これはイカンということで対策をすることに

まずは原因を解明しないと始まらないのでalter tableをしている場所のエラーメッセージをMySQLに残すようにしてみると...

  • db connection error
  • unable to open database file

なるほど、わからん。

あの世とコミュニケーション

アプリが起動しなくなるとアプリからお問い合わせもできなくなり原因究明も難しくなるので、アプリが起動しない場合はセーフモードなる画面が開くよう改善。

処理の初めの初めにちゃんと起動できたかフラグ=false(デフォルトがtrue)をUserDefaults(アプリを閉じても残るデータ)にセットして、ちゃんと起動できたらこのフラグにtrueをセットするシンプルな仕組み。次の起動でこのフラグを見てfalseだったらセーフモード画面を起動する。

セーフモード画面では、全メモの閲覧とお問い合わせができる感じ。このセーフモードには後に、1週間分の自動バックアップファイルを用意してソコから復元させる機能を追加した所、復活した人が現れたので、何か解決した気になっていた。

さらに前進

そんなある日、何度も起動しなくなってはお問い合わせをしてくれ、なんとか毎回復活していたAさんからまた起動しなくなったというメールが。

ちょっと起動しなくなる頻度が多すぎるのではないか...。Aさんはかなり前からアプリを使ってくれているから、やはり最初に考えた通りsqliteファイルが老朽化してバイナリーレベルで何かが壊れているのかもしれないと睨み、新しいsqliteファイルにデータを全部移して入れ替える機能をセーフモード画面に追加。

試してもらった所、全然ダメだった。

真相究明!

もう実際のsqliteファイルをもらって手元の環境で動かさないと分からないと思い、セーフモード画面にsqliteファイルをメールで送る機能を追加する事に。

だが秘密は守ると約束して生データをそのままもらっても、コチラとはまったく関係ないルートで後々メモの内容が漏れた時に調査で生データを送ったせいだと疑われると非常にマズイ。どうしようかポクポク考えた結果、ユーザが記入した内容は全てsecretという文字で置き換えた加工済データを送ってもらうことにした。頭いい。

ユーザーさんにもちゃんとsecretに置き換えてるよ!って見せるために置き換え後のデータ一覧も見せる念の入れよう。カテゴリー名もメモ内容も全部secret.

それでもメールにsqliteファイルを直接貼り付けて送ってもらうのはまだセキュリティを疑われる心配があったのでパスワード付きzipにして添付するように。

届いたzipファイルを見ると、サイズが181MB。sqliteってゴリゴリ使ってても1MBも超えないと勝手に思っていたので嫌な予感...。

zipを解凍すると2.43GB!!!ちっともliteじゃない。

どんだけメモしてるのか確認してみるとメモの数は普通だったが、メモを間違って変更したけど戻せないという人がいたことから追加したメモの履歴テーブルに200万件以上データが入っていた。

メモを削除する時に履歴も一緒に削除する仕組みだったから問題無いと思っていたが、Aさんはメモを捨てないで新しく上書きして利用するスタイルだったようで、数年で2GBを超えるデータに育っていた。

2GB以上に膨らんだsqliteファイルへのalter tableはモバイル環境では厳しく、さらにalter tableの後に実行していたデータを整理するためのvacuumがとどめを刺していた。

1メモあたりの履歴を10件に制限して残りの余分なデータを全てdeleteするSQLを5分ほど掛けて実行するとsqliteファイルは200MBに縮み、無事アプリが起動できることを確認。(SQLはGPT師匠に聞いた)
ただ、Macbook Pro上では動いたdeleteが、iPhone15 Proの実機上で動かすと固まって動かなかったので1000件ずつ何度も実行して消すバッチ処理に変更をした。(バッチ処理はGPT師匠に聞いた)

こうして何年も悩まされていたalter table連続殺人事件は幕を閉じたのだった。

Discussion