[groonga-dev,03236] Re: mroongaで同一レコードの登録、削除を繰り返すと値が抜ける事がある

Back to archive index

Kouhei Sutou kou****@clear*****
2015年 5月 15日 (金) 23:00:42 JST


須藤です。

In <20150****@domai*****>
  "[groonga-dev,03229] mroongaで同一レコードの登録、削除を繰り返すと値が抜ける事がある" on Thu, 14 May 2015 18:30:39 +0900,
  各務 洋 <kagam****@outwa*****> wrote:

> 同一レコードの登録、削除を連続で繰り返すと、値が抜けた状態で保存される
> のが見えましたのでお送りします。

これは仕様なんです。

Mroongaはデータストアはカラムストアタイプで、最小の更新操作
はたとえば次のようなものです。

  * 1レコードの追加・削除(レコードのみ。カラムは別。)
  * 1レコード内の1カラムの値の設定

つまり、「レコードを追加して全部のカラムの設定」は最小の更新
操作ではありません。

最小の更新操作でないということは途中の状態が見えるということ
です。

たとえば、

> +------+---+-------+---------------------+
> | 1517 | 1 | test1 | 0000-00-00 00:00:00 |
> +------+---+-------+---------------------+

は、「レコードの追加」と「カラムの値の設定」 * 3個が終わった
状態が見えています。

> +---+---+--+---------------------+
> | 0 | 0 |  | 0000-00-00 00:00:00 |
> +---+---+--+---------------------+

は、「レコードの追加」終わった状態が見えています。

> +------+---+--+---------------------+
> | 2113 | 0 |  | 0000-00-00 00:00:00 |
> +------+---+--+---------------------+

は、「レコードの追加」と「カラムの値の設定」 * 1個が終わった
状態が見えています。

「レコードの追加とすべてのカラムの設定」が終わるまで見えない
で欲しい場合は次のようにロックをかけてください。

LOCK TABLES tbl_test_pat_0002 WRITE;
INSERT INTO tbl_test_pat_0002 (a_id, t_key, t_date) VALUES (1, 'test1', '0000-00-00');
UNLOCK TABLES;

LOCK TABLES tbl_test_pat_0002 WRITE;
DELETE FROM tbl_test_pat_0002 WHERE a_id = 1;
UNLOCK TABLES;

こうすると、「すべてのカラムが設定されたレコードが見える」か、
「レコードが削除された状態が見える(= なにも見えない)」かの
どちらかになります。

> ENGINE = innodb で作成すると発生しない。(そして遅い)

InnoDBは「レコードを追加して全部のカラムの設定」が最小の更新
操作になっているからです。

> 実際に
> +---+---+--+---------------------+
> | 0 | 0 |  | 0000-00-00 00:00:00 |
> +---+---+--+---------------------+
> で止まった状態のレコードは確認できなかったものの、このテストとは別件で、
> 数日前に本番環境でリリース準備をしていたところ、テーブルが壊れたとの報
> 告があり、確認したところ
> 
> +---+---+--+---------------------+
> | 0 | 0 |  | 0000-00-00 00:00:00 |
> | 0 | 0 |  | 0000-00-00 00:00:00 |
> +---+---+--+---------------------+
> このような2レコードのみが格納された状態になっていました。
> ※本番環境 mroonga 4.01

手元だと最終的には0件になったんですが、そうではなく2件残った
ということですか?

そのとき、INSERT/DELETEしている接続は1つだけでしたか?それと
も複数の接続からINSERT/DELETEしていましたか?

もし、複数の接続からINSERT/DELETEしていて、DELETEするときの
WHEREが同じものがあったのなら起こりえる気がします。具体的に
は次のタイミングのときに起こると思います。

接続1がINSERT、接続2がDELETEをしているとします。

INSERT: INSERT INTO tbl_test_pat_0002 (a_id, t_key, t_date) VALUES (1, 'test1', '0000-00-00');
DELETE: DELETE FROM tbl_test_pat_0002 WHERE a_id = 1;

  1-a. レコードを作る
  2-a. a_id=1でレコードを検索
  1-b. a_id=1をユニークキーに登録
  1-c. a_id=1でユニークキーが登録されたのでカラムの登録を開始
  1-d. a_id=1を保存
  1-e. t_key='test1'を保存
  1-f. t_date='0000-00-00'を保存
  2-b. 検索して見つからなかったのでなにも削除しない(レコードが残る)

なんか書いていてあれ?こう?とか思いながら書いていますが、↑
じゃなくても期待しない結果になることはある気がします。

それを防ぎたい場合はLOCK TABLESするようにしてください。

-- 
須藤 功平 <kou****@clear*****>
株式会社クリアコード <http://www.clear-code.com/>

Groongaベースの全文検索システムを総合サポート:
  http://groonga.org/ja/support/
パッチ採用 - プログラミングが楽しい人向けの採用プロセス:
  http://www.clear-code.com/recruitment/
プログラミングが好きな学生のための勉強会:
  http://www.seplus.jp/sezemi/




groonga-dev メーリングリストの案内
Back to archive index