diff options
author | Matthew Sackman <matthew@rabbitmq.com> | 2010-06-10 18:35:39 +0100 |
---|---|---|
committer | Matthew Sackman <matthew@rabbitmq.com> | 2010-06-10 18:35:39 +0100 |
commit | bd2423da0244f0be90bdd0bce5464edd138ad12c (patch) | |
tree | d2130aac7a92df9ed3ce5f5994cb190bc191bfe7 | |
parent | 32d4495501f4a1881ec16054d1e5c24e22ad899b (diff) | |
parent | 140d75a1c239d4243d339dd19838fa84a3c1feb9 (diff) | |
download | rabbitmq-server-bd2423da0244f0be90bdd0bce5464edd138ad12c.tar.gz |
Merging bug 22848 onto default
-rw-r--r-- | include/rabbit_exchange_type_spec.hrl | 1 | ||||
-rw-r--r-- | src/rabbit_channel.erl | 24 | ||||
-rw-r--r-- | src/rabbit_exchange.erl | 43 | ||||
-rw-r--r-- | src/rabbit_exchange_type.erl | 6 | ||||
-rw-r--r-- | src/rabbit_exchange_type_direct.erl | 4 | ||||
-rw-r--r-- | src/rabbit_exchange_type_fanout.erl | 4 | ||||
-rw-r--r-- | src/rabbit_exchange_type_headers.erl | 4 | ||||
-rw-r--r-- | src/rabbit_exchange_type_topic.erl | 4 |
8 files changed, 71 insertions, 19 deletions
diff --git a/include/rabbit_exchange_type_spec.hrl b/include/rabbit_exchange_type_spec.hrl index 38057beb..cb564365 100644 --- a/include/rabbit_exchange_type_spec.hrl +++ b/include/rabbit_exchange_type_spec.hrl @@ -38,5 +38,6 @@ -spec(delete/2 :: (exchange(), list(binding())) -> 'ok'). -spec(add_binding/2 :: (exchange(), binding()) -> 'ok'). -spec(remove_bindings/2 :: (exchange(), list(binding())) -> 'ok'). +-spec(assert_args_equivalence/2 :: (exchange(), amqp_table()) -> 'ok'). -endif. diff --git a/src/rabbit_channel.erl b/src/rabbit_channel.erl index 21595f82..3ae554d0 100644 --- a/src/rabbit_channel.erl +++ b/src/rabbit_channel.erl @@ -687,18 +687,17 @@ handle_method(#'exchange.declare'{exchange = ExchangeNameBin, AutoDelete, Args) end, - ok = rabbit_exchange:assert_type(X, CheckedType), + ok = rabbit_exchange:assert_equivalence(X, CheckedType, Durable, + AutoDelete, Args), return_ok(State, NoWait, #'exchange.declare_ok'{}); handle_method(#'exchange.declare'{exchange = ExchangeNameBin, - type = TypeNameBin, passive = true, nowait = NoWait}, _, State = #ch{ virtual_host = VHostPath }) -> ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin), check_configure_permitted(ExchangeName, State), - X = rabbit_exchange:lookup_or_die(ExchangeName), - ok = rabbit_exchange:assert_type(X, rabbit_exchange:check_type(TypeNameBin)), + _ = rabbit_exchange:lookup_or_die(ExchangeName), return_ok(State, NoWait, #'exchange.declare_ok'{}); handle_method(#'exchange.delete'{exchange = ExchangeNameBin, @@ -733,14 +732,27 @@ handle_method(#'queue.declare'{queue = QueueNameBin, end, %% We use this in both branches, because queue_declare may yet return an %% existing queue. - Finish = fun (#amqqueue{name = QueueName} = Q) -> + Finish = fun (#amqqueue{name = QueueName, + durable = Durable1, + auto_delete = AutoDelete1} = Q) + when Durable =:= Durable1, AutoDelete =:= AutoDelete1 -> check_exclusive_access(Q, Owner, strict), check_configure_permitted(QueueName, State), + %% We need to notify the reader within the channel + %% process so that we can be sure there are no + %% outstanding exclusive queues being declared as the + %% connection shuts down. case Owner of none -> ok; _ -> ok = rabbit_reader_queue_collector:register_exclusive_queue(CollectorPid, Q) end, - Q + Q; + %% non-equivalence trumps exclusivity arbitrarily + (#amqqueue{name = QueueName}) -> + rabbit_misc:protocol_error( + precondition_failed, + "parameters for ~s not equivalent", + [rabbit_misc:rs(QueueName)]) end, Q = case rabbit_amqqueue:with( rabbit_misc:r(VHostPath, queue, QueueNameBin), diff --git a/src/rabbit_exchange.erl b/src/rabbit_exchange.erl index 99799f7a..c5149b08 100644 --- a/src/rabbit_exchange.erl +++ b/src/rabbit_exchange.erl @@ -39,7 +39,9 @@ -export([add_binding/5, delete_binding/5, list_bindings/1]). -export([delete/2]). -export([delete_queue_bindings/1, delete_transient_queue_bindings/1]). --export([check_type/1, assert_type/2]). +-export([assert_equivalence/5]). +-export([assert_args_equivalence/2]). +-export([check_type/1]). %% EXTENDED API -export([list_exchange_bindings/1]). @@ -64,7 +66,9 @@ -spec(declare/5 :: (exchange_name(), exchange_type(), boolean(), boolean(), amqp_table()) -> exchange()). -spec(check_type/1 :: (binary()) -> atom()). --spec(assert_type/2 :: (exchange(), atom()) -> 'ok'). +-spec(assert_equivalence/5 :: (exchange(), atom(), boolean(), boolean(), + amqp_table()) -> 'ok'). +-spec(assert_args_equivalence/2 :: (exchange(), amqp_table()) -> 'ok'). -spec(lookup/1 :: (exchange_name()) -> {'ok', exchange()} | not_found()). -spec(lookup_or_die/1 :: (exchange_name()) -> exchange()). -spec(list/1 :: (vhost()) -> [exchange()]). @@ -185,13 +189,36 @@ check_type(TypeBin) -> T end. -assert_type(#exchange{ type = ActualType }, RequiredType) - when ActualType == RequiredType -> - ok; -assert_type(#exchange{ name = Name, type = ActualType }, RequiredType) -> +assert_equivalence(X = #exchange{ durable = Durable, + auto_delete = AutoDelete, + type = Type}, + Type, Durable, AutoDelete, + RequiredArgs) -> + ok = (type_to_module(Type)):assert_args_equivalence(X, RequiredArgs); +assert_equivalence(#exchange{ name = Name }, _Type, _Durable, _AutoDelete, + _Args) -> rabbit_misc:protocol_error( - not_allowed, "cannot redeclare ~s of type '~s' with type '~s'", - [rabbit_misc:rs(Name), ActualType, RequiredType]). + precondition_failed, + "cannot redeclare ~s with different type, durable or autodelete value", + [rabbit_misc:rs(Name)]). + +alternate_exchange_value(Args) -> + lists:keysearch(<<"alternate-exchange">>, 1, Args). + +assert_args_equivalence(#exchange{ name = Name, + arguments = Args }, + RequiredArgs) -> + %% The spec says "Arguments are compared for semantic + %% equivalence". The only arg we care about is + %% "alternate-exchange". + Ae1 = alternate_exchange_value(RequiredArgs), + Ae2 = alternate_exchange_value(Args), + if Ae1==Ae2 -> ok; + true -> rabbit_misc:protocol_error( + precondition_failed, + "cannot redeclare ~s with inequivalent args", + [rabbit_misc:rs(Name)]) + end. lookup(Name) -> rabbit_misc:dirty_read({rabbit_exchange, Name}). diff --git a/src/rabbit_exchange_type.erl b/src/rabbit_exchange_type.erl index 699250f7..85760edc 100644 --- a/src/rabbit_exchange_type.erl +++ b/src/rabbit_exchange_type.erl @@ -54,7 +54,11 @@ behaviour_info(callbacks) -> {add_binding, 2}, %% called after bindings have been deleted. - {remove_bindings, 2} + {remove_bindings, 2}, + + %% called when comparing exchanges for equivalence - should return ok or + %% exit with #amqp_error{} + {assert_args_equivalence, 2} ]; behaviour_info(_Other) -> diff --git a/src/rabbit_exchange_type_direct.erl b/src/rabbit_exchange_type_direct.erl index c3fb2588..4f6eb851 100644 --- a/src/rabbit_exchange_type_direct.erl +++ b/src/rabbit_exchange_type_direct.erl @@ -36,7 +36,7 @@ -export([description/0, publish/2]). -export([validate/1, create/1, recover/2, delete/2, - add_binding/2, remove_bindings/2]). + add_binding/2, remove_bindings/2, assert_args_equivalence/2]). -include("rabbit_exchange_type_spec.hrl"). -rabbit_boot_step({?MODULE, @@ -61,3 +61,5 @@ recover(_X, _Bs) -> ok. delete(_X, _Bs) -> ok. add_binding(_X, _B) -> ok. remove_bindings(_X, _Bs) -> ok. +assert_args_equivalence(X, Args) -> + rabbit_exchange:assert_args_equivalence(X, Args). diff --git a/src/rabbit_exchange_type_fanout.erl b/src/rabbit_exchange_type_fanout.erl index 62c862a5..4f9712b1 100644 --- a/src/rabbit_exchange_type_fanout.erl +++ b/src/rabbit_exchange_type_fanout.erl @@ -36,7 +36,7 @@ -export([description/0, publish/2]). -export([validate/1, create/1, recover/2, delete/2, - add_binding/2, remove_bindings/2]). + add_binding/2, remove_bindings/2, assert_args_equivalence/2]). -include("rabbit_exchange_type_spec.hrl"). -rabbit_boot_step({?MODULE, @@ -59,3 +59,5 @@ recover(_X, _Bs) -> ok. delete(_X, _Bs) -> ok. add_binding(_X, _B) -> ok. remove_bindings(_X, _Bs) -> ok. +assert_args_equivalence(X, Args) -> + rabbit_exchange:assert_args_equivalence(X, Args). diff --git a/src/rabbit_exchange_type_headers.erl b/src/rabbit_exchange_type_headers.erl index 0991bf0d..315e8000 100644 --- a/src/rabbit_exchange_type_headers.erl +++ b/src/rabbit_exchange_type_headers.erl @@ -37,7 +37,7 @@ -export([description/0, publish/2]). -export([validate/1, create/1, recover/2, delete/2, - add_binding/2, remove_bindings/2]). + add_binding/2, remove_bindings/2, assert_args_equivalence/2]). -include("rabbit_exchange_type_spec.hrl"). -rabbit_boot_step({?MODULE, @@ -135,3 +135,5 @@ recover(_X, _Bs) -> ok. delete(_X, _Bs) -> ok. add_binding(_X, _B) -> ok. remove_bindings(_X, _Bs) -> ok. +assert_args_equivalence(X, Args) -> + rabbit_exchange:assert_args_equivalence(X, Args). diff --git a/src/rabbit_exchange_type_topic.erl b/src/rabbit_exchange_type_topic.erl index e42c4518..0e22d545 100644 --- a/src/rabbit_exchange_type_topic.erl +++ b/src/rabbit_exchange_type_topic.erl @@ -36,7 +36,7 @@ -export([description/0, publish/2]). -export([validate/1, create/1, recover/2, delete/2, - add_binding/2, remove_bindings/2]). + add_binding/2, remove_bindings/2, assert_args_equivalence/2]). -include("rabbit_exchange_type_spec.hrl"). -rabbit_boot_step({?MODULE, @@ -99,3 +99,5 @@ recover(_X, _Bs) -> ok. delete(_X, _Bs) -> ok. add_binding(_X, _B) -> ok. remove_bindings(_X, _Bs) -> ok. +assert_args_equivalence(X, Args) -> + rabbit_exchange:assert_args_equivalence(X, Args). |