summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rabbit.erl19
-rw-r--r--src/rabbit_mnesia.erl10
-rw-r--r--src/rabbit_upgrade.erl135
-rw-r--r--src/rabbit_upgrades.erl60
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.