From 22d9ab0a1bd2903856577177e1b7e750435844ce Mon Sep 17 00:00:00 2001 From: Simon MacMullen Date: Mon, 1 Dec 2014 13:57:37 +0000 Subject: Allow argument-pairs to rename_cluster_node to go in any order (and thus allow remote-only renamings). Don't use mnesia:transform_table/3 since it's rather picky about which disk nodes are up. --- src/rabbit_control_main.erl | 15 ++++++------ src/rabbit_mnesia_rename.erl | 54 +++++++++++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/rabbit_control_main.erl b/src/rabbit_control_main.erl index d9bae4c4..e7e28890 100644 --- a/src/rabbit_control_main.erl +++ b/src/rabbit_control_main.erl @@ -235,13 +235,10 @@ action(forget_cluster_node, Node, [ClusterNodeS], Opts, Inform) -> [ClusterNode, false]) end; -action(rename_cluster_node, _Node, [FromNodeS, ToNodeS | OthersS], _Opts, - Inform) -> - Others = [list_to_atom(N) || N <- OthersS], - FromNode = list_to_atom(FromNodeS), - ToNode = list_to_atom(ToNodeS), - Inform("Renaming local cluster node ~s to ~s", [FromNode, ToNode]), - rabbit_mnesia_rename:rename(FromNode, ToNode, Others); +action(rename_cluster_node, Node, NodesS, _Opts, Inform) -> + Nodes = split_list([list_to_atom(N) || N <- NodesS]), + Inform("Renaming cluster nodes:~n ~p~n", [Nodes]), + rabbit_mnesia_rename:rename(Node, Nodes); action(force_boot, Node, [], _Opts, Inform) -> Inform("Forcing boot for Mnesia dir ~s", [mnesia:system_info(directory)]), @@ -729,3 +726,7 @@ prettify_typed_amqp_value(table, Value) -> prettify_amqp_table(Value); prettify_typed_amqp_value(array, Value) -> [prettify_typed_amqp_value(T, V) || {T, V} <- Value]; prettify_typed_amqp_value(_Type, Value) -> Value. + +split_list([]) -> []; +split_list([_]) -> exit(even_list_needed); +split_list([A, B | T]) -> [{A, B} | split_list(T)]. diff --git a/src/rabbit_mnesia_rename.erl b/src/rabbit_mnesia_rename.erl index a8cf2991..c505c896 100644 --- a/src/rabbit_mnesia_rename.erl +++ b/src/rabbit_mnesia_rename.erl @@ -17,7 +17,7 @@ -module(rabbit_mnesia_rename). -include("rabbit.hrl"). --export([rename/3]). +-export([rename/2]). -export([maybe_finish/1]). -define(CONVERT_TABLES, [schema, rabbit_durable_queue]). @@ -26,23 +26,37 @@ -ifdef(use_specs). --spec(rename/3 :: (node(), node(), [node()]) -> 'ok'). +-spec(rename/2 :: (node(), [{node(), node()}]) -> 'ok'). -spec(maybe_finish/1 :: ([node()]) -> 'ok'). -endif. %%---------------------------------------------------------------------------- -rename(FromNode, ToNode, Others) -> - NodeMap = dict:from_list(split_others([FromNode, ToNode | Others])), +rename(Node, NodeMapList) -> try + NodeMap = dict:from_list(NodeMapList), + {FromNodes, ToNodes} = lists:unzip(NodeMapList), + case length(FromNodes) - length(lists:usort(ToNodes)) of + 0 -> ok; + _ -> exit({duplicate_node, ToNodes}) + end, + FromNode = case [From || {From, To} <- NodeMapList, + To =:= Node] of + [N] -> N; + [] -> Node + end, + ToNode = case dict:find(FromNode, NodeMap) of + {ok, N2} -> N2; + error -> FromNode + end, rabbit_control_main:become(FromNode), start_mnesia(), Nodes = rabbit_mnesia:cluster_nodes(all), - case {lists:member(FromNode, Nodes), lists:member(ToNode, Nodes)} of - {true, false} -> ok; - {false, _} -> exit({node_not_in_cluster, FromNode}); - {_, true} -> exit({node_already_in_cluster, ToNode}) + case {FromNodes -- Nodes, ToNodes -- (ToNodes -- Nodes)} of + {[], []} -> ok; + {F, []} -> exit({nodes_not_in_cluster, F}); + {_, T} -> exit({nodes_already_in_cluster, T}) end, rabbit_table:force_load(), rabbit_table:wait_for_replicated(), @@ -59,10 +73,6 @@ rename(FromNode, ToNode, Others) -> stop_mnesia() end. -split_others([]) -> []; -split_others([_]) -> exit(even_list_needed); -split_others([A, B | T]) -> [{A, B} | split_others(T)]. - maybe_finish(AllNodes) -> case rabbit_file:read_term_file(rename_config_name()) of {ok, [{FromNode, ToNode}]} -> finish(FromNode, ToNode, AllNodes); @@ -171,9 +181,21 @@ rename_remote_node(FromNode, ToNode) -> {true, _} -> exit({old_node_running, FromNode}); {_, false} -> exit({new_node_not_in_cluster, ToNode}) end, - mnesia:del_table_copy(schema, FromNode), + {atomic, ok} = mnesia:del_table_copy(schema, FromNode), Map = mini_map(FromNode, ToNode), - {atomic, ok} = mnesia:transform_table( - rabbit_durable_queue, fun (Q) -> update_term(Map, Q) end, - record_info(fields, amqqueue)), + {atomic, _} = transform_table(rabbit_durable_queue, Map), ok. + +transform_table(Table, Map) -> + mnesia:sync_transaction( + fun () -> + mnesia:lock({table, Table}, write), + transform_table(Table, Map, mnesia:first(Table)) + end). + +transform_table(Table, Map, '$end_of_table') -> + ok; +transform_table(Table, Map, Key) -> + [Term] = mnesia:read(Table, Key, write), + ok = mnesia:write(Table, update_term(Map, Term), write), + transform_table(Table, Map, mnesia:next(Table, Key)). -- cgit v1.2.1