summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Radestock <matthias@rabbitmq.com>2011-12-01 21:57:32 +0000
committerMatthias Radestock <matthias@rabbitmq.com>2011-12-01 21:57:32 +0000
commitefc13c9e00e185ca81fc2b8d1239390d5c5acae7 (patch)
treed7b63a7a42ec84f198576b99a3775243bdc3cc5e
parent79a2e2da9bfc918f48b7e6ed92f1f573c4afae8a (diff)
downloadrabbitmq-server-bug24607.tar.gz
reduce queue/exchange deletion complexitybug24607
from O(binding_count^2) to O(binding_count)
-rw-r--r--src/rabbit_binding.erl22
1 files changed, 22 insertions, 0 deletions
diff --git a/src/rabbit_binding.erl b/src/rabbit_binding.erl
index e625a427..0d221b05 100644
--- a/src/rabbit_binding.erl
+++ b/src/rabbit_binding.erl
@@ -277,6 +277,7 @@ has_for_source(SrcName) ->
contains(rabbit_semi_durable_route, Match).
remove_for_source(SrcName) ->
+ lock_route_tables(),
Match = #route{binding = #binding{source = SrcName, _ = '_'}},
Routes = lists:usort(
mnesia:match_object(rabbit_route, Match, write) ++
@@ -351,7 +352,28 @@ continue('$end_of_table') -> false;
continue({[_|_], _}) -> true;
continue({[], Continuation}) -> continue(mnesia:select(Continuation)).
+%% For bulk operations we lock the tables we are operating on in order
+%% to reduce the time complexity. Without the table locks we end up
+%% with num_tables*num_bulk_bindings row-level locks. Takiing each
+%% lock takes time proportional to the number of existing locks, thus
+%% resulting in O(num_bulk_bindings^2) complexity.
+%%
+%% The locks need to be write locks since ultimately we end up
+%% removing all these rows.
+%%
+%% The downside of all this is that no other binding operations except
+%% lookup/routing (which uses dirty ops) can take place
+%% concurrently. However, that is the case already since the bulk
+%% operations involve mnesia:match_object calls with a partial key,
+%% which entails taking a table lock.
+lock_route_tables() ->
+ [mnesia:lock({table, T}, write) || T <- [rabbit_route,
+ rabbit_reverse_route,
+ rabbit_semi_durable_route,
+ rabbit_durable_route]].
+
remove_for_destination(DstName, DeleteFun) ->
+ lock_route_tables(),
Match = reverse_route(
#route{binding = #binding{destination = DstName, _ = '_'}}),
ReverseRoutes = mnesia:match_object(rabbit_reverse_route, Match, write),