diff options
| author | Simon MacMullen <simon@rabbitmq.com> | 2010-10-15 15:50:11 +0100 |
|---|---|---|
| committer | Simon MacMullen <simon@rabbitmq.com> | 2010-10-15 15:50:11 +0100 |
| commit | ae61bb5c450a998aa27a8fd3a03ecc3b94d9cd40 (patch) | |
| tree | ea676eea4f493ed040557c8e8279de5a3b99102f /src | |
| parent | 0ff769aeab32f67308ffea0eb2555fb8b9a90245 (diff) | |
| download | rabbitmq-server-git-ae61bb5c450a998aa27a8fd3a03ecc3b94d9cd40.tar.gz | |
DAG for upgrade steps.
Diffstat (limited to 'src')
| -rw-r--r-- | src/rabbit.erl | 19 | ||||
| -rw-r--r-- | src/rabbit_mnesia.erl | 10 | ||||
| -rw-r--r-- | src/rabbit_upgrade.erl | 135 | ||||
| -rw-r--r-- | src/rabbit_upgrades.erl | 60 |
4 files changed, 209 insertions, 15 deletions
diff --git a/src/rabbit.erl b/src/rabbit.erl index 8c36a9f0a4..206cb4211d 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -40,6 +40,8 @@ -export([log_location/1]). +-export([all_module_attributes/1]). + %%--------------------------------------------------------------------------- %% Boot steps. -export([maybe_insert_default_data/0]). @@ -313,20 +315,21 @@ module_attributes(Module) -> V end. -boot_steps() -> +all_module_attributes(Name) -> 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) -> - [{StepName, Attributes} - || {rabbit_boot_step, [{StepName, Attributes}]} - <- module_attributes(Module)] - end, Modules), - sort_boot_steps(UnsortedSteps). + lists:flatmap(fun (Module) -> + [{StepName, Attributes} + || {N, [{StepName, Attributes}]} + <- module_attributes(Module), N =:= Name] + end, Modules). + +boot_steps() -> + sort_boot_steps(all_module_attributes(rabbit_boot_step)). sort_boot_steps(UnsortedSteps) -> G = digraph:new([acyclic]), diff --git a/src/rabbit_mnesia.erl b/src/rabbit_mnesia.erl index 577d206d1b..cd072b9cb4 100644 --- a/src/rabbit_mnesia.erl +++ b/src/rabbit_mnesia.erl @@ -44,9 +44,6 @@ -include("rabbit.hrl"). --define(SCHEMA_VERSION_SET, []). --define(SCHEMA_VERSION_FILENAME, "schema_version"). - %%---------------------------------------------------------------------------- -ifdef(use_specs). @@ -94,9 +91,6 @@ init() -> ok = ensure_mnesia_running(), ok = ensure_mnesia_dir(), ok = init_db(read_cluster_nodes_config(), true), - ok = rabbit_misc:write_term_file(filename:join( - dir(), ?SCHEMA_VERSION_FILENAME), - [?SCHEMA_VERSION_SET]), ok. is_db_empty() -> @@ -384,6 +378,7 @@ init_db(ClusterNodes, Force) -> [] -> case mnesia:system_info(use_dir) of true -> + rabbit_upgrade:maybe_upgrade(dir()), case check_schema_integrity() of ok -> ok; @@ -428,7 +423,8 @@ create_schema() -> cannot_start_mnesia), ok = create_tables(), ok = ensure_schema_integrity(), - ok = wait_for_tables(). + ok = wait_for_tables(), + ok = rabbit_upgrade:write_version(dir()). move_db() -> mnesia:stop(), diff --git a/src/rabbit_upgrade.erl b/src/rabbit_upgrade.erl new file mode 100644 index 0000000000..acefc5b4b1 --- /dev/null +++ b/src/rabbit_upgrade.erl @@ -0,0 +1,135 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developers of the Original Code are LShift Ltd, +%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. +%% +%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, +%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd +%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial +%% Technologies LLC, and Rabbit Technologies Ltd. +%% +%% Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift +%% Ltd. Portions created by Cohesive Financial Technologies LLC are +%% Copyright (C) 2007-2010 Cohesive Financial Technologies +%% LLC. Portions created by Rabbit Technologies Ltd are Copyright +%% (C) 2007-2010 Rabbit Technologies Ltd. +%% +%% All Rights Reserved. +%% +%% Contributor(s): ______________________________________. +%% +-module(rabbit_upgrade). + +-export([maybe_upgrade/1, write_version/1]). + +-include("rabbit.hrl"). + +-define(SCHEMA_VERSION_FILENAME, "schema_version"). + +%% API --------------------------------------------------------------- + +%% Try to upgrade the schema. If no information on the existing schema could +%% be found, do nothing. rabbit_mnesia:check_schema_integrity() will catch the +%% problem. +%% TODO detect failed upgrades +maybe_upgrade(Dir) -> + case rabbit_misc:read_term_file(schema_filename(Dir)) of + {ok, [CurrentHeads]} -> + G = load_graph(), + case check_unknown_heads(CurrentHeads, G) of + ok -> + Upgrades = upgrades_to_apply(CurrentHeads, G), + [apply_upgrade(Upgrade) || Upgrade <- Upgrades], + case length(Upgrades) of + 0 -> ok; + _ -> write_version(Dir) + end; + _ -> + ok + end, + digraph:delete(G), + ok; + {error, enoent} -> + ok + end. + +write_version(Dir) -> + G = load_graph(), + rabbit_misc:write_term_file(schema_filename(Dir), [heads(G)]), + digraph:delete(G). + +%% Graphs ------------------------------------------------------------ + +load_graph() -> + G = digraph:new([acyclic]), + Upgrades = rabbit:all_module_attributes(rabbit_upgrade), + [case digraph:vertex(G, StepName) of + false -> digraph:add_vertex(G, StepName, Step); + _ -> throw({duplicate_upgrade, StepName}) + end || Step = {StepName, _Attrs} <- Upgrades], + + lists:foreach(fun ({Upgrade, Attributes}) -> + [add_edges(G, Requires, Upgrade) + || {requires, Requires} <- Attributes] + end, Upgrades), + G. + +add_edges(G, Requires, Upgrade) -> + Results = [digraph:add_edge(G, R, Upgrade) || R <- Requires], + case [E || {error, _} = E <- Results] of + [] -> ok; + L -> exit(L) + end. + +check_unknown_heads(Heads, G) -> + case [H || H <- Heads, digraph:vertex(G, H) =:= false] of + [] -> + ok; + Unknown -> + [warn("Data store has had future upgrade ~w applied. Will not " ++ + "upgrade.~n", [U]) || U <- Unknown], + Unknown + end. + +upgrades_to_apply(Heads, G) -> + Unsorted = sets:to_list( + sets:subtract( + sets:from_list(digraph:vertices(G)), + sets:from_list(digraph_utils:reaching(Heads, G)))), + [begin + {StepName, Step} = digraph:vertex(G, StepName), + Step + end || StepName <- digraph_utils:topsort( + digraph_utils:subgraph(G, Unsorted))]. + +heads(G) -> + [V || V <- digraph:vertices(G), digraph:out_degree(G, V) =:= 0]. + +%% Upgrades----------------------------------------------------------- + +apply_upgrade({Name, Props}) -> + info("Applying upgrade ~w~n", [Name]), + {Module, Function} = proplists:get_value(mf, Props), + info("-> ~w:~w~n", [Module, Function]). + +%% Utils ------------------------------------------------------------- + +schema_filename(Dir) -> + filename:join(Dir, ?SCHEMA_VERSION_FILENAME). + +%% NB: we cannot use rabbit_log here since it may not have been started yet +info(Msg, Args) -> + error_logger:info_msg(Msg, Args). + +warn(Msg, Args) -> + error_logger:warning_msg(Msg, Args). diff --git a/src/rabbit_upgrades.erl b/src/rabbit_upgrades.erl new file mode 100644 index 0000000000..8e962b206c --- /dev/null +++ b/src/rabbit_upgrades.erl @@ -0,0 +1,60 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developers of the Original Code are LShift Ltd, +%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. +%% +%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, +%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd +%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial +%% Technologies LLC, and Rabbit Technologies Ltd. +%% +%% Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift +%% Ltd. Portions created by Cohesive Financial Technologies LLC are +%% Copyright (C) 2007-2010 Cohesive Financial Technologies +%% LLC. Portions created by Rabbit Technologies Ltd are Copyright +%% (C) 2007-2010 Rabbit Technologies Ltd. +%% +%% All Rights Reserved. +%% +%% Contributor(s): ______________________________________. +%% +-module(rabbit_upgrades). + +-include("rabbit.hrl"). + +-compile([export_all]). + +-rabbit_upgrade({foo, + [{mf, {rabbit_upgrades, foo}}, + {requires, []}]}). + +-rabbit_upgrade({bar, + [{mf, {rabbit_upgrades, foo}}, + {requires, []}]}). + +-rabbit_upgrade({remove_user_scope, + [{mf, {rabbit_upgrades, remove_user_scope}}, + {requires, [foo]}]}). + +-rabbit_upgrade({remove_user_scope2, + [{mf, {rabbit_upgrades, foo}}, + {requires, [remove_user_scope]}]}). + +-rabbit_upgrade({baz, + [{mf, {rabbit_upgrades, foo}}, + {requires, [bar]}]}). + +%%-------------------------------------------------------------------- + +remove_user_scope() -> + ok. |
