|
| 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