Skip to content

Commit d19b9b6

Browse files
committed
Transactionally delete all exchanges during vhost deletion
Currently we delete each exchange one-by-one which requires three commands: the delete itself plus a put and delete for a runtime parameter that acts as a lock to prevent a client from declaring an exchange while it's being deleted. The lock is unnecessary during vhost deletion because permissions are cleared for the vhost before any resources are deleted. We can use a transaction to delete all exchanges and bindings for a vhost in a single command against the Khepri store. This minimizes the number of commands we need to send against the store and therefore the latency of the deletion. In a quick test with a vhost containing only 10,000 exchanges (no bindings, queues, users, etc.), this is an order of magnitude speedup: the prior commit takes 22s to delete the vhost while with this commit the vhost is deleted in 2s.
1 parent 868b41e commit d19b9b6

File tree

3 files changed

+77
-3
lines changed

3 files changed

+77
-3
lines changed

deps/rabbit/src/rabbit_db_exchange.erl

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
peek_serial/1,
2727
next_serial/1,
2828
delete/2,
29+
delete_all/1,
2930
delete_serial/1,
3031
recover/1,
3132
match/1,
@@ -657,6 +658,69 @@ delete_in_khepri(X = #exchange{name = XName}, OnlyDurable, RemoveBindingsForSour
657658
ok = khepri_tx:delete(khepri_exchange_path(XName)),
658659
rabbit_db_binding:delete_all_for_exchange_in_khepri(X, OnlyDurable, RemoveBindingsForSource).
659660

661+
%% -------------------------------------------------------------------
662+
%% delete_all().
663+
%% -------------------------------------------------------------------
664+
665+
-spec delete_all(VHostName) -> Ret when
666+
VHostName :: vhost:name(),
667+
Deletions :: rabbit_binding:deletions(),
668+
Ret :: {ok, Deletions}.
669+
%% @doc Deletes all exchanges for a given vhost.
670+
%%
671+
%% @returns an `{ok, Deletions}' tuple containing the {@link
672+
%% rabbit_binding:deletions()} caused by deleting the exchanges under the given
673+
%% vhost.
674+
%%
675+
%% @private
676+
677+
delete_all(VHostName) ->
678+
rabbit_khepri:handle_fallback(
679+
#{mnesia => fun() -> delete_all_in_mnesia(VHostName) end,
680+
khepri => fun() -> delete_all_in_khepri(VHostName) end
681+
}).
682+
683+
delete_all_in_mnesia(VHostName) ->
684+
rabbit_mnesia:execute_mnesia_transaction(
685+
fun() ->
686+
delete_all_in_mnesia_tx(VHostName)
687+
end).
688+
689+
delete_all_in_mnesia_tx(VHostName) ->
690+
Match = #exchange{name = rabbit_misc:r(VHostName, exchange), _ = '_'},
691+
Xs = mnesia:match_object(?MNESIA_TABLE, Match, write),
692+
Deletions =
693+
lists:foldl(
694+
fun(X, Acc) ->
695+
{deleted, #exchange{name = XName}, Bindings, XDeletions} =
696+
unconditional_delete_in_mnesia( X, false),
697+
XDeletions1 = rabbit_binding:add_deletion(
698+
XName, {X, deleted, Bindings}, XDeletions),
699+
rabbit_binding:combine_deletions(Acc, XDeletions1)
700+
end, rabbit_binding:new_deletions(), Xs),
701+
{ok, Deletions}.
702+
703+
delete_all_in_khepri(VHostName) ->
704+
rabbit_khepri:transaction(
705+
fun() ->
706+
delete_all_in_khepri_tx(VHostName)
707+
end, rw, #{timeout => infinity}).
708+
709+
delete_all_in_khepri_tx(VHostName) ->
710+
Pattern = khepri_exchange_path(VHostName, ?KHEPRI_WILDCARD_STAR),
711+
{ok, NodeProps} = khepri_tx_adv:delete_many(Pattern),
712+
Deletions =
713+
maps:fold(
714+
fun(_Path, #{data := X}, Deletions) ->
715+
{deleted, #exchange{name = XName}, Bindings, XDeletions} =
716+
rabbit_db_binding:delete_all_for_exchange_in_khepri(
717+
X, false, true),
718+
Deletions1 = rabbit_binding:add_deletion(
719+
XName, {X, deleted, Bindings}, XDeletions),
720+
rabbit_binding:combine_deletions(Deletions, Deletions1)
721+
end, rabbit_binding:new_deletions(), NodeProps),
722+
{ok, Deletions}.
723+
660724
%% -------------------------------------------------------------------
661725
%% delete_serial().
662726
%% -------------------------------------------------------------------

deps/rabbit/src/rabbit_exchange.erl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
update_scratch/3, update_decorators/2, immutable/1,
1515
info_keys/0, info/1, info/2, info_all/1, info_all/2, info_all/4,
1616
route/2, route/3, delete/3, validate_binding/2, count/0,
17-
ensure_deleted/3]).
17+
ensure_deleted/3, delete_all/2]).
1818
-export([list_names/0]).
1919
-export([serialise_events/1]).
2020
-export([serial/1, peek_serial/1]).
@@ -484,6 +484,17 @@ delete(XName, IfUnused, Username) ->
484484
XName#resource.name, Username)
485485
end.
486486

487+
-spec delete_all(VHostName, ActingUser) -> Ret when
488+
VHostName :: vhost:name(),
489+
ActingUser :: rabbit_types:username(),
490+
Ret :: ok.
491+
492+
delete_all(VHostName, ActingUser) ->
493+
{ok, Deletions} = rabbit_db_exchange:delete_all(VHostName),
494+
Deletions1 = rabbit_binding:process_deletions(Deletions),
495+
rabbit_binding:notify_deletions(Deletions1, ActingUser),
496+
ok.
497+
487498
process_deletions({error, _} = E) ->
488499
E;
489500
process_deletions({deleted, #exchange{name = XName} = X, Bs, Deletions}) ->

deps/rabbit/src/rabbit_vhost.erl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,7 @@ delete(VHost, ActingUser) ->
299299
assert_benign(rabbit_amqqueue:with(Name, QDelFun), ActingUser)
300300
end || Q <- rabbit_amqqueue:list(VHost)],
301301
rabbit_log:info("Deleting exchanges in vhost '~ts' because it's being deleted", [VHost]),
302-
[ok = rabbit_exchange:ensure_deleted(Name, false, ActingUser) ||
303-
#exchange{name = Name} <- rabbit_exchange:list(VHost)],
302+
ok = rabbit_exchange:delete_all(VHost, ActingUser),
304303
rabbit_log:info("Clearing policies and runtime parameters in vhost '~ts' because it's being deleted", [VHost]),
305304
_ = rabbit_runtime_parameters:clear_vhost(VHost, ActingUser),
306305
rabbit_log:debug("Removing vhost '~ts' from the metadata storage because it's being deleted", [VHost]),

0 commit comments

Comments
 (0)