From 04811f9b349e548bf030cd9797eaf6034a6e4229 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Tue, 5 Nov 2013 14:50:33 +0000 Subject: Restructure our boot procedure for more flexible boot-step handling --- src/rabbit.erl | 136 +++------------------------------------------------------ 1 file changed, 5 insertions(+), 131 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 1b7fe6da..562497b3 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -312,8 +312,7 @@ start() -> ok = ensure_working_log_handlers(), rabbit_node_monitor:prepare_cluster_status_files(), rabbit_mnesia:check_cluster_consistency(), - ok = app_utils:start_applications( - app_startup_order(), fun handle_app_error/2), + ok = rabbit_boot:start(app_startup_order()), ok = log_broker_started(rabbit_plugins:active()) end). @@ -331,20 +330,10 @@ boot() -> rabbit_mnesia:check_cluster_consistency(), Plugins = rabbit_plugins:setup(), ToBeLoaded = Plugins ++ ?APPS, - ok = app_utils:load_applications(ToBeLoaded), - StartupApps = app_utils:app_dependency_order(ToBeLoaded, - false), - ok = app_utils:start_applications( - StartupApps, fun handle_app_error/2), + ok = rabbit_boot:start(ToBeLoaded), ok = log_broker_started(Plugins) end). -handle_app_error(App, {bad_return, {_MFA, {'EXIT', {Reason, _}}}}) -> - throw({could_not_start, App, Reason}); - -handle_app_error(App, Reason) -> - throw({could_not_start, App, Reason}). - start_it(StartFun) -> Marker = spawn_link(fun() -> receive stop -> ok end end), register(rabbit_boot, Marker), @@ -352,9 +341,9 @@ start_it(StartFun) -> StartFun() catch throw:{could_not_start, _App, _Reason}=Err -> - boot_error(Err, not_available); + rabbit_boot:boot_error(Err, not_available); _:Reason -> - boot_error(Reason, erlang:get_stacktrace()) + rabbit_boot:boot_error(Reason, erlang:get_stacktrace()) after unlink(Marker), Marker ! stop, @@ -367,7 +356,7 @@ stop() -> undefined -> ok; _ -> await_startup() end, - rabbit_log:info("Stopping RabbitMQ~n"), + rabbit_log:info("Stopping RabbitMQ~n"), %% TODO: move this to boot:stop/1 ok = app_utils:stop_applications(app_shutdown_order()). stop_and_halt() -> @@ -441,7 +430,6 @@ start(normal, []) -> true = register(rabbit, self()), print_banner(), log_banner(), - [ok = run_boot_step(Step) || Step <- boot_steps()], {ok, SupPid}; Error -> Error @@ -466,120 +454,6 @@ app_shutdown_order() -> Apps = ?APPS ++ rabbit_plugins:active(), app_utils:app_dependency_order(Apps, true). -%%--------------------------------------------------------------------------- -%% boot step logic - -run_boot_step({_StepName, Attributes}) -> - case [MFA || {mfa, MFA} <- Attributes] of - [] -> - ok; - MFAs -> - [try - apply(M,F,A) - of - ok -> ok; - {error, Reason} -> boot_error(Reason, not_available) - catch - _:Reason -> boot_error(Reason, erlang:get_stacktrace()) - end || {M,F,A} <- MFAs], - ok - end. - -boot_steps() -> - sort_boot_steps(rabbit_misc:all_module_attributes(rabbit_boot_step)). - -vertices(_Module, Steps) -> - [{StepName, {StepName, Atts}} || {StepName, Atts} <- Steps]. - -edges(_Module, Steps) -> - [case Key of - requires -> {StepName, OtherStep}; - enables -> {OtherStep, StepName} - end || {StepName, Atts} <- Steps, - {Key, OtherStep} <- Atts, - Key =:= requires orelse Key =:= enables]. - -sort_boot_steps(UnsortedSteps) -> - case rabbit_misc:build_acyclic_graph(fun vertices/2, fun edges/2, - UnsortedSteps) of - {ok, G} -> - %% Use topological sort to find a consistent ordering (if - %% there is one, otherwise fail). - SortedSteps = lists:reverse( - [begin - {StepName, Step} = digraph:vertex(G, - StepName), - Step - end || StepName <- digraph_utils:topsort(G)]), - digraph:delete(G), - %% Check that all mentioned {M,F,A} triples are exported. - case [{StepName, {M,F,A}} || - {StepName, Attributes} <- SortedSteps, - {mfa, {M,F,A}} <- Attributes, - not erlang:function_exported(M, F, length(A))] of - [] -> SortedSteps; - MissingFunctions -> basic_boot_error( - {missing_functions, MissingFunctions}, - "Boot step functions not exported: ~p~n", - [MissingFunctions]) - end; - {error, {vertex, duplicate, StepName}} -> - basic_boot_error({duplicate_boot_step, StepName}, - "Duplicate boot step name: ~w~n", [StepName]); - {error, {edge, Reason, From, To}} -> - basic_boot_error( - {invalid_boot_step_dependency, From, To}, - "Could not add boot step dependency of ~w on ~w:~n~s", - [To, From, - case Reason of - {bad_vertex, V} -> - io_lib:format("Boot step not registered: ~w~n", [V]); - {bad_edge, [First | Rest]} -> - [io_lib:format("Cyclic dependency: ~w", [First]), - [io_lib:format(" depends on ~w", [Next]) || - Next <- Rest], - io_lib:format(" depends on ~w~n", [First])] - end]) - end. - --ifdef(use_specs). --spec(boot_error/2 :: (term(), not_available | [tuple()]) -> no_return()). --endif. -boot_error(Term={error, {timeout_waiting_for_tables, _}}, _Stacktrace) -> - AllNodes = rabbit_mnesia:cluster_nodes(all), - {Err, Nodes} = - case AllNodes -- [node()] of - [] -> {"Timeout contacting cluster nodes. Since RabbitMQ was" - " shut down forcefully~nit cannot determine which nodes" - " are timing out.~n", []}; - Ns -> {rabbit_misc:format( - "Timeout contacting cluster nodes: ~p.~n", [Ns]), - Ns} - end, - basic_boot_error(Term, - Err ++ rabbit_nodes:diagnostics(Nodes) ++ "~n~n", []); -boot_error(Reason, Stacktrace) -> - Fmt = "Error description:~n ~p~n~n" ++ - "Log files (may contain more information):~n ~s~n ~s~n~n", - Args = [Reason, log_location(kernel), log_location(sasl)], - boot_error(Reason, Fmt, Args, Stacktrace). - --ifdef(use_specs). --spec(boot_error/4 :: (term(), string(), [any()], not_available | [tuple()]) - -> no_return()). --endif. -boot_error(Reason, Fmt, Args, not_available) -> - basic_boot_error(Reason, Fmt, Args); -boot_error(Reason, Fmt, Args, Stacktrace) -> - basic_boot_error(Reason, Fmt ++ "Stack trace:~n ~p~n~n", - Args ++ [Stacktrace]). - -basic_boot_error(Reason, Format, Args) -> - io:format("~n~nBOOT FAILED~n===========~n~n" ++ Format, Args), - rabbit_misc:local_info_msg(Format, Args), - timer:sleep(1000), - exit({?MODULE, failure_during_boot, Reason}). - %%--------------------------------------------------------------------------- %% boot step functions -- cgit v1.2.1 From 34127a2ab633e8d54acc67bab24d802cd50d9798 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Wed, 6 Nov 2013 11:51:07 +0000 Subject: track boot status throughout a node's lifetime --- src/rabbit.erl | 80 +++++++++++++++++++++++----------------------------------- 1 file changed, 31 insertions(+), 49 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 562497b3..74efbf22 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -305,59 +305,40 @@ ensure_application_loaded() -> end. start() -> - start_it(fun() -> - %% We do not want to HiPE compile or upgrade - %% mnesia after just restarting the app - ok = ensure_application_loaded(), - ok = ensure_working_log_handlers(), - rabbit_node_monitor:prepare_cluster_status_files(), - rabbit_mnesia:check_cluster_consistency(), - ok = rabbit_boot:start(app_startup_order()), - ok = log_broker_started(rabbit_plugins:active()) - end). + rabbit_boot:boot_with( + fun() -> + %% We do not want to HiPE compile or upgrade + %% mnesia after just restarting the app + ok = ensure_application_loaded(), + ok = ensure_working_log_handlers(), + rabbit_node_monitor:prepare_cluster_status_files(), + rabbit_mnesia:check_cluster_consistency(), + ok = rabbit_boot:start(app_startup_order()), + ok = log_broker_started(rabbit_plugins:active()) + end). boot() -> - start_it(fun() -> - ok = ensure_application_loaded(), - Success = maybe_hipe_compile(), - ok = ensure_working_log_handlers(), - warn_if_hipe_compilation_failed(Success), - rabbit_node_monitor:prepare_cluster_status_files(), - ok = rabbit_upgrade:maybe_upgrade_mnesia(), - %% It's important that the consistency check happens after - %% the upgrade, since if we are a secondary node the - %% primary node will have forgotten us - rabbit_mnesia:check_cluster_consistency(), - Plugins = rabbit_plugins:setup(), - ToBeLoaded = Plugins ++ ?APPS, - ok = rabbit_boot:start(ToBeLoaded), - ok = log_broker_started(Plugins) - end). - -start_it(StartFun) -> - Marker = spawn_link(fun() -> receive stop -> ok end end), - register(rabbit_boot, Marker), - try - StartFun() - catch - throw:{could_not_start, _App, _Reason}=Err -> - rabbit_boot:boot_error(Err, not_available); - _:Reason -> - rabbit_boot:boot_error(Reason, erlang:get_stacktrace()) - after - unlink(Marker), - Marker ! stop, - %% give the error loggers some time to catch up - timer:sleep(100) - end. + rabbit_boot:boot_with( + fun() -> + ok = ensure_application_loaded(), + Success = maybe_hipe_compile(), + ok = ensure_working_log_handlers(), + warn_if_hipe_compilation_failed(Success), + rabbit_node_monitor:prepare_cluster_status_files(), + ok = rabbit_upgrade:maybe_upgrade_mnesia(), + %% It's important that the consistency check happens after + %% the upgrade, since if we are a secondary node the + %% primary node will have forgotten us + rabbit_mnesia:check_cluster_consistency(), + Plugins = rabbit_plugins:setup(), + ToBeLoaded = Plugins ++ ?APPS, + ok = rabbit_boot:start(ToBeLoaded), + ok = log_broker_started(Plugins) + end). stop() -> - case whereis(rabbit_boot) of - undefined -> ok; - _ -> await_startup() - end, - rabbit_log:info("Stopping RabbitMQ~n"), %% TODO: move this to boot:stop/1 - ok = app_utils:stop_applications(app_shutdown_order()). + rabbit_log:info("Stopping RabbitMQ~n"), + rabbit_boot:shutdown(app_shutdown_order()). stop_and_halt() -> try @@ -441,6 +422,7 @@ stop(_State) -> true -> rabbit_amqqueue:on_node_down(node()); false -> rabbit_table:clear_ram_only_tables() end, + ok = rabbit_boot:shutdown(), ok. %%--------------------------------------------------------------------------- -- cgit v1.2.1 From 4d5ac08b57dd4ac2f68244f3c6a08d96d8551cbc Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Wed, 20 Nov 2013 12:13:05 +0000 Subject: Various boot procedure improvements We ensure that all dependent applications are stopped, but also that dependencies shared by multiple applications (e.g., amqp_client) are not. --- src/rabbit.erl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 74efbf22..44cd275d 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -457,12 +457,12 @@ maybe_insert_default_data() -> end. insert_default_data() -> - {ok, DefaultUser} = application:get_env(default_user), - {ok, DefaultPass} = application:get_env(default_pass), - {ok, DefaultTags} = application:get_env(default_user_tags), - {ok, DefaultVHost} = application:get_env(default_vhost), + {ok, DefaultUser} = application:get_env(rabbit, default_user), + {ok, DefaultPass} = application:get_env(rabbit, default_pass), + {ok, DefaultTags} = application:get_env(rabbit, default_user_tags), + {ok, DefaultVHost} = application:get_env(rabbit, default_vhost), {ok, [DefaultConfigurePerm, DefaultWritePerm, DefaultReadPerm]} = - application:get_env(default_permissions), + application:get_env(rabbit, default_permissions), ok = rabbit_vhost:add(DefaultVHost), ok = rabbit_auth_backend_internal:add_user(DefaultUser, DefaultPass), ok = rabbit_auth_backend_internal:set_tags(DefaultUser, DefaultTags), -- cgit v1.2.1 From b54be485a07a9bf3e96133f4b2c588f8a5b97e88 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Thu, 21 Nov 2013 21:59:55 +0000 Subject: Re-work boot step handling We need to support interleaving plugin boot steps with rabbit?s own (internal) ones during the boot/start sequence, and also running them independently during runtime activation. This commit also drops the use of an ets table to track which cleanup steps we?ve run, and simplifies the boot step execution procedures. --- src/rabbit.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 44cd275d..374fccc3 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -411,6 +411,7 @@ start(normal, []) -> true = register(rabbit, self()), print_banner(), log_banner(), + rabbit_boot:run_boot_steps(), {ok, SupPid}; Error -> Error -- cgit v1.2.1 From 37a44282681ceadfe812810a1ff1b25f0dc9fbba Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Tue, 18 Feb 2014 13:03:29 +0000 Subject: Use a gen_server to keep the boot steps table around --- src/rabbit.erl | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 081e2e22..102d9815 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -41,6 +41,12 @@ {requires, pre_boot}, {enables, external_infrastructure}]}). +-rabbit_boot_step({boot_table, + [{mfa, {rabbit_sup, start_child, + [rabbit_boot_table, rabbit_boot, []]}}, + {requires, file_handle_cache}, + {enables, external_infrastructure}]}). + -rabbit_boot_step({database, [{mfa, {rabbit_mnesia, init, []}}, {requires, file_handle_cache}, -- cgit v1.2.1 From e280ff6cc2bebfb13e3f6ca8951bf931e6e9fade Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Tue, 18 Feb 2014 13:55:51 +0000 Subject: Simplifying refactor Since the "rabbit" process /always/ starts before everything else, handle boot table creation at that point and avoid the ets ownership issue and corresponding messiness. The previous worries about handling situations where we want to run rabbit_boot code whilst rabbit is offline aren't an issue for us. --- src/rabbit.erl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 102d9815..3690329f 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -41,12 +41,6 @@ {requires, pre_boot}, {enables, external_infrastructure}]}). --rabbit_boot_step({boot_table, - [{mfa, {rabbit_sup, start_child, - [rabbit_boot_table, rabbit_boot, []]}}, - {requires, file_handle_cache}, - {enables, external_infrastructure}]}). - -rabbit_boot_step({database, [{mfa, {rabbit_mnesia, init, []}}, {requires, file_handle_cache}, @@ -425,6 +419,7 @@ start(normal, []) -> true = register(rabbit, self()), print_banner(), log_banner(), + rabbit_boot:prepare_boot_table(), rabbit_boot:run_boot_steps(), {ok, SupPid}; Error -> -- cgit v1.2.1 From 43e19adfecf51a7854ac91b8b3c6dd7ecd05ca10 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Tue, 18 Feb 2014 15:01:19 +0000 Subject: Try and reduce the distance to default --- src/rabbit.erl | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 2 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 3690329f..5d9aaa5f 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -318,7 +318,7 @@ start() -> end). boot() -> - rabbit_boot:boot_with( + boot_with( fun() -> ok = ensure_application_loaded(), Success = maybe_hipe_compile(), @@ -336,6 +336,35 @@ boot() -> ok = log_broker_started(Plugins) end). +handle_app_error(App, {bad_return, {_MFA, {'EXIT', {Reason, _}}}}) -> + throw({could_not_start, App, Reason}); + +handle_app_error(App, Reason) -> + throw({could_not_start, App, Reason}). + +boot_with(StartFun) -> + Marker = spawn_link(fun() -> receive stop -> ok end end), + case catch register(rabbit_boot, Marker) of + true -> try + case rabbit:is_running() of + true -> ok; + false -> StartFun() + end + catch + throw:{could_not_start, _App, _Reason}=Err -> + boot_error(Err, not_available); + _:Reason -> + boot_error(Reason, erlang:get_stacktrace()) + after + unlink(Marker), + Marker ! stop, + %% give the error loggers some time to catch up + timer:sleep(100) + end; + _ -> unlink(Marker), + Marker ! stop + end. + stop() -> rabbit_log:info("Stopping RabbitMQ~n"), rabbit_boot:shutdown(app_shutdown_order()). @@ -420,7 +449,7 @@ start(normal, []) -> print_banner(), log_banner(), rabbit_boot:prepare_boot_table(), - rabbit_boot:run_boot_steps(), + run_boot_steps(), {ok, SupPid}; Error -> Error @@ -446,6 +475,159 @@ app_shutdown_order() -> Apps = ?APPS ++ rabbit_plugins:active(), app_utils:app_dependency_order(Apps, true). +%%--------------------------------------------------------------------------- +%% boot step logic + +run_boot_steps() -> + Steps = rabbit_boot:load_steps(boot), + [ok = run_boot_step(Step) || Step <- Steps], + ok. + +run_boot_step({_, StepName, Attributes}) -> + case catch rabbit_boot:already_run(StepName) of + false -> ok = run_step(StepName, Attributes, mfa), + rabbit_boot:mark_complete(StepName); + _ -> ok + end, + ok. + +run_step(StepName, Attributes, AttributeName) -> + case [MFA || {Key, MFA} <- Attributes, + Key =:= AttributeName] of + [] -> + ok; + MFAs -> + [try + apply(M,F,A) + of + ok -> ok; + {error, Reason} -> boot_error({boot_step, StepName, Reason}, + not_available) + catch + _:Reason -> boot_error({boot_step, StepName, Reason}, + erlang:get_stacktrace()) + end || {M,F,A} <- MFAs], + ok + end. + +load_steps(Type) -> + StepAttrs = rabbit_misc:all_module_attributes_with_app(rabbit_boot_step), + sort_boot_steps( + Type, + lists:usort( + [{Mod, {AppName, Steps}} || {AppName, Mod, Steps} <- StepAttrs])). + +vertices(_Module, {AppName, Steps}) -> + [{StepName, {AppName, StepName, Atts}} || {StepName, Atts} <- Steps]. + +edges(Type) -> + %% When running "boot" steps, both hard _and_ soft dependencies are + %% considered equally. When running "cleanup" steps however, we only + %% consider /hard/ dependencies (i.e., of the form + %% {DependencyType, {hard, StepName}}) as dependencies. + fun (_Module, {_AppName, Steps}) -> + [case Key of + requires -> {StepName, strip_type(OtherStep)}; + enables -> {strip_type(OtherStep), StepName} + end || {StepName, Atts} <- Steps, + {Key, OtherStep} <- Atts, + filter_dependent_steps(Key, OtherStep, Type)] + end. + +filter_dependent_steps(Key, Dependency, Type) + when Key =:= requires orelse Key =:= enables -> + case {Dependency, Type} of + {{hard, _}, cleanup} -> true; + {_SoftReqs, cleanup} -> false; + {_, boot} -> true + end; +filter_dependent_steps(_, _, _) -> + false. + +strip_type({hard, Step}) -> Step; +strip_type(Step) -> Step. + +sort_boot_steps(Type, UnsortedSteps) -> + case rabbit_misc:build_acyclic_graph(fun vertices/2, edges(Type), + UnsortedSteps) of + {ok, G} -> + %% Use topological sort to find a consistent ordering (if + %% there is one, otherwise fail). + SortedSteps = lists:reverse( + [begin + {StepName, Step} = digraph:vertex(G, + StepName), + Step + end || StepName <- digraph_utils:topsort(G)]), + digraph:delete(G), + %% Check that all mentioned {M,F,A} triples are exported. + case [{StepName, {M,F,A}} || + {_App, StepName, Attributes} <- SortedSteps, + {mfa, {M,F,A}} <- Attributes, + not erlang:function_exported(M, F, length(A))] of + [] -> SortedSteps; + MissingFunctions -> basic_boot_error( + {missing_functions, MissingFunctions}, + "Boot step functions not exported: ~p~n", + [MissingFunctions]) + end; + {error, {vertex, duplicate, StepName}} -> + basic_boot_error({duplicate_boot_step, StepName}, + "Duplicate boot step name: ~w~n", [StepName]); + {error, {edge, Reason, From, To}} -> + basic_boot_error( + {invalid_boot_step_dependency, From, To}, + "Could not add boot step dependency of ~w on ~w:~n~s", + [To, From, + case Reason of + {bad_vertex, V} -> + io_lib:format("Boot step not registered: ~w~n", [V]); + {bad_edge, [First | Rest]} -> + [io_lib:format("Cyclic dependency: ~w", [First]), + [io_lib:format(" depends on ~w", [Next]) || + Next <- Rest], + io_lib:format(" depends on ~w~n", [First])] + end]) + end. + +-ifdef(use_specs). +-spec(boot_error/2 :: (term(), not_available | [tuple()]) -> no_return()). +-endif. +boot_error(Term={error, {timeout_waiting_for_tables, _}}, _Stacktrace) -> + AllNodes = rabbit_mnesia:cluster_nodes(all), + {Err, Nodes} = + case AllNodes -- [node()] of + [] -> {"Timeout contacting cluster nodes. Since RabbitMQ was" + " shut down forcefully~nit cannot determine which nodes" + " are timing out.~n", []}; + Ns -> {rabbit_misc:format( + "Timeout contacting cluster nodes: ~p.~n", [Ns]), + Ns} + end, + basic_boot_error(Term, + Err ++ rabbit_nodes:diagnostics(Nodes) ++ "~n~n", []); +boot_error(Reason, Stacktrace) -> + Fmt = "Error description:~n ~p~n~n" ++ + "Log files (may contain more information):~n ~s~n ~s~n~n", + Args = [Reason, log_location(kernel), log_location(sasl)], + boot_error(Reason, Fmt, Args, Stacktrace). + +-ifdef(use_specs). +-spec(boot_error/4 :: (term(), string(), [any()], not_available | [tuple()]) + -> no_return()). +-endif. +boot_error(Reason, Fmt, Args, not_available) -> + basic_boot_error(Reason, Fmt, Args); +boot_error(Reason, Fmt, Args, Stacktrace) -> + basic_boot_error(Reason, Fmt ++ "Stack trace:~n ~p~n~n", + Args ++ [Stacktrace]). + +basic_boot_error(Reason, Format, Args) -> + io:format("~n~nBOOT FAILED~n===========~n~n" ++ Format, Args), + rabbit_misc:local_info_msg(Format, Args), + timer:sleep(1000), + exit({?MODULE, failure_during_boot, Reason}). + %%--------------------------------------------------------------------------- %% boot step functions @@ -486,6 +668,19 @@ insert_default_data() -> %%--------------------------------------------------------------------------- %% logging +log_location(Type) -> + case application:get_env(rabbit, case Type of + kernel -> error_logger; + sasl -> sasl_error_logger + end) of + {ok, {file, File}} -> File; + {ok, false} -> undefined; + {ok, tty} -> tty; + {ok, silent} -> undefined; + {ok, Bad} -> throw({error, {cannot_log_to_file, Bad}}); + _ -> undefined + end. + ensure_working_log_handlers() -> Handlers = gen_event:which_handlers(error_logger), ok = ensure_working_log_handler(error_logger_tty_h, -- cgit v1.2.1 From 04df9801211ae8defb19a296c4154d7e4594304d Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Tue, 18 Feb 2014 15:10:32 +0000 Subject: Fix various oopses and reduce the distance to default some more --- src/rabbit.erl | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 5d9aaa5f..e7aaee51 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -22,7 +22,7 @@ stop_and_halt/0, await_startup/0, status/0, is_running/0, is_running/1, environment/0, rotate_logs/1, force_event_refresh/1, start_fhc/0]). - +-export([run_boot_steps/0, load_steps/1, run_step/3]). -export([start/2, stop/1]). -export([log_location/1]). %% for testing @@ -305,7 +305,7 @@ ensure_application_loaded() -> end. start() -> - rabbit_boot:boot_with( + boot_with( fun() -> %% We do not want to HiPE compile or upgrade %% mnesia after just restarting the app @@ -336,12 +336,6 @@ boot() -> ok = log_broker_started(Plugins) end). -handle_app_error(App, {bad_return, {_MFA, {'EXIT', {Reason, _}}}}) -> - throw({could_not_start, App, Reason}); - -handle_app_error(App, Reason) -> - throw({could_not_start, App, Reason}). - boot_with(StartFun) -> Marker = spawn_link(fun() -> receive stop -> ok end end), case catch register(rabbit_boot, Marker) of @@ -479,7 +473,7 @@ app_shutdown_order() -> %% boot step logic run_boot_steps() -> - Steps = rabbit_boot:load_steps(boot), + Steps = load_steps(boot), [ok = run_boot_step(Step) || Step <- Steps], ok. @@ -668,19 +662,6 @@ insert_default_data() -> %%--------------------------------------------------------------------------- %% logging -log_location(Type) -> - case application:get_env(rabbit, case Type of - kernel -> error_logger; - sasl -> sasl_error_logger - end) of - {ok, {file, File}} -> File; - {ok, false} -> undefined; - {ok, tty} -> tty; - {ok, silent} -> undefined; - {ok, Bad} -> throw({error, {cannot_log_to_file, Bad}}); - _ -> undefined - end. - ensure_working_log_handlers() -> Handlers = gen_event:which_handlers(error_logger), ok = ensure_working_log_handler(error_logger_tty_h, -- cgit v1.2.1 From 17d987ebfa1f859bd0412ade9c589e2397e97247 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Fri, 21 Feb 2014 10:45:11 +0000 Subject: Cosmetic - reduce the distance to default a bit more --- src/rabbit.erl | 57 +++++++++++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 30 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index e7aaee51..adfb934e 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -305,42 +305,40 @@ ensure_application_loaded() -> end. start() -> - boot_with( - fun() -> - %% We do not want to HiPE compile or upgrade - %% mnesia after just restarting the app - ok = ensure_application_loaded(), - ok = ensure_working_log_handlers(), - rabbit_node_monitor:prepare_cluster_status_files(), - rabbit_mnesia:check_cluster_consistency(), - ok = rabbit_boot:start(app_startup_order()), - ok = log_broker_started(rabbit_plugins:active()) - end). + boot_with(fun() -> + %% We do not want to HiPE compile or upgrade + %% mnesia after just restarting the app + ok = ensure_application_loaded(), + ok = ensure_working_log_handlers(), + rabbit_node_monitor:prepare_cluster_status_files(), + rabbit_mnesia:check_cluster_consistency(), + ok = rabbit_boot:start(app_startup_order()), + ok = log_broker_started(rabbit_plugins:active()) + end). boot() -> - boot_with( - fun() -> - ok = ensure_application_loaded(), - Success = maybe_hipe_compile(), - ok = ensure_working_log_handlers(), - warn_if_hipe_compilation_failed(Success), - rabbit_node_monitor:prepare_cluster_status_files(), - ok = rabbit_upgrade:maybe_upgrade_mnesia(), - %% It's important that the consistency check happens after - %% the upgrade, since if we are a secondary node the - %% primary node will have forgotten us - rabbit_mnesia:check_cluster_consistency(), - Plugins = rabbit_plugins:setup(), - ToBeLoaded = Plugins ++ ?APPS, - ok = rabbit_boot:start(ToBeLoaded), - ok = log_broker_started(Plugins) - end). + boot_with(fun() -> + ok = ensure_application_loaded(), + Success = maybe_hipe_compile(), + ok = ensure_working_log_handlers(), + warn_if_hipe_compilation_failed(Success), + rabbit_node_monitor:prepare_cluster_status_files(), + ok = rabbit_upgrade:maybe_upgrade_mnesia(), + %% It's important that the consistency check happens after + %% the upgrade, since if we are a secondary node the + %% primary node will have forgotten us + rabbit_mnesia:check_cluster_consistency(), + Plugins = rabbit_plugins:setup(), + ToBeLoaded = Plugins ++ ?APPS, + ok = rabbit_boot:start(ToBeLoaded), + ok = log_broker_started(Plugins) + end). boot_with(StartFun) -> Marker = spawn_link(fun() -> receive stop -> ok end end), case catch register(rabbit_boot, Marker) of true -> try - case rabbit:is_running() of + case is_running() of true -> ok; false -> StartFun() end @@ -455,7 +453,6 @@ stop(_State) -> true -> rabbit_amqqueue:on_node_down(node()); false -> rabbit_table:clear_ram_only_tables() end, - ok = rabbit_boot:shutdown(), ok. %%--------------------------------------------------------------------------- -- cgit v1.2.1 From 191ea8407b55f7ddd2473b762fa935159737d9ca Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Fri, 21 Feb 2014 12:50:14 +0000 Subject: Simply application:get_env calls and reduce distance to default again --- src/rabbit.erl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index adfb934e..f2aa18a3 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -640,12 +640,12 @@ maybe_insert_default_data() -> end. insert_default_data() -> - {ok, DefaultUser} = application:get_env(rabbit, default_user), - {ok, DefaultPass} = application:get_env(rabbit, default_pass), - {ok, DefaultTags} = application:get_env(rabbit, default_user_tags), - {ok, DefaultVHost} = application:get_env(rabbit, default_vhost), + {ok, DefaultUser} = application:get_env(default_user), + {ok, DefaultPass} = application:get_env(default_pass), + {ok, DefaultTags} = application:get_env(default_user_tags), + {ok, DefaultVHost} = application:get_env(default_vhost), {ok, [DefaultConfigurePerm, DefaultWritePerm, DefaultReadPerm]} = - application:get_env(rabbit, default_permissions), + application:get_env(default_permissions), ok = rabbit_vhost:add(DefaultVHost), ok = rabbit_auth_backend_internal:add_user(DefaultUser, DefaultPass), ok = rabbit_auth_backend_internal:set_tags(DefaultUser, DefaultTags), -- cgit v1.2.1 From e282caeebce551b1fa7d4f121e8312679e7fd21b Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Tue, 4 Mar 2014 11:37:56 +0000 Subject: Reduce the distance to default a bit more --- src/rabbit.erl | 67 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 31 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index f2aa18a3..2070713e 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -305,36 +305,36 @@ ensure_application_loaded() -> end. start() -> - boot_with(fun() -> - %% We do not want to HiPE compile or upgrade - %% mnesia after just restarting the app - ok = ensure_application_loaded(), - ok = ensure_working_log_handlers(), - rabbit_node_monitor:prepare_cluster_status_files(), - rabbit_mnesia:check_cluster_consistency(), - ok = rabbit_boot:start(app_startup_order()), - ok = log_broker_started(rabbit_plugins:active()) - end). + start_it(fun() -> + %% We do not want to HiPE compile or upgrade + %% mnesia after just restarting the app + ok = ensure_application_loaded(), + ok = ensure_working_log_handlers(), + rabbit_node_monitor:prepare_cluster_status_files(), + rabbit_mnesia:check_cluster_consistency(), + ok = rabbit_boot:start(app_startup_order()), + ok = log_broker_started(rabbit_plugins:active()) + end). boot() -> - boot_with(fun() -> - ok = ensure_application_loaded(), - Success = maybe_hipe_compile(), - ok = ensure_working_log_handlers(), - warn_if_hipe_compilation_failed(Success), - rabbit_node_monitor:prepare_cluster_status_files(), - ok = rabbit_upgrade:maybe_upgrade_mnesia(), - %% It's important that the consistency check happens after - %% the upgrade, since if we are a secondary node the - %% primary node will have forgotten us - rabbit_mnesia:check_cluster_consistency(), - Plugins = rabbit_plugins:setup(), - ToBeLoaded = Plugins ++ ?APPS, - ok = rabbit_boot:start(ToBeLoaded), - ok = log_broker_started(Plugins) - end). - -boot_with(StartFun) -> + start_it(fun() -> + ok = ensure_application_loaded(), + Success = maybe_hipe_compile(), + ok = ensure_working_log_handlers(), + warn_if_hipe_compilation_failed(Success), + rabbit_node_monitor:prepare_cluster_status_files(), + ok = rabbit_upgrade:maybe_upgrade_mnesia(), + %% It's important that the consistency check happens after + %% the upgrade, since if we are a secondary node the + %% primary node will have forgotten us + rabbit_mnesia:check_cluster_consistency(), + Plugins = rabbit_plugins:setup(), + ToBeLoaded = Plugins ++ ?APPS, + ok = rabbit_boot:start(ToBeLoaded), + ok = log_broker_started(Plugins) + end). + +start_it(StartFun) -> Marker = spawn_link(fun() -> receive stop -> ok end end), case catch register(rabbit_boot, Marker) of true -> try @@ -358,8 +358,13 @@ boot_with(StartFun) -> end. stop() -> + Apps = app_shutdown_order(), + case whereis(?MODULE) of + undefined -> ok; + _ -> app_utils:wait_for_applications(Apps) + end, rabbit_log:info("Stopping RabbitMQ~n"), - rabbit_boot:shutdown(app_shutdown_order()). + ok = app_utils:stop_applications(Apps). stop_and_halt() -> try @@ -604,8 +609,8 @@ boot_error(Reason, Stacktrace) -> boot_error(Reason, Fmt, Args, Stacktrace). -ifdef(use_specs). --spec(boot_error/4 :: (term(), string(), [any()], not_available | [tuple()]) - -> no_return()). +-spec(boot_error/4 :: (term(), string(), [any()], not_available | [tuple()]) + -> no_return()). -endif. boot_error(Reason, Fmt, Args, not_available) -> basic_boot_error(Reason, Fmt, Args); -- cgit v1.2.1 From c944edb4f5306068a66c19543853a74e5ee5667c Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Tue, 4 Mar 2014 12:15:35 +0000 Subject: Inline some more and get closer still to default --- src/rabbit.erl | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 2070713e..9644f75e 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -24,7 +24,7 @@ start_fhc/0]). -export([run_boot_steps/0, load_steps/1, run_step/3]). -export([start/2, stop/1]). - +-export([handle_app_error/1, start_apps/1]). -export([log_location/1]). %% for testing %%--------------------------------------------------------------------------- @@ -242,6 +242,7 @@ -spec(maybe_insert_default_data/0 :: () -> 'ok'). -spec(boot_delegate/0 :: () -> 'ok'). -spec(recover/0 :: () -> 'ok'). +-spec(handle_app_error/1 :: (term()) -> fun((atom(), term()) -> no_return())). -endif. @@ -312,7 +313,7 @@ start() -> ok = ensure_working_log_handlers(), rabbit_node_monitor:prepare_cluster_status_files(), rabbit_mnesia:check_cluster_consistency(), - ok = rabbit_boot:start(app_startup_order()), + ok = start_apps(app_startup_order()), ok = log_broker_started(rabbit_plugins:active()) end). @@ -330,10 +331,27 @@ boot() -> rabbit_mnesia:check_cluster_consistency(), Plugins = rabbit_plugins:setup(), ToBeLoaded = Plugins ++ ?APPS, - ok = rabbit_boot:start(ToBeLoaded), + ok = start_apps(ToBeLoaded), ok = log_broker_started(Plugins) end). +handle_app_error(Term) -> + fun(App, {bad_return, {_MFA, {'EXIT', {ExitReason, _}}}}) -> + throw({Term, App, ExitReason}); + (App, Reason) -> + throw({Term, App, Reason}) + end. + +start_apps(Apps) -> + rabbit_boot:force_reload(Apps), + StartupApps = app_utils:app_dependency_order(Apps, false), + case whereis(?MODULE) of + undefined -> rabbit:run_boot_steps(); + _ -> ok + end, + ok = app_utils:start_applications(StartupApps, + handle_app_error(could_not_start)). + start_it(StartFun) -> Marker = spawn_link(fun() -> receive stop -> ok end end), case catch register(rabbit_boot, Marker) of -- cgit v1.2.1 From 5f5a8f2863c325cc7d8810d8b19ff0f1192a1c08 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Tue, 4 Mar 2014 14:02:59 +0000 Subject: Fix an oops in rabbit:stop/0 and apply consistent parameter names in r_plugins --- src/rabbit.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 9644f75e..82394cd9 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -377,7 +377,7 @@ start_it(StartFun) -> stop() -> Apps = app_shutdown_order(), - case whereis(?MODULE) of + case whereis(rabbit_boot) of undefined -> ok; _ -> app_utils:wait_for_applications(Apps) end, -- cgit v1.2.1 From aea7d7763d89bd3395147f2c0d056d4301ef9cc0 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Wed, 5 Mar 2014 13:49:48 +0000 Subject: We missed another change when moving code back into rabbit.erl --- src/rabbit.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 82394cd9..46838364 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -345,7 +345,7 @@ handle_app_error(Term) -> start_apps(Apps) -> rabbit_boot:force_reload(Apps), StartupApps = app_utils:app_dependency_order(Apps, false), - case whereis(?MODULE) of + case whereis(rabbit_boot) of undefined -> rabbit:run_boot_steps(); _ -> ok end, -- cgit v1.2.1 From 5f8d433a545c7ec150fc69c9f94be67ed6219325 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Thu, 13 Mar 2014 22:49:16 +0000 Subject: Refactor: Simplify boot/cleanup step handling and unify modules Isolate boot steps to a set of applications and avoid using ets to track which have run. This also simplifies cleanup step execution. The force_reload code isn't needed, since the real issue preventing updated versions of modules from being found lay in the proper expansion of (the correct set of) .ez archives, which was fixed in revision 1918e77. Unify all the boot handling code under rabbit.erl once again and now completely remove rabbit_boot, since it's no longer needed. Remove unused exports and tidy. --- src/rabbit.erl | 137 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 90 insertions(+), 47 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 46838364..c703fedb 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -24,7 +24,7 @@ start_fhc/0]). -export([run_boot_steps/0, load_steps/1, run_step/3]). -export([start/2, stop/1]). --export([handle_app_error/1, start_apps/1]). +-export([start_apps/1, stop_apps/1]). -export([log_location/1]). %% for testing %%--------------------------------------------------------------------------- @@ -242,7 +242,6 @@ -spec(maybe_insert_default_data/0 :: () -> 'ok'). -spec(boot_delegate/0 :: () -> 'ok'). -spec(recover/0 :: () -> 'ok'). --spec(handle_app_error/1 :: (term()) -> fun((atom(), term()) -> no_return())). -endif. @@ -343,10 +342,10 @@ handle_app_error(Term) -> end. start_apps(Apps) -> - rabbit_boot:force_reload(Apps), + app_utils:load_applications(Apps), StartupApps = app_utils:app_dependency_order(Apps, false), case whereis(rabbit_boot) of - undefined -> rabbit:run_boot_steps(); + undefined -> run_boot_steps(Apps); _ -> ok end, ok = app_utils:start_applications(StartupApps, @@ -393,6 +392,29 @@ stop_and_halt() -> end, ok. +stop_apps(Apps) -> + try + ok = app_utils:stop_applications( + Apps, handle_app_error(error_during_shutdown)) + after + run_cleanup_steps(Apps), + [begin + {ok, Mods} = application:get_key(App, modules), + [begin + code:soft_purge(Mod), + code:delete(Mod), + false = code:is_loaded(Mod) + end || Mod <- Mods], + application:unload(App) + end || App <- Apps] + end. + +run_cleanup_steps(Apps) -> + [run_step(Name, Attributes, cleanup) || + {App, Name, Attributes} <- load_steps(Apps), + lists:member(App, Apps)], + ok. + await_startup() -> app_utils:wait_for_applications(app_startup_order()). @@ -463,7 +485,6 @@ start(normal, []) -> true = register(rabbit, self()), print_banner(), log_banner(), - rabbit_boot:prepare_boot_table(), run_boot_steps(), {ok, SupPid}; Error -> @@ -493,16 +514,12 @@ app_shutdown_order() -> %% boot step logic run_boot_steps() -> - Steps = load_steps(boot), - [ok = run_boot_step(Step) || Step <- Steps], - ok. + run_boot_steps([App || {App, _, _} <- application:loaded_applications()]). -run_boot_step({_, StepName, Attributes}) -> - case catch rabbit_boot:already_run(StepName) of - false -> ok = run_step(StepName, Attributes, mfa), - rabbit_boot:mark_complete(StepName); - _ -> ok - end, +run_boot_steps(Apps) -> + Steps = load_steps(Apps), + [ok = run_step(StepName, Attributes, mfa) || + {_, StepName, Attributes} <- Steps], ok. run_step(StepName, Attributes, AttributeName) -> @@ -524,45 +541,71 @@ run_step(StepName, Attributes, AttributeName) -> ok end. -load_steps(Type) -> +load_steps(BaseApps) -> + Apps = BaseApps -- app_utils:which_applications(), %% exclude running apps StepAttrs = rabbit_misc:all_module_attributes_with_app(rabbit_boot_step), - sort_boot_steps( - Type, - lists:usort( - [{Mod, {AppName, Steps}} || {AppName, Mod, Steps} <- StepAttrs])). + {AllSteps, StepsDict} = + lists:foldl( + fun({AppName, Mod, Steps}, {AccSteps, AccDict}) -> + {[{Mod, {AppName, Steps}}|AccSteps], + lists:foldl( + fun({StepName, _}, Acc) -> + dict:store(StepName, AppName, Acc) + end, AccDict, Steps)} + end, {[], dict:new()}, StepAttrs), + Steps = lists:foldl(filter_steps(Apps, StepsDict), [], AllSteps), + sort_boot_steps(lists:usort(Steps)). + +filter_steps(Apps, Dict) -> + fun({Mod, {AppName, Steps}}, Acc) -> + Steps2 = [begin + Filtered = lists:foldl(filter_attrs(Apps, Dict), + [], Attrs), + {Step, Filtered} + end || {Step, Attrs} <- Steps, + filter_app(Apps, Dict, Step)], + [{Mod, {AppName, Steps2}}|Acc] + end. + +filter_app(Apps, Dict, Step) -> + case dict:find(Step, Dict) of + {ok, App} -> lists:member(App, Apps); + error -> false + end. + +filter_attrs(Apps, Dict) -> + fun(Attr={Type, Other}, AccAttrs) when Type =:= requires orelse + Type =:= enables -> + %% If we don't know about a dependency, we allow it through, + %% since we don't *know* that it should be ignored. If, on + %% the other hand, we recognise a dependency then we _only_ + %% include it (i.e., the requires/enables attribute itself) + %% if the referenced step comes from one of the Apps we're + %% actively working with at this point. + case dict:find(Other, Dict) of + error -> [Attr | AccAttrs]; + {ok, App} -> case lists:member(App, Apps) of + true -> [Attr | AccAttrs]; + false -> AccAttrs + end + end; + (Attr, AccAttrs) -> + [Attr | AccAttrs] + end. vertices(_Module, {AppName, Steps}) -> [{StepName, {AppName, StepName, Atts}} || {StepName, Atts} <- Steps]. -edges(Type) -> - %% When running "boot" steps, both hard _and_ soft dependencies are - %% considered equally. When running "cleanup" steps however, we only - %% consider /hard/ dependencies (i.e., of the form - %% {DependencyType, {hard, StepName}}) as dependencies. - fun (_Module, {_AppName, Steps}) -> - [case Key of - requires -> {StepName, strip_type(OtherStep)}; - enables -> {strip_type(OtherStep), StepName} - end || {StepName, Atts} <- Steps, - {Key, OtherStep} <- Atts, - filter_dependent_steps(Key, OtherStep, Type)] - end. +edges(_Module, {_AppName, Steps}) -> + [case Key of + requires -> {StepName, OtherStep}; + enables -> {OtherStep, StepName} + end || {StepName, Atts} <- Steps, + {Key, OtherStep} <- Atts, + Key =:= requires orelse Key =:= enables]. -filter_dependent_steps(Key, Dependency, Type) - when Key =:= requires orelse Key =:= enables -> - case {Dependency, Type} of - {{hard, _}, cleanup} -> true; - {_SoftReqs, cleanup} -> false; - {_, boot} -> true - end; -filter_dependent_steps(_, _, _) -> - false. - -strip_type({hard, Step}) -> Step; -strip_type(Step) -> Step. - -sort_boot_steps(Type, UnsortedSteps) -> - case rabbit_misc:build_acyclic_graph(fun vertices/2, edges(Type), +sort_boot_steps(UnsortedSteps) -> + case rabbit_misc:build_acyclic_graph(fun vertices/2, fun edges/2, UnsortedSteps) of {ok, G} -> %% Use topological sort to find a consistent ordering (if -- cgit v1.2.1 From 3de081adf60d9348f73b3401e81b1570a2419c2e Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Mon, 17 Mar 2014 15:58:47 +0000 Subject: Inline app_utils:update_running_apps/2 --- src/rabbit.erl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 062b9355..3d043b50 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -312,7 +312,7 @@ start() -> ok = ensure_working_log_handlers(), rabbit_node_monitor:prepare_cluster_status_files(), rabbit_mnesia:check_cluster_consistency(), - ok = start_apps(app_startup_order()), + start_apps(app_startup_order()), ok = log_broker_started(rabbit_plugins:active()) end). @@ -330,7 +330,7 @@ boot() -> rabbit_mnesia:check_cluster_consistency(), Plugins = rabbit_plugins:setup(), ToBeLoaded = Plugins ++ ?APPS, - ok = start_apps(ToBeLoaded), + start_apps(ToBeLoaded), ok = log_broker_started(Plugins) end). @@ -349,7 +349,8 @@ start_apps(Apps) -> _ -> ok end, ok = app_utils:start_applications(StartupApps, - handle_app_error(could_not_start)). + handle_app_error(could_not_start)), + StartupApps. start_it(StartFun) -> Marker = spawn_link(fun() -> receive stop -> ok end end), -- cgit v1.2.1 From 8fb1d1ea7f3b35ad9e1fb89548d1af91db275ef9 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Mon, 17 Mar 2014 19:52:29 +0000 Subject: Refactor (inline a little bit more) app_utils:which_applications/0 => inlined, rabbit_misc:all_module_attributes{_with_app} => unified --- src/rabbit.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 3d043b50..9b827d83 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -543,8 +543,8 @@ run_step(StepName, Attributes, AttributeName) -> end. load_steps(BaseApps) -> - Apps = BaseApps -- app_utils:which_applications(), %% exclude running apps - StepAttrs = rabbit_misc:all_module_attributes_with_app(rabbit_boot_step), + Apps = BaseApps -- [App || {App, _, _} <- rabbit_misc:which_applications()], + StepAttrs = rabbit_misc:all_module_attributes(rabbit_boot_step), {AllSteps, StepsDict} = lists:foldl( fun({AppName, Mod, Steps}, {AccSteps, AccDict}) -> -- cgit v1.2.1 From b2db9e0e6884ebf9e7654d8aad1a13529843a703 Mon Sep 17 00:00:00 2001 From: Simon MacMullen Date: Wed, 19 Mar 2014 15:43:12 +0000 Subject: If we refactor rabbit_misc:build_acyclic_graph so that we don't assume the arity of the functions we pass in, then it's easy to build the complete graph then filter it by application, rather than the other way round - avoiding rather a lot of work. --- src/rabbit.erl | 66 +++++++++------------------------------------------------- 1 file changed, 10 insertions(+), 56 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 16106145..07b21e50 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -531,11 +531,17 @@ run_boot_steps() -> run_boot_steps([App || {App, _, _} <- application:loaded_applications()]). run_boot_steps(Apps) -> - Steps = load_steps(Apps), + Steps = find_steps(Apps), [ok = run_step(StepName, Attributes, mfa) || {_, StepName, Attributes} <- Steps], ok. +find_steps(BaseApps) -> + Apps = BaseApps -- [App || {App, _, _} <- rabbit_misc:which_applications()], + FullBoot = sort_boot_steps( + rabbit_misc:all_module_attributes(rabbit_boot_step)), + [Step || {App, _, _} = Step <- FullBoot, lists:member(App, Apps)]. + run_step(StepName, Attributes, AttributeName) -> case [MFA || {Key, MFA} <- Attributes, Key =:= AttributeName] of @@ -555,62 +561,10 @@ run_step(StepName, Attributes, AttributeName) -> ok end. -load_steps(BaseApps) -> - Apps = BaseApps -- [App || {App, _, _} <- rabbit_misc:which_applications()], - StepAttrs = rabbit_misc:all_module_attributes(rabbit_boot_step), - {AllSteps, StepsDict} = - lists:foldl( - fun({AppName, Mod, Steps}, {AccSteps, AccDict}) -> - {[{Mod, {AppName, Steps}}|AccSteps], - lists:foldl( - fun({StepName, _}, Acc) -> - dict:store(StepName, AppName, Acc) - end, AccDict, Steps)} - end, {[], dict:new()}, StepAttrs), - Steps = lists:foldl(filter_steps(Apps, StepsDict), [], AllSteps), - sort_boot_steps(lists:usort(Steps)). - -filter_steps(Apps, Dict) -> - fun({Mod, {AppName, Steps}}, Acc) -> - Steps2 = [begin - Filtered = lists:foldl(filter_attrs(Apps, Dict), - [], Attrs), - {Step, Filtered} - end || {Step, Attrs} <- Steps, - filter_app(Apps, Dict, Step)], - [{Mod, {AppName, Steps2}}|Acc] - end. - -filter_app(Apps, Dict, Step) -> - case dict:find(Step, Dict) of - {ok, App} -> lists:member(App, Apps); - error -> false - end. - -filter_attrs(Apps, Dict) -> - fun(Attr={Type, Other}, AccAttrs) when Type =:= requires orelse - Type =:= enables -> - %% If we don't know about a dependency, we allow it through, - %% since we don't *know* that it should be ignored. If, on - %% the other hand, we recognise a dependency then we _only_ - %% include it (i.e., the requires/enables attribute itself) - %% if the referenced step comes from one of the Apps we're - %% actively working with at this point. - case dict:find(Other, Dict) of - error -> [Attr | AccAttrs]; - {ok, App} -> case lists:member(App, Apps) of - true -> [Attr | AccAttrs]; - false -> AccAttrs - end - end; - (Attr, AccAttrs) -> - [Attr | AccAttrs] - end. - -vertices(_Module, {AppName, Steps}) -> +vertices({AppName, _Module, Steps}) -> [{StepName, {AppName, StepName, Atts}} || {StepName, Atts} <- Steps]. -edges(_Module, {_AppName, Steps}) -> +edges({_AppName, _Module, Steps}) -> [case Key of requires -> {StepName, OtherStep}; enables -> {OtherStep, StepName} @@ -619,7 +573,7 @@ edges(_Module, {_AppName, Steps}) -> Key =:= requires orelse Key =:= enables]. sort_boot_steps(UnsortedSteps) -> - case rabbit_misc:build_acyclic_graph(fun vertices/2, fun edges/2, + case rabbit_misc:build_acyclic_graph(fun vertices/1, fun edges/1, UnsortedSteps) of {ok, G} -> %% Use topological sort to find a consistent ordering (if -- cgit v1.2.1 From a75d518ae4b914a4bd9ef8f23d2cec8cf3ec6477 Mon Sep 17 00:00:00 2001 From: Simon MacMullen Date: Wed, 19 Mar 2014 15:56:48 +0000 Subject: Oops, complete renaming that function. Also remove some exports that seem no longer used. --- src/rabbit.erl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 07b21e50..b4943a30 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -22,7 +22,6 @@ stop_and_halt/0, await_startup/0, status/0, is_running/0, is_running/1, environment/0, rotate_logs/1, force_event_refresh/1, start_fhc/0]). --export([run_boot_steps/0, load_steps/1, run_step/3]). -export([start/2, stop/1]). -export([start_apps/1, stop_apps/1]). -export([log_location/1]). %% for testing @@ -412,7 +411,7 @@ stop_apps(Apps) -> run_cleanup_steps(Apps) -> [run_step(Name, Attributes, cleanup) || - {App, Name, Attributes} <- load_steps(Apps), + {App, Name, Attributes} <- find_steps(Apps), lists:member(App, Apps)], ok. -- cgit v1.2.1 From a994cd8db832684b837ede757d7b2052a9593e57 Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Fri, 28 Mar 2014 13:46:10 +0000 Subject: Ensure start_app considers plugins when using RABBITMQ_NODE_ONLY - always start all enabled plugins, regardless of startup type - only disable plugins that are currently running The latter incidentally fixes bug 24941. --- src/rabbit.erl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index b4943a30..6c08520f 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -311,8 +311,7 @@ start() -> ok = ensure_working_log_handlers(), rabbit_node_monitor:prepare_cluster_status_files(), rabbit_mnesia:check_cluster_consistency(), - start_apps(app_startup_order()), - ok = log_broker_started(rabbit_plugins:active()) + broker_start() end). boot() -> @@ -327,12 +326,15 @@ boot() -> %% the upgrade, since if we are a secondary node the %% primary node will have forgotten us rabbit_mnesia:check_cluster_consistency(), - Plugins = rabbit_plugins:setup(), - ToBeLoaded = Plugins ++ ?APPS, - start_apps(ToBeLoaded), - ok = log_broker_started(Plugins) + broker_start() end). +broker_start() -> + Plugins = rabbit_plugins:setup(), + ToBeLoaded = Plugins ++ ?APPS, + start_apps(ToBeLoaded), + ok = log_broker_started(rabbit_plugins:active()). + handle_app_error(Term) -> fun(App, {bad_return, {_MFA, {'EXIT', {ExitReason, _}}}}) -> throw({Term, App, ExitReason}); -- cgit v1.2.1 From 021819d55ad25b563bdb75ade2c796a756ea4ebb Mon Sep 17 00:00:00 2001 From: Tim Watson Date: Tue, 8 Apr 2014 13:55:36 +0100 Subject: Fix management extension enable/disable handling When notifying about 'enabled' plugins, limit to explicitly given. When handling 'disabled' plugins, call the event handler(s) synchronously (while we still have loaded modules) prior to stopping and unloading any apps. --- src/rabbit.erl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/rabbit.erl') diff --git a/src/rabbit.erl b/src/rabbit.erl index 6c08520f..8a682616 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -210,6 +210,7 @@ %% this really should be an abstract type -type(log_location() :: 'tty' | 'undefined' | file:filename()). -type(param() :: atom()). +-type(app_name() :: atom()). -spec(start/0 :: () -> 'ok'). -spec(boot/0 :: () -> 'ok'). @@ -241,6 +242,8 @@ -spec(maybe_insert_default_data/0 :: () -> 'ok'). -spec(boot_delegate/0 :: () -> 'ok'). -spec(recover/0 :: () -> 'ok'). +-spec(start_apps/1 :: ([app_name()]) -> 'ok'). +-spec(stop_apps/1 :: ([app_name()]) -> 'ok'). -endif. @@ -350,8 +353,7 @@ start_apps(Apps) -> _ -> ok end, ok = app_utils:start_applications(StartupApps, - handle_app_error(could_not_start)), - StartupApps. + handle_app_error(could_not_start)). start_it(StartFun) -> Marker = spawn_link(fun() -> receive stop -> ok end end), -- cgit v1.2.1