mrb_stateを共有しているRubyコード間でuserdataを読み書きできるmruby-userdata作った

mrubyにおいて、mrb_stateを共有しているRubyコード間で、userdataを自由に読み書きできるmruby-userdataというmrbgemを作りました。

これは、mrubyの状態遷移情報を格納しているmrb_stateを共有している限り、あるタイミングでコードAが呼ばれて、次に別のタイミングでコードBが呼ばれた場合、コードAでuserdataオブジェクトを保存しておけば、コードBからそのオブジェクトを取り出せる仕組みです。

グローバル変数を使えばコード間でやり取りができますが、なんとなくグローバル変数を使うのは実装上バグを生みそうなので、C側にuserdataを保存しておくハッシュテーブルオブジェクトを作っておいて、そこにRuby側から保存したい時に保存しておき、取り出したい時に取り出すためのRubyメソッドによるインターフェイスを実装しました。

比較的安全にuserdataを保存しておけると思います。

userdataの操作例

例えば以下のようなコードAがあるとします。

[program lang=’ruby’ escaped=’true’]

u = Userdata.new
u.hoge = {:test => 1}

[/program]

このように、userdataにhogeというオブジェクト名で何かハッシュを保存しておきます。

そして、同じmrb_stateで実行される他のコードB上から、以下のようなコードを実行すると、

[program lang=’ruby’ escaped=’true’]

u = Userdata.new
hash = u.hoge
hash[:foo] = 2
u.hoge = hash

p u.hoge # => {:test => 1, :foo =>2}

[/program]

このように、別のコードで保存しておいたuserdataオブジェクトを取り出して、さらに上書きすることができます。

userdataキーを使う場合

さらに、Userdataインスタンス生成時に、引数にキーを渡す事で、userdataキーによって保存しておきたいuserdataを複数作る事ができます。

例えば、以下のようなmirb結果になります。

[program lang=’ruby’ escaped=’true’]

mirb - Embeddable Interactive Ruby Shell

This is a very early version, please test and report errors.
Thanks :)

> u = Userdata.new
 => #<Userdata:0x7f96ca808ad0 mrb_userdata_key_store="mrb_userdata_default_key">
> u.hoge
 => nil
> u.hoge = 1
 => 1
> u.hoge
 => 1
> q = Userdata.new
 => #<Userdata:0x7f96ca808590 mrb_userdata_key_store="mrb_userdata_default_key">
> q.hoge
 => 1
> q.hoge = q.hoge + 1
 => 2
> u.hoge
 => 2
> s = Userdata.new "my_key"
 => #<Userdata:0x7f96ca807d80 mrb_userdata_key_store="my_key">
> s.hoge
 => nil
> s.hoge = 1
 => 1
> u.hoge
 => 2
> q.hoge
 => 2

[/program]

何もuserdataキーの指定がない場合は、デフォルトのuserdataキー名を使用するので、uインスタンスもqインスタンスも同じuserdataを参照できています。

一方で、”my_key”という独自のuserdataキーを指定したsインスタンスは、uやqインスタンスとは違うuserdataを扱えている事がわかります。

最後に

このように、mrb_stateを共有している場合のメリットとして、userdataの受け渡しが可能なmrbgemを作りました。これによって、mod_mrubyやngx_mrubyにおいて、初期化時にredisに接続しておいて、そのredisコンテキストオブジェクトをuserdataに保存しておけば、次のフックのタイミングで、redisに再接続することなくredisコンテキストオブジェクトを取り出して、redisの操作をすることが可能になるでしょう。

これで色々捗りそうです。