summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Klishin <michael@novemberain.com>2016-04-20 13:39:12 +0300
committerMichael Klishin <michael@novemberain.com>2016-04-20 13:39:12 +0300
commit91c668480ca95a5ae19c86cec20cd4a1ec4f3afe (patch)
tree510a0b0b0a86528e20097a0aaa5d730e0689f83a
parentaf96cc83f4159b875c87fb8a8d9662f439c48add (diff)
parentcc258d7a04d336883c12277b1a432f8c9a630e35 (diff)
downloadrabbitmq-server-git-91c668480ca95a5ae19c86cec20cd4a1ec4f3afe.tar.gz
Merge pull request #723 from rabbitmq/rabbitmq-server-698
Replace OTP version consistency with mnesia protocol consistency
-rw-r--r--src/rabbit_mnesia.erl111
1 files changed, 88 insertions, 23 deletions
diff --git a/src/rabbit_mnesia.erl b/src/rabbit_mnesia.erl
index afd0508aac..6a57f6bb2c 100644
--- a/src/rabbit_mnesia.erl
+++ b/src/rabbit_mnesia.erl
@@ -423,6 +423,7 @@ cluster_status(WhichNodes) ->
node_info() ->
{rabbit_misc:otp_release(), rabbit_misc:version(),
+ mnesia:system_info(protocol_version),
cluster_status_from_mnesia()}.
node_type() ->
@@ -593,26 +594,37 @@ check_cluster_consistency() ->
end.
check_cluster_consistency(Node, CheckNodesConsistency) ->
- case rpc:call(Node, rabbit_mnesia, node_info, []) of
+ case remote_node_info(Node) of
{badrpc, _Reason} ->
{error, not_found};
- {_OTP, _Rabbit, {error, _}} ->
+ {_OTP, Rabbit, DelegateModuleHash, _Status} when is_binary(DelegateModuleHash) ->
+ %% when a delegate module .beam file hash is present
+ %% in the tuple, we are dealing with an old version
+ rabbit_version:version_error("Rabbit", rabbit_misc:version(), Rabbit);
+ {_OTP, _Rabbit, _Protocol, {error, _}} ->
{error, not_found};
- {OTP, Rabbit, {ok, Status}} when CheckNodesConsistency ->
- case check_consistency(OTP, Rabbit, Node, Status) of
+ {OTP, Rabbit, Protocol, {ok, Status}} when CheckNodesConsistency ->
+ case check_consistency(Node, OTP, Rabbit, Protocol, Status) of
{error, _} = E -> E;
{ok, Res} -> {ok, Res}
end;
- {OTP, Rabbit, {ok, Status}} ->
- case check_consistency(OTP, Rabbit) of
+ {OTP, Rabbit, Protocol, {ok, Status}} ->
+ case check_consistency(Node, OTP, Rabbit, Protocol) of
{error, _} = E -> E;
ok -> {ok, Status}
- end;
- {_OTP, Rabbit, _Hash, _Status} ->
- %% delegate hash checking implies version mismatch
- rabbit_version:version_error("Rabbit", rabbit_misc:version(), Rabbit)
+ end
+ end.
+
+remote_node_info(Node) ->
+ case rpc:call(Node, rabbit_mnesia, node_info, []) of
+ {badrpc, _} = Error -> Error;
+ %% RabbitMQ prior to 3.6.2
+ {OTP, Rabbit, Status} -> {OTP, Rabbit, unsupported, Status};
+ %% RabbitMQ 3.6.2 or later
+ {OTP, Rabbit, Protocol, Status} -> {OTP, Rabbit, Protocol, Status}
end.
+
%%--------------------------------------------------------------------
%% Hooks for `rabbit_node_monitor'
%%--------------------------------------------------------------------
@@ -763,14 +775,14 @@ change_extra_db_nodes(ClusterNodes0, CheckOtherNodes) ->
Nodes
end.
-check_consistency(OTP, Rabbit) ->
+check_consistency(Node, OTP, Rabbit, ProtocolVersion) ->
rabbit_misc:sequence_error(
- [rabbit_version:check_otp_consistency(OTP),
+ [check_mnesia_or_otp_consistency(Node, ProtocolVersion, OTP),
check_rabbit_consistency(Rabbit)]).
-check_consistency(OTP, Rabbit, Node, Status) ->
+check_consistency(Node, OTP, Rabbit, ProtocolVersion, Status) ->
rabbit_misc:sequence_error(
- [rabbit_version:check_otp_consistency(OTP),
+ [check_mnesia_or_otp_consistency(Node, ProtocolVersion, OTP),
check_rabbit_consistency(Rabbit),
check_nodes_consistency(Node, Status)]).
@@ -785,6 +797,55 @@ check_nodes_consistency(Node, RemoteStatus = {RemoteAllNodes, _, _}) ->
[node(), Node, Node])}}
end.
+check_mnesia_or_otp_consistency(_Node, unsupported, OTP) ->
+ rabbit_version:check_otp_consistency(OTP);
+check_mnesia_or_otp_consistency(Node, ProtocolVersion, _) ->
+ check_mnesia_consistency(Node, ProtocolVersion).
+
+check_mnesia_consistency(Node, ProtocolVersion) ->
+ % If mnesia is running we will just check protocol version
+ % If it's not running, we don't want it to join cluster until all checks pass
+ % so we start it without `dir` env variable to prevent
+ % joining cluster and/or corrupting data
+ with_running_or_clean_mnesia(fun() ->
+ case negotiate_protocol([Node]) of
+ [Node] -> ok;
+ [] ->
+ LocalVersion = mnesia:system_info(protocol_version),
+ {error, {inconsistent_cluster,
+ rabbit_misc:format("Mnesia protocol negotiation failed."
+ " Local version: ~p."
+ " Remote version ~p",
+ [LocalVersion, ProtocolVersion])}}
+ end
+ end).
+
+negotiate_protocol([Node]) ->
+ mnesia_monitor:negotiate_protocol([Node]).
+
+with_running_or_clean_mnesia(Fun) ->
+ IsMnesiaRunning = case mnesia:system_info(is_running) of
+ yes -> true;
+ no -> false;
+ stopping ->
+ ensure_mnesia_not_running(),
+ false;
+ starting ->
+ ensure_mnesia_running(),
+ true
+ end,
+ case IsMnesiaRunning of
+ true -> Fun();
+ false ->
+ {ok, MnesiaDir} = application:get_env(mnesia, dir),
+ application:unset_env(mnesia, dir),
+ mnesia:start(),
+ Result = Fun(),
+ application:stop(mnesia),
+ application:set_env(mnesia, dir, MnesiaDir),
+ Result
+ end.
+
check_rabbit_consistency(Remote) ->
rabbit_version:check_version_consistency(
rabbit_misc:version(), Remote, "Rabbit",
@@ -819,16 +880,20 @@ find_auto_cluster_node([Node | Nodes]) ->
"Could not auto-cluster with ~s: " ++ Fmt, [Node | Args]),
find_auto_cluster_node(Nodes)
end,
- case rpc:call(Node, rabbit_mnesia, node_info, []) of
- {badrpc, _} = Reason -> Fail("~p~n", [Reason]);
+ case remote_node_info(Node) of
+ {badrpc, _} = Reason ->
+ Fail("~p~n", [Reason]);
%% old delegate hash check
- {_OTP, RMQ, _Hash, _} -> Fail("version ~s~n", [RMQ]);
- {_OTP, _RMQ, {error, _} = E} -> Fail("~p~n", [E]);
- {OTP, RMQ, _} -> case check_consistency(OTP, RMQ) of
- {error, _} -> Fail("versions ~p~n",
- [{OTP, RMQ}]);
- ok -> {ok, Node}
- end
+ {_OTP, RMQ, Hash, _} when is_binary(Hash) ->
+ Fail("version ~s~n", [RMQ]);
+ {_OTP, _RMQ, _Protocol, {error, _} = E} ->
+ Fail("~p~n", [E]);
+ {OTP, RMQ, Protocol, _} ->
+ case check_consistency(Node, OTP, RMQ, Protocol) of
+ {error, _} -> Fail("versions ~p~n",
+ [{OTP, RMQ}]);
+ ok -> {ok, Node}
+ end
end.
is_only_clustered_disc_node() ->