summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon MacMullen <simon@rabbitmq.com>2013-08-15 17:33:18 +0100
committerSimon MacMullen <simon@rabbitmq.com>2013-08-15 17:33:18 +0100
commiteb18c78fcfcff9622a43e8823dee83f8348ca3c0 (patch)
tree9377b8f7578887712bb4f8e22491c8b07ca186d9
parent0f52df179315cad77348ac6a541cd747991abaf6 (diff)
downloadrabbitmq-server-bug25716.tar.gz
Make delete and unbind idempotent.bug25716
-rw-r--r--src/rabbit_binding.erl41
-rw-r--r--src/rabbit_channel.erl14
2 files changed, 35 insertions, 20 deletions
diff --git a/src/rabbit_binding.erl b/src/rabbit_binding.erl
index 91f42e9c..98b427c7 100644
--- a/src/rabbit_binding.erl
+++ b/src/rabbit_binding.erl
@@ -152,7 +152,7 @@ exists(Binding) ->
binding_action(
Binding, fun (_Src, _Dst, B) ->
rabbit_misc:const(mnesia:read({rabbit_route, B}) /= [])
- end).
+ end, fun not_found_or_absent_errs/1).
add(Binding) -> add(Binding, fun (_Src, _Dst) -> ok end).
@@ -177,7 +177,7 @@ add(Binding, InnerFun) ->
{error, _} = Err ->
rabbit_misc:const(Err)
end
- end).
+ end, fun not_found_or_absent_errs/1).
add(Src, Dst, B) ->
[SrcDurable, DstDurable] = [durable(E) || E <- [Src, Dst]],
@@ -200,14 +200,15 @@ remove(Binding, InnerFun) ->
binding_action(
Binding,
fun (Src, Dst, B) ->
- case mnesia:read(rabbit_route, B, write) of
- [] -> rabbit_misc:const({error, binding_not_found});
- [_] -> case InnerFun(Src, Dst) of
- ok -> remove(Src, Dst, B);
- {error, _} = Err -> rabbit_misc:const(Err)
- end
+ case mnesia:read(rabbit_route, B, write) =:= [] andalso
+ mnesia:read(rabbit_durable_route, B, write) =/= [] of
+ true -> rabbit_misc:const({error, binding_not_found});
+ false -> case InnerFun(Src, Dst) of
+ ok -> remove(Src, Dst, B);
+ {error, _} = Err -> rabbit_misc:const(Err)
+ end
end
- end).
+ end, fun absent_errs_only/1).
remove(Src, Dst, B) ->
ok = sync_route(#route{binding = B}, durable(Src), durable(Dst),
@@ -306,13 +307,13 @@ durable(#amqqueue{durable = D}) -> D.
binding_action(Binding = #binding{source = SrcName,
destination = DstName,
- args = Arguments}, Fun) ->
+ args = Arguments}, Fun, ErrFun) ->
call_with_source_and_destination(
SrcName, DstName,
fun (Src, Dst) ->
SortedArgs = rabbit_misc:sort_field_table(Arguments),
Fun(Src, Dst, Binding#binding{args = SortedArgs})
- end).
+ end, ErrFun).
delete_object(Tab, Record, LockKind) ->
%% this 'guarded' delete prevents unnecessary writes to the mnesia
@@ -339,13 +340,9 @@ sync_transient_route(Route, Fun) ->
ok = Fun(rabbit_route, Route, write),
ok = Fun(rabbit_reverse_route, reverse_route(Route), write).
-call_with_source_and_destination(SrcName, DstName, Fun) ->
+call_with_source_and_destination(SrcName, DstName, Fun, ErrFun) ->
SrcTable = table_for_resource(SrcName),
DstTable = table_for_resource(DstName),
- 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}),
@@ -357,6 +354,18 @@ call_with_source_and_destination(SrcName, DstName, Fun) ->
end
end).
+not_found_or_absent_errs(Names) ->
+ Errs = [not_found_or_absent(Name) || Name <- Names],
+ rabbit_misc:const({error, {resources_missing, Errs}}).
+
+absent_errs_only(Names) ->
+ Errs = [E || Name <- Names,
+ {absent, _Q} = E <- [not_found_or_absent(Name)]],
+ rabbit_misc:const(case Errs of
+ [] -> ok;
+ _ -> {error, {resources_missing, Errs}}
+ end).
+
table_for_resource(#resource{kind = exchange}) -> rabbit_exchange;
table_for_resource(#resource{kind = queue}) -> rabbit_queue.
diff --git a/src/rabbit_channel.erl b/src/rabbit_channel.erl
index d6c1e8c0..2cfbd96d 100644
--- a/src/rabbit_channel.erl
+++ b/src/rabbit_channel.erl
@@ -934,7 +934,7 @@ handle_method(#'exchange.delete'{exchange = ExchangeNameBin,
check_configure_permitted(ExchangeName, State),
case rabbit_exchange:delete(ExchangeName, IfUnused) of
{error, not_found} ->
- rabbit_misc:not_found(ExchangeName);
+ return_ok(State, NoWait, #'exchange.delete_ok'{});
{error, in_use} ->
precondition_failed("~s in use", [rabbit_misc:rs(ExchangeName)]);
ok ->
@@ -1047,9 +1047,15 @@ handle_method(#'queue.delete'{queue = QueueNameBin,
_, State = #ch{conn_pid = ConnPid}) ->
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
check_configure_permitted(QueueName, State),
- case rabbit_amqqueue:with_exclusive_access_or_die(
- QueueName, ConnPid,
- fun (Q) -> rabbit_amqqueue:delete(Q, IfUnused, IfEmpty) end) of
+ case rabbit_amqqueue:with(
+ QueueName,
+ fun (Q) ->
+ rabbit_amqqueue:check_exclusive_access(Q, ConnPid),
+ rabbit_amqqueue:delete(Q, IfUnused, IfEmpty)
+ end,
+ fun (not_found) -> {ok, 0};
+ ({absent, Q}) -> rabbit_misc:absent(Q)
+ end) of
{error, in_use} ->
precondition_failed("~s in use", [rabbit_misc:rs(QueueName)]);
{error, not_empty} ->