Get around the confusing documentation of Riak client for Erlang
Someone told me that Riak is a good K/V store to work with, it’s very scalable, and it’s written in Erlang. Since my application is also written in Erlang, that sounds like a good thing to try out.
I have been working with MongoDB, and it’s actually quite nice, although the Erlang driver is not an officially supported one from the company. But the Foursquare incident got me thinking. I took a look at Riak, and the distributed architecture seems very interesting to me.
So I downloaded the latest stable server and client library for Erlang. The server package installed and started up without any problem.
When compiling the client library, I got the following error:
xp@shanghai:~/project-workspace/erlang/basho-riak-erlang-client-a1545e5$ make
./rebar get-deps
==> basho-riak-erlang-client-a1545e5 (get-deps)
Pulling protobuffs from {hg,"http://bitbucket.org/basho/protobuffs",
"protobuffs-0.5.0"}
requesting all changes
adding changesets
adding manifests
adding file changes
added 91 changesets with 243 changes to 93 files (+2 heads)
29 files updated, 0 files merged, 0 files removed, 0 files unresolved
==> protobuffs (get-deps)
./rebar compile
==> protobuffs (compile)
Compiled src/pokemon_pb.erl
Compiled src/protobuffs.erl
Compiled src/protobuffs_parser.erl
Compiled src/protobuffs_compile.erl
==> basho-riak-erlang-client-a1545e5 (compile)
Compiling src/riakclient.proto
src/riakc_pb_socket.erl:73: type ctx() undefined
src/riakc_pb_socket.erl:73: type rpb_req() undefined
src/riakc_pb_socket.erl:78: type option() undefined
src/riakc_pb_socket.erl:79: Warning: type option() is unused
src/riakc_pb_socket.erl:87: Warning: type rpb_req() is unused
src/riakc_pb_socket.erl:88: Warning: type ctx() is unused
make: *** [compile] Error 1
Ok, so it got nowhere. That should not be a deterrence, right? I just grabbed the latest code from the tip instead:
hg clone http://bitbucket.org/basho/riak-erlang-client
Everything built just fine, so it’s now time to test it. I started reading the documentation and started an Erlang shell and ran through the example:
xp@shanghai:~/project-workspace/erlang/riak-erlang-client/ebin$ erl -pa `pwd`
Erlang R13B03 (erts-5.7.4) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.4 (abort with ^G)
1> code:which(riakc_pb_socket).
"/home/xp/project-workspace/erlang/riak-erlang-client/ebin/riakc_pb_socket.beam"
2> {ok, Pid} = riakc_pb_socket:start_link("127.0.0.1", 8087).
{ok,<0.38.0>}
3> riakc_pb_socket:ping(Pid).
pong
4> Object = riakc_obj:new(<<"groceries">>, <<"mine">>, <<"egg & bacon">>).
{riakc_obj,<<"groceries">>,<<"mine">>,undefined,[],
undefined,<<"egg & bacon">>}
5> riakc_pb_socket:put(Pid, Object).
=ERROR REPORT==== 10-Dec-2010::15:45:55 ===
** Generic server <0.38.0> terminating
** Last message in was {req,
{rpbputreq,<<"groceries">>,<<"mine">>,undefined,
{rpbcontent,<<"egg & bacon">>,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,undefined},
undefined,undefined,undefined},
60000}
** When Server state == {state,"127.0.0.1",8087,false,false,#Port<0.627>,
undefined,
{[],[]},
1,[],infinity,100}
** Reason for termination ==
** {'module could not be loaded',
[{protobuffs,encode,[1,<<"groceries">>,bytes]},
{riakclient_pb,iolist,2},
{riakc_pb,encode,1},
{riakc_pb_socket,send_request,2},
{riakc_pb_socket,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}
** exception exit: undef
in function protobuffs:encode/3
called as protobuffs:encode(1,<<"groceries">>,bytes)
in call from riakclient_pb:iolist/2
in call from riakc_pb:encode/1
in call from riakc_pb_socket:send_request/2
in call from riakc_pb_socket:handle_call/3
in call from gen_server:handle_msg/5
in call from proc_lib:init_p_do_apply/3
Oh well, so I got stuck again. I didn’t scan the error code carefully, and thought that it might be related to the default configuration. Since the document mentioned about the {w, W} option, which stated that W is the minimum number of nodes that must respond with success for the write to be considered successful, and the default is currently set on the server at 2. Since I’m running Riak on a single node, does that mean the configuration is causing the error?
I tried to write the object again, this time by setting the W value to 1. The result is no go, same error.
After searching in a lot of places without results, I then looked carefully at the error, and saw something undef. Some functions have not been loaded correctly. Digging into the code to see what’s going on, it looked like it’s got something to do with the Protocol Buffer API stuff. Going back to the Riak Client project structure to see where that code would be put in, and I found it in the deps directory.
Oh so that’s what you need to add to your search path as well. Starting Erlang shell like this would work:
erl -pa $RIAKC_PATH/ebin $RIAKC_PATH/deps/protobuffs/ebin
Now you can write and read from Riak.
That’s a lot of frustration for nothing, the document could save people a lot of time by providing the correct information. It turns out the initial client library compilation was because it only supported R13B04 and above, and that’s not mentioned anywhere either. My Ubuntu 10.10 has a version that is slightly earlier than that, and it got stuck. I upgraded my Erlang to R14B and it compiled without problem. The code that I grabbed from the tip had a fix that also supports earlier release of Erlang.