Erlang Aerospike Client
- Uses Aerospike Binary protocol,
aspike-protocol, https://github.com/vsavkov/aspike-protocol - Uses
shackle, High-Performance Erlang Network Client Framework, https://github.com/lpgauth/shackle
$ rebar3 compile- Aerospike Cluster Standard/Enterprise/Cloud (https://aerospike.com/products/features-and-editions/);
- Aerospike Cluster Community Edition (CE) (https://hub.docker.com/r/aerospike/aerospike-server);
- Aerospike Server Emulator (EM) (https://github.com/vsavkov/aspike-server).
Follow the instructions on https://hub.docker.com/r/aerospike/aerospike-server
- Clone https://github.com/vsavkov/aspike-server;
- From terminal, in
aspike-serverdirectory, run
iex -S mix
[info] Accepting connections on port 4040
[info] Accepting connections on port 4041Aerospike Server Emulator accepts its own text protocol on port 4040.
Aerospike Server Emulator accepts Aerospike binary protocol on port 4041.
- Create
namespacetestfor the following examples
- From another terminal run
telnetornc(akanetcat)
nc -vv 127.0.0.1 4040- To create
namespacetest, type in
CREATE test
- To check that
namespacetestexists, type in
NAMESPACES
[test]
OK
indicates that `namespace` `test` exists.
From aspike-node directory run
$ rebar3 shell
Start shackle
1> application:ensure_all_started(shackle).
{ok,[granderl,metal,compiler,syntax_tools,foil,shackle]}Prepare parameters to connect to an Aerospike node
2> rr("include/aspike.hrl").
[aspike_connection_options,aspike_endpoint,aspike_node_params,aspike_pool_options,aspike_user]3> Endpoint_CE = #aspike_endpoint{name = "Node_CE", address = "127.0.0.1", port = 3000}.
4> User_CE = #aspike_user{name = "User", credential = "password"}.
5> Socket_options = [{mode, binary}, {packet, raw}, {buffer, 65535}, {nodelay, true}, {send_timeout, 50}, {send_timeout_close, true}].
6> Connection_options = #aspike_connection_options{reconnect = false, reconnect_time_min = 2_000, reconnect_time_max = 120_000, socket_options = Socket_options}.
7> Pool_options = #aspike_pool_options{backlog_size = 1_024, max_retries = 0, pool_size = 1, pool_strategy = random}.
8> Node_params_CE = #aspike_node_params{endpoint = Endpoint_CE, user = User_CE, connection_options = Connection_options, pool_options = Pool_options}.
9> Node_id_CE = node_CE.
11> #aspike_pool_options{pool_size = Pool_size} = Pool_options.
12> Pool_size.
1Connect to the node
10> aspike_node:start(Node_id_CE, Node_params_CE).
okCheck that connection(s) established
11> [shackle_status:active({Node_id_CE, I}) || I <- lists:seq(1, Pool_size)].
[true]Prepare key digest
12> Set = "set1", Key1 = "key1", Key1_digest = aspike_protocol:digest(Set, Key1).Put key-value
13> aspike_node:put(Node_id_CE, "test", Set, Key1_digest, [{"bin1", "value1"}]).
okGet key-value
14> aspike_node:get(Node_id_CE, "test", Set, Key1_digest, []).
{ok,[{"bin1","value1"}]}Check, if key exists
15> aspike_node:exists(Node_id_CE, "test", Set, Key1_digest).
trueRemove key
16> aspike_node:remove(Node_id_CE, "test", Set, Key1_digest).
okCheck, if the removed key exists
17> aspike_node:exists(Node_id_CE, "test", Set, Key1_digest).
falseGet the removed key
18> aspike_node:get(Node_id_CE, "test", Set, Key1_digest, []).
{error,record_not_found}Async put key-value
19> Ref_put = aspike_node:async_put(Node_id_CE, "test", Set, Key1_digest, [{"bin1", "value1"}]).
20> aspike_node:receive_response(Ref_put).
okAsync get key
21> Ref_get = aspike_node:async_get(Node_id_CE, "test", Set, Key1_digest, []).
22> aspike_node:receive_response(Ref_get).
{ok,[{"bin1","value1"}]}3> Endpoint_EM = #aspike_endpoint{name = "Node_EM", address = "127.0.0.1", port = 4041}.Aerospike Server Emulator, as Aerospike Cluster Standard/Enterprise/Cloud, requires Blowfish-encrypted password.
(WARNING! The encryption rate of the implementation is slow, could take 2-5 seconds to encrypt password)
4> Credential = aspike_blowfish:crypt("pass1").
<<"$2a$10$7EqJtq98hPqEX7fNZaFWoOOY1Ba9.gZNwHJkrSKJl7mXQyPCsCrQa">>4> User_EM = #aspike_user{name = "User1", credential = Credential}.
5> Socket_options = [{mode, binary}, {packet, raw}, {buffer, 65535}, {nodelay, true}, {send_timeout, 50}, {send_timeout_close, true}].
6> Connection_options = #aspike_connection_options{reconnect = false, reconnect_time_min = 2_000, reconnect_time_max = 120_000, socket_options = Socket_options}.
7> Pool_options_EM = #aspike_pool_options{backlog_size = 1_024, max_retries = 0, pool_size = 3, pool_strategy = random}.
8> Node_params_EM = #aspike_node_params{endpoint = Endpoint_EM, user = User_EM, connection_options = Connection_options, pool_options = Pool_options_EM}.
9> Node_id_EM = node_EM.
11> #aspike_pool_options{pool_size = Pool_size_EM} = Pool_options_EM.
12> Pool_size_EM.
3Connect to the node
10> aspike_node:start(Node_id_EM, Node_params_EM).
okCheck that connection(s) established
11> [shackle_status:active({Node_id_EM, I}) || I <- lists:seq(1, Pool_size_EM)].
[true,true,true]Prepare key digest
12> Set_EM = "set1", Key_EM = "key1-EM", Key_EM_digest = aspike_protocol:digest(Set_EM, Key_EM).Put key-value
13> aspike_node:put(Node_id_EM, "test", Set_EM, Key_EM_digest, [{"bin1_EM", "value1_EM"}]).If namespace test was not created as descibed in Aerospike Server Emulator (EM) Setup, then the response will be as follows
{error,{20,<<"AEROSPIKE_ERR_NAMESPACE_NOT_FOUND">>, <<"Namespace in request not found on server.">>}}Otherwise,
okGet key-value
14> aspike_node:get(Node_id_EM, "test", Set_EM, Key_EM_digest, []).
{ok,[{"bin1_EM","value1_EM"}]}Check, if key exists
15> aspike_node:exists(Node_id_EM, "test", Set_EM, Key_EM_digest).
trueRemove key
16> aspike_node:remove(Node_id_EM, "test", Set_EM, Key_EM_digest).
okCheck, if the removed key exists
17> aspike_node:exists(Node_id_EM, "test", Set_EM, Key_EM_digest).
falseGet the removed key
18> aspike_node:get(Node_id_EM, "test", Set_EM, Key_EM_digest, []).
{error,record_not_found}Async put key-value
19> Ref_put_EM = aspike_node:async_put(Node_id_EM, "test", Set_EM, Key_EM_digest, [{"bin2_EM", "value2_EM"}, {"bin3_EM", 123}]).
20> aspike_node:receive_response(Ref_put_EM).
okAsync get key
21> Ref_get_EM = aspike_node:async_get(Node_id_EM, "test", Set_EM, Key_EM_digest, []).
22> aspike_node:receive_response(Ref_get_EM).
{ok,[{"bin2_EM","value2_EM"},{"bin3_EM",123}]}