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;

Reply via email to