Skip to content

Commit 3ce37e1

Browse files
authored
Merge pull request #8502 from rabbitmq/move-clustering-steps-to-rabbit_db_cluster
rabbit_db: Further split Mnesia-specific and non-Mnesia-specific clustering steps
2 parents 9716602 + f4d75ae commit 3ce37e1

13 files changed

+492
-388
lines changed

deps/rabbit/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ rabbitmq_suite(
553553

554554
rabbitmq_integration_suite(
555555
name = "peer_discovery_classic_config_SUITE",
556-
size = "medium",
556+
size = "large",
557557
flaky = True,
558558
)
559559

deps/rabbit/src/rabbit_db.erl

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,23 @@ init() ->
4242
?LOG_DEBUG(
4343
"DB: this node is virgin: ~ts", [IsVirgin],
4444
#{domain => ?RMQLOG_DOMAIN_DB}),
45+
4546
ensure_dir_exists(),
46-
case init_using_mnesia() of
47+
rabbit_peer_discovery:log_configured_backend(),
48+
rabbit_peer_discovery:maybe_init(),
49+
50+
pre_init(IsVirgin),
51+
52+
Ret = run(
53+
#{mnesia => fun init_using_mnesia/0}),
54+
case Ret of
4755
ok ->
4856
?LOG_DEBUG(
4957
"DB: initialization successeful",
5058
#{domain => ?RMQLOG_DOMAIN_DB}),
59+
60+
post_init(IsVirgin),
61+
5162
ok;
5263
Error ->
5364
?LOG_DEBUG(
@@ -56,6 +67,17 @@ init() ->
5667
Error
5768
end.
5869

70+
pre_init(IsVirgin) ->
71+
Members = rabbit_db_cluster:members(),
72+
OtherMembers = rabbit_nodes:nodes_excl_me(Members),
73+
rabbit_db_cluster:ensure_feature_flags_are_in_sync(OtherMembers, IsVirgin).
74+
75+
post_init(false = _IsVirgin) ->
76+
rabbit_peer_discovery:maybe_register();
77+
post_init(true = _IsVirgin) ->
78+
%% Registration handled by rabbit_peer_discovery.
79+
ok.
80+
5981
init_using_mnesia() ->
6082
?LOG_DEBUG(
6183
"DB: initialize Mnesia",
@@ -69,11 +91,12 @@ init_using_mnesia() ->
6991
%% @doc Resets the database and the node.
7092

7193
reset() ->
72-
reset_using_mnesia().
94+
run(
95+
#{mnesia => fun reset_using_mnesia/0}).
7396

7497
reset_using_mnesia() ->
75-
?LOG_DEBUG(
76-
"DB: resetting node",
98+
?LOG_INFO(
99+
"DB: resetting node (using Mnesia)",
77100
#{domain => ?RMQLOG_DOMAIN_DB}),
78101
rabbit_mnesia:reset().
79102

@@ -82,11 +105,12 @@ reset_using_mnesia() ->
82105
%% @doc Resets the database and the node.
83106

84107
force_reset() ->
85-
force_reset_using_mnesia().
108+
run(
109+
#{mnesia => fun force_reset_using_mnesia/0}).
86110

87111
force_reset_using_mnesia() ->
88112
?LOG_DEBUG(
89-
"DB: resetting node forcefully",
113+
"DB: resetting node forcefully (using Mnesia)",
90114
#{domain => ?RMQLOG_DOMAIN_DB}),
91115
rabbit_mnesia:force_reset().
92116

@@ -98,11 +122,12 @@ force_reset_using_mnesia() ->
98122
%% state, like if critical members are MIA.
99123

100124
force_load_on_next_boot() ->
101-
force_load_on_next_boot_using_mnesia().
125+
run(
126+
#{mnesia => fun force_load_on_next_boot_using_mnesia/0}).
102127

103128
force_load_on_next_boot_using_mnesia() ->
104129
?LOG_DEBUG(
105-
"DB: resetting node forcefully",
130+
"DB: force load on next boot (using Mnesia)",
106131
#{domain => ?RMQLOG_DOMAIN_DB}),
107132
rabbit_mnesia:force_load_next_boot().
108133

@@ -115,8 +140,11 @@ force_load_on_next_boot_using_mnesia() ->
115140
%% @see is_virgin_node/1.
116141

117142
is_virgin_node() ->
118-
ThisNode = node(),
119-
is_virgin_node(ThisNode).
143+
run(
144+
#{mnesia => fun is_virgin_node_using_mnesia/0}).
145+
146+
is_virgin_node_using_mnesia() ->
147+
rabbit_mnesia:is_virgin_node().
120148

121149
-spec is_virgin_node(Node) -> IsVirgin | undefined when
122150
Node :: node(),
@@ -129,14 +157,11 @@ is_virgin_node() ->
129157
%% @returns `true' if the node is virgin, `false' if it is not, or `undefined'
130158
%% if the given node is remote and we couldn't determine it.
131159

160+
is_virgin_node(Node) when Node =:= node() ->
161+
is_virgin_node();
132162
is_virgin_node(Node) when is_atom(Node) ->
133-
is_virgin_node_with_mnesia(Node).
134-
135-
is_virgin_node_with_mnesia(Node) when Node =:= node() ->
136-
rabbit_mnesia:is_virgin_node();
137-
is_virgin_node_with_mnesia(Node) ->
138163
try
139-
erpc:call(Node, rabbit_mnesia, is_virgin_node, [], ?TIMEOUT)
164+
erpc:call(Node, ?MODULE, is_virgin_node, [], ?TIMEOUT)
140165
catch
141166
_:_ ->
142167
undefined
@@ -149,7 +174,8 @@ is_virgin_node_with_mnesia(Node) ->
149174
%% @returns the directory path.
150175

151176
dir() ->
152-
mnesia_dir().
177+
run(
178+
#{mnesia => fun mnesia_dir/0}).
153179

154180
mnesia_dir() ->
155181
rabbit_mnesia:dir().
@@ -183,9 +209,9 @@ ensure_dir_exists() ->
183209
run(Funs)
184210
when is_map(Funs) andalso is_map_key(mnesia, Funs) ->
185211
#{mnesia := MnesiaFun} = Funs,
186-
run_with_mnesia(MnesiaFun).
212+
run_using_mnesia(MnesiaFun).
187213

188-
run_with_mnesia(Fun) ->
214+
run_using_mnesia(Fun) ->
189215
Fun().
190216

191217
list_in_mnesia(Table, Match) ->

deps/rabbit/src/rabbit_db_cluster.erl

Lines changed: 93 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111

1212
-include_lib("rabbit_common/include/logging.hrl").
1313

14-
-export([join/2,
14+
-export([ensure_feature_flags_are_in_sync/2,
15+
join/2,
1516
forget_member/2]).
1617
-export([change_node_type/1]).
1718
-export([is_clustered/0,
1819
members/0,
1920
disc_members/0,
2021
node_type/0,
22+
check_compatibility/1,
2123
check_consistency/0,
2224
cli_cluster_status/0]).
2325

@@ -35,6 +37,36 @@
3537
%% Cluster formation.
3638
%% -------------------------------------------------------------------
3739

40+
ensure_feature_flags_are_in_sync(Nodes, NodeIsVirgin) ->
41+
Ret = rabbit_feature_flags:sync_feature_flags_with_cluster(
42+
Nodes, NodeIsVirgin),
43+
case Ret of
44+
ok -> ok;
45+
{error, Reason} -> throw({error, {incompatible_feature_flags, Reason}})
46+
end.
47+
48+
-spec can_join(RemoteNode) -> Ret when
49+
RemoteNode :: node(),
50+
Ret :: Ok | Error,
51+
Ok :: {ok, [node()]} | {ok, already_member},
52+
Error :: {error, {inconsistent_cluster, string()}}.
53+
54+
can_join(RemoteNode) ->
55+
?LOG_INFO(
56+
"DB: checking if `~ts` can join cluster using remote node `~ts`",
57+
[node(), RemoteNode],
58+
#{domain => ?RMQLOG_DOMAIN_DB}),
59+
case rabbit_feature_flags:check_node_compatibility(RemoteNode) of
60+
ok ->
61+
rabbit_db:run(
62+
#{mnesia => fun() -> can_join_using_mnesia(RemoteNode) end});
63+
Error ->
64+
Error
65+
end.
66+
67+
can_join_using_mnesia(RemoteNode) ->
68+
rabbit_mnesia:can_join_cluster(RemoteNode).
69+
3870
-spec join(RemoteNode, NodeType) -> Ret when
3971
RemoteNode :: node(),
4072
NodeType :: rabbit_db_cluster:node_type(),
@@ -45,21 +77,41 @@
4577

4678
join(RemoteNode, NodeType)
4779
when is_atom(RemoteNode) andalso ?IS_NODE_TYPE(NodeType) ->
48-
?LOG_DEBUG(
49-
"DB: joining cluster using remote node `~ts`", [RemoteNode],
50-
#{domain => ?RMQLOG_DOMAIN_DB}),
51-
join_using_mnesia(RemoteNode, NodeType).
80+
case can_join(RemoteNode) of
81+
{ok, ClusterNodes} when is_list(ClusterNodes) ->
82+
rabbit_db:reset(),
83+
84+
?LOG_INFO(
85+
"DB: joining cluster using remote nodes:~n~tp", [ClusterNodes],
86+
#{domain => ?RMQLOG_DOMAIN_DB}),
87+
Ret = rabbit_db:run(
88+
#{mnesia =>
89+
fun() -> join_using_mnesia(ClusterNodes, NodeType) end}),
90+
case Ret of
91+
ok ->
92+
rabbit_node_monitor:notify_joined_cluster(),
93+
ok;
94+
{error, _} = Error ->
95+
Error
96+
end;
97+
{ok, already_member} ->
98+
{ok, already_member};
99+
{error, _} = Error ->
100+
Error
101+
end.
52102

53-
join_using_mnesia(RemoteNode, NodeType) ->
54-
rabbit_mnesia:join_cluster(RemoteNode, NodeType).
103+
join_using_mnesia(ClusterNodes, NodeType) when is_list(ClusterNodes) ->
104+
rabbit_mnesia:join_cluster(ClusterNodes, NodeType).
55105

56106
-spec forget_member(Node, RemoveWhenOffline) -> ok when
57107
Node :: node(),
58108
RemoveWhenOffline :: boolean().
59109
%% @doc Removes `Node' from the cluster.
60110

61111
forget_member(Node, RemoveWhenOffline) ->
62-
forget_member_using_mnesia(Node, RemoveWhenOffline).
112+
rabbit_db:run(
113+
#{mnesia =>
114+
fun() -> forget_member_using_mnesia(Node, RemoveWhenOffline) end}).
63115

64116
forget_member_using_mnesia(Node, RemoveWhenOffline) ->
65117
rabbit_mnesia:forget_cluster_node(Node, RemoveWhenOffline).
@@ -75,7 +127,8 @@ forget_member_using_mnesia(Node, RemoveWhenOffline) ->
75127
%% Node types may not all be valid with all databases.
76128

77129
change_node_type(NodeType) ->
78-
change_node_type_using_mnesia(NodeType).
130+
rabbit_db:run(
131+
#{mnesia => fun() -> change_node_type_using_mnesia(NodeType) end}).
79132

80133
change_node_type_using_mnesia(NodeType) ->
81134
rabbit_mnesia:change_cluster_node_type(NodeType).
@@ -89,7 +142,8 @@ change_node_type_using_mnesia(NodeType) ->
89142
%% @doc Indicates if this node is clustered with other nodes or not.
90143

91144
is_clustered() ->
92-
is_clustered_using_mnesia().
145+
rabbit_db:run(
146+
#{mnesia => fun is_clustered_using_mnesia/0}).
93147

94148
is_clustered_using_mnesia() ->
95149
rabbit_mnesia:is_clustered().
@@ -99,7 +153,8 @@ is_clustered_using_mnesia() ->
99153
%% @doc Returns the list of cluster members.
100154

101155
members() ->
102-
members_using_mnesia().
156+
rabbit_db:run(
157+
#{mnesia => fun members_using_mnesia/0}).
103158

104159
members_using_mnesia() ->
105160
case rabbit_mnesia:is_running() andalso rabbit_table:is_present() of
@@ -127,7 +182,8 @@ members_using_mnesia() ->
127182
%% @private
128183

129184
disc_members() ->
130-
disc_members_using_mnesia().
185+
rabbit_db:run(
186+
#{mnesia => fun disc_members_using_mnesia/0}).
131187

132188
disc_members_using_mnesia() ->
133189
rabbit_mnesia:cluster_nodes(disc).
@@ -139,16 +195,37 @@ disc_members_using_mnesia() ->
139195
%% Node types may not all be relevant with all databases.
140196

141197
node_type() ->
142-
node_type_using_mnesia().
198+
rabbit_db:run(
199+
#{mnesia => fun node_type_using_mnesia/0}).
143200

144201
node_type_using_mnesia() ->
145202
rabbit_mnesia:node_type().
146203

204+
-spec check_compatibility(RemoteNode) -> ok | {error, Reason} when
205+
RemoteNode :: node(),
206+
Reason :: any().
207+
%% @doc Ensures the given remote node is compatible with the node calling this
208+
%% function.
209+
210+
check_compatibility(RemoteNode) ->
211+
case rabbit_feature_flags:check_node_compatibility(RemoteNode) of
212+
ok ->
213+
rabbit_db:run(
214+
#{mnesia =>
215+
fun() -> check_compatibility_using_mnesia(RemoteNode) end});
216+
Error ->
217+
Error
218+
end.
219+
220+
check_compatibility_using_mnesia(RemoteNode) ->
221+
rabbit_mnesia:check_mnesia_consistency(RemoteNode).
222+
147223
-spec check_consistency() -> ok.
148224
%% @doc Ensures the cluster is consistent.
149225

150226
check_consistency() ->
151-
check_consistency_using_mnesia().
227+
rabbit_db:run(
228+
#{mnesia => fun check_consistency_using_mnesia/0}).
152229

153230
check_consistency_using_mnesia() ->
154231
rabbit_mnesia:check_cluster_consistency().
@@ -161,7 +238,8 @@ check_consistency_using_mnesia() ->
161238
%% command.
162239

163240
cli_cluster_status() ->
164-
cli_cluster_status_using_mnesia().
241+
rabbit_db:run(
242+
#{mnesia => fun cli_cluster_status_using_mnesia/0}).
165243

166244
cli_cluster_status_using_mnesia() ->
167245
rabbit_mnesia:status().

0 commit comments

Comments
 (0)