summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon MacMullen <simon@rabbitmq.com>2010-11-18 13:25:36 +0000
committerSimon MacMullen <simon@rabbitmq.com>2010-11-18 13:25:36 +0000
commit09a05a6c8a202ba81b26678d8477e2fb6aac9e6c (patch)
tree03c1e91ad7c378af29523f3ec047bbe60f335a44
parent631f130edc3f8fbb704e1c1390925b8d7009b103 (diff)
downloadrabbitmq-server-09a05a6c8a202ba81b26678d8477e2fb6aac9e6c.tar.gz
Take a backup before upgrading.
-rw-r--r--src/rabbit_misc.erl32
-rw-r--r--src/rabbit_upgrade.erl25
2 files changed, 53 insertions, 4 deletions
diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl
index 9290508f..44fbe4ad 100644
--- a/src/rabbit_misc.erl
+++ b/src/rabbit_misc.erl
@@ -61,7 +61,7 @@
-export([sort_field_table/1]).
-export([pid_to_string/1, string_to_pid/1]).
-export([version_compare/2, version_compare/3]).
--export([recursive_delete/1, dict_cons/3, orddict_cons/3,
+-export([recursive_delete/1, recursive_copy/2, dict_cons/3, orddict_cons/3,
unlink_and_capture_exit/1]).
-export([get_options/2]).
-export([all_module_attributes/1, build_acyclic_graph/4]).
@@ -184,6 +184,9 @@
-spec(recursive_delete/1 ::
([file:filename()])
-> rabbit_types:ok_or_error({file:filename(), any()})).
+-spec(recursive_copy/2 ::
+ (file:filename(), file:filename())
+ -> rabbit_types:ok_or_error({file:filename(), file:filename(), any()})).
-spec(dict_cons/3 :: (any(), any(), dict()) -> dict()).
-spec(orddict_cons/3 :: (any(), any(), orddict:orddict()) -> orddict:orddict()).
-spec(unlink_and_capture_exit/1 :: (pid()) -> 'ok').
@@ -684,6 +687,33 @@ recursive_delete1(Path) ->
end
end.
+recursive_copy(Src, Dest) ->
+ case filelib:is_dir(Src) of
+ false -> case file:copy(Src, Dest) of
+ {ok, _Bytes} -> ok;
+ {error, enoent} -> ok; %% Path doesn't exist anyway
+ {error, Err} -> {error, {Src, Dest, Err}}
+ end;
+ true -> case file:list_dir(Src) of
+ {ok, FileNames} ->
+ case file:make_dir(Dest) of
+ ok ->
+ lists:foldl(
+ fun (FileName, ok) ->
+ recursive_copy(
+ filename:join(Src, FileName),
+ filename:join(Dest, FileName));
+ (_FileName, Error) ->
+ Error
+ end, ok, FileNames);
+ {error, Err} ->
+ {error, {Src, Dest, Err}}
+ end;
+ {error, Err} ->
+ {error, {Src, Dest, Err}}
+ end
+ end.
+
dict_cons(Key, Value, Dict) ->
dict:update(Key, fun (List) -> [Value | List] end, [Value], Dict).
diff --git a/src/rabbit_upgrade.erl b/src/rabbit_upgrade.erl
index 9522227e..4b7b4342 100644
--- a/src/rabbit_upgrade.erl
+++ b/src/rabbit_upgrade.erl
@@ -120,14 +120,33 @@ heads(G) ->
%% -------------------------------------------------------------------
apply_upgrades(Upgrades) ->
- LockFile = lock_filename(),
+ LockFile = lock_filename(dir()),
case file:open(LockFile, [write, exclusive]) of
{ok, Lock} ->
ok = file:close(Lock),
+ BackupDir = dir() ++ "-upgrade-backup",
info("Upgrades: ~w to apply~n", [length(Upgrades)]),
+ case rabbit_misc:recursive_copy(dir(), BackupDir) of
+ ok ->
+ %% We need to make the backup after creating the lock file
+ %% so that it protects us from trying to overwrite the
+ %% backup. Unfortunately this means the lock file exists in
+ %% the backup too, which is not intuitive. Remove it.
+ ok = file:delete(lock_filename(BackupDir)),
+ ok;
+ {error, E} ->
+ %% If we can't backup, the upgrade hasn't started hence we
+ %% don't need the lockfile since the real mnesia dir is the
+ %% good one.
+ ok = file:delete(LockFile),
+ exit({could_not_back_up_mnesia_dir, E})
+ end,
+ info("Upgrades: Mnesia dir backed up to ~p~n", [BackupDir]),
[apply_upgrade(Upgrade) || Upgrade <- Upgrades],
- info("Upgrades: All applied~n", []),
+ info("Upgrades: All upgrades applied successfully~n", []),
ok = write_version(),
+ ok = rabbit_misc:recursive_delete([BackupDir]),
+ info("Upgrades: Mnesia backup removed~n", []),
ok = file:delete(LockFile);
{error, eexist} ->
exit(previous_upgrade_failed);
@@ -145,7 +164,7 @@ dir() -> rabbit_mnesia:dir().
schema_filename() -> filename:join(dir(), ?VERSION_FILENAME).
-lock_filename() -> filename:join(dir(), ?LOCK_FILENAME).
+lock_filename(Dir) -> filename:join(Dir, ?LOCK_FILENAME).
%% NB: we cannot use rabbit_log here since it may not have been
%% started yet