summaryrefslogtreecommitdiff
path: root/src/mem3.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem3.erl')
-rw-r--r--src/mem3.erl56
1 files changed, 52 insertions, 4 deletions
diff --git a/src/mem3.erl b/src/mem3.erl
index 4f7c6ade..e6ee5bf8 100644
--- a/src/mem3.erl
+++ b/src/mem3.erl
@@ -1,7 +1,7 @@
-module(mem3).
--author('Brad Anderson <brad@cloudant.com>').
--export([start/0, stop/0, restart/0, state/0]).
+-export([start/0, stop/0, restart/0, state/0, nodes/0, shards/1, shards/2,
+ choose_shards/2]).
-include("mem3.hrl").
@@ -22,7 +22,7 @@ restart() ->
%% key and the nodes holding that state as the value. Also reports member
%% nodes which fail to respond and nodes which are connected but are not
%% cluster members. Useful for debugging.
--spec state() -> [{mem_state() | bad_nodes | non_member_nodes, [node()]}].
+-spec state() -> [{any | bad_nodes | non_member_nodes, [node()]}].
state() ->
{ok, Nodes} = mem3:nodes(),
AllNodes = erlang:nodes([this, visible]),
@@ -30,4 +30,52 @@ state() ->
Dict = lists:foldl(fun({Node, {ok,State}}, D) ->
orddict:append(State, Node, D)
end, orddict:new(), Replies),
- [{non_member_nodes, AllNodes -- Nodes}, {bad_nodes, BadNodes} | Dict]. \ No newline at end of file
+ [{non_member_nodes, AllNodes -- Nodes}, {bad_nodes, BadNodes} | Dict].
+
+-spec nodes() -> [node()].
+nodes() ->
+ mem3_nodes:get_nodelist().
+
+-spec shards(DbName::binary()) -> [#shard{}].
+shards(DbName) ->
+ case ets:lookup(partitions, DbName) of
+ [] ->
+ % TODO fall back to checking dbs.couch directly
+ erlang:error(database_does_not_exist);
+ Else ->
+ Else
+ end.
+
+-spec shards(DbName::binary(), DocId::binary()) -> [#shard{}].
+shards(DbName, DocId) ->
+ HashKey = mem3_util:hash(DocId),
+ Head = #shard{
+ name = '_',
+ node = '_',
+ dbname = DbName,
+ range = ['$1','$2'],
+ ref = '_'
+ },
+ % TODO these conditions assume A < B, which we don't require
+ Conditions = [{'<', '$1', HashKey}, {'=<', HashKey, '$2'}],
+ case ets:select(partitions, [{Head, Conditions, ['$_']}]) of
+ [] ->
+ % TODO fall back to checking dbs.couch directly
+ erlang:error(database_does_not_exist);
+ Shards ->
+ Shards
+ end.
+
+choose_shards(DbName, Options) ->
+ try shards(DbName)
+ catch error:database_does_not_exist ->
+ Nodes = mem3:nodes(),
+ NodeCount = length(Nodes),
+ 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"))),
+ % 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)
+ end.