shimxmemo

メモをのこすよ!

Q4MにてSELECT COUNTで件数がとれるがSELECT *もdequeueもできない場合の強引な対処

某日Q4Mが動いているサーバがダウンしまして。

 

再起動後、Q4Mを立ち上げなおした所、Worker(Perl製。参照 http://perl-users.jp/articles/advent-calendar/2009/data-model/22.html)がQueueを受け取れなくなってました。

 

mysql> SELECT COUNT(*) FROM queue_table;
+----------+
| COUNT(*) |
+----------+
|   365474 |
+----------+
1 row in set (0.00 sec)

と件数がとれるんですが、

mysql> SELECT * FROM queue_table LIMIT 2;
Empty set (0.01 sec)

と中身がとれないという、おかしなことに。

もちろんqueue_wait()もできません。

ただ、enqueueはできています。

 

今回の環境は

CentOS 6.2 + MySQL 5.1.48 + Q4M 0.9.4
※Q4Mコンパイル時のconfigureはディレクトリ指定以外デフォルト

です。

 

今回は、消えても復旧できるログだったので力技で解決する事に。

 

同じ構成でテーブル作って、実データであるQ4Mファイルをコピーすれば同様に動くんですよ…

 

対応方法1

対象テーブルは

queue_table

 

  • Worker停止、enqueueも停止
  • 移行先テーブル作成
CREATE TABLE `queue_table_` (
  `id` char(255) DEFAULT NULL,
  `job_data` blob,
  `priority` tinyint(4) unsigned DEFAULT '10'
) ENGINE=QUEUE DEFAULT CHARSET=sjis;
  • ファイル確認
cd /usr/local/mysql_q4m/var/project
ls -la queue_table.Q4M queue_table_.Q4M
  • 実データコピー
cp -ap queue_table.Q4M queue_table_.Q4M
  • MySQLからのアクセス確認
mysql> SELECT * FROM queue_table_ LIMIT 2;
mysql> SELECT COUNT(*) from queue_table_;
mysql> SELECT queue_wait('queue_table_');
mysql> SELECT * FROM queue_table_;
mysql> SELECT queue_abort();
mysql> SELECT COUNT(*) FROM queue_table_;
※データが取得できればOK
  • テーブルリネーム
ALTER TABLE `queue_table` RENAME `queue_table_bak`;
ALTER TABLE `queue_table_` RENAME `queue_table`;
  • 確認できたら古いテーブルを消す
DROP TABLE `queue_table_bak`;
  • Worker開始、問題なければenqueueも開始

 

対応方法2

対象テーブルは

queue_table2

こちらは

  • 対応1やっても無理(表題の事象が起こる)
  • select count(*)は取れるがselect *は取れない
  • Workerを回している間はselect *投げて帰ってきたり返ってこなかったりする

どうもWorkerのqueue_runningで1件dequeueしている間は、select *でとれるようだ!?

そんなバカな。だが目の前にある現実。

 

  • enqueue停止

 

  • Workerを動かす

ただし、挙動的にはqueue_wait()queue_abort()を繰り返している

 

  • 移行先テーブル作成
CREATE TABLE `queue_table2_` (
  `id` char(255) DEFAULT NULL,
  `job_data` blob,
  `priority` tinyint(4) unsigned DEFAULT '10'
) ENGINE=QUEUE DEFAULT CHARSET=sjis;
  • 実データコピー
mysql> INSERT INTO `queue_table2_` (`id`,`job_data`,`priority`) SELECT * FROM `queue_table2`;
0件ならもう一度試す
  • MySQLからのアクセス確認
mysql> SELECT * FROM queue_table2_ LIMIT 2;
mysql> SELECT COUNT(*) from queue_table2_;
mysql> SELECT queue_wait('queue_table2_');
mysql> SELECT * FROM queue_table2_;
mysql> SELECT queue_abort();
mysql> SELECT COUNT(*) FROM queue_table2_;
※データが取得できればOK

ただし、

mysql> SELECT COUNT(*) FROM queue_table2;
+----------+
| COUNT(*) |
+----------+
|   365474 |
+----------+
1 row in set (0.00 sec)

mysql> SELECT COUNT(*) FROM queue_table2_;
+----------+
| COUNT(*) |
+----------+
|   365473 |
+----------+
1 row in set (0.00 sec)

多分Workerでdequeueしている分がないんだと思う。

データが1件欠損する。

 

  • Worker停止
  • テーブルリネーム
ALTER TABLE `queue_table2` RENAME `queue_table2_bak`;
ALTER TABLE `queue_table2_` RENAME `queue_table2`;

 

  • 確認できたら古いテーブルを消す
DROP TABLE `queue_table2_bak`;

 

  • Worker開始、問題なければenqueueも開始

 

とまあ、力技で解決しました。

テーブル構造が壊れてたのかなあ。

オススメできない対処方法です。