summaryrefslogtreecommitdiff
path: root/src/rabbit.erl
diff options
context:
space:
mode:
authorTony Garnock-Jones <tonyg@lshift.net>2009-12-14 21:45:31 +0000
committerTony Garnock-Jones <tonyg@lshift.net>2009-12-14 21:45:31 +0000
commit69f5859a2e2b6631cd21896d267543e9627ea101 (patch)
tree3b79390a1600a3884b20c4ff3b9e950e0c81037b /src/rabbit.erl
parent0b511d1b3f4872c0bc96fa06d73e163ab1cb41ec (diff)
downloadrabbitmq-server-git-69f5859a2e2b6631cd21896d267543e9627ea101.tar.gz
Move planning code out of activator and into rabbit proper.
Diffstat (limited to 'src/rabbit.erl')
-rw-r--r--src/rabbit.erl120
1 files changed, 90 insertions, 30 deletions
diff --git a/src/rabbit.erl b/src/rabbit.erl
index 78bf7e3873..dd5f221a32 100644
--- a/src/rabbit.erl
+++ b/src/rabbit.erl
@@ -33,7 +33,7 @@
-behaviour(application).
--export([prepare/0, start/0, finish_boot/1, stop/0, stop_and_halt/0, status/0, rotate_logs/1]).
+-export([prepare/0, start/0, stop/0, stop_and_halt/0, status/0, rotate_logs/1]).
-export([start/2, stop/1]).
@@ -80,11 +80,9 @@
-type(log_location() :: 'tty' | 'undefined' | string()).
-type(file_suffix() :: binary()).
--type(boot_step() :: {{atom(), {atom(), 0}}, [{atom(), any()}]}).
-spec(prepare/0 :: () -> 'ok').
-spec(start/0 :: () -> 'ok').
--spec(finish_boot/1 :: ([boot_step()]) -> 'ok').
-spec(stop/0 :: () -> 'ok').
-spec(stop_and_halt/0 :: () -> 'ok').
-spec(rotate_logs/1 :: (file_suffix()) -> 'ok' | {'error', any()}).
@@ -141,24 +139,33 @@ rotate_logs(BinarySuffix) ->
%%--------------------------------------------------------------------
start(normal, []) ->
- {ok, _SupPid} = rabbit_sup:start_link().
-
-finish_boot(BootSteps) ->
- %% We set our group_leader so we appear to OTP to be part of the
- %% rabbit application.
- case application_controller:get_master(rabbit) of
- undefined ->
- exit({?MODULE, finish_boot, could_not_find_rabbit});
- MasterPid when is_pid(MasterPid) ->
- group_leader(MasterPid, self())
- end,
+ {ok, SupPid} = rabbit_sup:start_link(),
print_banner(),
- [ok = run_boot_step(Step) || Step <- BootSteps],
+ [ok = run_boot_step(Step) || Step <- boot_steps()],
io:format("~nbroker running~n"),
+
+ {ok, SupPid}.
+
+
+stop(_State) ->
+ terminated_ok = error_logger:delete_report_handler(rabbit_error_logger),
+ ok = rabbit_alarm:stop(),
+ ok = case rabbit_mnesia:is_clustered() of
+ true -> rabbit_amqqueue:on_node_down(node());
+ false -> rabbit_mnesia:empty_ram_only_tables()
+ end,
ok.
-run_boot_step({ModFunSpec = {Module, {Fun, 0}}, Attributes}) ->
+%%---------------------------------------------------------------------------
+
+boot_error(Format, Args) ->
+ io:format(Format, Args),
+ error_logger:error_msg(Format, Args),
+ timer:sleep(1000),
+ exit({?MODULE, failure_during_boot}).
+
+run_boot_step({{Module, {Fun, 0}}, Attributes}) ->
Description = case lists:keysearch(description, 1, Attributes) of
{value, {_, D}} -> D;
false -> lists:flatten(io_lib:format("~w:~w", [Module, Fun]))
@@ -166,16 +173,78 @@ run_boot_step({ModFunSpec = {Module, {Fun, 0}}, Attributes}) ->
io:format("starting ~-20s ...", [Description]),
case catch Module:Fun() of
{'EXIT', Reason} ->
- io:format("FAILED~nReason: ~p~n", [Reason]),
- ChainedReason = {?MODULE, finish_boot, failed, ModFunSpec, Reason},
- error_logger:error_report(ChainedReason),
- timer:sleep(1000),
- exit(ChainedReason);
+ boot_error("FAILED~nReason: ~p~n", [Reason]);
ok ->
io:format("done~n"),
ok
end.
+boot_steps() ->
+ AllApps = [App || {App, _, _} <- application:loaded_applications()],
+ Modules = lists:usort(
+ lists:append([Modules
+ || {ok, Modules} <- [application:get_key(App, modules)
+ || App <- AllApps]])),
+ UnsortedSteps =
+ lists:flatmap(fun (Module) ->
+ [{{Module, FunSpec}, Attributes}
+ || {rabbit_boot_step, [{FunSpec, Attributes}]}
+ <- Module:module_info(attributes)]
+ end, Modules),
+ sort_boot_steps(UnsortedSteps).
+
+sort_boot_steps(UnsortedSteps) ->
+ G = digraph:new([acyclic]),
+ [digraph:add_vertex(G, ModFunSpec, Step) || Step = {ModFunSpec, _Attrs} <- UnsortedSteps],
+ lists:foreach(fun ({ModFunSpec, Attributes}) ->
+ [add_boot_step_dep(G, ModFunSpec, PostModFunSpec)
+ || {post, PostModFunSpec} <- Attributes],
+ [add_boot_step_dep(G, PreModFunSpec, ModFunSpec)
+ || {pre, PreModFunSpec} <- Attributes]
+ end, UnsortedSteps),
+ SortedStepsRev = [begin
+ {ModFunSpec, Step} = digraph:vertex(G, ModFunSpec),
+ Step
+ end || ModFunSpec <- digraph_utils:topsort(G)],
+ SortedSteps = lists:reverse(SortedStepsRev),
+ digraph:delete(G),
+ check_boot_steps(SortedSteps).
+
+add_boot_step_dep(G, RunsSecond, RunsFirst) ->
+ case digraph:add_edge(G, RunsSecond, RunsFirst) of
+ {error, Reason} ->
+ boot_error(
+ "Could not add boot step dependency of ~s on ~s:~n~s",
+ [format_modfunspec(RunsSecond), format_modfunspec(RunsFirst),
+ case Reason of
+ {bad_vertex, V} ->
+ io_lib:format("Boot step not registered: ~s~n",
+ [format_modfunspec(V)]);
+ {bad_edge, [First | Rest]} ->
+ [io_lib:format("Cyclic dependency: ~s", [format_modfunspec(First)]),
+ [io_lib:format(" depends on ~s", [format_modfunspec(Next)])
+ || Next <- Rest],
+ io_lib:format(" depends on ~s~n", [format_modfunspec(First)])]
+ end]);
+ _ ->
+ ok
+ end.
+
+check_boot_steps(SortedSteps) ->
+ case [ModFunSpec || {ModFunSpec = {Module, {Fun, Arity}}, _} <- SortedSteps,
+ not erlang:function_exported(Module, Fun, Arity)] of
+ [] ->
+ SortedSteps;
+ MissingFunctions ->
+ boot_error("Boot steps not exported:~s~n",
+ [[[" ", format_modfunspec(MFS)] || MFS <- MissingFunctions]])
+ end.
+
+format_modfunspec({Module, {Fun, Arity}}) ->
+ lists:flatten(io_lib:format("~w:~w/~b", [Module, Fun, Arity])).
+
+%%---------------------------------------------------------------------------
+
boot_database() ->
ok = rabbit_mnesia:init().
@@ -235,15 +304,6 @@ boot_ssl_listeners() ->
ok
end.
-stop(_State) ->
- terminated_ok = error_logger:delete_report_handler(rabbit_error_logger),
- ok = rabbit_alarm:stop(),
- ok = case rabbit_mnesia:is_clustered() of
- true -> rabbit_amqqueue:on_node_down(node());
- false -> rabbit_mnesia:empty_ram_only_tables()
- end,
- ok.
-
%---------------------------------------------------------------------------
log_location(Type) ->