Riak_Core with Elixir : Part four
This is the 4th part in riak_core series. Till now we have done following
- Created our app with riak_core as dependency
- Initializing riak_core ring and understanding various riak_core components.
- Understanding Vnode behaviour
In this post, we will explore riak_core APIs. Riak_core provides various way in which we can interact with riak_core. These interaction involves storing or retrieve data from Vnode.
We have already setup or riak_core ring and the vnode, we can start interacting with the riak_core using below functions.
riak_core_util:chash_key/1, riak_core_vnode_master:command/3, and riak_core_vnode_master:sync_spawn_command/3
riak_core_util.chash_key/1
This function is used to hash a key.It returns an integer between 0 and 2¹⁶⁰- 1. The obtained integer refers to a particular position in Riak Core’s 160-bit circular key-space.
function signature :
doc_idx = chash_key(Key :: {any(), any()}) -> binary().
chash_key takes a key to be hashed, but interestingly this key has to be in form of two element tuple (an obvious artifact from the times when Riak Core was hardcoded in Riak ) .
Now we are going to call chash_key function passing it a two element tuple as key.
{"ping", :erlang.term_to_binary(:os.timestamp())}
here we are hashing current time so that every time we send a different key to the riak_core.
doc_idx =:riak_core_util.chash_key({"ping", :erlang.term_to_binary(:os.timestamp())})
riak_core_apl.get_primary_apl/3
get_primary_apl(HashedKey :: binary(), N :: non_neg_integer(),Service::atom()) -> [{integer(), node()}]
The list of nodes that is responsible for storing a particular key is called the active preference list.
This function is used to get the Active Preference List (APL) for a given (hashed) key. One can specify how many vnodes will be returned. An exception is thrown if the requested number of vnodes is greater than the number of partitions. The last parameter is the service name which is calling this method.
This method return a list vnodes, where each vnode is represented as a 2-element tuple where the first element (index_node) denotes the first key in the partition the vnode is responsible for (as an integer), and the second element refers to the (physical) node the vnode is running on.
So in our case, we will get_primary_apl as below:
pref_list = :riak_core_apl.get_primary_apl(doc_idx, 1, Vyuha.Service)
[{index_node, _type}] = pref_list
where doc_idx is the hashed key returned by :riak_core_util.chash_key, 1 is the number of Vnodes that we want this function to return. Last argument is the service name.
:riak_core_vnode_master.sync_spawn_command/3
sync_spawn_command(To :: any_integer, Request :: any(), Master :: atom()) -> any().
This function is similar to gen_server’s call/2 function. It is used to send a request to a particular vnode process. Note, however, that, unlike gen_server’s call/2, this function requires a third argument, which is nothing but a reference to the riak_core_vnode_master
one must start when initialising Riak Core’s ring.
This function does not block the riak_core_vnode_master
process. That is, it lets the riak_core_vnode_master
process handle multiple requests concurrently.
:riak_core_vnode_master.sync_spawn_command(index_node, :ping, Vyuha.Vnode_master)
Here we are passing index_node which we got in previous call (get_primary_apl/3). Second parameter is the command that we want to send to Vnode (this can be any thing an atom or a tuple). Third parameter is Vyuha.Vnode_master.
if you go back to Vnode module, you will see that we have defined handle_command/3 function clause there.
def handle_command(:ping, _sender, state) do
Logger.warn("got a ping request!")
{:reply, :pong, state}
end
this function clause will match the request send by :riak_core_vnode_master.sync_spawn_command, as the second parameter in this method (which is :ping) defines the request and our function clause in Vnode module will match against it and reply with :pong.
Now try to run the app with below command
iex --name nav@127.0.0.1 -S mix
App should start fine (if it doesn’t try deleting ring_state_dir and start again). Now on console call ping method on Vyuha.Service as shown below
> Vyuha.Service.ping
You should be getting response as:
11:00:44.143 [warn] got a ping request!
:pong
Code up to this point can be found here.