Skip to content

Commit 42bcd94

Browse files
committed
rabbit_db_cluster: New module on top of databases clustering
This new module sits on top of `rabbit_mnesia` and provide an API with all cluster-related functions. `rabbit_mnesia` should be called directly inside Mnesia-specific code only, `rabbit_mnesia_rename` or classic mirrored queues for instance. Otherwise, `rabbit_db_cluster` must be used. Several modules, in particular in `rabbitmq_cli`, continue to call `rabbit_mnesia` as a fallback option if the `rabbit_db_cluster` module unavailable. This will be the case when the CLI will interact with an older RabbitMQ version. This will help with the introduction of a new database backend.
1 parent a826b57 commit 42bcd94

19 files changed

+274
-36
lines changed

deps/rabbit/src/rabbit.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ prep_stop(State) ->
10261026

10271027
stop(State) ->
10281028
ok = rabbit_alarm:stop(),
1029-
ok = case rabbit_mnesia:is_clustered() of
1029+
ok = case rabbit_db_cluster:is_clustered() of
10301030
true -> ok;
10311031
false -> rabbit_table:clear_ram_only_tables()
10321032
end,

deps/rabbit/src/rabbit_db.erl

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
-include_lib("rabbit_common/include/logging.hrl").
1414

1515
-export([init/0,
16+
reset/0,
17+
force_reset/0,
18+
force_load_on_next_boot/0,
1619
is_virgin_node/0, is_virgin_node/1,
1720
dir/0,
1821
ensure_dir_exists/0]).
@@ -40,7 +43,7 @@ init() ->
4043
"DB: this node is virgin: ~ts", [IsVirgin],
4144
#{domain => ?RMQLOG_DOMAIN_DB}),
4245
ensure_dir_exists(),
43-
case init_mnesia() of
46+
case init_using_mnesia() of
4447
ok ->
4548
?LOG_DEBUG(
4649
"DB: initialization successeful",
@@ -53,14 +56,56 @@ init() ->
5356
Error
5457
end.
5558

56-
init_mnesia() ->
59+
init_using_mnesia() ->
5760
?LOG_DEBUG(
5861
"DB: initialize Mnesia",
5962
#{domain => ?RMQLOG_DOMAIN_DB}),
6063
ok = rabbit_mnesia:init(),
6164
?assertEqual(rabbit:data_dir(), mnesia_dir()),
6265
rabbit_sup:start_child(mnesia_sync).
6366

67+
-spec reset() -> Ret when
68+
Ret :: ok.
69+
%% @doc Resets the database and the node.
70+
71+
reset() ->
72+
reset_using_mnesia().
73+
74+
reset_using_mnesia() ->
75+
?LOG_DEBUG(
76+
"DB: resetting node",
77+
#{domain => ?RMQLOG_DOMAIN_DB}),
78+
rabbit_mnesia:reset().
79+
80+
-spec force_reset() -> Ret when
81+
Ret :: ok.
82+
%% @doc Resets the database and the node.
83+
84+
force_reset() ->
85+
force_reset_using_mnesia().
86+
87+
force_reset_using_mnesia() ->
88+
?LOG_DEBUG(
89+
"DB: resetting node forcefully",
90+
#{domain => ?RMQLOG_DOMAIN_DB}),
91+
rabbit_mnesia:force_reset().
92+
93+
-spec force_load_on_next_boot() -> Ret when
94+
Ret :: ok.
95+
%% @doc Requests that the database to be forcefully loaded during next boot.
96+
%%
97+
%% This is necessary when a node refuses to boot when the cluster is in a bad
98+
%% state, like if critical members are MIA.
99+
100+
force_load_on_next_boot() ->
101+
force_load_on_next_boot_using_mnesia().
102+
103+
force_load_on_next_boot_using_mnesia() ->
104+
?LOG_DEBUG(
105+
"DB: resetting node forcefully",
106+
#{domain => ?RMQLOG_DOMAIN_DB}),
107+
rabbit_mnesia:force_load_next_boot().
108+
64109
-spec is_virgin_node() -> IsVirgin when
65110
IsVirgin :: boolean().
66111
%% @doc Indicates if this RabbitMQ node is virgin.

deps/rabbit/src/rabbit_db_cluster.erl

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
%% This Source Code Form is subject to the terms of the Mozilla Public
2+
%% License, v. 2.0. If a copy of the MPL was not distributed with this
3+
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
%%
5+
%% Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved.
6+
%%
7+
8+
-module(rabbit_db_cluster).
9+
10+
-include_lib("kernel/include/logger.hrl").
11+
-include_lib("stdlib/include/assert.hrl").
12+
13+
-include_lib("rabbit_common/include/logging.hrl").
14+
15+
-export([join/2,
16+
forget_member/2]).
17+
-export([change_node_type/1]).
18+
-export([is_clustered/0,
19+
members/0,
20+
disc_members/0,
21+
node_type/0,
22+
check_consistency/0,
23+
cli_cluster_status/0]).
24+
25+
-type node_type() :: disc_node_type() | ram_node_type().
26+
-type disc_node_type() :: disc.
27+
-type ram_node_type() :: ram.
28+
29+
-export_type([node_type/0, disc_node_type/0, ram_node_type/0]).
30+
31+
-define(
32+
IS_NODE_TYPE(NodeType),
33+
((NodeType) =:= disc orelse (NodeType) =:= ram)).
34+
35+
%% -------------------------------------------------------------------
36+
%% Cluster formation.
37+
%% -------------------------------------------------------------------
38+
39+
-spec join(RemoteNode, NodeType) -> Ret when
40+
RemoteNode :: node(),
41+
NodeType :: rabbit_db_cluster:node_type(),
42+
Ret :: Ok | Error,
43+
Ok :: ok | {ok, already_member},
44+
Error :: {error, {inconsistent_cluster, string()}}.
45+
%% @doc Adds this node to a cluster using `RemoteNode' to reach it.
46+
47+
join(RemoteNode, NodeType)
48+
when is_atom(RemoteNode) andalso ?IS_NODE_TYPE(NodeType) ->
49+
?LOG_DEBUG(
50+
"DB: joining cluster using remote node `~ts`", [RemoteNode],
51+
#{domain => ?RMQLOG_DOMAIN_DB}),
52+
join_using_mnesia(RemoteNode, NodeType).
53+
54+
join_using_mnesia(RemoteNode, NodeType) ->
55+
rabbit_mnesia:join_cluster(RemoteNode, NodeType).
56+
57+
-spec forget_member(Node, RemoveWhenOffline) -> ok when
58+
Node :: node(),
59+
RemoveWhenOffline :: boolean().
60+
%% @doc Removes `Node' from the cluster.
61+
62+
forget_member(Node, RemoveWhenOffline) ->
63+
forget_member_using_mnesia(Node, RemoveWhenOffline).
64+
65+
forget_member_using_mnesia(Node, RemoveWhenOffline) ->
66+
rabbit_mnesia:forget_cluster_node(Node, RemoveWhenOffline).
67+
68+
%% -------------------------------------------------------------------
69+
%% Cluster update.
70+
%% -------------------------------------------------------------------
71+
72+
-spec change_node_type(NodeType) -> ok when
73+
NodeType :: rabbit_db_cluster:node_type().
74+
%% @doc Changes the node type to `NodeType'.
75+
%%
76+
%% Node types may not all be valid with all databases.
77+
78+
change_node_type(NodeType) ->
79+
change_node_type_using_mnesia(NodeType).
80+
81+
change_node_type_using_mnesia(NodeType) ->
82+
rabbit_mnesia:change_cluster_node_type(NodeType).
83+
84+
%% -------------------------------------------------------------------
85+
%% Cluster status.
86+
%% -------------------------------------------------------------------
87+
88+
-spec is_clustered() -> IsClustered when
89+
IsClustered :: boolean().
90+
%% @doc Indicates if this node is clustered with other nodes or not.
91+
92+
is_clustered() ->
93+
is_clustered_using_mnesia().
94+
95+
is_clustered_using_mnesia() ->
96+
rabbit_mnesia:is_clustered().
97+
98+
-spec members() -> Members when
99+
Members :: [node()].
100+
%% @doc Returns the list of cluster members.
101+
102+
members() ->
103+
members_using_mnesia().
104+
105+
members_using_mnesia() ->
106+
mnesia:system_info(db_nodes).
107+
108+
-spec disc_members() -> Members when
109+
Members :: [node()].
110+
%% @private
111+
112+
disc_members() ->
113+
disc_members_using_mnesia().
114+
115+
disc_members_using_mnesia() ->
116+
rabbit_mnesia:cluster_nodes(disc).
117+
118+
-spec node_type() -> NodeType when
119+
NodeType :: rabbit_db_cluster:node_type().
120+
%% @doc Returns the type of this node, `disc' or `ram'.
121+
%%
122+
%% Node types may not all be relevant with all databases.
123+
124+
node_type() ->
125+
node_type_using_mnesia().
126+
127+
node_type_using_mnesia() ->
128+
rabbit_mnesia:node_type().
129+
130+
-spec check_consistency() -> ok.
131+
%% @doc Ensures the cluster is consistent.
132+
133+
check_consistency() ->
134+
check_consistency_using_mnesia().
135+
136+
check_consistency_using_mnesia() ->
137+
rabbit_mnesia:check_cluster_consistency().
138+
139+
-spec cli_cluster_status() -> ClusterStatus when
140+
ClusterStatus :: [{nodes, [{rabbit_db_cluster:node_type(), [node()]}]} |
141+
{running_nodes, [node()]} |
142+
{partitions, [{node(), [node()]}]}].
143+
%% @doc Returns information from the cluster for the `cluster_status' CLI
144+
%% command.
145+
146+
cli_cluster_status() ->
147+
cli_cluster_status_using_mnesia().
148+
149+
cli_cluster_status_using_mnesia() ->
150+
rabbit_mnesia:status().

deps/rabbit/src/rabbit_mnesia.erl

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,8 @@
7070

7171
%%----------------------------------------------------------------------------
7272

73-
-export_type([node_type/0, cluster_status/0]).
73+
-export_type([cluster_status/0]).
7474

75-
-type node_type() :: disc | ram.
7675
-type cluster_status() :: {[node()], [node()], [node()]}.
7776

7877
%%----------------------------------------------------------------------------
@@ -137,12 +136,12 @@ init_with_lock(Retries, Timeout, RunPeerDiscovery) ->
137136
init_with_lock(Retries - 1, Timeout, RunPeerDiscovery)
138137
end.
139138

140-
-spec run_peer_discovery() -> ok | {[node()], node_type()}.
139+
-spec run_peer_discovery() -> ok | {[node()], rabbit_db_cluster:node_type()}.
141140
run_peer_discovery() ->
142141
{RetriesLeft, DelayInterval} = rabbit_peer_discovery:discovery_retries(),
143142
run_peer_discovery_with_retries(RetriesLeft, DelayInterval).
144143

145-
-spec run_peer_discovery_with_retries(non_neg_integer(), non_neg_integer()) -> ok | {[node()], node_type()}.
144+
-spec run_peer_discovery_with_retries(non_neg_integer(), non_neg_integer()) -> ok | {[node()], rabbit_db_cluster:node_type()}.
146145
run_peer_discovery_with_retries(0, _DelayInterval) ->
147146
ok;
148147
run_peer_discovery_with_retries(RetriesLeft, DelayInterval) ->
@@ -228,7 +227,7 @@ join_discovered_peers_with_retries(TryNodes, NodeType, RetriesLeft, DelayInterva
228227
%% all in the same cluster, we simply pick the first online node and
229228
%% we cluster to its cluster.
230229

231-
-spec join_cluster(node(), node_type())
230+
-spec join_cluster(node(), rabbit_db_cluster:node_type())
232231
-> ok | {ok, already_member} | {error, {inconsistent_cluster, string()}}.
233232

234233
join_cluster(DiscoveryNode, NodeType) ->
@@ -317,7 +316,7 @@ wipe() ->
317316
ok = rabbit_node_monitor:reset_cluster_status(),
318317
ok.
319318

320-
-spec change_cluster_node_type(node_type()) -> 'ok'.
319+
-spec change_cluster_node_type(rabbit_db_cluster:node_type()) -> 'ok'.
321320

322321
change_cluster_node_type(Type) ->
323322
ensure_mnesia_not_running(),
@@ -421,7 +420,7 @@ remove_node_offline_node(Node) ->
421420
%% Queries
422421
%%----------------------------------------------------------------------------
423422

424-
-spec status() -> [{'nodes', [{node_type(), [node()]}]} |
423+
-spec status() -> [{'nodes', [{rabbit_db_cluster:node_type(), [node()]}]} |
425424
{'running_nodes', [node()]} |
426425
{'partitions', [{node(), [node()]}]}].
427426

@@ -539,7 +538,7 @@ node_info() ->
539538
mnesia:system_info(protocol_version),
540539
cluster_status_from_mnesia()}.
541540

542-
-spec node_type() -> node_type().
541+
-spec node_type() -> rabbit_db_cluster:node_type().
543542

544543
node_type() ->
545544
{_AllNodes, DiscNodes, _RunningNodes} =
@@ -607,7 +606,7 @@ init_db(ClusterNodes, NodeType, CheckOtherNodes) ->
607606
rabbit_node_monitor:update_cluster_status(),
608607
ok.
609608

610-
-spec init_db_unchecked([node()], node_type()) -> 'ok'.
609+
-spec init_db_unchecked([node()], rabbit_db_cluster:node_type()) -> 'ok'.
611610

612611
init_db_unchecked(ClusterNodes, NodeType) ->
613612
init_db(ClusterNodes, NodeType, false).

deps/rabbit/src/rabbit_node_monitor.erl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ notify_joined_cluster() ->
169169
NewMember = node(),
170170
Nodes = rabbit_nodes:list_running() -- [NewMember],
171171
gen_server:abcast(Nodes, ?SERVER,
172-
{joined_cluster, node(), rabbit_mnesia:node_type()}),
172+
{joined_cluster, node(), rabbit_db_cluster:node_type()}),
173173

174174
ok.
175175

@@ -415,9 +415,9 @@ handle_call(_Request, _From, State) ->
415415
handle_cast(notify_node_up, State = #state{guid = GUID}) ->
416416
Nodes = rabbit_nodes:list_running() -- [node()],
417417
gen_server:abcast(Nodes, ?SERVER,
418-
{node_up, node(), rabbit_mnesia:node_type(), GUID}),
418+
{node_up, node(), rabbit_db_cluster:node_type(), GUID}),
419419
%% register other active rabbits with this rabbit
420-
DiskNodes = rabbit_mnesia:cluster_nodes(disc),
420+
DiskNodes = rabbit_db_cluster:disc_members(),
421421
[gen_server:cast(?SERVER, {node_up, N, case lists:member(N, DiskNodes) of
422422
true -> disc;
423423
false -> ram

deps/rabbit/src/rabbit_nodes.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ is_member(Node) when is_atom(Node) ->
180180
%% @see filter_members/1.
181181

182182
list_members() ->
183-
mnesia:system_info(db_nodes).
183+
rabbit_db_cluster:members().
184184

185185
-spec filter_members(Nodes) -> Nodes when
186186
Nodes :: [node()].

deps/rabbit/src/rabbit_prelaunch_cluster.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ setup(Context) ->
3030
?LOG_DEBUG(
3131
"Checking cluster consistency", [],
3232
#{domain => ?RMQLOG_DOMAIN_PRELAUNCH}),
33-
rabbit_mnesia:check_cluster_consistency(),
33+
rabbit_db_cluster:check_consistency(),
3434
ok.

deps/rabbit/test/clustering_management_SUITE.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ wait_for_cluster_status(N, Max, Status, AllNodes, Nodes) ->
780780

781781
verify_status_equal(Node, Status, AllNodes) ->
782782
NodeStatus = sort_cluster_status(cluster_status(Node)),
783-
(AllNodes =/= [Node]) =:= rpc:call(Node, rabbit_mnesia, is_clustered, [])
783+
(AllNodes =/= [Node]) =:= rpc:call(Node, rabbit_db_cluster, is_clustered, [])
784784
andalso NodeStatus =:= Status.
785785

786786
cluster_status(Node) ->

deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/change_cluster_node_type_command.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ChangeClusterNodeTypeCommand do
2929

3030
def run([node_type_arg], %{node: node_name}) do
3131
normalized_type = normalize_type(String.to_atom(node_type_arg))
32-
current_type = :rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :node_type, [])
32+
current_type = :rabbit_misc.rpc_call(node_name, :rabbit_db_cluster, :node_type, [])
3333

3434
case current_type do
3535
^normalized_type ->
3636
{:ok, "Node type is already #{normalized_type}"}
3737

3838
_ ->
39-
:rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :change_cluster_node_type, [
39+
:rabbit_misc.rpc_call(node_name, :rabbit_db_cluster, :change_node_type, [
4040
normalized_type
4141
])
4242
end

deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/cluster_status_command.ex

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,19 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClusterStatusCommand do
3333
use RabbitMQ.CLI.Core.RequiresRabbitAppRunning
3434

3535
def run([], %{node: node_name, timeout: timeout}) do
36-
case :rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :status, []) do
36+
status =
37+
case :rabbit_misc.rpc_call(node_name, :rabbit_db_cluster, :cli_cluster_status, []) do
38+
{:badrpc, {:EXIT, {:undef, _}}} ->
39+
:rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :status, [])
40+
41+
{:badrpc, _} = err ->
42+
err
43+
44+
status ->
45+
status
46+
end
47+
48+
case status do
3749
{:badrpc, _} = err ->
3850
err
3951

0 commit comments

Comments
 (0)