Skip to content

Commit

Permalink
Release 0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
vkaa committed Dec 29, 2023
1 parent a255d21 commit b73c0a6
Show file tree
Hide file tree
Showing 17 changed files with 1,756 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ clean:

compile:
@echo "Running rebar3 compile..."
@$(REBAR3) as compile compile
@$(REBAR3) compile

eunit:
@echo "Running rebar3 eunit..."
Expand Down
179 changes: 177 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,184 @@
aspike_protocol
=====

An OTP library
Implementation of Aerospike binary protocol in Erlang

Binary protocol
---------------

Aerospike Binary protocol is described in 'doc/Aerospike_packet_structure.txt'.

Aerospike Cluster Discovery is described in 'doc/Aerospike_cluster_discovery.txt'.

Build
-----

$ rebar3 compile
$ make compile

Test
-----

$ make eunit

Usage
-----
Examples can be run in the following environments:
- 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 (https://github.com/vsavkov/aspike-server).

To start Aerospike Cluster Community edition follow the instructions on https://hub.docker.com/r/aerospike/aerospike-server).

To start Aerospike Server Emulator:
1. Clone https://github.com/vsavkov/aspike-server;
2. Run command 'iex -S mix' from 'aspike-server' director;
3. Aerospike Server Emulator listens for the Aerospike protocol on port 4041;
4. Aerospike Server Emulator listens for text protocol on port 4040;
5. Use text protocol to create namespace 'test' for examples that involve Key-Value operations:

Start telnet or nc (aka netcat) in a separate terminal:

$ nc -vv 127.0.0.1 4040

type in:

CREATE test

OK

to check that namespace 'test' exists type in:

NAMESPACES

[test]

Examples
--------

$ rebar3 shell
Erlang/OTP ...

Password encryption
-------------------
Aerospike uses Blowfish cipher to encrypt password that is sent from client to cluster.

Aerospike has some specifics in Blowfish cipher implementation.

'aspike_blowfish:crypt/1' implements the Aerospike-specific Blowfish cipher.

WARNING: The encryption rate of the implementation is slow.

To encrypt password

> Encrypted = aspike_blowfish:crypt("password").
<<"$2a$10$7EqJtq98hPqEX7fNZaFWoOqUH6KN8IKy3Yk5Kz..RHGKNAUCoP/LG">>

NOTE: Aerospike CE does not require LOGIN, but accept LOGIN as no op.

Cluster Login
-------------

> c("examples/login_example.erl").
% Login to Aerospike CE
> login_example:login("127.0.0.1", 3000, "User", "pwd").
ok
% Login to Aerospike Emulator
> login_example:login("127.0.0.1", 4041, "User1", "pass1").
ok

Cluster Information
-------------------
NOTE: Aerospike Emulator does not support cluster information retrieval at the present time.

> c("examples/info.erl").
> info_example:info("127.0.0.1", 3000, "", "", ["build"], 1000).
[{<<"build">>,<<"6.3.0.5">>},{<<>>}]
> info_example:info("127.0.0.1", 3000, "", "", ["namespaces"], 1000).
[{<<"namespaces">>,<<"test">>},{<<>>}]
> info_example:info("127.0.0.1", 3000, "", "", ["partitions", "replicas"], 1000).
[{<<"partitions">>,<<"4096">>},
{<<"replicas">>,
<<"test:0,1,///////////////////////////////////////////////////////////////////////////////////////////"...>>},
{<<>>}]

PUT Key-Value
-------------
> c("examples/put_example.erl").
% PUT, Aerospike CE
> put_example:put("127.0.0.1", 3000, "", "", "test", "set1", "key1", [{"bin1", "value1"}]).
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
% PUT, Aerospike Emulator
% Encrypt password for Aerospike Emulator
> Encrypted_password = aspike_blowfish:crypt("pass1").
> put_example:put("127.0.0.1", 4041, "User1", Encrypted_password, "test", "set1", "key1", [{"bin1", "value1"}]).
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}

GET Key-Value
-------------
> c("examples/get_example.erl").
% GET, Aerospike CE
> get_example:get("127.0.0.1", 3000, "", "", "test", "set1", "key1", []).
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
[], [{<<"bin1">>,"value1"}]
% GET, Aerospike Emulator
> get_example:get("127.0.0.1", 4041, "User1", Encrypted_password, "test", "set1", "key1", ["bin1"]).
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
[], [{<<"bin1">>,"value1"}]

REMOVE Key
----------
> c("examples/get_example.erl").
% REMOVE, Aerospike CE
> remove_example:remove("127.0.0.1", 3000, "", "", "test", "set1", "key1").
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
% REMOVE again
> remove_example:remove("127.0.0.1", 3000, "", "", "test", "set1", "key1").
{2,<<"AEROSPIKE_ERR_RECORD_NOT_FOUND">>, <<"Record does not exist in database.">>}
% REMOVE, Aerospike Emulator
> remove_example:remove("127.0.0.1", 4041, "User1", Encrypted_password, "test", "set1", "key1").
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
% REMOVE again
> remove_example:remove("127.0.0.1", 4041, "User1", Encrypted_password, "test", "set1", "key1").
{2,<<"AEROSPIKE_ERR_RECORD_NOT_FOUND">>, <<"Record does not exist in database.">>}

EXISTS Key
----------
> c("examples/exists_example.erl").

