riak source code reading #2: erlang client

25
riak-erlang-client 2012/12/11 @nobu_k Thursday, December 13, 12

Upload: nobuk

Post on 22-May-2015

807 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Riak Source Code Reading #2: Erlang Client

riak-erlang-client2012/12/11 @nobu_k

Thursday, December 13, 12

Page 2: Riak Source Code Reading #2: Erlang Client

自己紹介• 久保田展行(@nobu_k)

• Preferred Infrastructure(PFI, ピーFI)

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

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

Thursday, December 13, 12

Page 3: Riak Source Code Reading #2: Erlang Client

読むもの

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

• riak_pb (pb=Protocol Buffers)• riak_kv

• リクエストを処理してる部分

Thursday, December 13, 12

Page 4: Riak Source Code Reading #2: Erlang Client

riak-erlang-client

Thursday, December 13, 12

Page 5: Riak Source Code Reading #2: Erlang Client

概要

• Erlang用のクライアント

• ソースコード

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

Thursday, December 13, 12

Page 6: Riak Source Code Reading #2: Erlang Client

使い方

• 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

Page 7: Riak Source Code Reading #2: Erlang Client

本日のターゲット

• riakc_obj.erl• 値

• riakc_pb_socket.erl• API

Thursday, December 13, 12

Page 8: Riak Source Code Reading #2: Erlang Client

riakc_obj.erl

Thursday, December 13, 12

Page 9: Riak Source Code Reading #2: Erlang Client

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

Page 10: Riak Source Code Reading #2: Erlang Client

中身

-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

Page 11: Riak Source Code Reading #2: Erlang Client

関数とか

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

• ところで

?MD_CTYPEの頭に付いてる?はなに?dict:store(?MD_CTYPE, CT, M1)

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

Thursday, December 13, 12

Page 12: Riak Source Code Reading #2: Erlang Client

set系の関数はどこ?

• contentなどをセットする関数はない

• 代わりにupdateがある

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

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

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

• Riakから元のcontentsは消える

Thursday, December 13, 12

Page 13: Riak Source Code Reading #2: Erlang Client

なんでcontentsは配列?

• コンフリクトしたときのため

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

• updateに適切な値を入れる

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

Thursday, December 13, 12

Page 14: Riak Source Code Reading #2: Erlang Client

riakc_pb_socket.erl

Thursday, December 13, 12

Page 15: Riak Source Code Reading #2: Erlang Client

riakc_pb_socket.erl

• RPC(?)の部分

• 読む順序

• 通信っぽい部分

• CRUD関係

• list系

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

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

Thursday, December 13, 12

Page 16: Riak Source Code Reading #2: Erlang Client

全体的なメモ1

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

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

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

• コードの40%がテスト

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

Thursday, December 13, 12

Page 17: Riak Source Code Reading #2: Erlang Client

全体的なメモ2

• 基本はgen_server:call

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

• {req, #pbなrecord, Timeout}

Thursday, December 13, 12

Page 18: Riak Source Code Reading #2: Erlang Client

get/putの疑問点

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

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

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

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

Thursday, December 13, 12

Page 19: Riak Source Code Reading #2: Erlang Client

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

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

• →riak_kv/riak_kv_pb_object.erl

• processのgetreqを処理してるやつ

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

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

Thursday, December 13, 12

Page 20: Riak Source Code Reading #2: Erlang Client

get: riak_objectの処理• local_clientが返した値の処理を追う

• riakc_objじゃなくてriak_object

• riak_pb_kv_codec:encode_contents

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

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

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

Thursday, December 13, 12

Page 21: Riak Source Code Reading #2: Erlang Client

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

Page 22: Riak Source Code Reading #2: Erlang Client

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

Page 23: Riak Source Code Reading #2: Erlang Client

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

Page 24: Riak Source Code Reading #2: Erlang Client

まとめ

Thursday, December 13, 12

Page 25: Riak Source Code Reading #2: Erlang Client

まとめ• 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