Skip to content

Commit 233314c

Browse files
committed
Initial commit
1 parent 48c31ed commit 233314c

File tree

7 files changed

+579
-11
lines changed

7 files changed

+579
-11
lines changed

.gitignore

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1+
.rebar3
2+
_build
3+
_checkouts
4+
_vendor
15
.eunit
26
*.o
37
*.beam
48
*.plt
9+
*.swp
10+
*.swo
11+
.erlang.cookie
12+
ebin
13+
log
514
erl_crash.dump
6-
.concrete/DEV_MODE
7-
8-
# rebar 2.x
915
.rebar
10-
rel/example_project
11-
ebin/*.beam
12-
deps
13-
14-
# rebar 3
15-
.rebar3
16-
_build/
17-
_checkouts/
16+
logs
17+
.idea
18+
*.iml
19+
rebar3.crashdump
20+
*~

rebar.config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{erl_opts, [debug_info]}.
2+
{deps, []}.

rebar.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[].

src/ring_calculator.app.src

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{application, ring_calculator, [
2+
{description, "A rebar plugin for Riak to compute ring configurations"},
3+
{vsn, "1.0.0"},
4+
{registered, []},
5+
{applications, [
6+
kernel,
7+
stdlib
8+
]},
9+
{env, []},
10+
{modules, []},
11+
{licenses, ["Apache-2.0"]},
12+
{links, []}
13+
]}.

src/ring_calculator.erl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-module(ring_calculator).
2+
3+
-export([init/1]).
4+
5+
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
6+
init(State) ->
7+
{ok, State1} = ring_calculator_prv:init(State),
8+
{ok, State1}.

src/ring_calculator_prv.erl

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
-module(ring_calculator_prv).
2+
3+
-export([init/1, do/1, format_error/1]).
4+
5+
-define(PROVIDER, ring_calculator).
6+
-define(DEPS, [app_discovery]).
7+
8+
%% ===================================================================
9+
%% Public API
10+
%% ===================================================================
11+
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
12+
init(State) ->
13+
Provider = providers:create([
14+
{name, ?PROVIDER}, % The 'user friendly' name of the task
15+
{module, ?MODULE}, % The module implementation of the task
16+
{bare, true}, % The task can be run by the user, always true
17+
{deps, ?DEPS}, % The list of dependencies
18+
{example, "rebar3 ring_calcular --ring_size 32 --nodes 8 --locations 3 "}, % How to use the plugin
19+
{opts, [{ring_size, $s, "ring_size", integer, "size of riak ring (default 64)"},
20+
{nodes, $n, "nodes", integer, "number of available riak nodes"},
21+
{locations, $l, "locations", integer, "number of physical locations you can run the nodes on"},
22+
{verbose, $v, "verbose", boolean, "print computation details"}
23+
]}, % list of options understood by the plugin
24+
{short_desc, "Compute Riak ring configurations"},
25+
{desc, "Compute Riak ring configurations based upon the number "
26+
"of nodes one has available, the number of different locations "
27+
"and the prefered ring size. In summary, it provides the "
28+
"best possible target n-val for the nodes and the best possible "
29+
"location val given your available nodes and locations."
30+
}
31+
]),
32+
{ok, rebar_state:add_provider(State, Provider)}.
33+
34+
35+
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
36+
do(State) ->
37+
{KVs, _} = rebar_state:command_parsed_args(State),
38+
RingSize = proplists:get_value(ring_size, KVs, 64),
39+
NrNodes = proplists:get_value(nodes, KVs, 8),
40+
Locs = proplists:get_value(locations, KVs, 4),
41+
Verbose = proplists:get_value(verbose, KVs, false),
42+
calc_nvals(RingSize, NrNodes, Locs, Verbose),
43+
{ok, State}.
44+
45+
-spec format_error(any()) -> iolist().
46+
format_error(Reason) ->
47+
io_lib:format("~p", [Reason]).
48+
49+
calc_nvals(RingSize, NrMachines, NrLocations, Verbose) when NrMachines > 0, NrLocations > 0 ->
50+
LVals = lists:seq(1, min(NrMachines, NrLocations)),
51+
TargetNVals = lists:seq(1, NrMachines),
52+
Sols = lists:flatten([ solutions(RingSize, LVal, TargetNVals, NrMachines, Locs, Verbose)
53+
|| LVal <- LVals, %% NVal <- TargetNVals,
54+
Locs <- lists:seq(1, NrLocations) ]),
55+
case Sols of
56+
[] ->
57+
io:format("No solution~n");
58+
_ ->
59+
{BestLVal, BestNVal, Config, Ring} =
60+
lists:last(lists:sort([ Sol || {_, _, _, _} = Sol <- Sols ])),
61+
io:format("~nBest solution:~nTarget Nval ~p~nLocation val ~p~nConfig ~p~nRing: ~s~n",
62+
[BestNVal, BestLVal, Config, ring_calculator_ring:show(Ring, {BestNVal, BestLVal})])
63+
end.
64+
65+
solutions(RingSize, LVal, [NVal | NVals], NrMachines, NrLocations, Verbose) when 0 < LVal, LVal =< NrLocations ->
66+
%% spread machines evenly
67+
Config = spread_over_locations(lists:duplicate(NrLocations, 0), NrMachines),
68+
[ io:format("Config ~p ", [Config]) || Verbose ],
69+
Solution = ring_calculator_ring:solve(RingSize, Config, {NVal, LVal}),
70+
ZeroViolations = ring_calculator_ring:zero_violations(Solution, {NVal, LVal}),
71+
[ io:format("Target Nval: ~p, Locaction val: ~p Success: ~p~n", [NVal, LVal, ZeroViolations ]) || Verbose ],
72+
if ZeroViolations ->
73+
[ io:format(".") || not Verbose ],
74+
[{LVal, NVal, Config, Solution} | solutions(RingSize, LVal, NVals, NrMachines, NrLocations, Verbose) ];
75+
true ->
76+
[ io:format("x") || not Verbose ],
77+
[]
78+
end;
79+
solutions(_RingSize, _LVal, _, _NrMachines, _NrLocations, _Verbose) ->
80+
[].
81+
82+
spread_over_locations(Config, 0) ->
83+
Config;
84+
spread_over_locations([Hd | Tl], NrMachines) ->
85+
spread_over_locations(Tl++[Hd + 1], NrMachines - 1).

0 commit comments

Comments
 (0)