riak-erlang-client
                                2012/12/11 @nobu_k




Thursday, December 13, 12
自己紹介
                    • 久保田展行(@nobu_k)

                    • Preferred Infrastructure(PFI, ピーFI)

                            • Architect: Sedue, Bazil
                    • DB, Distributed Systems, C++
                    • Erlang素人

                            • Riakのコードを読みながら勉強したい
                    •       IIDX




Thursday, December 13, 12
読むもの

                    • riak-erlang-client
                    • +周辺のコード

                            • riak_pb (pb=Protocol Buffers)
                            • riak_kv
                             • リクエストを処理してる部分


Thursday, December 13, 12
riak-erlang-client



Thursday, December 13, 12
概要


                    • Erlang用のクライアント

                    • ソースコード

                            • git://github.com/basho/riak-erlang-
                              client.git



Thursday, December 13, 12
使い方
                > {ok, Pid} = riakc_pb_socket:start_link(Address, Port).
                {ok,<0.34.0>}
                > riakc_pb_socket:ping(Pid).
                pong


                    • https://github.com/basho/riak-erlang-
                      client
                            • githubのREADMEがわかりやすい

                    • Portはconfigのriak_api/pb_portの値

                    • 返値のPidをriakc_pb_socketに渡す感じで

Thursday, December 13, 12
本日のターゲット


                    • riakc_obj.erl
                            • 値

                    • riakc_pb_socket.erl
                            • API



Thursday, December 13, 12
riakc_obj.erl



Thursday, December 13, 12
riak_obj.erl
                > Object = riakc_obj:new(<<"groceries">>, <<"mine">>,
                                         <<"eggs & bacon">>).
                {riakc_obj,<<"groceries">>,<<"mine">>,undefined,
                 [],undefined,<<"eggs & bacon">>}



                    • Riakに保存される値の情報

                    • riakc_obj:new(Bucket, Key, Value).
                            • getで取得する値もこれ


Thursday, December 13, 12
中身
                            -type   bucket() :: binary().
                            -type   key() :: binary() | 'undefined'.
                            -type   vclock() :: binary().
                            -type   metadata() :: dict().
                            -type   content_type() :: string().
                            -type   value() :: binary().
                            -type   contents() :: [{metadata(), value()}].


                            -record(riakc_obj, {
                                      bucket :: bucket(),
                                      key :: key(),
                                      vclock :: vclock(),
                                      contents :: contents(),
                                      updatemetadata :: dict(),
                                      updatevalue :: value()
                                     }).




Thursday, December 13, 12
関数とか


                    • recordの中身に対する操作がほとんど

                    • ところで
                            dict:store(?MD_CTYPE, CT, M1)


                            ?MD_CTYPEの頭に付いてる?はなに?

                            追記:マクロと教えて頂きました!

Thursday, December 13, 12
set系の関数はどこ?
                    • contentなどをセットする関数はない

                    • 代わりにupdateがある

                            • 今の値と更新後の値を別扱い

                            • newに渡した値はupdateに入る

                            • putするとupdateの値が保存される

                             • Riakから元のcontentsは消える

Thursday, December 13, 12
なんでcontentsは配列?
                    • コンフリクトしたときのため

                    • riakc_obj:value_count(Obj).
                    • riakc_obj:get_values(Obj).
                    • コンフリクト除去

                            • updateに適切な値を入れる

                            • 値を選択 or 適切にマージ

Thursday, December 13, 12
riakc_pb_socket.erl



Thursday, December 13, 12
riakc_pb_socket.erl
                    • RPC(?)の部分

                    • 読む順序

                            • 通信っぽい部分

                            • CRUD関係

                            • list系

                            • mapredはMasahitoさんから解説がありそう

                    • 後は実際にコードを読みながら・・・

Thursday, December 13, 12
全体的なメモ1

                    • ***_optionsの書き方が綺麗

                            • リスト+中身のパターンマッチングで再帰

                    • rpb***req
                            • riak_pbのriak_kv.protoを参照

                    • コードの40%がテスト

                            • Riakが起動してることが前提?

