summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon MacMullen <simon@rabbitmq.com>2013-03-14 11:35:07 +0000
committerSimon MacMullen <simon@rabbitmq.com>2013-03-14 11:35:07 +0000
commitfaf5177eebe306d79d91a8e1d6b59cd72daa81a8 (patch)
treef400a3cc5954eb46ad00da6719b86d553a14f822
parent797354c2bf2baa43eb9e44eb4d636e876f403e5c (diff)
downloadrabbitmq-server-faf5177eebe306d79d91a8e1d6b59cd72daa81a8.tar.gz
Move the check inside the tx - this means we only lookup the exchange once and there's no possible race. It means we have to convert the exception to an {error, #amqp_error{}} which then gets converted back to an exception, but never mind...
-rw-r--r--src/rabbit_binding.erl30
-rw-r--r--src/rabbit_exchange.erl15
2 files changed, 30 insertions, 15 deletions
diff --git a/src/rabbit_binding.erl b/src/rabbit_binding.erl
index 54136404..6bc17482 100644
--- a/src/rabbit_binding.erl
+++ b/src/rabbit_binding.erl
@@ -153,22 +153,26 @@ exists(Binding) ->
add(Binding) -> add(Binding, fun (_Src, _Dst) -> ok end).
-add(Binding = #binding{source = XName}, InnerFun) ->
- {ok, X = #exchange{type = XType}} = rabbit_exchange:lookup(XName),
- Module = rabbit_exchange:type_to_module(XType),
- Module:validate_binding(X, Binding),
+add(Binding, InnerFun) ->
binding_action(
Binding,
fun (Src, Dst, B) ->
- %% this argument is used to check queue exclusivity;
- %% in general, we want to fail on that in preference to
- %% anything else
- case InnerFun(Src, Dst) of
- ok -> case mnesia:read({rabbit_route, B}) of
- [] -> add(Src, Dst, B);
- [_] -> fun rabbit_misc:const_ok/0
- end;
- {error, _} = Err -> rabbit_misc:const(Err)
+ case rabbit_exchange:validate_binding(Src, B) of
+ ok ->
+ %% this argument is used to check queue exclusivity;
+ %% in general, we want to fail on that in preference to
+ %% anything else
+ case InnerFun(Src, Dst) of
+ ok ->
+ case mnesia:read({rabbit_route, B}) of
+ [] -> add(Src, Dst, B);
+ [_] -> fun rabbit_misc:const_ok/0
+ end;
+ {error, _} = Err ->
+ rabbit_misc:const(Err)
+ end;
+ {error, _} = Err ->
+ rabbit_misc:const(Err)
end
end).
diff --git a/src/rabbit_exchange.erl b/src/rabbit_exchange.erl
index 94a37148..18ec83c1 100644
--- a/src/rabbit_exchange.erl
+++ b/src/rabbit_exchange.erl
@@ -22,7 +22,7 @@
assert_equivalence/6, assert_args_equivalence/2, check_type/1,
lookup/1, lookup_or_die/1, list/1, lookup_scratch/2, update_scratch/3,
info_keys/0, info/1, info/2, info_all/1, info_all/2,
- route/2, delete/2, type_to_module/1]).
+ route/2, delete/2, validate_binding/2]).
%% these must be run inside a mnesia tx
-export([maybe_auto_delete/1, serial/1, peek_serial/1, update/2]).
@@ -83,7 +83,9 @@
(name(), boolean())-> 'ok' |
rabbit_types:error('not_found') |
rabbit_types:error('in_use')).
--spec(type_to_module/1 :: (type()) -> atom()).
+-spec(validate_binding/2 ::
+ (rabbit_types:exchange(), rabbit_types:binding())
+ -> rabbit_types:ok_or_error(rabbit_types:amqp_error())).
-spec(maybe_auto_delete/1::
(rabbit_types:exchange())
-> 'not_deleted' | {'deleted', rabbit_binding:deletions()}).
@@ -400,6 +402,15 @@ delete(XName, IfUnused) ->
end
end).
+validate_binding(X = #exchange{type = XType}, Binding) ->
+ Module = type_to_module(XType),
+ try
+ Module:validate_binding(X, Binding)
+ catch
+ exit:Error ->
+ {error, Error}
+ end.
+
maybe_auto_delete(#exchange{auto_delete = false}) ->
not_deleted;
maybe_auto_delete(#exchange{auto_delete = true} = X) ->