Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Max value version of eleveldb #2

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6f1036e
first version of antidote_db with eleveldb as backend
santialvarezcolombo Jan 22, 2016
2e3fd26
added options to fold methods
santialvarezcolombo Jan 22, 2016
deac50b
fix esport parameters for fold methods
santialvarezcolombo Jan 22, 2016
e37bad9
antidote db sup first version
santialvarezcolombo Jan 22, 2016
1f4c0e2
fix bug while passing keys to binary
santialvarezcolombo Jan 22, 2016
1336486
Added antidote_db_wrapper, originally on the main Antidote repo. Firs…
santialvarezcolombo Aug 22, 2016
f8d7ba3
Changed dependency for antidote utils branch
santialvarezcolombo Aug 23, 2016
eaf5db9
Fixed branch in rebar config for antidote utils dependency
santialvarezcolombo Aug 24, 2016
ca2eb9f
Added the licence to missing files
santialvarezcolombo Aug 26, 2016
af40b72
Switched branch order in get_ops to make code more readable
santialvarezcolombo Aug 29, 2016
7b87efd
Fixed accumulation in the resulting list of the get_ops method
santialvarezcolombo Aug 29, 2016
03fbcdc
Updated the wrapper with to use the log_record provided in antidote_u…
santialvarezcolombo Sep 7, 2016
20148ab
Updated spec return type in get_ops
santialvarezcolombo Sep 7, 2016
e3bff37
Renamed and refactored the antidote_db and the leveldb_wrapper
santialvarezcolombo Sep 20, 2016
17377dc
Added a test for to check the reutnr type in all methods
santialvarezcolombo Sep 20, 2016
0cba2b8
Changes to use the materealized_snapshot in antidote_uti.s
santialvarezcolombo Sep 21, 2016
ffb1b10
Fixed upper bound in get_ops method
santialvarezcolombo Sep 26, 2016
992109e
Added the get_ops_applicable_to_snapshot method and it's tests.
santialvarezcolombo Sep 26, 2016
eeb1968
Refactored tests and added comments
santialvarezcolombo Sep 26, 2016
17fbcfc
Added the get_ops_applicable_to_snapshot method to the antidote_db in…
santialvarezcolombo Sep 26, 2016
28b0d8b
Fixed lower bound in get_ops range
santialvarezcolombo Sep 28, 2016
26f66a8
Fixed bug with concurrent ops
santialvarezcolombo Sep 28, 2016
f965f2b
Fixed begening key to start looking in fold
santialvarezcolombo Sep 30, 2016
d9047aa
First version using the bigger DC ordering function
santialvarezcolombo Oct 21, 2016
19b3e92
New version with redefined logic to check that a VC is in the require…
santialvarezcolombo Oct 21, 2016
0fb06cf
First working version with the latest version of the comparator
santialvarezcolombo Oct 23, 2016
f8e994b
Refactor + code cleanup
santialvarezcolombo Oct 23, 2016
d0175c4
Migration to rebar3
santialvarezcolombo Oct 23, 2016
01acbf4
Created the test folder with the leveldb_wrapper suite.
santialvarezcolombo Oct 23, 2016
620deab
Added proper
santialvarezcolombo Oct 23, 2016
7c85839
Fixed range when VCs have different keys
santialvarezcolombo Oct 24, 2016
9a76b7b
Removed tests in the leveldb_wrapper module since they are replaced w…
santialvarezcolombo Oct 25, 2016
dad3820
Added the antidote_db_SUITE for testing antidote_db module
santialvarezcolombo Oct 25, 2016
c0b389a
Updated get_snapshot method to match new sorting order
santialvarezcolombo Oct 25, 2016
d9cfd7d
Added meck dependecy for mocking
santialvarezcolombo Oct 26, 2016
f1f5a40
Tests for antidote_db module using meck
santialvarezcolombo Oct 26, 2016
68749d9
Update README.md
santialvarezcolombo Oct 26, 2016
bdc1189
Commented meck tests that fail on Erlang 18+ because of a Meck problem.
santialvarezcolombo Oct 30, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
m
_build/
*.beam
.eunit
deps/*
ebin/*
rel/antidote
dev
apps/antidote/src/*
*.swp
*.swo
src/*.swo
Expand All @@ -13,9 +10,16 @@ dialyzer_unhandled_warnings
dialyzer_warnings
doc/
.DS_Store
log/
logs/
tags
rel/vars/*.config
.rebar/*
*.dump

rebar.lock
docs/_site/
docs/.sass-cache/
docs/.jekyll-metadata
docs/_pdf
docs/.idea/
log/
data/
compile_commands.json
test/.rebar3/
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,44 @@
# AntidoteDB

Erlang Rebar application, used as the DataStore for [Antidote](https://github.com/SyncFree/antidote). This module exposes a simple API, so the datastore can be configurable and changed, without affecting Antidote code.
Erlang Rebar application, used as the backend DataStore for [Antidote](https://github.com/SyncFree/antidote). This module exposes a simple API, so the datastore can be configurable and changed, without affecting Antidote code.

This project is structured as a rebar3 project, and today contains two modules:

+ **antidote_db**: contains a basic API to interact with the DB. Today it only contains the methods for a eleveldb backend.
+ **leveldb_wrapper**: contains a wrapper of the API provided by eleveldb, with added code containing Antidote logic.

All tests are under the respective *_SUITE modules, and should be run using `rebar3 ct`.

## ElevelDB

Today, this application uses SyncFree [ElevelDB](https://github.com/SyncFree/eleveldb) fork.

As this application is intended to be used in [Antidote](https://github.com/SyncFree/antidote), it uses the 'Antidote Comparator' by default.

### Composition of keys

Keys are composed as follows:

`{antidote_key, max_value_in_vc, vc_hash, op/snap, vc}`

+ **antidote_key**: Same key as in Antidote.
+ **max_value_in_vc**: The max value for all DCs in the VC.
+ **vc_hash**: A hash of the VC. This is done in order to provide a more performant sorting algorithm, since we don't need to compare all the VC, to find that keys are different. If the hash matches, we also compare the VC, just to make sure it's not a collision.
+ **op/snap**: an atom indicating if the stored value corresponds to an operation or a snapshot.
+ **vc**: the vc of when the op/snap ocurred.

### Sorting of keys

Keys get sorted first by the Antidote key.
Then we look at the MAX value of it's VC, sorting first the biggest one. We reverse the "natural" order, so we can have the most recent operations first.
If the max value for two keys matches, we sort taking into account the hash value.
For matching hashes, we check the rest of the key, sorting accordingly.

### Testing

As stated before, the modules have their corresponding *_SUITE modules for unit testing. The antidote_db module uses [meck](https://github.com/eproxus/meck) to mock the calls to eleveldb and the leveldb_wrapper.

In addition to this tests, and thanks to @peterzeller, we have a Proper module to test the get_ops method. This module generates operations by simulating incrementing a
vectorclock and merging them. This tests can be run using "rebar3 proper -m prop_get_ops -n TESTS" where TESTS is the amount of random inputs that Proper should run with.

This two modules have more than a 90% code coverage.
26 changes: 26 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{deps, [
{eleveldb, ".*", {git, "git://github.com/SyncFree/eleveldb", {branch, "max_order_comparator"}}},
{antidote_utils, ".*", {git, "git://github.com/SyncFree/antidote_utils", {branch, "additions_for_antidote_db"}}},
{meck, ".*", {git, "https://github.com/eproxus/meck.git", {tag, "0.8.3"}}}
]}.

%% Required to assemble a native library like eleveldb when compiling with Rebar3
{overrides, [
{override, eleveldb, [
{plugins, [pc]},
{artifacts, ["priv/eleveldb.so"]},

{provider_hooks, [
{post, [
{compile, {pc, compile}},
{clean, {pc, clean}}
]}
]}
]}
]}.

{plugins, [rebar3_proper]}.

{profiles,
[{test, [{deps, [{proper, "1.1.1-beta"}]}]}]
}.
13 changes: 13 additions & 0 deletions src/antidote_db.app.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{application, antidote_db,
[
{description, "Antidote DataBase application"},
{vsn, "1"},
{registered, []},
{applications, [
kernel,
stdlib,
eleveldb
]},
{mod, { antidote_db, []}},
{env, []}
]}.
114 changes: 114 additions & 0 deletions src/antidote_db.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
%% -------------------------------------------------------------------
%%
%% Copyright (c) 2014 SyncFree Consortium. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------

-module(antidote_db).

-include_lib("antidote_utils/include/antidote_utils.hrl").

-export([
new/2,
close_and_destroy/2,
close/1,
get_snapshot/3,
put_snapshot/3,
get_ops/4,
put_op/4]).

-type antidote_db() :: {leveldb, eleveldb:db_ref()}.

-type antidote_db_type() :: leveldb.

-export_type([antidote_db/0, antidote_db_type/0]).

%% Given a name, returns a new AntidoteDB (for now, only ElevelDB is supported)
%% OpenOptions are set to use Antidote special comparator in the case of Eleveldb
-spec new(atom(), antidote_db_type()) -> {ok, antidote_db()} | {error, any()}.
new(Name, Type) ->
case Type of
leveldb ->
{ok, Ref} = eleveldb:open(Name, [{create_if_missing, true}, {antidote, true}]),
{ok, {leveldb, Ref}};
_ ->
{error, type_not_supported}
end.


%% Closes and destroys the given base
-spec close_and_destroy(antidote_db(), atom()) -> ok | {error, any()}.
close_and_destroy({Type, DB}, Name) ->
case Type of
leveldb ->
eleveldb:close(DB),
eleveldb:destroy(Name, []);
_ ->
{error, type_not_supported}
end.

-spec close(antidote_db()) -> ok | {error, any()}.
close({Type, DB}) ->
case Type of
leveldb ->
eleveldb:close(DB);
_ ->
{error, type_not_supported}
end.

%% Gets the most suitable snapshot for Key that has been committed
%% before CommitTime. If its nothing is found, returns {error, not_found}
-spec get_snapshot(antidote_db:antidote_db(), key(),
snapshot_time()) -> {ok, #materialized_snapshot{}} | {error, not_found}.
get_snapshot({Type, DB}, Key, CommitTime) ->
case Type of
leveldb ->
leveldb_wrapper:get_snapshot(DB, Key, CommitTime);
_ ->
{error, type_not_supported}
end.

%% Saves the snapshot into AntidoteDB
-spec put_snapshot(antidote_db:antidote_db(), key(), #materialized_snapshot{}) -> ok | error.
put_snapshot({Type, DB}, Key, Snapshot) ->
case Type of
leveldb ->
leveldb_wrapper:put_snapshot(DB, Key, Snapshot);
_ ->
{error, type_not_supported}
end.

%% Returns a list of operations that have commit time in the range [VCFrom, VCTo]
-spec get_ops(antidote_db:antidote_db(), key(), vectorclock(), vectorclock()) -> [#log_record{}].
get_ops({Type, DB}, Key, VCFrom, VCTo) ->
case Type of
leveldb ->
leveldb_wrapper:get_ops(DB, Key, VCFrom, VCTo);
_ ->
{error, type_not_supported}
end.


%% Saves the operation into AntidoteDB
-spec put_op(antidote_db:antidote_db(), key(), vectorclock(), #log_record{}) -> ok | error.
put_op({Type, DB}, Key, VC, Record) ->
case Type of
leveldb ->
leveldb_wrapper:put_op(DB, Key, VC, Record);
_ ->
{error, type_not_supported}
end.
45 changes: 45 additions & 0 deletions src/antidote_db_sup.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
%% -------------------------------------------------------------------
%%
%% Copyright (c) 2014 SyncFree Consortium. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
-module(antidote_db_sup).

-behaviour(supervisor).

%% API
-export([start_link/0]).

%% Supervisor callbacks
-export([init/1]).

%% Helper macro for declaring children of supervisor
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).

%% ===================================================================
%% API functions
%% ===================================================================

start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).

%% ===================================================================
%% Supervisor callbacks
%% ===================================================================

init([]) ->
{ok, { {one_for_one, 5, 10}, []} }.
Loading