summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Watson <watson.timothy@gmail.com>2014-01-12 12:38:38 +0000
committerTim Watson <watson.timothy@gmail.com>2014-01-12 12:38:38 +0000
commit15ddd5a5e6bcee80e0065112fb156fe14112b5f7 (patch)
treedbfc5d692512cc3a3dc7491500fb0758ec1f6c30
parente52fb99e9b38ae2845d51951ac66dd8cb0e32c5d (diff)
downloadrabbitmq-server-git-15ddd5a5e6bcee80e0065112fb156fe14112b5f7.tar.gz
Refactor (simplify application stop handling)
The offline plugin handling does a fine job of detecting which apps need to be stopped/unloaded when disabling a plugin at runtime. We previously had problems accidentally stopping things like stdlib and mnesia by accident, but only because we went searching for the app dependencies ourselves! Instead, we stop only those applications (i.e., plugins) that rabbit_plugins_main has requested. In doing so, we remove a considerable amount of (new) digraph hacking from app_utils and reduce the complexity of rabbit_boot somewhat.
-rw-r--r--src/app_utils.erl36
-rw-r--r--src/rabbit_boot.erl21
2 files changed, 7 insertions, 50 deletions
diff --git a/src/app_utils.erl b/src/app_utils.erl
index 1037fa3461..4622f6e0a8 100644
--- a/src/app_utils.erl
+++ b/src/app_utils.erl
@@ -18,7 +18,6 @@
-export([load_applications/1, start_applications/1, start_applications/2,
stop_applications/1, stop_applications/2, app_dependency_order/2,
running_applications/0, wait_for_applications/1, app_dependencies/1]).
--export([isolated_dependencies/1]).
-ifdef(use_specs).
@@ -32,7 +31,6 @@
-spec wait_for_applications([atom()]) -> 'ok'.
-spec app_dependency_order([atom()], boolean()) -> [digraph:vertex()].
-spec app_dependencies(atom()) -> [atom()].
--spec isolated_dependencies(atom()) -> [atom()].
-endif.
@@ -77,35 +75,6 @@ stop_applications(Apps, ErrorHandler) ->
wait_for_applications(Apps) ->
[wait_for_application(App) || App <- Apps], ok.
-isolated_dependencies(Root) ->
- Loaded = application:loaded_applications(),
- {ok, G} = rabbit_misc:build_graph(
- fun() -> [{App, App} || {App, _, _} <- Loaded] end,
- fun() -> [{App, Dep} ||
- {App, Deps} <- [{App, app_dependencies(App)} ||
- {App, _Desc, _Vsn} <- Loaded],
- Dep <- Deps]
- end,
- digraph:new()),
- try
- Deps = lists:foldl(
- fun(E, Acc) ->
- {_, _InVertex, OutVertex, _Label} = digraph:edge(G, E),
- case is_reachable(G, OutVertex, Root) of
- [] -> sets:add_element(OutVertex, Acc);
- _ -> Acc
- end
- end,
- sets:from_list([Root]),
- digraph:out_edges(G, Root)),
- sets:to_list(Deps)
- after
- true = digraph:delete(G)
- end.
-
-is_reachable(G, OutVertex, Root) ->
- digraph_utils:reaching_neighbours([OutVertex], G) -- [Root].
-
app_dependency_order(RootApps, StripUnreachable) ->
{ok, G} = rabbit_misc:build_acyclic_graph(
fun (App, _Deps) -> [{App, App}] end,
@@ -127,11 +96,6 @@ app_dependency_order(RootApps, StripUnreachable) ->
%%---------------------------------------------------------------------------
%% Private API
-%% It might be worth documenting this on the plugin author's guide/page.
-%% A plugin should expect its boot steps to run /before/ the application
-%% is started, and its cleanup steps to run /after/ the application has
-%% fully stopped.
-
wait_for_application(Application) ->
case lists:keymember(Application, 1, rabbit_misc:which_applications()) of
true -> ok;
diff --git a/src/rabbit_boot.erl b/src/rabbit_boot.erl
index 7112af7c05..12a0116168 100644
--- a/src/rabbit_boot.erl
+++ b/src/rabbit_boot.erl
@@ -118,23 +118,16 @@ start(Apps) ->
stop(Apps) ->
ensure_boot_table(),
- TargetApps =
- sets:to_list(
- lists:foldl(
- fun(App, Set) ->
- lists:foldl(fun sets:add_element/2, Set,
- app_utils:isolated_dependencies(App) -- [rabbit])
- end, sets:new(), Apps)),
try
ok = app_utils:stop_applications(
- TargetApps, handle_app_error(error_during_shutdown))
+ Apps, handle_app_error(error_during_shutdown))
after
try
BootSteps = load_steps(boot),
ToDelete = [Step || {App, _, _}=Step <- BootSteps,
- lists:member(App, TargetApps)],
+ lists:member(App, Apps)],
[ets:delete(?MODULE, Step) || {_, Step, _} <- ToDelete],
- run_cleanup_steps(TargetApps)
+ run_cleanup_steps(Apps)
after
save_boot_table()
end,
@@ -146,7 +139,7 @@ stop(Apps) ->
false = code:is_loaded(Mod)
end || Mod <- Mods],
application:unload(App)
- end || App <- TargetApps]
+ end || App <- Apps]
end.
run_cleanup_steps(Apps) ->
@@ -170,7 +163,6 @@ run_boot_steps() ->
ok.
load_steps(Type) ->
- io:format("Loading steps for ~p~n", [Type]),
StepAttrs = rabbit_misc:all_app_module_attributes(rabbit_boot_step),
sort_boot_steps(
Type,
@@ -347,8 +339,9 @@ vertices(_Module, {AppName, 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 {Key, {hard, StepName}})
- %% as needing to run before or after our own cleanup actions.
+ %% consider /hard/ dependencies (i.e., of the form
+ %% {DependencyType, {hard, StepName}}) as needing to run before or after
+ %% our own cleanup actions.
fun (_Module, {_AppName, Steps}) ->
[case Key of
requires -> {StepName, strip_type(OtherStep)};