summaryrefslogtreecommitdiff
path: root/src/fabric_create_db.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/fabric_create_db.erl')
-rw-r--r--src/fabric_create_db.erl66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/fabric_create_db.erl b/src/fabric_create_db.erl
new file mode 100644
index 00000000..b0ff39ce
--- /dev/null
+++ b/src/fabric_create_db.erl
@@ -0,0 +1,66 @@
+-module(fabric_create_db).
+-author(brad@cloudant.com).
+
+-export([create_db/2]).
+
+-include("../../couch/src/couch_db.hrl").
+-include("../../dynomite/include/membership.hrl").
+
+
+%% @doc Create a new database, and all its partition files across the cluster
+%% Options is proplist with user_ctx, n, q
+-spec create_db(binary(), list()) -> {ok, #db{}} | {error, any()}.
+create_db(DbName, Options) ->
+ Fullmap = partitions:fullmap(DbName, Options),
+ {ok, FullNodes} = mem3:fullnodes(),
+ RefPartMap = send_create_calls(Fullmap, Options),
+ Acc0 = {false, length(RefPartMap), lists:usort([ {Beg, false} ||
+ {_,#shard{range=[Beg,_]}} <- RefPartMap])},
+ Result = case fabric_util:receive_loop(
+ RefPartMap, 1, fun handle_create_msg/3, Acc0) of
+ {ok, _Results} -> ok;
+ Error -> Error
+ end,
+ % always install partition map, even w/ errors, so delete is possible
+ partitions:install_fullmap(DbName, Fullmap, FullNodes, Options),
+ Result.
+
+%%
+%% internal
+%%
+
+%% @doc create the partitions on all appropriate nodes (rexi calls)
+-spec send_create_calls(fullmap(), list()) -> [{reference(), part()}].
+send_create_calls(Fullmap, Options) ->
+ lists:map(fun(#shard{node=Node, name=ShardName} = Part) ->
+ Ref = rexi:async_server_call({couch_server, Node},
+ {create, ShardName, Options}),
+ {Ref, Part}
+ end, Fullmap).
+
+%% @doc handle create messages from shards
+handle_create_msg(_, file_exists, _) ->
+ {error, file_exists};
+handle_create_msg(_, {rexi_EXIT, _Reason}, {Complete, N, Parts}) ->
+ {ok, {Complete, N-1, Parts}};
+handle_create_msg(_, {rexi_DOWN, _, _, _}, {Complete, _N, _Parts}) ->
+ if
+ Complete -> {stop, ok};
+ true -> {error, create_db_fubar}
+ end;
+handle_create_msg(_, _, {true, 1, _Acc}) ->
+ {stop, ok};
+handle_create_msg({_, #shard{range=[Beg,_]}}, {ok, _}, {false, 1, PartResults0}) ->
+ PartResults = lists:keyreplace(Beg, 1, PartResults0, {Beg, true}),
+ case is_complete(PartResults) of
+ true -> {stop, ok};
+ false -> {error, create_db_fubar}
+ end;
+handle_create_msg(_RefPart, {ok, _}, {true, N, Parts}) ->
+ {ok, {true, N-1, Parts}};
+handle_create_msg({_Ref, #shard{range=[Beg,_]}}, {ok, _}, {false, Rem, PartResults0}) ->
+ PartResults = lists:keyreplace(Beg, 1, PartResults0, {Beg, true}),
+ {ok, {is_complete(PartResults), Rem-1, PartResults}}.
+
+is_complete(List) ->
+ lists:all(fun({_,Bool}) -> Bool end, List).