Skip to content

Commit

Permalink
[#28] Support for option {nodes, [nodes()]} when calling `shards:ne…
Browse files Browse the repository at this point in the history
…w/2`.
  • Loading branch information
cabol committed Dec 10, 2016
1 parent 606bc7a commit e73ed46
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 43 deletions.
74 changes: 48 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Option | Description | Default
`{restart_strategy, one_for_one | one_for_all}` | Allows to configure the restart strategy for `shards_owner_sup`. | `one_for_one`
`{pick_shard_fun, pick_fun()}` | Function to pick the **shard** on which the `key` will be handled locally – used by `shards_local`. See [shards_state](./src/shards_state.erl). | `shards_local:pick/3`
`{pick_node_fun, pick_fun()}` | Function to pick the **node** on which the `key` will be handled globally/distributed – used by `shards_dist`. See [shards_state](./src/shards_state.erl). | `shards_local:pick/3`
`{nodes, [node()]}` | Allows to set a list of nodes to auto setup a distributed table – the table is created in all given nodes and then all nodes are joined. This option only has effect if the option `{scope, g}` has been set. | `[]`

> **NOTE:** By default `shards` uses a built-in functions to pick the **shard** (local scope)
and the **node** (distributed scope) on which the key will be handled. BUT you can override
Expand Down Expand Up @@ -282,47 +283,68 @@ distributed.
Node `a`:

```
$ erl -sname a@localhost -pa _build/default/lib/*/ebin -s shards
$ rebar3 shell --sname a@localhost
```

Node `b`:

```
$ erl -sname b@localhost -pa _build/default/lib/*/ebin -s shards
$ rebar3 shell --sname b@localhost
```

Node `c`:

```
$ erl -sname c@localhost -pa _build/default/lib/*/ebin -s shards
$ rebar3 shell --sname c@localhost
```

**2.** Create a table with global scope (`{scope, g}`) on each node:
**2.** Create a table with global scope (`{scope, g}`) on each node and then join them.

```erlang
% when a tables is created with {scope, g}, the module shards_dist is used
% internally by shards
> shards:new(mytab, [{n_shards, 4}, {scope, g}]).
mytab
```

**3.** Setup the `shards` cluster.

From node `a`, join `b` and `c` nodes:

```erlang
> shards:join(mytab, ['b@localhost', 'c@localhost']).
[a@localhost,b@localhost,c@localhost]
```
There are two ways to achieve this:

Let's check that all nodes have the same nodes running next function on each node:
```erlang
> shards:get_nodes(mytab).
[a@localhost,b@localhost,c@localhost]
```
1. Manually, create the table on each node and then from any of them, join the rest.

Create the table on each node:

```erlang
% when a tables is created with {scope, g}, the module shards_dist is used
% internally by shards
> shards:new(mytab, [{scope, g}]).
mytab
```

Join them. From node `a`, join `b` and `c` nodes:

```erlang
> shards:join(mytab, ['b@localhost', 'c@localhost']).
[a@localhost,b@localhost,c@localhost]
```

Let's check that all nodes have the same nodes running next function on each node:
```erlang
> shards:get_nodes(mytab).
[a@localhost,b@localhost,c@localhost]
```
2. The easier way, call `shards:new/3` but passing the option `{nodes, Nodes}`,
where `Nodes` is the list of nodes you want to join.
From Node `a`:
```erlang
> shards:new(mytab, [{scope, g}, {nodes, ['b@localhost', 'c@localhost']}]).
mytab
```
Let's check again on all nodes:

```erlang
> shards:get_nodes(mytab).
[a@localhost,b@localhost,c@localhost]
```

**4.** Now **Shards** cluster is ready, let's do some basic operations:
**3.** Now **Shards** cluster is ready, let's do some basic operations:
From node `a`:
Expand Down
20 changes: 20 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,26 @@

{deps, []}.

%% == Common Test ==

{ct_compile_opts, [
debug_info,
warnings_as_errors,
warn_unused_vars,
ewarn_export_all,
warn_shadow_vars,
warn_unused_import,
warn_unused_function,
warn_bif_clash,
warn_unused_record,
warn_deprecated_function,
warn_obsolete_guard,
strict_validation,
warn_export_vars,
warn_exported_vars,
warn_untyped_record
]}.

%% == EDoc ==

{edoc_opts, []}.
Expand Down
2 changes: 1 addition & 1 deletion src/shards.app.src
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{application, shards, [
{description, "ETS with Sharding support."},
{vsn, "0.3.2"},
{vsn, "0.4.0"},
{registered, []},
{mod, {shards, []}},
{applications, [kernel, stdlib]},
Expand Down
2 changes: 1 addition & 1 deletion src/shards.erl
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ member(Tab, Key) ->
%% @end
-spec new(Name, Options) -> Name when
Name :: atom(),
Options :: [shards_local:option()].
Options :: [shards_dist:option()].
new(Name, Options) ->
case lists:keyfind(scope, 1, Options) of
{scope, g} -> shards_dist:new(Name, Options);
Expand Down
39 changes: 31 additions & 8 deletions src/shards_dist.erl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@
%% Macro to get the default module to use: `shards_local'.
-define(SHARDS, shards_local).

%% @type option() :: {nodes, [node()]} | shards_local:option().
-type option() :: {nodes, [node()]} | shards_local:option().

% Exported Types
-export_type([
option/0
]).

%%%===================================================================
%%% Extended API
%%%===================================================================
Expand All @@ -52,13 +60,14 @@ join(Tab, Nodes) ->
FilteredNodes = lists:filter(fun(Node) ->
not lists:member(Node, get_nodes(Tab))
end, Nodes),
global:trans({?MODULE, Tab}, fun() ->
_ = global:trans({?MODULE, Tab}, fun() ->
rpc:multicall(FilteredNodes, erlang, apply, [fun join_/1, [Tab]])
end),
get_nodes(Tab).

%% @private
join_(Tab) -> pg2:join(Tab, whereis(Tab)).
join_(Tab) ->
pg2:join(Tab, whereis(Tab)).

-spec leave(Tab, Nodes) -> LeavedNodes when
Tab :: atom(),
Expand Down Expand Up @@ -86,7 +95,7 @@ get_nodes(Tab) ->

-spec delete(Tab :: atom()) -> true.
delete(Tab) ->
mapred(Tab, {?SHARDS, delete, [Tab]}, nil, shards_state:get(Tab), d),
_ = mapred(Tab, {?SHARDS, delete, [Tab]}, nil, shards_state:get(Tab), d),
true.

-spec delete(Tab, Key, State) -> true when
Expand All @@ -95,15 +104,15 @@ delete(Tab) ->
State :: shards_state:state().
delete(Tab, Key, State) ->
Map = {?SHARDS, delete, [Tab, Key, State]},
mapred(Tab, Key, Map, nil, State, d),
_ = mapred(Tab, Key, Map, nil, State, d),
true.

-spec delete_all_objects(Tab, State) -> true when
Tab :: atom(),
State :: shards_state:state().
delete_all_objects(Tab, State) ->
Map = {?SHARDS, delete_all_objects, [Tab, State]},
mapred(Tab, Map, nil, State, d),
_ = mapred(Tab, Map, nil, State, d),
true.

-spec delete_object(Tab, Object, State) -> true when
Expand All @@ -113,7 +122,7 @@ delete_all_objects(Tab, State) ->
delete_object(Tab, Object, State) when is_tuple(Object) ->
[Key | _] = tuple_to_list(Object),
Map = {?SHARDS, delete_object, [Tab, Object, State]},
mapred(Tab, Key, Map, nil, State, d),
_ = mapred(Tab, Key, Map, nil, State, d),
true.

-spec insert(Tab, ObjOrObjL, State) -> true when
Expand Down Expand Up @@ -235,9 +244,23 @@ member(Tab, Key, State) ->

-spec new(Name, Options) -> Name when
Name :: atom(),
Options :: [shards_local:option()].
Options :: [option()].
new(Name, Options) ->
shards_local:new(Name, Options).
case lists:keytake(nodes, 1, Options) of
{value, {nodes, Nodes}, Options1} ->
new(Name, Options1, Nodes);
_ ->
shards_local:new(Name, Options)
end.

%% @private
new(Name, Options, Nodes) ->
AllNodes = lists:usort([node() | Nodes]),
_ = global:trans({?MODULE, Name}, fun() ->
rpc:multicall(AllNodes, shards_local, new, [Name, Options])
end),
_ = join(Name, AllNodes),
Name.

-spec select(Tab, MatchSpec, State) -> [Match] when
Tab :: atom(),
Expand Down
6 changes: 3 additions & 3 deletions src/shards_local.erl
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ delete(Tab, Key) ->
Key :: term(),
State :: shards_state:state().
delete(Tab, Key, State) ->
mapred(Tab, Key, {fun ets:delete/2, [Key]}, nil, State, d),
_ = mapred(Tab, Key, {fun ets:delete/2, [Key]}, nil, State, d),
true.

%% @equiv delete_all_objects(Tab, shards_state:new())
Expand All @@ -251,7 +251,7 @@ delete_all_objects(Tab) ->
Tab :: atom(),
State :: shards_state:state().
delete_all_objects(Tab, State) ->
mapred(Tab, fun ets:delete_all_objects/1, State),
_ = mapred(Tab, fun ets:delete_all_objects/1, State),
true.

%% @equiv delete_object(Tab, Object, shards_state:new())
Expand All @@ -269,7 +269,7 @@ delete_object(Tab, Object) ->
State :: shards_state:state().
delete_object(Tab, Object, State) when is_tuple(Object) ->
[Key | _] = tuple_to_list(Object),
mapred(Tab, Key, {fun ets:delete_object/2, [Object]}, nil, State, d),
_ = mapred(Tab, Key, {fun ets:delete_object/2, [Object]}, nil, State, d),
true.

%% @equiv file2tab(Filenames, [])
Expand Down
3 changes: 0 additions & 3 deletions src/shards_owner_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
%% Macro to setup a supervisor worker
-define(worker(Mod, Args, Spec), child(worker, Mod, Args, Spec)).

%% Default number of shards
-define(N_SHARDS, erlang:system_info(schedulers_online)).

%% Macro to check if restart strategy is allowed
-define(is_restart_strategy(S_), S_ == one_for_one; S_ == one_for_all).

Expand Down
2 changes: 1 addition & 1 deletion test/test_helper.hrl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
%%%-------------------------------------------------------------------
%%% @doc
%%% Common definitions.
%%% Commons.
%%% @end
%%%-------------------------------------------------------------------

Expand Down

0 comments on commit e73ed46

Please sign in to comment.