Table of Contents
# per-key options have been implemented but not yet deployed in a production setting.
Erlang’s Key Benefits are
In the event of physical node failure, bricks automatically shift roles and each chain continues to provide service to clients.
Motivations for rebalancing of data:
As a key-value store, Hibari’s core data model and client API model are simple by design:
blob-based key-value pairs
operations
Hibari supports multiple client API implementations:
You can develop Hibari client applications in a variety of languages including Java, C/C++, Python, Ruby, and Erlang.
Intermission #1
An atom is a literal, a constant with name. An atom should be enclosed in single quotes (') if it does not begin with a lower-case letter or if it contains other characters than alphanumeric characters, underscore (_), or @.
hello phone_number 'Monday' 'phone number' 'hello' 'phone_number'
A bit string is used to store an area of untyped memory. A bit string that consists of a number of bits that is evenly divisible by eight is called a binary.
<<10,20>> <<"ABC">>
A tuple is a compound data type with a fixed number of terms, enclosed by braces:
{Term1,...,TermN}
A list is a compound data type with a variable number of terms, enclosed by square brackets:
[Term1,...,TermN]
true
and false
are used to denote Boolean values.
… plus a few others
The file "math.erl" contains the following program:
-module(math). -export([fac/1]). fac(N) when N > 0 -> N * fac(N-1); fac(0) -> 1.
This program can be compiled and run using the Erlang shell.
$ erl Erlang R14B01 (erts-5.8.2) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.8.2 (abort with ^G) 1> c(math). {ok,math} 2> math:fac(25). 15511210043330985984000000
Let it crash …
3> math:fac(-1). ** exception error: no function clause matching math:fac(-1)
append([], L) -> L; append([H | T], L) -> [H | append(T, L)].
qsort([]) -> []; qsort([H | T]) -> qsort([ X || X <- T, X < H ]) ++ [H] ++ qsort([ X || X <- T, X >= H ]).
> Adder = fun(N) -> fun(X) -> X + N end end. #Fun<erl_eval.6.13229925> > G = Adder(10). #Fun<erl_eval.6.13229925> > G(5). 15
{'ok', timestamp(), val()}
.
{ok, {[{key(), timestamp(), val()}], boolean()}}
.
'txn'
|OpList]
"single" operations are implemented (under the hood) using the do/4 function. |
Tab
Type:
Tab = table()
table() = atom()
Key
Type:
Key = key()
key() = iodata()
iodata() = iolist() | binary()
iolist() = [char() | binary() | iolist()]
|
Value
Type:
Value = val()
val() = iodata()
iodata() = iolist() | binary()
iolist() = [char() | binary() | iolist()]
ExpTime
Type:
ExpTime = exp_time()
exp_time() = time_t()
time_t() = integer()
Flags
Type:
Flags = flags_list()
flags_list() = [do_op_flag() | property()]
do_op_flag() = {'testset', timestamp()}
timestamp() = integer()
property() = atom() | {term(), term()}
Operational flag usage
{'testset', timestamp()}
timestamp()
. If used inside a
micro-transaction, abort the transaction if the key’s timestamp
is not exactly equal to timestamp()
.
Timeout
Type:
Timeout = timeout()
timeout() = integer()
Error returns
'key_not_exist'
{'key_exists',timestamp()}
timestamp() = integer()
{'ts_error', timestamp()}
{'testset', timestamp()}
flag
was used and there was a timestamp mismatch. The timestamp()
in
the return is the current value of the existing key’s timestamp.
timestamp() = integer()
'invalid_flag_present'
do_op_flag()
was found
in the Flags
argument.
'brick_not_available'
{{'nodedown',node()},{'gen_server','call',term()}}
node() = atom()
Operational flag usage
'get_all_attribs'
witness
flag.
'witness'
Success returns
{'ok', timestamp(), val()}
{'ok', timestamp()}
'witness'
but not 'get_all_attribs'
.
{'ok', timestamp(), proplist()}
'witness'
and 'get_all_attribs'
.
{'ok', timestamp(), val(), exp_time(), proplist()}
'get_all_attribs'
but not 'witness'
.
For proplists, |
Operational flag usage
'get_all_attribs'
witness
flag.
'witness'
{'binary_prefix', binary()}
binary()
.
{'max_bytes', integer()}
integer()
bytes.
If this flag is not explicity specified in a client request,
the value defaults to 2GB.
{'max_num', integer()}
Success returns
{ok, {[{key(), timestamp(), val()}], boolean()}}
{ok, {[{key(), timestamp()}], boolean()}}
get_many
uses 'witness'
but not
'get_all_attribs'
.
{ok, {[{key(), timestamp(), proplist()}], boolean()}}
get_many
uses both 'witness'
and
'get_all_attribs'
.
{ok, {[{key(), timestamp(), val(), exp_time(), proplist()}],
boolean()}}
get_many
uses 'get_all_attribs'
but
not 'witness'
.
|
For proplists, |
Error returns
{txn_fail, [{integer(), do1_res_fail()}]}
do
request and one or more primitive operations within the
transaction failed. The integer()
identifies the failed
primitive operation by its position within the request’s
OpList
. For example, a 2 indicates that the second primitive
listed in the request’s OpList
failed. Note that this position
identifier does not count the txn()
specifier at the start of
the OpList
.
Create a directory
$ mkdir running-directory
untar Hibari tarball package - "hibari-X.Y.Z-DIST-ARCH-WORDSIZE.tgz"
$ tar -C running-directory -xvf hibari-X.Y.Z-DIST-ARCH-WORDSIZE.tgz
Start Hibari:
$ running-directory/hibari/bin/hibari start
Bootstrap the system:
$ running-directory/hibari/bin/hibari-admin bootstrap ok
Stop Hibari (later when needed):
$ running-directory/hibari/bin/hibari stop
Confirm that you can open the "Hibari Web Administration" page:
$ firefox http://127.0.0.1:23080 &
Confirm that you can successfully ping the Hibari node:
$ running-directory/hibari/bin/hibari ping pong
A single-node Hibari system is hard-coded to listen on the localhost address 127.0.0.1. Consequently the Hibari node is reachable only from the node itself. |
Connect to Hibari using Erlang’s remote shell
$ running-directory/hibari/erts-5.8.2/bin/erl -name hogehoge@127.0.0.1 -setcookie hibari -kernel net_ticktime 20 -remsh hibari@127.0.0.1 Erlang R14B01 (erts-5.8.2) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.8.2 (abort with ^G) (hibari@127.0.0.1)1>
Check your node name and the set of connected Erlang nodes.
(hibari@127.0.0.1)1> node(). 'hibari@127.0.0.1' (hibari@127.0.0.1)2> nodes(). ['hogehoge@127.0.0.1'] (hibari@127.0.0.1)3>
Hibari’s name, cookie, and kernel net_ticktime are configurable and located in the running-directory/hibari/etc/vm.args file. |
The "rlwrap -a running-directory/hibari/erts-5.8.2/bin/erl" tool is helpful for keeping track of your Erlang shell history (e.g. yum install rlwrap). |
Create a new table having a hash prefix of 2 and having 3 bricks per chain.
$ running-directory/hibari/bin/hibari-admin create-table tab2 \ -bigdata -disklogging -syncwrites \ -varprefix -varprefixsep 47 -varprefixnum 2 \ -bricksperchain 3 \ hibari@127.0.0.1 hibari@127.0.0.1 hibari@127.0.0.1
For example, let’s assume the first part of a key represent’s a user’s id. A hash prefix of 2 makes the keys of each individual user to be stored on the same chain … but not necessarily on the same chain as other user’s keys.
: /user1/adir/ /user1/adir/file1 /user1/adir/file3 /user1/file1 /user1/file4 /user1/xdir/ /user1/xdir/fileY : /user2/file1 : /user3/file4 :
Tables can also be created using Hibari’s Admin Server
Webpage. Open |
The goal of these exercises is to learn more about Hibari and to implement and to test your own Hibari mini-applications using Hibari’s Native Erlang Client.
Wait 15 seconds (or so) and then make a backup of Hibari’s Schema.local file and data files:
$ tar -cvzf backup.tgz running-directory/hibari/Schema.local running-directory/hibari/data/brick
Delete Hibari’s Schema.local and data files:
$ rm -r running-directory/hibari/Schema.local running-directory/hibari/data/brick/*
Restore Hibari’s Schema.local and data files:
$ tar -xvzf backup.tgz
Using the Erlang Shell, repeat the examples listed in Hibari’s Application Developer Guide.
What changes can be seen on Hibari’s Admin Server Webpages during and after doing these example exercises?
Implement a new API for Hibari but doing so on the client (and not server) side.
⇒ 'ok'
|
'key_not_exist'
| {'ts_error', timestamp()}
| {'key_exists',timestamp()}
'testset'
flag).
'key_not_exist'
.
{'testset', timestamp()}
, and
there is a timestamp mismatch with the OldKey, return {'ts_error',
timestamp()}
.
{'key_exists',timestamp()}
.
proplists:delete/2
and proplists:get_value/3
can
be used for Flags filtering.
{'testset', timestamp()}
flag is your friend.
Mnesia is a distributed Database Management System distributed with Erlang/OTP. Mnesia supports a dirty_update_counter/3 operation. Implement a similiar API for Hibari but doing so on the client (and not server) side.
⇒ {'ok', NewVal}
| 'invalid_arg_present'
| {non_integer,timestamp()}
| exit by Timeout.
'invalid_arg_present'
.
{'ok', NewVal}
of the counter is returned.
{'testset', timestamp()}
flag is your friend.
if is_integer(X) -> ...; true -> ... end.
to check if a term is an
integer or not.
erlang:integer_to_binary/1
and
erlang:binary_to_integer/1
are very helpful (and necessary).
erlang:now/0
and timer:now_diff/2
can be
used to create an absolute now time and to compare with a new
abosolute now time, respectively. Timeout is in milliseconds. Now
is in microseconds.
Implement a filesystem-like Client API using Hibari’s Key-Value Data Model.
'ok'
| {'dir_exists', timestamp()}
.
{'ok', Names}
| 'dir_not_exist'
.
'ok'
| 'dir_not_exist'
| 'dir_not_empty'
.
'ok'
| 'dir_not_exist'
| {'file_exists', timestamp()}
.
'ok'
| 'file_not_exist'
.
'ok'
| 'file_not_exist'
.
{'ok', Data}
| 'file_not_exist'
.
Please check Hibari’s GitHub repositories and webpages for updates.
Hibari Open Source project | |
Hibari Twitter |
@hibaridb Hashtag: #hibaridb |
Gemini Twitter |
@geminimobile |
Big Data blog | |
Slideshare |