%% Aerospike CE section
% First, PUT Key-Value
> put_example:put("127.0.0.1", 3000, "", "", "test", "set1", "key1", [{"bin1", "value1"}]).
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
% Next, check that Key EXISTS
> exists_example:exists("127.0.0.1", 3000, "", "", "test", "set1", "key1").
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
% GET Key
> get_example:get("127.0.0.1", 3000, "", "", "test", "set1", "key1", []).
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
[], [{<<"bin1">>,"value1"}]
% Now, REMOVE Key
> remove_example:remove("127.0.0.1", 3000, "", "", "test", "set1", "key1").
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
% Check again, whether the Key exists
> exists_example:exists("127.0.0.1", 3000, "", "", "test", "set1", "key1").
{2,<<"AEROSPIKE_ERR_RECORD_NOT_FOUND">>, <<"Record does not exist in database.">>}
%% Aerospike CE section. End

%% Aerospike Emulator section
% First, PUT Key-Value
> put_example:put("127.0.0.1", 4041, "User1", Encrypted_password, "test", "set1", "key1", [{"bin1", "value1"}]).
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
% Next, check that Key EXISTS
> exists_example:exists("127.0.0.1", 4041, "User1", Encrypted_password, "test", "set1", "key1").
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
% GET Key
> get_example:get("127.0.0.1", 4041, "User1", Encrypted_password, "test", "set1", "key1", ["bin1"]).
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
[], [{<<"bin1">>,"value1"}]
% Now, REMOVE Key
> remove_example:remove("127.0.0.1", 4041, "User1", Encrypted_password, "test", "set1", "key1").
{0,<<"AEROSPIKE_OK">>,<<"Generic success.">>}
% Check again, whether the Key exists
> exists_example:exists("127.0.0.1", 4041, "User1", Encrypted_password, "test", "set1", "key1").
{2,<<"AEROSPIKE_ERR_RECORD_NOT_FOUND">>, <<"Record does not exist in database.">>}
%% Aerospike Emulator section. End
70 changes: 70 additions & 0 deletions doc/Aerospike_cluster_discovery.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
Pre-requisites:
1. a 'Cluster Seed': <IP-address>:<port>;
2. Term 'connection' means 'TCP connection' in this document.

Step 1.1. Establish connection to a 'Cluster Seed';
Step 1.2. LOGIN to the 'Cluster Seed' providing 'User name' and 'Blowfish-encrypted password';
Step 1.3. Request 'Access node' IP-address and Port from the 'Cluster Seed';

Step 2.1. Establish connection to the 'Access node';
Step 2.2. LOGIN to the 'Access node' providing 'User name' and 'Blowfish-encrypted password';
Step 2.3. Request list of cluster Node's IP-addresses and Ports;

For each Node (IP-address and Port) acquired in Step 2.3. perform
Step 3.1. Establish connection to the 'Node';
Step 3.2. LOGIN to the 'Node' providing 'User name' and 'Blowfish-encrypted password';
Step 3.3. Request list of 'Namespaces' from the 'Node'.

Each 'Namespace' information in the response to the request in Step 3.3. contains the following:
4.1. 'Namespace' name as an ASCII-string;
4.2. List of 'Replicas' supported by the 'Node' for this 'Namespace'.

Each 'Replica' information from the item 4.2. contains the following:
5.1. Base64 encoding of the 'Partitions' bitmap represented by the 'Replica'.



=========================================
| Namespace 'Test' |
|---------------------------------------|
| K1 |
| K2 |
=========================================
|
Assignment of keys to partitions
|
V
=========================================
| | K1 | | | K2 | | | |
|---------------------------------------|
| P0 | P1 | P2 | P3 | P4 | P5 | P6 | P7 |
=========================================
|
Assignment of partitions to replicas
|
-------------------------------------
| |
V V
[====== Replica1 =============================] [============================= Replica2 ======]
================ =========== ================ =========== ================ ================
| P0 | P1 | P2 | | P3 | P4 | | P5 | P6 | P7 | | P4 | P7 | | P0 | P3 | P6 | | P1 | P2 | P5 |
|--------------| |---------| |--------------| |---------| |--------------| |--------------|
| Node1 | | Node2 | | Node3 | | Node1 | | Node2 | | Node3 |
|--------------| |---------| |--------------| |---------| |--------------| |--------------|
| | K1 | | | | K2 | | | | | | K2 | | | | | | | K1 | | |
================ =========== ================ =========== ================ ================

Node1 response to 4.1., 4.2., 5.1.:
Test1: - Namespace name
Replica1: 11100000 - Node1 participates in partitions P0, P1, P2 for Replica1
Replica2: 00001001 - Node1 participates in partitions P4, P7 for Replica2

Node2 response to 4.1., 4.2., 5.1.:
Test1: - Namespace name
Replica1: 00011000 - Node2 participates in partitions P3, P4 for Replica1
Replica2: 10010010 - Node1 participates in partitions P0, P3, P6 for Replica2

Node3 response to 4.1., 4.2., 5.1.:
Test1: - Namespace name
Replica1: 00000111 - Node3 participates in partitions P5, P6, P7 for Replica1
Replica2: 01100100 - Node1 participates in partitions P1, P2, P5 for Replica2
Loading

0 comments on commit b73c0a6

Please sign in to comment.