Skip to content

Commit 12ec3a5

Browse files
committed
rabbit_vhost:set_tags/2 avoids notifying if tags are unchanged
Additionally, tags are now always sorted when set
1 parent d07e479 commit 12ec3a5

File tree

5 files changed

+98
-4
lines changed

5 files changed

+98
-4
lines changed

deps/rabbit/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,9 @@ rabbitmq_integration_suite(
10431043
name = "vhost_SUITE",
10441044
size = "medium",
10451045
flaky = True,
1046+
additional_srcs = [
1047+
"test/test_rabbit_event_handler.erl",
1048+
],
10461049
)
10471050

10481051
rabbitmq_suite(

deps/rabbit/src/rabbit_db_vhost.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ merge_metadata_in_mnesia_tx(VHostName, Metadata) ->
132132

133133
set_tags(VHostName, Tags)
134134
when is_binary(VHostName) andalso is_list(Tags) ->
135-
ConvertedTags = [rabbit_data_coercion:to_atom(Tag) || Tag <- Tags],
135+
ConvertedTags = lists:usort([rabbit_data_coercion:to_atom(Tag) || Tag <- Tags]),
136136
rabbit_db:run(
137137
#{mnesia => fun() -> set_tags_in_mnesia(VHostName, ConvertedTags) end}).
138138

deps/rabbit/src/rabbit_vhost.erl

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -518,15 +518,36 @@ assert(VHostName) ->
518518
false -> throw({error, {no_such_vhost, VHostName}})
519519
end.
520520

521+
are_different0([], []) ->
522+
false;
523+
are_different0([], [_ | _]) ->
524+
true;
525+
are_different0([_ | _], []) ->
526+
true;
527+
are_different0([E], [E]) ->
528+
false;
529+
are_different0([E | R1], [E | R2]) ->
530+
are_different0(R1, R2);
531+
are_different0(_, _) ->
532+
true.
533+
534+
are_different(L1, L2) ->
535+
are_different0(lists:usort(L1), lists:usort(L2)).
536+
521537
-spec update_tags(vhost:name(), [vhost_tag()], rabbit_types:username()) -> vhost:vhost().
522538
update_tags(VHostName, Tags, ActingUser) ->
523539
try
540+
CurrentTags = case rabbit_db_vhost:get(VHostName) of
541+
undefined -> [];
542+
V -> vhost:get_tags(V)
543+
end,
524544
VHost = rabbit_db_vhost:set_tags(VHostName, Tags),
525545
ConvertedTags = vhost:get_tags(VHost),
526546
rabbit_log:info("Successfully set tags for virtual host '~ts' to ~tp", [VHostName, ConvertedTags]),
527-
rabbit_event:notify(vhost_tags_set, [{name, VHostName},
528-
{tags, ConvertedTags},
529-
{user_who_performed_action, ActingUser}]),
547+
rabbit_event:notify_if(are_different(CurrentTags, ConvertedTags),
548+
vhost_tags_set, [{name, VHostName},
549+
{tags, ConvertedTags},
550+
{user_who_performed_action, ActingUser}]),
530551
VHost
531552
catch
532553
throw:{error, {no_such_vhost, _}} = Error ->
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
-module(test_rabbit_event_handler).
2+
3+
-behaviour(gen_event).
4+
5+
-export([okay/0]).
6+
-export([init/1, handle_call/2, handle_event/2, handle_info/2,
7+
terminate/2, code_change/3]).
8+
9+
-include_lib("rabbit_common/include/rabbit.hrl").
10+
11+
% an exported callable func, used to allow rabbit_ct_broker_helpers
12+
% to load this code when rpc'd
13+
okay() -> ok.
14+
15+
init([]) ->
16+
{ok, #{events => []}}.
17+
18+
handle_event(#event{} = Event, #{events := Events} = State) ->
19+
{ok, State#{events => [Event | Events]}};
20+
handle_event(_, State) ->
21+
{ok, State}.
22+
23+
handle_call(events, #{events := Events} = State) ->
24+
{ok, Events, State}.
25+
26+
handle_info(_Info, State) ->
27+
{ok, State}.
28+
29+
terminate(_Arg, _State) ->
30+
ok.
31+
32+
code_change(_OldVsn, State, _Extra) ->
33+
{ok, State}.

deps/rabbit/test/vhost_SUITE.erl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ groups() ->
2828
single_node_vhost_deletion_forces_connection_closure,
2929
vhost_failure_forces_connection_closure,
3030
vhost_creation_idempotency,
31+
vhost_update_idempotency,
3132
parse_tags
3233
],
3334
ClusterSize2Tests = [
@@ -321,6 +322,42 @@ vhost_creation_idempotency(Config) ->
321322
rabbit_ct_broker_helpers:delete_vhost(Config, VHost)
322323
end.
323324

325+
vhost_update_idempotency(Config) ->
326+
VHost = <<"update-idempotency-test">>,
327+
ActingUser = <<"acting-user">>,
328+
try
329+
% load the dummy event handler on the node
330+
ok = rabbit_ct_broker_helpers:rpc(Config, 0, test_rabbit_event_handler, okay, []),
331+
332+
ok = rabbit_ct_broker_helpers:rpc(Config, 0, gen_event, add_handler,
333+
[rabbit_event, test_rabbit_event_handler, []]),
334+
335+
?assertEqual(ok, rabbit_ct_broker_helpers:add_vhost(Config, VHost)),
336+
337+
?assertMatch({vhost,VHost, [], #{tags := [private,replicate]}},
338+
rabbit_ct_broker_helpers:rpc(Config, 0,
339+
rabbit_vhost, update_tags,
340+
[VHost, [private, replicate], ActingUser])),
341+
?assertMatch({vhost,VHost, [], #{tags := [private,replicate]}},
342+
rabbit_ct_broker_helpers:rpc(Config, 0,
343+
rabbit_vhost, update_tags,
344+
[VHost, [replicate, private], ActingUser])),
345+
346+
Events = rabbit_ct_broker_helpers:rpc(Config, 0,
347+
gen_event, call,
348+
[rabbit_event, test_rabbit_event_handler, events, 100]),
349+
ct:pal(?LOW_IMPORTANCE, "Events: ~p", [lists:reverse(Events)]),
350+
TagsSetEvents = lists:filter(fun
351+
(#event{type = vhost_tags_set}) -> true;
352+
(_) -> false
353+
end, Events),
354+
?assertMatch([#event{}], TagsSetEvents)
355+
after
356+
rabbit_ct_broker_helpers:rpc(Config, 0,
357+
gen_event, delete_handler, [rabbit_event, test_rabbit_event_handler, []]),
358+
rabbit_ct_broker_helpers:delete_vhost(Config, VHost)
359+
end.
360+
324361
vhost_is_created_with_default_limits(Config) ->
325362
VHost = <<"vhost1">>,
326363
Limits = [{<<"max-connections">>, 10}, {<<"max-queues">>, 1}],

0 commit comments

Comments
 (0)