summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Sackman <matthew@lshift.net>2009-05-27 13:33:24 +0100
committerMatthew Sackman <matthew@lshift.net>2009-05-27 13:33:24 +0100
commit6246085d1566ef701379006b2ed5ce1b45b4f434 (patch)
tree2937eade747010bfa7ebddc174edc83686544ff1
parent07a45e744d24384e3b2a1667d4b98650e83f671d (diff)
parent3120cdcb7b8f903c7236c636578ddabeb50068fd (diff)
downloadrabbitmq-server-git-6246085d1566ef701379006b2ed5ce1b45b4f434.tar.gz
just merging in default branch
-rw-r--r--Makefile7
-rw-r--r--docs/rabbitmqctl.1.pod2
-rw-r--r--packaging/RPMS/Fedora/init.d2
-rw-r--r--packaging/RPMS/Fedora/rabbitmq-server.spec34
-rw-r--r--packaging/debs/Debian/debian/changelog6
-rw-r--r--packaging/windows/rabbitmq-service.pod6
-rwxr-xr-xscripts/rabbitmq-multi.bat4
-rwxr-xr-xscripts/rabbitmq-server2
-rwxr-xr-xscripts/rabbitmq-server.bat1
-rw-r--r--src/priority_queue.erl2
-rw-r--r--src/rabbit.erl12
-rw-r--r--src/rabbit_amqqueue.erl29
-rw-r--r--src/rabbit_channel.erl13
-rw-r--r--src/rabbit_control.erl13
-rw-r--r--src/rabbit_exchange.erl63
-rw-r--r--src/rabbit_misc.erl22
-rw-r--r--src/rabbit_mnesia.erl13
-rw-r--r--src/rabbit_multi.erl11
-rw-r--r--src/rabbit_persister.erl2
-rw-r--r--src/rabbit_tests.erl6
20 files changed, 166 insertions, 84 deletions
diff --git a/Makefile b/Makefile
index b7464244c2..68fc57a53d 100644
--- a/Makefile
+++ b/Makefile
@@ -94,11 +94,10 @@ run-node: all
run-tests: all
echo "rabbit_tests:all_tests()." | $(ERL_CALL)
-start-background-node: stop-node
+start-background-node:
$(BASIC_SCRIPT_ENVIRONMENT_SETTINGS) \
RABBITMQ_NODE_ONLY=true \
- RABBITMQ_SERVER_START_ARGS="$(RABBITMQ_SERVER_START_ARGS) -detached" \
- ./scripts/rabbitmq-server ; sleep 1
+ ./scripts/rabbitmq-server -detached; sleep 1
start-rabbit-on-node: all
echo "rabbit:start()." | $(ERL_CALL)
@@ -130,7 +129,7 @@ srcdist: distclean
cp README.in $(TARGET_SRC_DIR)/README
elinks -dump -no-references -no-numbering $(WEB_URL)build-server.html \
>> $(TARGET_SRC_DIR)/BUILD
- sed -i 's/%%VERSION%%/$(VERSION)/' $(TARGET_SRC_DIR)/ebin/rabbit_app.in
+ sed -i.save 's/%%VERSION%%/$(VERSION)/' $(TARGET_SRC_DIR)/ebin/rabbit_app.in && rm -f $(TARGET_SRC_DIR)/ebin/rabbit_app.in.save
cp -r $(AMQP_CODEGEN_DIR)/* $(TARGET_SRC_DIR)/codegen/
cp codegen.py Makefile generate_app $(TARGET_SRC_DIR)
diff --git a/docs/rabbitmqctl.1.pod b/docs/rabbitmqctl.1.pod
index a0232a40f2..421568960e 100644
--- a/docs/rabbitmqctl.1.pod
+++ b/docs/rabbitmqctl.1.pod
@@ -201,7 +201,7 @@ name
URL-encoded name of the exchange
type
- exchange type (B<direct>, B<topic> or B<fanout>)
+ exchange type (B<direct>, B<topic>, B<fanout>, or B<headers>)
durable
whether the exchange survives server restarts
diff --git a/packaging/RPMS/Fedora/init.d b/packaging/RPMS/Fedora/init.d
index a9155f3b03..77a6a89af1 100644
--- a/packaging/RPMS/Fedora/init.d
+++ b/packaging/RPMS/Fedora/init.d
@@ -8,6 +8,8 @@
### BEGIN INIT INFO
# Provides: rabbitmq-server
+# Default-Start:
+# Default-Stop:
# Required-Start: $remote_fs $network
# Required-Stop: $remote_fs $network
# Description: RabbitMQ broker
diff --git a/packaging/RPMS/Fedora/rabbitmq-server.spec b/packaging/RPMS/Fedora/rabbitmq-server.spec
index 9a67a3410d..bed1611ab8 100644
--- a/packaging/RPMS/Fedora/rabbitmq-server.spec
+++ b/packaging/RPMS/Fedora/rabbitmq-server.spec
@@ -28,20 +28,17 @@ scalable implementation of an AMQP broker.
%define _maindir %{buildroot}%{_rabbit_erllibdir}
-%pre
-if [ $1 -gt 1 ]; then
- #Upgrade - stop and remove previous instance of rabbitmq-server init.d script
- /sbin/service rabbitmq-server stop
- /sbin/chkconfig --del rabbitmq-server
-fi
-
%prep
%setup -q
%build
cp %{S:2} %{_rabbit_wrapper}
-sed 's|/usr/lib/|%{_libdir}/|' %{_rabbit_wrapper}
-make %{?_smp_mflags}
+sed -i 's|/usr/lib/|%{_libdir}/|' %{_rabbit_wrapper}
+
+# The rabbitmq build needs escript, which is missing from /usr/bin in
+# some versions of the erlang RPM. See
+# <https://bugzilla.redhat.com/show_bug.cgi?id=481302>
+PATH=%{_libdir}/erlang/bin:$PATH make %{?_smp_mflags}
%install
rm -rf %{buildroot}
@@ -73,7 +70,14 @@ echo '%defattr(-,root,root, -)' >> %{_builddir}/filelist.%{name}.rpm
! -regex '\.\(%{_rabbit_erllibdir}\|%{_rabbit_libdir}\).*' \
| sed -e 's/^\.//' >> %{_builddir}/filelist.%{name}.rpm)
-%post
+%pre
+
+if [ $1 -gt 1 ]; then
+ #Upgrade - stop and remove previous instance of rabbitmq-server init.d script
+ /sbin/service rabbitmq-server stop
+ /sbin/chkconfig --del rabbitmq-server
+fi
+
# create rabbitmq group
if ! getent group rabbitmq >/dev/null; then
groupadd -r rabbitmq
@@ -81,10 +85,11 @@ fi
# create rabbitmq user
if ! getent passwd rabbitmq >/dev/null; then
- useradd -r -g rabbitmq -d %{_localstatedir}/lib/rabbitmq rabbitmq \
- -c "RabbitMQ messaging server" rabbitmq
+ useradd -r -g rabbitmq -d %{_localstatedir}/lib/rabbitmq rabbitmq \
+ -c "RabbitMQ messaging server"
fi
+%post
/sbin/chkconfig --add %{name}
%preun
@@ -106,12 +111,15 @@ fi
%{_rabbit_libdir}
%{_initrddir}/rabbitmq-server
%config(noreplace) %{_sysconfdir}/logrotate.d/rabbitmq-server
-%doc LICENSE LICENSE-MPL-RabbitMQ INSTALL
+%doc LICENSE LICENSE-MPL-RabbitMQ
%clean
rm -rf %{buildroot}
%changelog
+* Mon Apr 6 2009 Matthias Radestock <matthias@lshift.net> 1.5.4-1
+- Maintenance release for the 1.5.x series
+
* Tue Feb 24 2009 Tony Garnock-Jones <tonyg@lshift.net> 1.5.3-1
- Maintenance release for the 1.5.x series
diff --git a/packaging/debs/Debian/debian/changelog b/packaging/debs/Debian/debian/changelog
index 3be25f4836..d1ccd3a0c2 100644
--- a/packaging/debs/Debian/debian/changelog
+++ b/packaging/debs/Debian/debian/changelog
@@ -1,3 +1,9 @@
+rabbitmq-server (1.5.4-1) hardy; urgency=low
+
+ * New Upstream Release
+
+ -- Matthias Radestock <matthias@lshift.net> Mon, 06 Apr 2009 09:19:32 +0100
+
rabbitmq-server (1.5.3-1) hardy; urgency=low
* New Upstream Release
diff --git a/packaging/windows/rabbitmq-service.pod b/packaging/windows/rabbitmq-service.pod
index 7c4d3ef210..8a2d2e5b22 100644
--- a/packaging/windows/rabbitmq-service.pod
+++ b/packaging/windows/rabbitmq-service.pod
@@ -92,8 +92,10 @@ Defaults to 5672.
=head2 ERLANG_SERVICE_MANAGER_PATH
-Defaults to F<C:\Program Files\erl5.5.5\erts-5.5.5\bin>. This is
-the installation location of the Erlang service manager.
+Defaults to F<C:\Program Files\erl5.5.5\erts-5.5.5\bin>
+(or F<C:\Program Files (x86)\erl5.5.5\erts-5.5.5\bin> for 64-bit
+environments). This is the installation location of the Erlang service
+manager.
=head2 CLUSTER_CONFIG_FILE
diff --git a/scripts/rabbitmq-multi.bat b/scripts/rabbitmq-multi.bat
index 30f33a5a26..a30c0889ab 100755
--- a/scripts/rabbitmq-multi.bat
+++ b/scripts/rabbitmq-multi.bat
@@ -47,7 +47,7 @@ if "%RABBITMQ_NODE_PORT%"=="" (
)
set RABBITMQ_PIDS_FILE=%RABBITMQ_BASE%\rabbitmq.pids
-set RABBITMQ_SCRIPT_HOME=%~dp0%
+set RABBITMQ_SCRIPT_HOME=%~sdp0%
if "%ERLANG_HOME%"=="" (
set ERLANG_HOME=%~dp0%..\..\..
@@ -65,5 +65,5 @@ if not exist "%ERLANG_HOME%\bin\erl.exe" (
exit /B
)
-"%ERLANG_HOME%\bin\erl.exe" -pa "%~dp0..\ebin" -noinput -hidden -sname rabbitmq_multi -s rabbit_multi %START_ARGS% -extra %*
+"%ERLANG_HOME%\bin\erl.exe" -pa "%~dp0..\ebin" -noinput -hidden %RABBITMQ_MULTI_ERL_ARGS% -sname rabbitmq_multi -s rabbit_multi %RABBITMQ_MULTI_START_ARGS% -extra %*
diff --git a/scripts/rabbitmq-server b/scripts/rabbitmq-server
index d5be944a27..8502d60abc 100755
--- a/scripts/rabbitmq-server
+++ b/scripts/rabbitmq-server
@@ -36,7 +36,7 @@ NODE_PORT=5672
SERVER_ERL_ARGS="+K true +A30 \
-kernel inet_default_listen_options [{nodelay,true},{sndbuf,16384},{recbuf,4096}] \
-kernel inet_default_connect_options [{nodelay,true}]"
-CLUSTER_CONFIG_FILE=/etc/rabbitmq/cluster.config
+CLUSTER_CONFIG_FILE=/etc/rabbitmq/rabbitmq_cluster.config
LOG_BASE=/var/log/rabbitmq
MNESIA_BASE=/var/lib/rabbitmq/mnesia
SERVER_START_ARGS=
diff --git a/scripts/rabbitmq-server.bat b/scripts/rabbitmq-server.bat
index 5b20ef2010..9915727bd9 100755
--- a/scripts/rabbitmq-server.bat
+++ b/scripts/rabbitmq-server.bat
@@ -117,6 +117,7 @@ if "%RABBITMQ_MNESIA_DIR%"=="" (
-kernel inet_default_connect_options "[{nodelay, true}]" ^
-rabbit tcp_listeners "[{\"%RABBITMQ_NODE_IP_ADDRESS%\", %RABBITMQ_NODE_PORT%}]" ^
-kernel error_logger {file,\""%RABBITMQ_LOG_BASE%/%RABBITMQ_NODENAME%.log"\"} ^
+%RABBITMQ_SERVER_ERL_ARGS% ^
-sasl errlog_type error ^
-sasl sasl_error_logger {file,\""%RABBITMQ_LOG_BASE%/%RABBITMQ_NODENAME%-sasl.log"\"} ^
-os_mon start_cpu_sup true ^
diff --git a/src/priority_queue.erl b/src/priority_queue.erl
index 88ad0c182d..732757c41c 100644
--- a/src/priority_queue.erl
+++ b/src/priority_queue.erl
@@ -111,7 +111,7 @@ in(X, 0, {queue, [_] = In, []}) ->
{queue, [X], In};
in(X, 0, {queue, In, Out}) when is_list(In), is_list(Out) ->
{queue, [X|In], Out};
-in(X, Priority, Q = {queue, [], []}) ->
+in(X, Priority, _Q = {queue, [], []}) ->
in(X, Priority, {pqueue, []});
in(X, Priority, Q = {queue, _, _}) ->
in(X, Priority, {pqueue, [{0, Q}]});
diff --git a/src/rabbit.erl b/src/rabbit.erl
index 3a15e6b07c..c0d09547c5 100644
--- a/src/rabbit.erl
+++ b/src/rabbit.erl
@@ -216,10 +216,14 @@ print_banner() ->
[Product, Version,
?PROTOCOL_VERSION_MAJOR, ?PROTOCOL_VERSION_MINOR,
?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE]),
- io:format("Logging to ~p~nSASL logging to ~p~n~n",
- [log_location(kernel), log_location(sasl)]).
-
-
+ Settings = [{"node", node()},
+ {"log", log_location(kernel)},
+ {"sasl log", log_location(sasl)},
+ {"database dir", rabbit_mnesia:dir()}],
+ DescrLen = lists:max([length(K) || {K, _V} <- Settings]),
+ Format = "~-" ++ integer_to_list(DescrLen) ++ "s: ~s~n",
+ lists:foreach(fun ({K, V}) -> io:format(Format, [K, V]) end, Settings),
+ io:nl().
start_child(Mod) ->
{ok,_} = supervisor:start_child(rabbit_sup,
diff --git a/src/rabbit_amqqueue.erl b/src/rabbit_amqqueue.erl
index 06bb18f5d3..0316788fe1 100644
--- a/src/rabbit_amqqueue.erl
+++ b/src/rabbit_amqqueue.erl
@@ -201,9 +201,7 @@ with(Name, F, E) ->
with(Name, F) ->
with(Name, F, fun () -> {error, not_found} end).
with_or_die(Name, F) ->
- with(Name, F, fun () -> rabbit_misc:protocol_error(
- not_found, "no ~s", [rabbit_misc:rs(Name)])
- end).
+ with(Name, F, fun () -> rabbit_misc:not_found(Name) end).
list(VHostPath) ->
mnesia:dirty_match_object(
@@ -305,28 +303,29 @@ internal_delete(QueueName) ->
rabbit_misc:execute_mnesia_transaction(
fun () ->
case mnesia:wread({rabbit_queue, QueueName}) of
- [] -> {error, not_found};
- [Q] ->
- ok = delete_queue(Q),
+ [] -> {error, not_found};
+ [_] ->
+ ok = rabbit_exchange:delete_queue_bindings(QueueName),
+ ok = mnesia:delete({rabbit_queue, QueueName}),
ok = mnesia:delete({rabbit_durable_queue, QueueName}),
ok
end
end).
-delete_queue(#amqqueue{name = QueueName}) ->
- ok = rabbit_exchange:delete_bindings_for_queue(QueueName),
- ok = mnesia:delete({rabbit_queue, QueueName}),
- ok.
-
on_node_down(Node) ->
rabbit_misc:execute_mnesia_transaction(
fun () ->
qlc:fold(
- fun (Q, Acc) -> ok = delete_queue(Q), Acc end,
+ fun (QueueName, Acc) ->
+ ok = rabbit_exchange:delete_transient_queue_bindings(
+ QueueName),
+ ok = mnesia:delete({rabbit_queue, QueueName}),
+ Acc
+ end,
ok,
- qlc:q([Q || Q = #amqqueue{pid = Pid}
- <- mnesia:table(rabbit_queue),
- node(Pid) == Node]))
+ qlc:q([QueueName || #amqqueue{name = QueueName, pid = Pid}
+ <- mnesia:table(rabbit_queue),
+ node(Pid) == Node]))
end).
pseudo_queue(QueueName, Pid) ->
diff --git a/src/rabbit_channel.erl b/src/rabbit_channel.erl
index aeb15bd1b9..d14a01bee9 100644
--- a/src/rabbit_channel.erl
+++ b/src/rabbit_channel.erl
@@ -576,8 +576,7 @@ handle_method(#'exchange.delete'{exchange = ExchangeNameBin,
check_configure_permitted(ExchangeName, State),
case rabbit_exchange:delete(ExchangeName, IfUnused) of
{error, not_found} ->
- rabbit_misc:protocol_error(
- not_found, "no ~s", [rabbit_misc:rs(ExchangeName)]);
+ rabbit_misc:not_found(ExchangeName);
{error, in_use} ->
die_precondition_failed(
"~s in use", [rabbit_misc:rs(ExchangeName)]);
@@ -742,12 +741,14 @@ binding_action(Fun, ExchangeNameBin, QueueNameBin, RoutingKey, Arguments,
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
check_read_permitted(ExchangeName, State),
case Fun(ExchangeName, QueueName, ActualRoutingKey, Arguments) of
- {error, queue_not_found} ->
- rabbit_misc:protocol_error(
- not_found, "no ~s", [rabbit_misc:rs(QueueName)]);
{error, exchange_not_found} ->
+ rabbit_misc:not_found(ExchangeName);
+ {error, queue_not_found} ->
+ rabbit_misc:not_found(QueueName);
+ {error, exchange_and_queue_not_found} ->
rabbit_misc:protocol_error(
- not_found, "no ~s", [rabbit_misc:rs(ExchangeName)]);
+ not_found, "no ~s and no ~s", [rabbit_misc:rs(ExchangeName),
+ rabbit_misc:rs(QueueName)]);
{error, binding_not_found} ->
rabbit_misc:protocol_error(
not_found, "no binding ~s between ~s and ~s",
diff --git a/src/rabbit_control.erl b/src/rabbit_control.erl
index e6717d689f..6649899ade 100644
--- a/src/rabbit_control.erl
+++ b/src/rabbit_control.erl
@@ -38,6 +38,19 @@
-define(RPC_TIMEOUT, 30000).
+%%----------------------------------------------------------------------------
+
+-ifdef(use_specs).
+
+-spec(start/0 :: () -> no_return()).
+-spec(stop/0 :: () -> 'ok').
+-spec(action/4 :: (atom(), erlang_node(), [string()],
+ fun ((string(), [any()]) -> 'ok')) -> 'ok').
+
+-endif.
+
+%%----------------------------------------------------------------------------
+
start() ->
FullCommand = init:get_plain_arguments(),
#params{quiet = Quiet, node = Node, command = Command, args = Args} =
diff --git a/src/rabbit_exchange.erl b/src/rabbit_exchange.erl
index 9b3bbb1851..e0f76d895c 100644
--- a/src/rabbit_exchange.erl
+++ b/src/rabbit_exchange.erl
@@ -40,7 +40,7 @@
route/3]).
-export([add_binding/4, delete_binding/4, list_bindings/1]).
-export([delete/2]).
--export([delete_bindings_for_queue/1]).
+-export([delete_queue_bindings/1, delete_transient_queue_bindings/1]).
-export([check_type/1, assert_type/2, topic_matches/2, headers_match/2]).
%% EXTENDED API
@@ -59,8 +59,10 @@
-type(publish_res() :: {'ok', [pid()]} |
not_found() | {'error', 'unroutable' | 'not_delivered'}).
--type(bind_res() :: 'ok' |
- {'error', 'queue_not_found' | 'exchange_not_found'}).
+-type(bind_res() :: 'ok' | {'error',
+ 'queue_not_found' |
+ 'exchange_not_found' |
+ 'exchange_and_queue_not_found'}).
-spec(recover/0 :: () -> 'ok').
-spec(declare/5 :: (exchange_name(), exchange_type(), bool(), bool(),
amqp_table()) -> exchange()).
@@ -86,7 +88,8 @@
bind_res() | {'error', 'binding_not_found'}).
-spec(list_bindings/1 :: (vhost()) ->
[{exchange_name(), queue_name(), routing_key(), amqp_table()}]).
--spec(delete_bindings_for_queue/1 :: (queue_name()) -> 'ok').
+-spec(delete_queue_bindings/1 :: (queue_name()) -> 'ok').
+-spec(delete_transient_queue_bindings/1 :: (queue_name()) -> 'ok').
-spec(topic_matches/2 :: (binary(), binary()) -> bool()).
-spec(headers_match/2 :: (amqp_table(), amqp_table()) -> bool()).
-spec(delete/2 :: (exchange_name(), bool()) ->
@@ -161,9 +164,7 @@ lookup(Name) ->
lookup_or_die(Name) ->
case lookup(Name) of
{ok, X} -> X;
- {error, not_found} ->
- rabbit_misc:protocol_error(
- not_found, "no ~s", [rabbit_misc:rs(Name)])
+ {error, not_found} -> rabbit_misc:not_found(Name)
end.
list(VHostPath) ->
@@ -295,7 +296,7 @@ lookup_qpids(Queues) ->
%% refactored to its own module, especially seeing as unbind will have
%% to be implemented for 0.91 ?
-delete_bindings_for_exchange(ExchangeName) ->
+delete_exchange_bindings(ExchangeName) ->
[begin
ok = mnesia:delete_object(rabbit_reverse_route,
reverse_route(Route), write),
@@ -307,10 +308,16 @@ delete_bindings_for_exchange(ExchangeName) ->
write)],
ok.
-delete_bindings_for_queue(QueueName) ->
+delete_queue_bindings(QueueName) ->
+ delete_queue_bindings(QueueName, fun delete_forward_routes/1).
+
+delete_transient_queue_bindings(QueueName) ->
+ delete_queue_bindings(QueueName, fun delete_transient_forward_routes/1).
+
+delete_queue_bindings(QueueName, FwdDeleteFun) ->
Exchanges = exchanges_for_queue(QueueName),
[begin
- ok = delete_forward_routes(reverse_route(Route)),
+ ok = FwdDeleteFun(reverse_route(Route)),
ok = mnesia:delete_object(rabbit_reverse_route, Route, write)
end || Route <- mnesia:match_object(
rabbit_reverse_route,
@@ -328,6 +335,9 @@ delete_forward_routes(Route) ->
ok = mnesia:delete_object(rabbit_route, Route, write),
ok = mnesia:delete_object(rabbit_durable_route, Route, write).
+delete_transient_forward_routes(Route) ->
+ ok = mnesia:delete_object(rabbit_route, Route, write).
+
exchanges_for_queue(QueueName) ->
MatchHead = reverse_route(
#route{binding = #binding{exchange_name = '$1',
@@ -337,16 +347,13 @@ exchanges_for_queue(QueueName) ->
sets:from_list(
mnesia:select(rabbit_reverse_route, [{MatchHead, [], ['$1']}]))).
-has_bindings(ExchangeName) ->
- MatchHead = #route{binding = #binding{exchange_name = ExchangeName,
- _ = '_'}},
+contains(Table, MatchHead) ->
try
- continue(mnesia:select(rabbit_route, [{MatchHead, [], ['$_']}],
- 1, read))
+ continue(mnesia:select(Table, [{MatchHead, [], ['$_']}], 1, read))
catch exit:{aborted, {badarg, _}} ->
%% work around OTP-7025, which was fixed in R12B-1, by
%% falling back on a less efficient method
- case mnesia:match_object(rabbit_route, MatchHead, read) of
+ case mnesia:match_object(Table, MatchHead, read) of
[] -> false;
[_|_] -> true
end
@@ -359,18 +366,20 @@ continue({[], Continuation}) -> continue(mnesia:select(Continuation)).
call_with_exchange(Exchange, Fun) ->
rabbit_misc:execute_mnesia_transaction(
fun() -> case mnesia:read({rabbit_exchange, Exchange}) of
- [] -> {error, exchange_not_found};
+ [] -> {error, not_found};
[X] -> Fun(X)
end
end).
call_with_exchange_and_queue(Exchange, Queue, Fun) ->
- call_with_exchange(
- Exchange,
- fun(X) -> case mnesia:read({rabbit_queue, Queue}) of
- [] -> {error, queue_not_found};
- [Q] -> Fun(X, Q)
- end
+ rabbit_misc:execute_mnesia_transaction(
+ fun() -> case {mnesia:read({rabbit_exchange, Exchange}),
+ mnesia:read({rabbit_queue, Queue})} of
+ {[X], [Q]} -> Fun(X, Q);
+ {[ ], [_]} -> {error, exchange_not_found};
+ {[_], [ ]} -> {error, queue_not_found};
+ {[ ], [ ]} -> {error, exchange_and_queue_not_found}
+ end
end).
add_binding(ExchangeName, QueueName, RoutingKey, Arguments) ->
@@ -554,13 +563,17 @@ maybe_auto_delete(Exchange = #exchange{auto_delete = true}) ->
ok.
conditional_delete(Exchange = #exchange{name = ExchangeName}) ->
- case has_bindings(ExchangeName) of
+ Match = #route{binding = #binding{exchange_name = ExchangeName, _ = '_'}},
+ %% we need to check for durable routes here too in case a bunch of
+ %% routes to durable queues have been removed temporarily as a
+ %% result of a node failure
+ case contains(rabbit_route, Match) orelse contains(rabbit_durable_route, Match) of
false -> unconditional_delete(Exchange);
true -> {error, in_use}
end.
unconditional_delete(#exchange{name = ExchangeName}) ->
- ok = delete_bindings_for_exchange(ExchangeName),
+ ok = delete_exchange_bindings(ExchangeName),
ok = mnesia:delete({rabbit_durable_exchange, ExchangeName}),
ok = mnesia:delete({rabbit_exchange, ExchangeName}).
diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl
index 2f329aa91c..49faba293b 100644
--- a/src/rabbit_misc.erl
+++ b/src/rabbit_misc.erl
@@ -36,6 +36,7 @@
-export([method_record_type/1, polite_pause/0, polite_pause/1]).
-export([die/1, frame_error/2, protocol_error/3, protocol_error/4]).
+-export([not_found/1]).
-export([get_config/1, get_config/2, set_config/2]).
-export([dirty_read/1]).
-export([r/3, r/2, rs/1]).
@@ -73,6 +74,7 @@
(atom() | amqp_error(), string(), [any()]) -> no_return()).
-spec(protocol_error/4 ::
(atom() | amqp_error(), string(), [any()], atom()) -> no_return()).
+-spec(not_found/1 :: (r(atom())) -> no_return()).
-spec(get_config/1 :: (atom()) -> {'ok', any()} | not_found()).
-spec(get_config/2 :: (atom(), A) -> A).
-spec(set_config/2 :: (atom(), any()) -> 'ok').
@@ -107,7 +109,7 @@
-spec(dirty_dump_log/1 :: (string()) -> 'ok' | {'error', any()}).
-spec(append_file/2 :: (string(), string()) -> 'ok' | {'error', any()}).
-spec(ensure_parent_dirs_exist/1 :: (string()) -> 'ok').
--spec(format_stderr/2 :: (string(), [any()]) -> 'true').
+-spec(format_stderr/2 :: (string(), [any()]) -> 'ok').
-spec(start_applications/1 :: ([atom()]) -> 'ok').
-spec(stop_applications/1 :: ([atom()]) -> 'ok').
-spec(unfold/2 :: (fun ((A) -> ({'true', B, A} | 'false')), A) -> [B]).
@@ -141,6 +143,8 @@ protocol_error(Error, Explanation, Params, Method) ->
CompleteExplanation = lists:flatten(io_lib:format(Explanation, Params)),
exit({amqp, Error, CompleteExplanation, Method}).
+not_found(R) -> protocol_error(not_found, "no ~s", [rs(R)]).
+
get_config(Key) ->
case dirty_read({rabbit_config, Key}) of
{ok, {rabbit_config, Key, V}} -> {ok, V};
@@ -377,9 +381,19 @@ ensure_parent_dirs_exist(Filename) ->
end.
format_stderr(Fmt, Args) ->
- Port = open_port({fd, 0, 2}, [out]),
- port_command(Port, io_lib:format(Fmt, Args)),
- port_close(Port).
+ case os:type() of
+ {unix, _} ->
+ Port = open_port({fd, 0, 2}, [out]),
+ port_command(Port, io_lib:format(Fmt, Args)),
+ port_close(Port);
+ {win32, _} ->
+ %% stderr on Windows is buffered and I can't figure out a
+ %% way to trigger a fflush(stderr) in Erlang. So rather
+ %% than risk losing output we write to stdout instead,
+ %% which appears to be unbuffered.
+ io:format(Fmt, Args)
+ end,
+ ok.
manage_applications(Iterate, Do, Undo, SkipError, ErrorTag, Apps) ->
Iterate(fun (App, Acc) ->
diff --git a/src/rabbit_mnesia.erl b/src/rabbit_mnesia.erl
index d2b2b15c8a..cddcab643e 100644
--- a/src/rabbit_mnesia.erl
+++ b/src/rabbit_mnesia.erl
@@ -31,7 +31,7 @@
-module(rabbit_mnesia).
--export([ensure_mnesia_dir/0, status/0, init/0, is_db_empty/0,
+-export([ensure_mnesia_dir/0, dir/0, status/0, init/0, is_db_empty/0,
cluster/1, reset/0, force_reset/0]).
-export([table_names/0]).
@@ -47,6 +47,7 @@
-ifdef(use_specs).
-spec(status/0 :: () -> [{'nodes' | 'running_nodes', [erlang_node()]}]).
+-spec(dir/0 :: () -> string()).
-spec(ensure_mnesia_dir/0 :: () -> 'ok').
-spec(init/0 :: () -> 'ok').
-spec(is_db_empty/0 :: () -> bool()).
@@ -155,8 +156,10 @@ table_definitions() ->
table_names() ->
[Tab || {Tab, _} <- table_definitions()].
+dir() -> mnesia:system_info(directory).
+
ensure_mnesia_dir() ->
- MnesiaDir = mnesia:system_info(directory) ++ "/",
+ MnesiaDir = dir() ++ "/",
case filelib:ensure_dir(MnesiaDir) of
{error, Reason} ->
throw({error, {cannot_create_mnesia_dir, MnesiaDir, Reason}});
@@ -192,7 +195,7 @@ check_schema_integrity() ->
%% it doesn't.
cluster_nodes_config_filename() ->
- mnesia:system_info(directory) ++ "/cluster_nodes.config".
+ dir() ++ "/cluster_nodes.config".
create_cluster_nodes_config(ClusterNodes) ->
FileName = cluster_nodes_config_filename(),
@@ -308,7 +311,7 @@ create_schema() ->
move_db() ->
mnesia:stop(),
- MnesiaDir = filename:dirname(mnesia:system_info(directory) ++ "/"),
+ MnesiaDir = filename:dirname(dir() ++ "/"),
{{Year, Month, Day}, {Hour, Minute, Second}} = erlang:universaltime(),
BackupDir = lists:flatten(
io_lib:format("~s_~w~2..0w~2..0w~2..0w~2..0w~2..0w",
@@ -425,7 +428,7 @@ reset(Force) ->
ok = delete_cluster_nodes_config(),
%% remove persistet messages and any other garbage we find
lists:foreach(fun file:delete/1,
- filelib:wildcard(mnesia:system_info(directory) ++ "/*")),
+ filelib:wildcard(dir() ++ "/*")),
ok.
leave_cluster([], _) -> ok;
diff --git a/src/rabbit_multi.erl b/src/rabbit_multi.erl
index 5e8edd53a1..d91975359a 100644
--- a/src/rabbit_multi.erl
+++ b/src/rabbit_multi.erl
@@ -36,6 +36,17 @@
-define(RPC_SLEEP, 500).
+%%----------------------------------------------------------------------------
+
+-ifdef(use_specs).
+
+-spec(start/0 :: () -> no_return()).
+-spec(stop/0 :: () -> 'ok').
+
+-endif.
+
+%%----------------------------------------------------------------------------
+
start() ->
RpcTimeout =
case init:get_argument(maxwait) of
diff --git a/src/rabbit_persister.erl b/src/rabbit_persister.erl
index f4fa45993a..d0d60ddf3d 100644
--- a/src/rabbit_persister.erl
+++ b/src/rabbit_persister.erl
@@ -259,7 +259,7 @@ log(State = #pstate{deadline = ExistingDeadline, pending_logs = Logs},
pending_logs = [Message | Logs]}.
base_filename() ->
- mnesia:system_info(directory) ++ "/rabbit_persister.LOG".
+ rabbit_mnesia:dir() ++ "/rabbit_persister.LOG".
take_snapshot(LogHandle, OldFileName, Snapshot) ->
ok = disk_log:sync(LogHandle),
diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl
index 552e4ed959..597b0a76e6 100644
--- a/src/rabbit_tests.erl
+++ b/src/rabbit_tests.erl
@@ -490,7 +490,13 @@ test_cluster_management2(SecondaryNode) ->
ok = control_action(stop_app, []),
{error, {no_running_cluster_nodes, _, _}} =
control_action(reset, []),
+
+ %% leave system clustered, with the secondary node as a ram node
ok = control_action(force_reset, []),
+ ok = control_action(start_app, []),
+ ok = control_action(force_reset, SecondaryNode, []),
+ ok = control_action(cluster, SecondaryNode, [NodeS]),
+ ok = control_action(start_app, SecondaryNode, []),
passed.