diff options
author | Simon MacMullen <simon@rabbitmq.com> | 2013-03-14 11:35:07 +0000 |
---|---|---|
committer | Simon MacMullen <simon@rabbitmq.com> | 2013-03-14 11:35:07 +0000 |
commit | faf5177eebe306d79d91a8e1d6b59cd72daa81a8 (patch) | |
tree | f400a3cc5954eb46ad00da6719b86d553a14f822 | |
parent | 797354c2bf2baa43eb9e44eb4d636e876f403e5c (diff) | |
download | rabbitmq-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.erl | 30 | ||||
-rw-r--r-- | src/rabbit_exchange.erl | 15 |
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) -> |