Explicit zone placement
Project: http://git-wip-us.apache.org/repos/asf/couchdb-mem3/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-mem3/commit/d5f5ff2c Tree: http://git-wip-us.apache.org/repos/asf/couchdb-mem3/tree/d5f5ff2c Diff: http://git-wip-us.apache.org/repos/asf/couchdb-mem3/diff/d5f5ff2c Branch: refs/heads/import Commit: d5f5ff2ccdb44df5dbc0df61169163d90aced978 Parents: e108c74 Author: Robert Newson <robert.new...@cloudant.com> Authored: Thu Sep 27 00:38:09 2012 +0100 Committer: Robert Newson <robert.new...@cloudant.com> Committed: Thu Sep 27 13:48:02 2012 +0100 ---------------------------------------------------------------------- src/mem3.erl | 64 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-mem3/blob/d5f5ff2c/src/mem3.erl ---------------------------------------------------------------------- diff --git a/src/mem3.erl b/src/mem3.erl index 80283ae..41ad579 100644 --- a/src/mem3.erl +++ b/src/mem3.erl @@ -137,27 +137,53 @@ choose_shards(DbName, Options) -> try shards(DbName) catch error:E when E==database_does_not_exist; E==badarg -> Nodes = mem3:nodes(), - NodeCount = length(Nodes), - Zones = zones(Nodes), - ZoneCount = length(Zones), - if ZoneCount =:= 0 -> erlang:error(no_available_zones); true -> ok end, - N = mem3_util:n_val(couch_util:get_value(n, Options), NodeCount), - Q = mem3_util:to_integer(couch_util:get_value(q, Options, - couch_config:get("cluster", "q", "8"))), - Z = mem3_util:z_val(couch_util:get_value(z, Options), NodeCount, ZoneCount), - Suffix = couch_util:get_value(shard_suffix, Options, ""), - ChosenZones = lists:sublist(shuffle(Zones), Z), - lists:flatmap( - fun({Zone, N1}) -> - Nodes1 = nodes_in_zone(Nodes, Zone), - {A, B} = lists:split(crypto:rand_uniform(1,length(Nodes1)+1), Nodes1), - RotatedNodes = B ++ A, - mem3_util:create_partition_map(DbName, erlang:min(N1,length(Nodes1)), - Q, RotatedNodes, Suffix) - end, - lists:zip(ChosenZones, apportion(N, Z))) + case get_placement(Options) of + undefined -> + choose_shards(DbName, Nodes, Options); + Placement -> + lists:flatmap(fun({Zone, N}) -> + NodesInZone = nodes_in_zone(Nodes, Zone), + Options1 = lists:keymerge(1, [{n,N}], Options), + choose_shards(DbName, NodesInZone, Options1) + end, Placement) + end end. +choose_shards(DbName, Nodes, Options) -> + NodeCount = length(Nodes), + Suffix = couch_util:get_value(shard_suffix, Options, ""), + N = mem3_util:n_val(couch_util:get_value(n, Options), NodeCount), + if N =:= 0 -> erlang:error(no_nodes_in_zone); + true -> ok + end, + Q = mem3_util:to_integer(couch_util:get_value(q, Options, + couch_config:get("cluster", "q", "8"))), + %% rotate to a random entry in the nodelist for even distribution + {A, B} = lists:split(crypto:rand_uniform(1,length(Nodes)+1), Nodes), + RotatedNodes = B ++ A, + mem3_util:create_partition_map(DbName, N, Q, RotatedNodes, Suffix). + +%% either directly as [{term(), non_neg_integer()}] or +%% a config setting as "a:2,b:1" +get_placement(Options) -> + case couch_util:get_value(placement, Options) of + undefined -> + case couch_config:get("cluster", "placement") of + undefined -> + undefined; + PlacementStr -> + decode_placement_string(PlacementStr) + end; + Placement -> + Placement + end. + +decode_placement_string(PlacementStr) -> + [begin + [Zone, N] = string:tokens(Rule, ":"), + {list_to_binary(Zone), list_to_integer(N)} + end || Rule <- string:tokens(PlacementStr, ",")]. + -spec dbname(#shard{} | iodata()) -> binary(). dbname(#shard{dbname = DbName}) -> DbName;