メイン

[MySQL][Rails] Lost connection to MySQL server during query

こんにちわ。ばたっちです。

Railsのユニットテスト中にタイトルのエラーが出ることがあります。
調べてみたら、結構話題になってるみたいですね。

http://d.hatena.ne.jp/Rommy/20070814/p1
http://idm.s9.xrea.com/ratio/2006/04/08/000406.html


ユニットテストのエラーを見てると、
「Message: ActiveRecord::StatementInvalid: Mysql::Error: Lost connection to MySQL server during query」
と、
「Message: Errno::ECONNREFUSED: Connection refused - /tmp/mysql.sock」
が交互に出ている。

DB接続が切断(mysqld再起動?)→DB接続失敗を繰り返しているみたいですね。


MySQLのマニュアルを見てみると、どうやら MySQLクライアント―サーバ間で大きなサイズの
パケットが送られると接続が切れるそうです。

MySQL 4.1 リファレンスマニュアル :: A.2.9. Packet too large エラー
http://dev.mysql.com/doc/refman/4.1/ja/packet-too-large.html

my.cnfの [mysqld]セクションの max_allowed_packet を 1M→16Mに変更してみたらビンゴ。


[mysqld]
  :
max_allowed_packet = 16M
  :

/etc/init.d/mysql restart でMySQL再起動したら、ユニットテストが通るようになりました。
よかったよかった。A^^;


(追記)

一時的にうまくいっていたようで問題が再発。。orz

mysqld.logを見てみると「mysqld got signal 11」が始まるログが吐かれていて、
thd->query at 0xXXXXXXXX = DELETE FROM table1
というように、DELETE文実行時にエラーになっている模様。

MySQL+Senna(Tritonn)の全文検索を使っているのですが、下記のバージョンで修正された
「条件無しdeleteを実行するとインデックスのフラグ情報が欠けてしまう問題」というのが怪しそう。

http://qwik.jp/tritonn/ChangeLog.html#mysql-5_0_45-tritonn-1_0_7

MySQLのバージョンは変更できないので、条件なしDELETEにならない方法を考えることにしました。

エラーが発生しているのはユニットテストで、FULLTEXT INDEXを設定したテーブルに対する fixtureのロード中。
なので、test_helper.rbで fixtureロード中の DELETE文で WHERE句を追加するようにしてみました。


test/test_helper.rb
----
+class Fixtures < YAML::Omap
+  FULLTEXT_TABLES = ["table1"]
+  def delete_existing_fixtures
+    where = (FULLTEXT_TABLES.include?(@table_name)) ? "WHERE id>0" : ""
+    @connection.delete "DELETE FROM #{@table_name} #{where}", 'Fixture Delete'
+  end
+end

ファイルの最後に追加すればOKです。

FULLTEXT_TABLESに FULLTEXT INDEXを設定してあるテーブルを追加すれば、DELETE文に「WHERE id>0」を挿入します。
idフィールドがない(Railsで作ったテーブルなら通常はありますが)場合は、ここでテーブル毎の SQLを作るようにします。
(ちなみに「WHERE 1=1」みたいなのはダメみたい)

これでユニットテストのエラーが発生しなくなりました♪(^^)v

トラックバック

このエントリーのトラックバックURL:
http://pw.tech-arts.co.jp/cgi-bin/tamt32/mt-tb.cgi/70

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)