summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon MacMullen <simon@rabbitmq.com>2011-07-04 14:43:29 +0100
committerSimon MacMullen <simon@rabbitmq.com>2011-07-04 14:43:29 +0100
commit9db1caee2f802ecffa3d75baef984cd2d293a209 (patch)
tree1917a5e72f74cb0cc15f93116fb7e071e2482c63
parentaffb0a5024c8156961bc16b53f483b7a4a4a522d (diff)
downloadrabbitmq-server-git-9db1caee2f802ecffa3d75baef984cd2d293a209.tar.gz
Support childspecs returned from Module:init(). Unfortunately a bit fiddly as we need to cast a message to ourselves (since we can't start children until the overall supervisor is up) but then we need to cast another one back so as to still start up synchronously.
-rw-r--r--src/mirrored_supervisor.erl46
-rw-r--r--src/mirrored_supervisor_tests.erl24
2 files changed, 52 insertions, 18 deletions
diff --git a/src/mirrored_supervisor.erl b/src/mirrored_supervisor.erl
index add2c1208b..877efe4f6b 100644
--- a/src/mirrored_supervisor.erl
+++ b/src/mirrored_supervisor.erl
@@ -45,7 +45,7 @@
-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3,
handle_cast/2]).
--export([start_internal/2]).
+-export([start_internal/4]).
-export([create_tables/0, table_definitions/0]).
-record(mirrored_sup_childspec, {id, mirroring_pid, childspec}).
@@ -59,8 +59,12 @@ start_link(_Group, _Mod, _Args) ->
exit(mirrored_supervisors_must_be_locally_named).
start_link({local, SupName}, Group, Mod, Args) ->
- ?SUPERVISOR:start_link({local, SupName}, ?MODULE,
- {overall, SupName, Group, Mod, Args});
+ R = ?SUPERVISOR:start_link({local, SupName}, ?MODULE,
+ {overall, SupName, Group, Mod, Args, self()}),
+ receive
+ started -> ok
+ end,
+ R;
start_link({global, _SupName}, _Group, _Mod, _Args) ->
exit(mirrored_supervisors_must_be_locally_named).
@@ -84,20 +88,27 @@ child(Sup, Name) ->
%%----------------------------------------------------------------------------
-start_internal(Sup, Group) ->
+start_internal(Sup, Group, ChildSpecs, Notify) ->
?GEN_SERVER:start_link(
- ?MODULE, {mirroring, Sup, Group}, [{timeout, infinity}]).
+ ?MODULE, {mirroring, Sup, Group, ChildSpecs, Notify},
+ [{timeout, infinity}]).
%%----------------------------------------------------------------------------
-init({overall, SupName, Group, Mod, Args}) ->
- Delegate = {delegate, {?SUPERVISOR, start_link, [Mod, Args]},
+init({overall, SupName, Group, Mod, Args, Notify}) ->
+ {ok, {Restart, ChildSpecs}} = Mod:init(Args),
+ Delegate = {delegate, {?SUPERVISOR, start_link,
+ [?MODULE, {delegate, Restart}]},
transient, 16#ffffffff, supervisor, [?SUPERVISOR]},
- Mirroring = {mirroring, {?MODULE, start_internal, [SupName, Group]},
+ Mirroring = {mirroring, {?MODULE, start_internal,
+ [SupName, Group, ChildSpecs, Notify]},
transient, 16#ffffffff, worker, [?MODULE]},
{ok, {{one_for_all, 0, 1}, [Delegate, Mirroring]}};
-init({mirroring, Sup, Group}) ->
+init({delegate, Restart}) ->
+ {ok, {Restart, []}};
+
+init({mirroring, Sup, Group, ChildSpecs, Notify}) ->
pg2_fixed:create(Group),
[begin
gen_server2:call(Pid, {hello, self()}, infinity),
@@ -105,14 +116,12 @@ init({mirroring, Sup, Group}) ->
end
|| Pid <- pg2_fixed:get_members(Group)],
ok = pg2_fixed:join(Group, self()),
+ ?GEN_SERVER:cast(self(), {start_initial_children, ChildSpecs, Notify}),
{ok, #state{overall = Sup, group = Group}}.
handle_call({start_child, ChildSpec}, _From,
State = #state{overall = Overall}) ->
- {reply, case mnesia:transaction(fun() -> check_start(ChildSpec) end) of
- {atomic, start} -> start(Overall, ChildSpec);
- {atomic, Pid} -> {ok, Pid}
- end, State};
+ {reply, maybe_start(Overall, ChildSpec), State};
handle_call({delete_child, Id}, _From,
State = #state{overall = Overall}) ->
@@ -132,6 +141,12 @@ handle_call(overall_supervisor, _From, State = #state{overall = Sup}) ->
handle_call(Msg, _From, State) ->
{stop, {unexpected_call, Msg}, State}.
+handle_cast({start_initial_children, ChildSpecs, Notify},
+ State = #state{overall = Overall}) ->
+ [maybe_start(Overall, S) || S <- ChildSpecs],
+ Notify ! started,
+ {noreply, State};
+
handle_cast(Msg, State) ->
{stop, {unexpected_cast, Msg}, State}.
@@ -160,6 +175,11 @@ code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%----------------------------------------------------------------------------
+maybe_start(Overall, ChildSpec) ->
+ case mnesia:transaction(fun() -> check_start(ChildSpec) end) of
+ {atomic, start} -> start(Overall, ChildSpec);
+ {atomic, Pid} -> {ok, Pid}
+ end.
check_start(ChildSpec) ->
case mnesia:wread({?TABLE, id(ChildSpec)}) of
diff --git a/src/mirrored_supervisor_tests.erl b/src/mirrored_supervisor_tests.erl
index 7f69fb45d8..5a587df463 100644
--- a/src/mirrored_supervisor_tests.erl
+++ b/src/mirrored_supervisor_tests.erl
@@ -34,6 +34,7 @@ all_tests() ->
passed = test_already_there(),
passed = test_delete_restart(),
passed = test_large_group(),
+ passed = test_childspecs_at_init(),
passed.
%% Simplest test
@@ -91,6 +92,16 @@ test_large_group() ->
false = (Pid1 =:= Pid2)
end, [a, b, c, d]).
+%% Do childspecs work when returned from init?
+test_childspecs_at_init() ->
+ S = childspec(worker),
+ with_sups(fun([A, _]) ->
+ Pid1 = pid_of(worker),
+ kill(A),
+ Pid2 = pid_of(worker),
+ false = (Pid1 =:= Pid2)
+ end, [{a, [S]}, {b, [S]}]).
+
%% ---------------------------------------------------------------------------
with_sups(Fun, Sups) ->
@@ -99,16 +110,19 @@ with_sups(Fun, Sups) ->
[kill(Pid) || Pid <- Pids, is_process_alive(Pid)],
passed.
-start_sup(Name) ->
- start_sup(Name, group).
+start_sup(Spec) ->
+ start_sup(Spec, group).
-start_sup(Name, Group) ->
+start_sup({Name, ChildSpecs}, Group) ->
{ok, Pid} = mirrored_supervisor:start_link({local, Name}, Group,
- ?MODULE, []),
+ ?MODULE, ChildSpecs),
%% We are not a supervisor, when we kill the supervisor we do not
%% want to die!
unlink(Pid),
- {ok, Pid}.
+ {ok, Pid};
+
+start_sup(Name, Group) ->
+ start_sup({Name, []}, Group).
childspec(Id) ->
{Id, {?MODULE, start_gs, [Id]}, transient, 16#ffffffff, worker, [?MODULE]}.