riak source code reading #2: erlang client
TRANSCRIPT
riak-erlang-client2012/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
使い方
• https://github.com/basho/riak-erlang-client
• githubのREADMEがわかりやすい
• Portはconfigのriak_api/pb_portの値
• 返値のPidをriakc_pb_socketに渡す感じで
> {ok, Pid} = riakc_pb_socket:start_link(Address, Port).{ok,<0.34.0>}> riakc_pb_socket:ping(Pid).pong
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
• Riakに保存される値の情報
• riakc_obj:new(Bucket, Key, Value).• getで取得する値もこれ
> Object = riakc_obj:new(<<"groceries">>, <<"mine">>, <<"eggs & bacon">>).{riakc_obj,<<"groceries">>,<<"mine">>,undefined, [],undefined,<<"eggs & bacon">>}
Thursday, December 13, 12
中身
-record(riakc_obj, { bucket :: bucket(), key :: key(), vclock :: vclock(), contents :: contents(), updatemetadata :: dict(), updatevalue :: value() }).
-type bucket() :: binary(). -type key() :: binary() | 'undefined'. -type vclock() :: binary(). -type metadata() :: dict(). -type content_type() :: string(). -type value() :: binary(). -type contents() :: [{metadata(), value()}].
Thursday, December 13, 12
関数とか
• recordの中身に対する操作がほとんど
• ところで
?MD_CTYPEの頭に付いてる?はなに?dict:store(?MD_CTYPE, CT, M1)
追記:マクロと教えて頂きました!
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