Skip to content

Commit

Permalink
[#38] Improve test coverage – 100%
Browse files Browse the repository at this point in the history
  • Loading branch information
cabol committed Oct 21, 2017
1 parent f18a6b5 commit 5c5efd6
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 238 deletions.
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ all this, with **zero** effort. It provides an API compatible with [ETS](http://
the list of compatible ETS functions that **Shards** provides [HERE](https://github.com/cabol/shards/issues/1).


## Usage
## Installation

### Erlang

Expand Down Expand Up @@ -421,7 +421,9 @@ And again, let's check it out from any node:
basic functions have been implemented.


## Examples and/or Projects using Shards
## Important links

* [Blog Post – including load tests results](http://cabol.github.io/posts/2016/04/14/sharding-support-for-ets.html).

* [ExShards](https://github.com/cabol/ex_shards) – Elixir wrapper for
`shards` with extra and nicer functions.
Expand All @@ -432,9 +434,6 @@ And again, let's check it out from any node:
* [KVX](https://github.com/cabol/kvx) – Simple/basic Elixir in-memory Key/Value
Store using `shards` (default adapter).

* [ErlBus](https://github.com/cabol/erlbus) uses `shards` to scale-out
Topics/Pids table(s), which can be too large and with high concurrency level.

* [Cacherl](https://github.com/ferigis/cacherl) uses `shards` to implement a
Distributed Cache.

Expand All @@ -445,8 +444,6 @@ And again, let's check it out from any node:

You can find tests results in `_build/test/logs`, and coverage in `_build/test/cover`.

> **NOTE:** You can find some performance tests in this [BLOG POST](http://cabol.github.io/posts/2016/04/14/sharding-support-for-ets.html).

## Building Edoc

Expand Down
10 changes: 10 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

{cover_enabled, true}.

{cover_opts, [verbose]}.

%% == Common Test ==

{ct_compile_opts, [
Expand Down Expand Up @@ -54,6 +56,14 @@
{deps, [
{jchash, "0.1.0"},
{mixer, {git, "https://github.com/chef/mixer.git", {branch, "master"}}}
]},
{cover_excl_mods, [
shards_test_helpers,
shards_task_SUITE,
shards_state_SUITE,
shards_local_SUITE,
shards_lib_SUITE,
shards_dist_SUITE
]}
]}
]}.
Expand Down
9 changes: 6 additions & 3 deletions src/shards.app.src
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
{application, shards, [
{description, "ETS with Sharding support."},
{vsn, "0.5.0"},
{description, "Sharding support for ETS tables out-of-box"},
{vsn, "0.5.1"},
{registered, []},
{mod, {shards_app, []}},
{applications, [kernel, stdlib]},
{applications, [
kernel,
stdlib
]},
{env,[]},
{modules, []},
{maintainers, ["Carlos A Bolanos"]},
Expand Down
38 changes: 22 additions & 16 deletions src/shards_local.erl
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@
%%% Types & Macros
%%%===================================================================

%% ETS Types
-type access() :: public | protected | private.
-type tab() :: atom().
-type type() :: set | ordered_set | bag | duplicate_bag.
-type cont() :: '$end_of_table'
| {tab(), integer(), integer(), ets:comp_match_spec(), list(), integer()}
| {tab(), _, _, integer(), ets:comp_match_spec(), list(), integer(), integer()}.

%% @type tweaks() = {write_concurrency, boolean()}
%% | {read_concurrency, boolean()}
%% | compressed.
Expand All @@ -131,14 +139,14 @@
| {pick_node_fun, shards_state:pick_fun()}
| {restart_strategy, one_for_one | one_for_all}.

%% @type option() = ets:type() | ets:access() | named_table
%% @type option() = type() | access() | named_table
%% | {keypos, pos_integer()}
%% | {heir, pid(), HeirData :: term()}
%% | {heir, none} | tweaks()
%% | shards_opt().
%%
%% Create table options – used by `new/2'.
-type option() :: ets:type() | ets:access() | named_table
-type option() :: type() | access() | named_table
| {keypos, pos_integer()}
| {heir, pid(), HeirData :: term()}
| {heir, none} | tweaks()
Expand All @@ -153,9 +161,9 @@
| {named_table, boolean()}
| {node, node()}
| {owner, pid()}
| {protection, ets:access()}
| {protection, access()}
| {size, non_neg_integer()}
| {type, ets:type()}
| {type, type()}
| {write_concurrency, boolean()}
| {read_concurrency, boolean()}
| {shards, [atom()]}.
Expand All @@ -169,8 +177,8 @@

%% ETS TabInfo Item
-type tabinfo_item() :: {name, atom()}
| {type, ets:type()}
| {protection, ets:access()}
| {type, type()}
| {protection, access()}
| {named_table, boolean()}
| {keypos, non_neg_integer()}
| {size, non_neg_integer()}
Expand All @@ -183,7 +191,7 @@
%% MatchSpec :: ets:match_spec(),
%% Limit :: pos_integer(),
%% Shard :: non_neg_integer(),
%% Continuation :: ets:continuation()
%% Continuation :: cont()
%% }.
%%
%% Defines the convention to `ets:select/1,3' continuation:
Expand All @@ -199,7 +207,7 @@
MatchSpec :: ets:match_spec(),
Limit :: pos_integer(),
Shard :: non_neg_integer(),
Continuation :: ets:continuation()
Continuation :: cont()
}.

%% @type filename() = string() | binary() | atom().
Expand Down Expand Up @@ -941,12 +949,11 @@ rename(Tab, Name) ->
Name :: atom(),
State :: shards_state:state().
rename(Tab, Name, State) ->
ok =
lists:foreach(fun(Shard) ->
ShardName = shards_lib:shard_name(Tab, Shard),
NewShardName = shards_lib:shard_name(Name, Shard),
NewShardName = do_rename(ShardName, NewShardName)
end, shards_lib:iterator(State)),
ok = lists:foreach(fun(Shard) ->
ShardName = shards_lib:shard_name(Tab, Shard),
NewShardName = shards_lib:shard_name(Name, Shard),
NewShardName = do_rename(ShardName, NewShardName)
end, shards_lib:iterator(State)),
do_rename(Tab, Name).

%% @private
Expand Down Expand Up @@ -1448,8 +1455,7 @@ mapred_funs(MapFun, ReduceFun) ->
true -> {MapFun, []};
_ -> MapFun
end,
Reduce = {ReduceFun, []},
{Map, Reduce}.
{Map, {ReduceFun, []}}.

%% @private
fold(Tab, NumShards, Fold, [Fun, Acc]) ->
Expand Down
3 changes: 2 additions & 1 deletion src/shards_owner.erl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
%%% API
%%%===================================================================

-spec start_link(atom(), atom()) -> gen:start_ret().
-spec start_link(atom(), atom()) -> {ok, pid()} | ignore | {error, term()}.
start_link(Name, Options) ->
gen_server:start_link({local, Name}, ?MODULE, {Name, Options}, []).

Expand All @@ -47,6 +47,7 @@ stop(ShardName) ->

%% @hidden
init({Name, Options}) ->
_ = process_flag(trap_exit, true),
NewOpts =
case lists:keyfind(restore, 1, Options) of
{restore, _, _} = Val -> Val;
Expand Down
47 changes: 18 additions & 29 deletions src/shards_owner_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
-spec start_link(Name, Options) -> Response when
Name :: atom(),
Options :: [term()],
Response :: supervisor:startlink_ret().
Response :: {ok, pid()} | ignore | {error, term()}.
start_link(Name, Options) ->
supervisor:start_link(?MODULE, {Name, Options}).

Expand Down Expand Up @@ -65,15 +65,14 @@ init({Name, Options}) ->
true = ets:insert(Name, State),

% create children
Children =
[begin
% get a local name to shard
LocalShardName = shards_lib:shard_name(Name, Shard),
% save relationship between shard and shard name
true = ets:insert(Name, {Shard, LocalShardName}),
% shard worker spec
?worker(shards_owner, [LocalShardName, Opts], #{id => Shard})
end || Shard <- shards_lib:iterator(State)],
Children = [begin
% get a local name to shard
LocalShardName = shards_lib:shard_name(Name, Shard),
% save relationship between shard and shard name
true = ets:insert(Name, {Shard, LocalShardName}),
% shard worker spec
?worker(shards_owner, [LocalShardName, Opts], #{id => Shard})
end || Shard <- shards_lib:iterator(State)],

% init shards_dist pg2 group
Module = shards_state:module(State),
Expand All @@ -97,30 +96,20 @@ child(Type, Module, Args, Spec) when is_map(Spec) ->

%% @private
supervise(Children, SupFlagsMap) ->
ok = assert_unique_ids([Id || {Id, _, _, _, _, _} <- Children]),
SupFlags =
{maps:get(strategy, SupFlagsMap, one_for_one),
maps:get(intensity, SupFlagsMap, 1),
maps:get(period, SupFlagsMap, 5)},
SupFlags = {
maps:get(strategy, SupFlagsMap, one_for_one),
maps:get(intensity, SupFlagsMap, 1),
maps:get(period, SupFlagsMap, 5)
},
{ok, {SupFlags, Children}}.

%% @private
assert_unique_ids([]) ->
ok;
assert_unique_ids([Id | Rest]) ->
case lists:member(Id, Rest) of
true -> error({badarg, duplicated_id});
_ -> assert_unique_ids(Rest)
end.

%% @private
parse_opts(Opts) ->
StateMap = shards_state:to_map(shards_state:new()),
AccIn =
StateMap#{
opts => [],
restart_strategy => one_for_one
},
AccIn = StateMap#{
opts => [],
restart_strategy => one_for_one
},
AccOut = parse_opts(Opts, AccIn),
%% @TODO: this workaround must be fixed when a better strategy to support ordered_set be ready
case maps:get(type, AccOut, set) of
Expand Down
6 changes: 1 addition & 5 deletions src/shards_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,10 @@
start_link() ->
start_link(?MODULE).

-spec start_link(Name :: atom()) -> supervisor:startlink_ret().
-spec start_link(Name :: atom()) -> {ok, pid()} | ignore | {error, term()}.
start_link(Name) ->
supervisor:start_link({local, Name}, ?MODULE, {Name}).

%%%===================================================================
%%% shards_supervisor callbacks
%%%===================================================================

-spec start_child(SupName, TabName, Options) -> Return when
SupName :: atom(),
TabName :: atom(),
Expand Down
Loading

0 comments on commit 5c5efd6

Please sign in to comment.