summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Radestock <matthias@rabbitmq.com>2012-10-24 13:29:15 +0100
committerMatthias Radestock <matthias@rabbitmq.com>2012-10-24 13:29:15 +0100
commit6238c6e5d046f27898b4a1a16ea8ad54bec20e29 (patch)
tree213b1399ca1d48a318229a5f002004182cd74790
parent0fa431b83108b046869f4c534ed42b4911e85af8 (diff)
downloadrabbitmq-server-6238c6e5d046f27898b4a1a16ea8ad54bec20e29.tar.gz
better error messages for 'absent' queues in binding commands
- change binding:call_with_source_and_destination/3 to replace {error, source_not_found | destination_not_found | source_and_destination_not_found} with {error, {resources_missing, [{not_found, #resource{}} | {absent, Q}]}}. - the change ripples through rabbit_channel:binding_action, which can now produce nice not_founds. - We now only report one of the errors when there is something wrong with both source and destination. I reckon this is acceptable; we could do better but it would involve a fair bit of extra code.
-rw-r--r--src/rabbit_amqqueue.erl28
-rw-r--r--src/rabbit_binding.erl29
-rw-r--r--src/rabbit_channel.erl12
3 files changed, 45 insertions, 24 deletions
diff --git a/src/rabbit_amqqueue.erl b/src/rabbit_amqqueue.erl
index 0a544713..db1f5654 100644
--- a/src/rabbit_amqqueue.erl
+++ b/src/rabbit_amqqueue.erl
@@ -18,7 +18,7 @@
-export([start/0, stop/0, declare/5, delete_immediately/1, delete/3, purge/1]).
-export([pseudo_queue/2]).
--export([lookup/1, with/2, with_or_die/2, assert_equivalence/5,
+-export([lookup/1, lookup_absent/1, with/2, with_or_die/2, assert_equivalence/5,
check_exclusive_access/2, with_exclusive_access_or_die/3,
stat/1, deliver/2, deliver_flow/2, requeue/3, ack/3, reject/4]).
-export([list/0, list/1, info_keys/0, info/1, info/2, info_all/1, info_all/2]).
@@ -81,6 +81,9 @@
(name()) -> rabbit_types:ok(rabbit_types:amqqueue()) |
rabbit_types:error('not_found');
([name()]) -> [rabbit_types:amqqueue()]).
+-spec(lookup_absent/1 ::
+ (name()) -> rabbit_types:ok(rabbit_types:amqqueue()) |
+ rabbit_types:error('not_found')).
-spec(with/2 :: (name(), qfun(A)) ->
A | rabbit_types:error(
'not_found' | {'absent', rabbit_types:amqqueue()})).
@@ -236,13 +239,14 @@ internal_declare(Q = #amqqueue{name = QueueName}, false) ->
fun () ->
case mnesia:wread({rabbit_queue, QueueName}) of
[] ->
- case mnesia:read({rabbit_durable_queue, QueueName}) of
- [] -> Q1 = rabbit_policy:set(Q),
- ok = store_queue(Q1),
- B = add_default_binding(Q1),
- fun () -> B(), Q1 end;
- %% Q exists on stopped node
- [Q1] -> rabbit_misc:const({absent, Q1})
+ case lookup_absent(QueueName) of
+ {error, not_found} ->
+ Q1 = rabbit_policy:set(Q),
+ ok = store_queue(Q1),
+ B = add_default_binding(Q1),
+ fun () -> B(), Q1 end;
+ {ok, Q1} ->
+ rabbit_misc:const({absent, Q1})
end;
[ExistingQ = #amqqueue{pid = QPid}] ->
case rabbit_misc:is_process_alive(QPid) of
@@ -296,6 +300,14 @@ lookup(Names) when is_list(Names) ->
lookup(Name) ->
rabbit_misc:dirty_read({rabbit_queue, Name}).
+lookup_absent(Name) ->
+ %% NB: we assume that the caller has already performed a lookup on
+ %% rabbit_queue and not found anything
+ case mnesia:read({rabbit_durable_queue, Name}) of
+ [] -> {error, not_found};
+ [Q] -> {ok, Q} %% Q exists on stopped node
+ end.
+
with(Name, F, E) ->
case lookup(Name) of
{ok, Q = #amqqueue{pid = QPid}} ->
diff --git a/src/rabbit_binding.erl b/src/rabbit_binding.erl
index 0d23f716..1375facb 100644
--- a/src/rabbit_binding.erl
+++ b/src/rabbit_binding.erl
@@ -35,9 +35,11 @@
-type(key() :: binary()).
--type(bind_errors() :: rabbit_types:error('source_not_found' |
- 'destination_not_found' |
- 'source_and_destination_not_found')).
+-type(bind_errors() :: rabbit_types:error(
+ {'resources_missing',
+ [{'not_found', (rabbit_types:binding_source() |
+ rabbit_types:binding_destination())} |
+ {'absent', rabbit_types:amqqueue()}]})).
-type(bind_ok_or_error() :: 'ok' | bind_errors() |
rabbit_types:error('binding_not_found')).
-type(bind_res() :: bind_ok_or_error() | rabbit_misc:thunk(bind_ok_or_error())).
@@ -330,21 +332,32 @@ sync_transient_route(Route, Fun) ->
call_with_source_and_destination(SrcName, DstName, Fun) ->
SrcTable = table_for_resource(SrcName),
DstTable = table_for_resource(DstName),
- ErrFun = fun (Err) -> rabbit_misc:const({error, Err}) end,
+ ErrFun = fun (Names) ->
+ Errs = [not_found_or_absent(Name) || Name <- Names],
+ rabbit_misc:const({error, {resources_missing, Errs}})
+ end,
rabbit_misc:execute_mnesia_tx_with_tail(
fun () ->
case {mnesia:read({SrcTable, SrcName}),
mnesia:read({DstTable, DstName})} of
{[Src], [Dst]} -> Fun(Src, Dst);
- {[], [_] } -> ErrFun(source_not_found);
- {[_], [] } -> ErrFun(destination_not_found);
- {[], [] } -> ErrFun(source_and_destination_not_found)
- end
+ {[], [_] } -> ErrFun([SrcName]);
+ {[_], [] } -> ErrFun([DstName]);
+ {[], [] } -> ErrFun([SrcName, DstName])
+ end
end).
table_for_resource(#resource{kind = exchange}) -> rabbit_exchange;
table_for_resource(#resource{kind = queue}) -> rabbit_queue.
+not_found_or_absent(#resource{kind = exchange} = Name) ->
+ {not_found, Name};
+not_found_or_absent(#resource{kind = queue} = Name) ->
+ case rabbit_amqqueue:lookup_absent(Name) of
+ {error, not_found} -> {not_found, Name};
+ {ok, Q} -> {absent, Q}
+ end.
+
contains(Table, MatchHead) ->
continue(mnesia:select(Table, [{MatchHead, [], ['$_']}], 1, read)).
diff --git a/src/rabbit_channel.erl b/src/rabbit_channel.erl
index 91abcf1e..153193bf 100644
--- a/src/rabbit_channel.erl
+++ b/src/rabbit_channel.erl
@@ -1178,14 +1178,10 @@ binding_action(Fun, ExchangeNameBin, DestinationType, DestinationNameBin,
(_X, #exchange{}) ->
ok
end) of
- {error, source_not_found} ->
- rabbit_misc:not_found(ExchangeName);
- {error, destination_not_found} ->
- rabbit_misc:not_found(DestinationName);
- {error, source_and_destination_not_found} ->
- rabbit_misc:protocol_error(
- not_found, "no ~s and no ~s", [rabbit_misc:rs(ExchangeName),
- rabbit_misc:rs(DestinationName)]);
+ {error, {resources_missing, [{not_found, Name} | _]}} ->
+ rabbit_misc:not_found(Name);
+ {error, {resources_missing, [{absent, Q} | _]}} ->
+ rabbit_misc:absent(Q);
{error, binding_not_found} ->
rabbit_misc:protocol_error(
not_found, "no binding ~s between ~s and ~s",