Feature #1934

Updated by Kouhei Sutou almost 5 years ago

h2. 動機
----



現在のgroongaはクエリーオプティマイザーをCで書いている。Cで書いているため、こんな最適化はどうだろうか?などといったことを簡単に試すことができない。最適化することで1桁2桁速度が速くなることもあるので、いろいろな最適化を簡単に試すことができる仕組みが欲しい。

h2. ゴール
------


Rubyでクエリーオプティマイザーを書ける。lib/expr.c:scan_info_build()の中身をRubyで書けるとよい。 Rubyでクエリーオプティマイザーを書ける。例えば、こんな最適化ができるとよい。

クエリーオプティマイザーでは、こんな最適化ができるとよい。(これはこのチケットのゴールの範囲外。このチケットのゴールができた後の話。)

現在は"10 < a && a < 20"というクエリーを以下のように実行している。

- "10 < a"のレコードをインデックスで範囲検索してすべて取得する
- "a < 20"のレコードをインデックスで範囲検索してすべて取得する
- どちらにも含まれているレコードだけを結果として残す

しかし、上限と下限を指定して範囲検索することもできるため、最適化して以下のように実行したい。

- "10 < a < 20"のレコードをインデックスで範囲検索してすべて取得する

h2. 実現案
------


mrubyをgroongaに組み込み、Rubyでクエリーオプティマイザーを書けるようにする。mrubyの方がCより遅いがクエリーオプティマイザーの処理は検索処理に比べれば軽いので速度は問題にならないはずである。むしろ、クエリーを最適化することにより現在よりも速くなる可能性がある。

現在の実装は、grn_ctx毎にmrubyのインスタンスを持てるところまでいっている。(grn_ctx.impl.mrbがmruby_state)
しかし、groongaのmrubyバインディングがないため、mrubyからgroongaの情報を取得できないし、mrubyでgroongaのオブジェクトも作れない。

この状態からlib/expr.c:scan_info_build()の中身をRubyで書けるようになるところまでいきたい。"10 < a && a < 20"の最適化などは次の段階だろう。

mrubyバインディングの作成は以下の方針でいきたい。

* mrubyからはgroongaオブジェクトのメモリ管理をしない。単に参照するだけ。理由はGCによる停止期間を小さくしたいのと、クラッシュが怖いから。
* メモリプールみたいなCのオブジェクトを作ってそいつがメモリ管理するのがいいんじゃないかと思っている。aprのapr_poolとかnginxのngx_pool_tとかObjective-CのNSAutoreleasePoolみたいなイメージ。どうせ、scan_info_build()の中でしかRubyのコードを動かさないことがわかっているので、その間で作られたものはRubyのコードが終わったら開放できる。コードにするとこんなイメージ。

scan_info_build()
{
memory_pool *pool;
pool = pool_new();
mruby_plugin_exec(pool)
pool_destroy(pool);
}

* 最初にmruby_execコマンドを追加するプラグインを作ったほうがいいかもしれない。テストしやすそうだし。

Back