summaryrefslogtreecommitdiff
path: root/src/rabbit_mnesia.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rabbit_mnesia.erl')
-rw-r--r--src/rabbit_mnesia.erl64
1 files changed, 42 insertions, 22 deletions
diff --git a/src/rabbit_mnesia.erl b/src/rabbit_mnesia.erl
index 039a8c60..8cd976fa 100644
--- a/src/rabbit_mnesia.erl
+++ b/src/rabbit_mnesia.erl
@@ -65,7 +65,8 @@
%% Various queries to get the status of the db
-spec(status/0 :: () -> [{'nodes', [{node_type(), [node()]}]} |
- {'running_nodes', [node()]}]).
+ {'running_nodes', [node()]} |
+ {'partitions', [{node(), [node()]}]}]).
-spec(is_clustered/0 :: () -> boolean()).
-spec(cluster_nodes/1 :: ('all' | 'disc' | 'ram' | 'running') -> [node()]).
-spec(node_type/0 :: () -> node_type()).
@@ -403,7 +404,7 @@ cluster_status(WhichNodes) ->
node_info() ->
{erlang:system_info(otp_release), rabbit_misc:version(),
- cluster_status_from_mnesia()}.
+ delegate_beam_hash(), cluster_status_from_mnesia()}.
node_type() ->
DiscNodes = cluster_nodes(disc),
@@ -561,10 +562,13 @@ check_cluster_consistency(Node) ->
case rpc:call(Node, rabbit_mnesia, node_info, []) of
{badrpc, _Reason} ->
{error, not_found};
- {_OTP, _Rabbit, {error, _}} ->
+ {_OTP, _Rabbit, _Hash, {error, _}} ->
{error, not_found};
- {OTP, Rabbit, {ok, Status}} ->
- case check_consistency(OTP, Rabbit, Node, Status) of
+ {_OTP, Rabbit, _Status} ->
+ %% pre-2013/04 format implies version mismatch
+ version_error("Rabbit", rabbit_misc:version(), Rabbit);
+ {OTP, Rabbit, Hash, {ok, Status}} ->
+ case check_consistency(OTP, Rabbit, Hash, Node, Status) of
{error, _} = E -> E;
{ok, Res} -> {ok, Res}
end
@@ -599,19 +603,16 @@ discover_cluster(Nodes) when is_list(Nodes) ->
lists:foldl(fun (_, {ok, Res}) -> {ok, Res};
(Node, {error, _}) -> discover_cluster(Node)
end, {error, no_nodes_provided}, Nodes);
+discover_cluster(Node) when Node == node() ->
+ {error, {cannot_discover_cluster, "Cannot cluster node with itself"}};
discover_cluster(Node) ->
OfflineError =
{error, {cannot_discover_cluster,
"The nodes provided are either offline or not running"}},
- case node() of
- Node -> {error, {cannot_discover_cluster,
- "Cannot cluster node with itself"}};
- _ -> case rpc:call(Node,
- rabbit_mnesia, cluster_status_from_mnesia, []) of
- {badrpc, _Reason} -> OfflineError;
- {error, mnesia_not_running} -> OfflineError;
- {ok, Res} -> {ok, Res}
- end
+ case rpc:call(Node, rabbit_mnesia, cluster_status_from_mnesia, []) of
+ {badrpc, _Reason} -> OfflineError;
+ {error, mnesia_not_running} -> OfflineError;
+ {ok, Res} -> {ok, Res}
end.
schema_ok_or_move() ->
@@ -734,14 +735,17 @@ change_extra_db_nodes(ClusterNodes0, CheckOtherNodes) ->
Nodes
end.
-check_consistency(OTP, Rabbit) ->
+check_consistency(OTP, Rabbit, Hash) ->
rabbit_misc:sequence_error(
- [check_otp_consistency(OTP), check_rabbit_consistency(Rabbit)]).
+ [check_otp_consistency(OTP),
+ check_rabbit_consistency(Rabbit),
+ check_beam_compatibility(Hash)]).
-check_consistency(OTP, Rabbit, Node, Status) ->
+check_consistency(OTP, Rabbit, Hash, Node, Status) ->
rabbit_misc:sequence_error(
[check_otp_consistency(OTP),
check_rabbit_consistency(Rabbit),
+ check_beam_compatibility(Hash),
check_nodes_consistency(Node, Status)]).
check_nodes_consistency(Node, RemoteStatus = {RemoteAllNodes, _, _}) ->
@@ -782,6 +786,21 @@ check_rabbit_consistency(Remote) ->
rabbit_misc:version(), Remote, "Rabbit",
fun rabbit_misc:version_minor_equivalent/2).
+check_beam_compatibility(RemoteHash) ->
+ case RemoteHash == delegate_beam_hash() of
+ true -> ok;
+ false -> {error, {incompatible_bytecode,
+ "Incompatible Erlang bytecode found on nodes"}}
+ end.
+
+%% The delegate module sends functions across the cluster; if it is
+%% out of sync (say due to mixed compilers), we will get badfun
+%% exceptions when trying to do so. Let's detect that at startup.
+delegate_beam_hash() ->
+ {delegate, Obj, _} = code:get_object_code(delegate),
+ {ok, {delegate, Hash}} = beam_lib:md5(Obj),
+ Hash.
+
%% This is fairly tricky. We want to know if the node is in the state
%% that a `reset' would leave it in. We cannot simply check if the
%% mnesia tables aren't there because restarted RAM nodes won't have
@@ -807,11 +826,12 @@ find_good_node([]) ->
none;
find_good_node([Node | Nodes]) ->
case rpc:call(Node, rabbit_mnesia, node_info, []) of
- {badrpc, _Reason} -> find_good_node(Nodes);
- {OTP, Rabbit, _} -> case check_consistency(OTP, Rabbit) of
- {error, _} -> find_good_node(Nodes);
- ok -> {ok, Node}
- end
+ {badrpc, _Reason} -> find_good_node(Nodes);
+ {_OTP, _Rabbit, _} -> find_good_node(Nodes);
+ {OTP, Rabbit, Hash, _} -> case check_consistency(OTP, Rabbit, Hash) of
+ {error, _} -> find_good_node(Nodes);
+ ok -> {ok, Node}
+ end
end.
is_only_clustered_disc_node() ->