Thursday, December 13, 12
全体的なメモ2


                    • 基本はgen_server:call

                            • 値の入ったタプルを投げてるだけ

                            • {req, #pbなrecord, Timeout}




Thursday, December 13, 12
get/putの疑問点

                    • encode
                            • putではencodeした値を送っている

                            • getは受け取った値をそのまま返す

                                • どこかでdecodeされてる?
                    •       そもそもgen_server:callを理解してなかった

                            •   後述しますがhandle_infoの中でレスポンスを処理してます




Thursday, December 13, 12
get: サーバ側の処理
                    • リクエストの処理場所が分からない

                            • rpb***reqを処理してるとこを探す

                            • →riak_kv/riak_kv_pb_object.erl
                            • processのgetreqを処理してるやつ

                    • 中でriak:local_clientのgetを呼んでる

                            • が、今は追わなくてよさそう

Thursday, December 13, 12
get: riak_objectの処理
                    • local_clientが返した値の処理を追う

                            • riakc_objじゃなくてriak_object

                    • riak_pb_kv_codec:encode_contents
                            • 値を返す前にPBにエンコードしてる

                            • やっぱりclientでデコードが必要!?

                    • put側の処理も見てみる
                    •       TODO: vclockに対してなんかやってるのも気になる・・・



Thursday, December 13, 12
put: ちょっと寄り道
                    • clientがエンコードした値の処理され方

                            • riak_kv_pb_object.erl
                            • process putreqの中

                              • update_rpbcontentで値を取り出す

                              • ここでは明示的にデコードしてる

                  %% Update riak_object with the pbcontent provided
                  update_rpbcontent(O0, RpbContent) ->
                      {MetaData, Value} =
                          riak_pb_kv_codec:decode_content(RpbContent),
                      O1 = riak_object:update_metadata(O0, MetaData),
                        •
                      riak_object:update_value(O1, Value).

Thursday, December 13, 12
get: process_response
                    • clientに戻る

                    • decode_contentsを呼んでるとこ発見

                            • handle_info からの process_response
                            •   (再)そもそもgen_server:callを理解してなかった
               process_response(#request{msg = #rpbgetreq{bucket = Bucket, key = Key}},
                                #rpbgetresp{content = RpbContents, vclock = Vclock},
                                State) ->
                   Contents = riak_pb_kv_codec:decode_contents(RpbContents),
                   {reply, {ok, riakc_obj:new_obj(Bucket, Key, Vclock, Contents)},
                    State};




Thursday, December 13, 12
list_keys
                    • 中身はstream_list_keysとwait

                    • strean_list_keys
                            • キーをreceiveしまくる戦法

                            • 対応するのはriak_kv_pb_bucket.erl

                            • riak_clientのstream_list_keysを呼び出し

                             • 中身はまさかのmapred!?

Thursday, December 13, 12
まとめ



Thursday, December 13, 12
まとめ
                    •       riak-erlang-client
                            •   Protocol Buffersを使ってる

                            •   riak_kv/src/riak_kv_pb_{bucket,object}.erlに対応

                    •       すごいエロ本(Learn You Some Erlang for Great Good!)は神

                            •   分からないところを調べながらやってました!

                            •   翻訳した@ymotongpooさんも神

                    •       TODO
                            •   vclockまわり

                            •   サーバ側のリクエスト処理部をもうちょっと追いたい


Thursday, December 13, 12

Riak Source Code Reading #2: Erlang Client

  • 1.
    riak-erlang-client 2012/12/11 @nobu_k Thursday, December 13, 12
  • 2.
    自己紹介 • 久保田展行(@nobu_k) • Preferred Infrastructure(PFI, ピーFI) • Architect: Sedue, Bazil • DB, Distributed Systems, C++ • Erlang素人 • Riakのコードを読みながら勉強したい • IIDX Thursday, December 13, 12
  • 3.
    読むもの • riak-erlang-client • +周辺のコード • riak_pb (pb=Protocol Buffers) • riak_kv • リクエストを処理してる部分 Thursday, December 13, 12
  • 4.
  • 5.
    概要 • Erlang用のクライアント • ソースコード • git://github.com/basho/riak-erlang- client.git Thursday, December 13, 12
  • 6.
    使い方 > {ok, Pid} = riakc_pb_socket:start_link(Address, Port). {ok,<0.34.0>} > riakc_pb_socket:ping(Pid). pong • https://github.com/basho/riak-erlang- client • githubのREADMEがわかりやすい • Portはconfigのriak_api/pb_portの値 • 返値のPidをriakc_pb_socketに渡す感じで Thursday, December 13, 12
  • 7.
    本日のターゲット • riakc_obj.erl • 値 • riakc_pb_socket.erl • API Thursday, December 13, 12
  • 8.
  • 9.
    riak_obj.erl > Object = riakc_obj:new(<<"groceries">>, <<"mine">>, <<"eggs & bacon">>). {riakc_obj,<<"groceries">>,<<"mine">>,undefined, [],undefined,<<"eggs & bacon">>} • Riakに保存される値の情報 • riakc_obj:new(Bucket, Key, Value). • getで取得する値もこれ Thursday, December 13, 12
  • 10.
    中身 -type bucket() :: binary(). -type key() :: binary() | 'undefined'. -type vclock() :: binary(). -type metadata() :: dict(). -type content_type() :: string(). -type value() :: binary(). -type contents() :: [{metadata(), value()}]. -record(riakc_obj, { bucket :: bucket(), key :: key(), vclock :: vclock(), contents :: contents(), updatemetadata :: dict(), updatevalue :: value() }). Thursday, December 13, 12
  • 11.
    関数とか • recordの中身に対する操作がほとんど • ところで dict:store(?MD_CTYPE, CT, M1) ?MD_CTYPEの頭に付いてる?はなに? 追記:マクロと教えて頂きました! Thursday, December 13, 12
  • 12.
    set系の関数はどこ? • contentなどをセットする関数はない • 代わりにupdateがある • 今の値と更新後の値を別扱い • newに渡した値はupdateに入る • putするとupdateの値が保存される • Riakから元のcontentsは消える Thursday, December 13, 12
  • 13.
    なんでcontentsは配列? • コンフリクトしたときのため • riakc_obj:value_count(Obj). • riakc_obj:get_values(Obj). • コンフリクト除去 • updateに適切な値を入れる • 値を選択 or 適切にマージ Thursday, December 13, 12
  • 14.
  • 15.
    riakc_pb_socket.erl • RPC(?)の部分 • 読む順序 • 通信っぽい部分 • CRUD関係 • list系 • mapredはMasahitoさんから解説がありそう • 後は実際にコードを読みながら・・・ Thursday, December 13, 12
  • 16.
    全体的なメモ1 • ***_optionsの書き方が綺麗 • リスト+中身のパターンマッチングで再帰 • rpb***req • riak_pbのriak_kv.protoを参照 • コードの40%がテスト • Riakが起動してることが前提? Thursday, December 13, 12
  • 17.
    全体的なメモ2 • 基本はgen_server:call • 値の入ったタプルを投げてるだけ • {req, #pbなrecord, Timeout} Thursday, December 13, 12
  • 18.
    get/putの疑問点 • encode • putではencodeした値を送っている • getは受け取った値をそのまま返す • どこかでdecodeされてる? • そもそもgen_server:callを理解してなかった • 後述しますがhandle_infoの中でレスポンスを処理してます Thursday, December 13, 12
  • 19.
    get: サーバ側の処理 • リクエストの処理場所が分からない • rpb***reqを処理してるとこを探す • →riak_kv/riak_kv_pb_object.erl • processのgetreqを処理してるやつ • 中でriak:local_clientのgetを呼んでる • が、今は追わなくてよさそう Thursday, December 13, 12
  • 20.
    get: riak_objectの処理 • local_clientが返した値の処理を追う • riakc_objじゃなくてriak_object • riak_pb_kv_codec:encode_contents • 値を返す前にPBにエンコードしてる • やっぱりclientでデコードが必要!? • put側の処理も見てみる • TODO: vclockに対してなんかやってるのも気になる・・・ Thursday, December 13, 12
  • 21.
    put: ちょっと寄り道 • clientがエンコードした値の処理され方 • riak_kv_pb_object.erl • process putreqの中 • update_rpbcontentで値を取り出す • ここでは明示的にデコードしてる %% Update riak_object with the pbcontent provided update_rpbcontent(O0, RpbContent) -> {MetaData, Value} = riak_pb_kv_codec:decode_content(RpbContent), O1 = riak_object:update_metadata(O0, MetaData), • riak_object:update_value(O1, Value). Thursday, December 13, 12
  • 22.
    get: process_response • clientに戻る • decode_contentsを呼んでるとこ発見 • handle_info からの process_response • (再)そもそもgen_server:callを理解してなかった process_response(#request{msg = #rpbgetreq{bucket = Bucket, key = Key}}, #rpbgetresp{content = RpbContents, vclock = Vclock}, State) -> Contents = riak_pb_kv_codec:decode_contents(RpbContents), {reply, {ok, riakc_obj:new_obj(Bucket, Key, Vclock, Contents)}, State}; Thursday, December 13, 12
  • 23.
    list_keys • 中身はstream_list_keysとwait • strean_list_keys • キーをreceiveしまくる戦法 • 対応するのはriak_kv_pb_bucket.erl • riak_clientのstream_list_keysを呼び出し • 中身はまさかのmapred!? Thursday, December 13, 12
  • 24.
  • 25.
    まとめ • riak-erlang-client • Protocol Buffersを使ってる • riak_kv/src/riak_kv_pb_{bucket,object}.erlに対応 • すごいエロ本(Learn You Some Erlang for Great Good!)は神 • 分からないところを調べながらやってました! • 翻訳した@ymotongpooさんも神 • TODO • vclockまわり • サーバ側のリクエスト処理部をもうちょっと追いたい Thursday, December 13, 12