広告

posted by fanblog

database is lockedに悩んだら、コレで解決!原因は予想外のコイツ!でした

SQLite3でたまに発生するdatabase is lockedって悩ましいですよね。勝手にロック解除してくれるとありがたいんですがlock状態を継続してしまうので時間経過で問題も大きくなりがちです。ここではdatabase is lockedになったデータベースファイルをunlockの状態に戻す方法、真の原因、lockされているデータベースファイルを特定する方法などがわかります。

SQLite3データベースをunlockする方法


ここではロックされているデータベースをdb.sqlite3としています。アンロックする方法自体はとても簡単でした。リモートログインしてshell操作する必要があります。FTPでも同様のことができるかもしれませんが、ここでは試していないのです。

移動して、コピーすることで、unlockできました。

1. mv db.sqlite3 bk.db.sqlite3
ロックされているSQLite3のデータベースファイルを別名にします。(mv)
2. cp -p bk.db.sqlite3 db.sqlite3
元と同じファイル日付で、元と同じファイル名としてコピーします。(cp -p)

たったこれだけの操作で悩み悩んだdatabase is lockedが回避できました。

ファイルを別名し、コピーすることでロックが解除できます。
sqlite3データベースにロック情報が記録されているのであれば、この操作では中身を一切書き換えていないので、アンロックされることはあり得ません。
このことからロックの原因は、PHPのSQLite3 拡張モジュールで使われているflock系のシステムコールに起因すると想像しています。

database is lockedが発生した真の理由


SQLite3データベースをunlockする方法にflock系のシステムコールがロックの原因と書きました。これは誰かがflockしているからdatabase is lockedが発生してしまうことになります。では、誰が一体flockをやっているのか?遅延書き込みなどの要因?
疑問でしたが、ようやくわかりました。まず以下のような設計でクーロン実行させています。
  1. 1)プログラムはPHPで作っています。クーロン実行させています。
  2. 2)エックスサーバーのクーロンは、1回で動作できる時間が30秒までの制限があります。
    制限に達するとこのようなPHP Fatal error: Maximum execution time of 30 seconds exceededエラーメッセージとともに強制終了されます。
  3. 3)PHPプログラムは、SQLite3データベースに同時にアクセスしない設計になっています。そのタイミングでCRUDを行うのは1つのプログラムだけです


このような状況下で、database is lockedが発生しました。SQLite3データベースをunlockする方法で解決しますがロックさせてしまう根本的な対処にはなっていないですよね。

プログラムの設計上、シングルで動作しているのでロックされること自体ありえないって思っていました。原因は、プログラムの重複実行でした(笑)

予想外です。まさかの自分自身のプログラムがdatabase is lockedの要因を作っているなんて・・・


ただ、これ自分でプログラムを複数実行しているわけではないです。スケジュール実行で自動実行されています。今回対象のプログラムは30秒以上動作することがあるのでMaximum execution timeになり、プログラムが強制終了していたはずなのですが。。。どうやら生き残る生命力豊かなたくましい奴がたまに誕生するようです。
1)Maximum execution timeになる処理はデータベースの更新を含んでいるのでタイミングが悪いとトランザクションでロックした状態になりえます。
2)そのため次のスケジュール実行で動いたクーロンプログラムがdatabase is lockedで失敗する
この流れでdatabase is lockedが発生していたと確信しています。


根本的な原因はクーロンが生き残ることがあるということでしたね。あとはこれに対応できるようにプログラムを変えるだけです。例えば29秒経過したら自発的に正常終了させる、クーロン実行されたプログラムのPIDを記録して、killするようにする、ロックの回避方法はわかっているのでロックが発生したらロックの回避方法を試すなどのことをやればdatabase is lockedを撲滅できそうです!


ロックされている?データベースロックの確認方法


database is lockedエラーが発生した、1つのSQLite3データベースだけ扱っていればロックされたデータベースの特定は簡単ですよね。複数のSQLite3データベースがあるとどれ?これ?どうやって調べるの?となります。どうしたら単純に調べられるのか、コマンドを色々試して見つけたのがこの方法です。
この方法は、リモートログインして確認します。
シェルからsqlite3コマンドでSQLite3データベースファイルに対してVACUUMコマンドを実行する方法です。

$ sqlite3 データベース "vacuum;"

lockedの状態のデータベースファイルは、このコマンドを拒否します。
SQL error: database is locked
というメッセージが出力されます。

問題なければ、VACUUMにより空き領域が解放されます。データベースサイズが膨れていくので定期的にVACUUMコマンドを実行するのが良いとされていますよ。一石二鳥の確認方法ですね!

1つ注意点があって、他のプログラムやPHPからアクセス中にはやらない!ってことです。やっても良いですが失敗する可能性があるのと、参照している側もそのタイミングにアクセスすることでCRUDが失敗する恐れもあります。そのため、アクセスが少ない時にやったほうが良さそうです。

ちなみにCRUDは、Create/Read(select)/Update/Deleteのデータベース操作を示しす用語です。

まとめ


いかがでしたでしょうか?ここまでSQLite3データベースをunlockする方法、database is lockedが発生した真の理由、ロックされている?データベースロックの確認方法をご紹介してきました。

database is lockedは回避できましたでしょうか。

今回ご紹介したこの方法で私は回避できました。たまに間違えるのですが、mvは重要です。消すのは怖いからと代わりにcpでやると解決できません。lockの状態を継続しますよ。必ず元あったデータベースファイルの存在を消す!ってことが重要です


参考までに、この現象は、xserverで遭遇しました。
SQLite3のバージョンは、SQLite version 3.3.6です。
PHPのバージョンは、7.0.16です。

 

↓↓レンタルサーバーのオススメはコレ!↓↓

 

 

posted by scripts at 12:10 | Comment(0) | TrackBack(0) | php
この記事へのコメント
コメントを書く

お名前:

メールアドレス:


ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバックURL
http://fanblogs.jp/tb/6872938
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック
最新記事
最新コメント
タグクラウド
カテゴリアーカイブ
×

この広告は30日以上新しい記事の更新がないブログに表示されております。