[groonga-dev,00627] Re: groongaコマンドによるload文の連続実行で一部のカラムの値が混ざる

Back to archive index

Kouhei Sutou kou****@clear*****
2011年 11月 22日 (火) 19:17:54 JST


須藤です。

In <4EC5C****@maric*****>
  "[groonga-dev,00625] groongaコマンドによるload文の連続実行で一部のカラムの値が混ざる" on Fri, 18 Nov 2011 11:17:08 +0900,
  "Michisu, Toshikazu" <michi****@maric*****> wrote:

> 初めて投稿します。マリーチの道須と申します。
> grnwrapというスクリプトを書いた者です。 (https://github.com/michisu
> /grnwrap)

便利なツールを作ってくれてありがとうございます!

> いつもGroongaを便利に利用させていただいています。

ありがとうございます!

> load文の実行で不思議な現象に出会いましたので、ご報告いたします。

詳細な説明ありがとうございます。
とても助かります。

> OS: Amazon Linux 64bit(EC2)
> Groongaのバージョン: 1.2.3
> 現象: groongaコマンドによるload文の連続実行で一部のカラムの値が混ざる

念のため、最新のgroongaでも確認してもらえると嬉しいのですが、
変更点を見る限り、直ってはいなそうです。。。すみません。。。

> 後述の(1)のように、1文書が含まれたload文を複数回(〜数万回)記述したファ
> イルがあります。

loadを複数回実行という使い方はこれまであまり使われていないパ
ターンな気がします。怪しいですね。。。

ということで、そのようなケースになったらどうなるか、という観
点でソースコードを確認してみたのですが、怪しそうなところはあ
りませんでした。。。

loadで上書き更新だけではなくdeleteでレコード削除も行なってい
る、などはあるでしょうか?新規で登録すると問題がないというこ
となので、更新・削除が絡む問題なのかもしれないと予想していま
す。(あまり自信なし。)

> このファイルをgroongaコマンドでDBに読み込ませると、一部のレコードの一部
> のカラムの値が破損します。
> 
> 読み込み後、(2)のように、
> item_id(正): "fa9442097ecc7d21d9500de661ffd93fe85020fc" が、
> item_id(誤): "salus-naturalbeauty_PT-31-13-000087440fc"
> に変わっています。
> 当然ながら、load文を記述したファイル内に、同じ_keyのレコードは複数存在し
> ません。
> 
> この誤った値はシステム上に存在しないため、謎だと思っていたのですが、該当
> ファイル内の(1)よりも後ろに(3)のレコードがあることを発見しました。
> item_id: "salus-naturalbeauty_PT-31-13-00008744"
> この値と、正しい値の末尾が連結されている(上書きされている)ように見えます。
> なお、(3)のレコードは正しく登録されているようです。

怪しいですね。groongaでは内部では文字列を「'\0'で終端するバ
イト列」ではなく、「バイト列+長さ」で扱っているため「長さ」
を間違えるとそのようなことが発生しそうです。

ただ、(1)のすぐ次に(3)がある、ということではないんですよ
ね。。。すぐ次ならだいぶ怪しいのですが。。。

> 何か情報が足りなかったり、行っている方法がまずければご指摘をいただけると
> 助かります。

↑でも少し触れましたが、もし、データの更新関係でload以外も使っ
ていたりする場合はその使い方を教えて頂けるともしかしたら何か
のヒントになるかもしれません。

あと、もしよろしければ、壊れた状態のデータベースに対して以下
のコマンドを実行した結果を教えてもらえますか?

  % groonga DB_PATH check Item.item_id

何か意味のわからないものがでてくるかと思いますが、もしかした
らカラムの中身が壊れているかもしれないので念のため確認させて
もらえると嬉しいです。


あとは。。。
もし、私がこのシステムに直接触れるとしたら、1load単位でデー
タを更新しているという事なので、loadしてすぐにloadしたデータ
の内容が壊れていないか(正しい値で更新されているか)を確認す
るラッパースクリプトみたいなものを書いて様子を見てみる気がし
ます。

Rubyだとこんな感じになるのかしら。。。

  groonga = open("|groonga db", "r+")
  buffer = ""
  ARGF.each_line do |line|
    case line
    when /^load/
      unless buffer.empty?
        expected = # bufferからJSON部分だけを取り出す。
        groonga.write(buffer)
        puts groonga.gets
        groonga.write("select Item --query _key:#{input['_key']}\n")
        result = groonga.gets
        unless expected == resultからデータを取り出す
          puts "load失敗!?: #{buffer}"
        end
        buffer.clear
      end
    end
    buffer << line
  end
  unless buffer.empty?
    groonga.write(buffer)
    puts groonga.gets
  end

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

プログラミングが好きなソフトウェア開発者を募集中:
  http://www.clear-code.com/recruitment/




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