diff options
author | Matthias Radestock <matthias@rabbitmq.com> | 2012-10-24 09:37:04 +0100 |
---|---|---|
committer | Matthias Radestock <matthias@rabbitmq.com> | 2012-10-24 09:37:04 +0100 |
commit | 0fa431b83108b046869f4c534ed42b4911e85af8 (patch) | |
tree | 0bc1826477ff0fa96d39895e6e8ebde73aea57c4 | |
parent | 7a5c2bba14e02c1801ed30e16a5cce889b24d9c7 (diff) | |
download | rabbitmq-server-0fa431b83108b046869f4c534ed42b4911e85af8.tar.gz |
better error messages for 'absent' queues in various commands
- move channel:absent/1 to misc, since we need it in multiple modules
- change amqqueue:with/3 s.t. the error fun is invoked with
not_found|{'absent', Q}.
- let this change ripple through to with/2, making it return either
error. This in turn has just two call sites
- in 'queue.declare' in the channel, which we expand to handle the
'absent' case (producing a descriptive not_found error, as per
above)
- in mq_misc:if_mirrored_queue, whose callers currently do not
handle errors at all - see bug 25236
- let the change also ripple through to with_or_die, handling the new
'absent' case as above. This takes care of passive queue.declare.
- with_or_die is called by with_exclusive_access_or_die. This takes
care of basic.get, basic.consume, queue.delete and queue.purge
-rw-r--r-- | src/rabbit_amqqueue.erl | 39 | ||||
-rw-r--r-- | src/rabbit_channel.erl | 15 | ||||
-rw-r--r-- | src/rabbit_misc.erl | 12 |
3 files changed, 41 insertions, 25 deletions
diff --git a/src/rabbit_amqqueue.erl b/src/rabbit_amqqueue.erl index 8ab9bc87..0a544713 100644 --- a/src/rabbit_amqqueue.erl +++ b/src/rabbit_amqqueue.erl @@ -81,7 +81,9 @@ (name()) -> rabbit_types:ok(rabbit_types:amqqueue()) | rabbit_types:error('not_found'); ([name()]) -> [rabbit_types:amqqueue()]). --spec(with/2 :: (name(), qfun(A)) -> A | rabbit_types:error('not_found')). +-spec(with/2 :: (name(), qfun(A)) -> + A | rabbit_types:error( + 'not_found' | {'absent', rabbit_types:amqqueue()})). -spec(with_or_die/2 :: (name(), qfun(A)) -> A | rabbit_types:channel_exit()). -spec(assert_equivalence/5 :: @@ -300,22 +302,33 @@ with(Name, F, E) -> %% We check is_process_alive(QPid) in case we receive a %% nodedown (for example) in F() that has nothing to do %% with the QPid. - E1 = fun () -> - case rabbit_misc:is_process_alive(QPid) of - true -> E(); - false -> timer:sleep(25), - with(Name, F, E) - end - end, - rabbit_misc:with_exit_handler(E1, fun () -> F(Q) end); + rabbit_misc:with_exit_handler( + fun () -> + case rabbit_misc:is_process_alive(QPid) of + true -> E(not_found_or_absent(Name)); + false -> timer:sleep(25), + with(Name, F, E) + end + end, fun () -> F(Q) end); {error, not_found} -> - E() + E(not_found_or_absent(Name)) end. -with(Name, F) -> - with(Name, F, fun () -> {error, not_found} end). +not_found_or_absent(Name) -> + %% We should read from both tables inside a tx, to get a + %% consistent view. But the chances of an inconsistency are small, + %% and only affect the error kind. + case rabbit_misc:dirty_read({rabbit_durable_queue, Name}) of + {error, not_found} -> not_found; + {ok, Q} -> {absent, Q} + end. + +with(Name, F) -> with(Name, F, fun (E) -> {error, E} end). + with_or_die(Name, F) -> - with(Name, F, fun () -> rabbit_misc:not_found(Name) end). + with(Name, F, fun (not_found) -> rabbit_misc:not_found(Name); + ({absent, Q}) -> rabbit_misc:absent(Q) + end). assert_equivalence(#amqqueue{durable = Durable, auto_delete = AutoDelete} = Q, diff --git a/src/rabbit_channel.erl b/src/rabbit_channel.erl index 276ad38f..91abcf1e 100644 --- a/src/rabbit_channel.erl +++ b/src/rabbit_channel.erl @@ -423,15 +423,6 @@ precondition_failed(Format) -> precondition_failed(Format, []). precondition_failed(Format, Params) -> rabbit_misc:protocol_error(precondition_failed, Format, Params). -absent(#amqqueue{name = QueueName, pid = QPid, durable = true}) -> - %% The assertion of durability is mainly there because we mention - %% durability in the error message. That way we will hopefully - %% notice if at some future point our logic changes s.t. we get - %% here with non-durable queues. - rabbit_misc:protocol_error( - not_found, "home node '~s' of durable ~s is down or inaccessible", - [node(QPid), rabbit_misc:rs(QueueName)]). - return_queue_declare_ok(#resource{name = ActualName}, NoWait, MessageCount, ConsumerCount, State) -> return_ok(State#ch{most_recently_declared_queue = ActualName}, NoWait, @@ -971,8 +962,10 @@ handle_method(#'queue.declare'{queue = QueueNameBin, %% declare. Loop around again. handle_method(Declare, none, State); {absent, Q} -> - absent(Q) - end + rabbit_misc:absent(Q) + end; + {error, {absent, Q}} -> + rabbit_misc:absent(Q) end; handle_method(#'queue.declare'{queue = QueueNameBin, diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl index ab9a9ceb..78f25175 100644 --- a/src/rabbit_misc.erl +++ b/src/rabbit_misc.erl @@ -21,7 +21,7 @@ -export([method_record_type/1, polite_pause/0, polite_pause/1]). -export([die/1, frame_error/2, amqp_error/4, quit/1, protocol_error/3, protocol_error/4, protocol_error/1]). --export([not_found/1, assert_args_equivalence/4]). +-export([not_found/1, absent/1, assert_args_equivalence/4]). -export([dirty_read/1]). -export([table_lookup/2, set_table_value/4]). -export([r/3, r/2, r_arg/4, rs/1]). @@ -111,6 +111,7 @@ -spec(protocol_error/1 :: (rabbit_types:amqp_error()) -> channel_or_connection_exit()). -spec(not_found/1 :: (rabbit_types:r(atom())) -> rabbit_types:channel_exit()). +-spec(absent/1 :: (rabbit_types:amqqueue()) -> rabbit_types:channel_exit()). -spec(assert_args_equivalence/4 :: (rabbit_framing:amqp_table(), rabbit_framing:amqp_table(), rabbit_types:r(any()), [binary()]) -> @@ -266,6 +267,15 @@ protocol_error(#amqp_error{} = Error) -> not_found(R) -> protocol_error(not_found, "no ~s", [rs(R)]). +absent(#amqqueue{name = QueueName, pid = QPid, durable = true}) -> + %% The assertion of durability is mainly there because we mention + %% durability in the error message. That way we will hopefully + %% notice if at some future point our logic changes s.t. we get + %% here with non-durable queues. + protocol_error(not_found, + "home node '~s' of durable ~s is down or inaccessible", + [node(QPid), rs(QueueName)]). + type_class(byte) -> int; type_class(short) -> int; type_class(signedint) -> int; |