summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--codegen.py27
-rw-r--r--ebin/rabbit_app.in1
-rw-r--r--generate_app6
-rw-r--r--packaging/common/rabbitmq-asroot-script-wrapper18
-rw-r--r--packaging/common/rabbitmq-script-wrapper6
-rw-r--r--packaging/macports/net/rabbitmq-server/Portfile27
-rw-r--r--packaging/macports/net/rabbitmq-server/files/rabbitmq-script-wrapper4
-rwxr-xr-xscripts/rabbitmq-server1
-rwxr-xr-xscripts/rabbitmq-server.bat1
-rwxr-xr-xscripts/rabbitmq-service.bat28
-rw-r--r--src/gen_server2.erl14
-rw-r--r--src/rabbit.erl22
-rw-r--r--src/rabbit_binary_generator.erl95
-rw-r--r--src/rabbit_binary_parser.erl65
-rw-r--r--src/rabbit_mnesia.erl20
-rw-r--r--src/rabbit_plugin_activator.erl11
-rw-r--r--src/rabbit_tests.erl53
18 files changed, 274 insertions, 127 deletions
diff --git a/Makefile b/Makefile
index 8f877916a1..6330f86fb7 100644
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@ ERL_EBIN=erl -noinput -pa $(EBIN_DIR)
all: $(TARGETS)
$(EBIN_DIR)/rabbit.app: $(EBIN_DIR)/rabbit_app.in $(BEAM_TARGETS) generate_app
- escript generate_app $(EBIN_DIR) < $< > $@
+ escript generate_app $(EBIN_DIR) $@ < $<
$(EBIN_DIR)/gen_server2.beam: $(SOURCE_DIR)/gen_server2.erl
erlc $(ERLC_OPTS) $<
diff --git a/codegen.py b/codegen.py
index a21dd779d5..52c45a958c 100644
--- a/codegen.py
+++ b/codegen.py
@@ -228,12 +228,12 @@ def genErl(spec):
print " rabbit_binary_generator:encode_properties(%s, %s);" % \
(fieldTypeList(c.fields), fieldTempList(c.fields))
- def massageConstantClass(cls):
+ def messageConstantClass(cls):
# We do this because 0.8 uses "soft error" and 8.1 uses "soft-error".
return erlangConstantName(cls)
def genLookupException(c,v,cls):
- mCls = massageConstantClass(cls)
+ mCls = messageConstantClass(cls)
if mCls == 'SOFT_ERROR': genLookupException1(c,'false')
elif mCls == 'HARD_ERROR': genLookupException1(c, 'true')
elif mCls == '': pass
@@ -244,6 +244,20 @@ def genErl(spec):
print 'lookup_amqp_exception(%s) -> {%s, ?%s, <<"%s">>};' % \
(n.lower(), hardErrorBoolStr, n, n)
+ def genIsAmqpHardErrorCode(c,v,cls):
+ mCls = messageConstantClass(cls)
+ if mCls == 'SOFT_ERROR' : genIsAmqpHardErrorCode1(c,'false')
+ elif mCls == 'HARD_ERROR' : genIsAmqpHardErrorCode1(c,'true')
+ elif mCls == '' : pass
+ else: raise 'Unkown constant class', cls
+
+ def genIsAmqpHardErrorCode1(c,hardErrorBoolStr):
+ n = erlangConstantName(c)
+ print 'is_amqp_hard_error_code(?%s) -> %s;' % \
+ (n, hardErrorBoolStr)
+ print 'is_amqp_hard_error_code(%s) -> %s;' % \
+ (n.lower(), hardErrorBoolStr)
+
methods = spec.allMethods()
print """-module(rabbit_framing).
@@ -260,6 +274,7 @@ def genErl(spec):
-export([encode_method_fields/1]).
-export([encode_properties/1]).
-export([lookup_amqp_exception/1]).
+-export([is_amqp_hard_error_code/1]).
bitvalue(true) -> 1;
bitvalue(false) -> 0;
@@ -296,8 +311,14 @@ bitvalue(undefined) -> 0.
for (c,v,cls) in spec.constants: genLookupException(c,v,cls)
print "lookup_amqp_exception(Code) ->"
print " rabbit_log:warning(\"Unknown AMQP error code '~p'~n\", [Code]),"
- print " {true, ?INTERNAL_ERROR, <<\"INTERNAL_ERROR\">>}."
+ print " {true, ?INTERNAL_ERROR, <<\"INTERNAL_ERROR\">>}."
+ for(c,v,cls) in spec.constants: genIsAmqpHardErrorCode(c,v,cls)
+ print "is_amqp_hard_error_code(Code) when is_integer(Code) ->"
+ print " true;"
+ print "is_amqp_hard_error_code(Code) ->"
+ print " rabbit_log:warning(\"Unknown AMQP error code '~p'~n\", [Code]),"
+ print " true."
def genHrl(spec):
def erlType(domain):
diff --git a/ebin/rabbit_app.in b/ebin/rabbit_app.in
index 39f98cbe56..3616fcbf6c 100644
--- a/ebin/rabbit_app.in
+++ b/ebin/rabbit_app.in
@@ -17,6 +17,7 @@
{env, [{tcp_listeners, [{"0.0.0.0", 5672}]},
{ssl_listeners, []},
{ssl_options, []},
+ {vm_memory_high_watermark, 0.4},
{default_user, <<"guest">>},
{default_pass, <<"guest">>},
{default_vhost, <<"/">>},
diff --git a/generate_app b/generate_app
index 623012927e..576b485e1e 100644
--- a/generate_app
+++ b/generate_app
@@ -1,10 +1,12 @@
#!/usr/bin/env escript
%% -*- erlang -*-
-main([BeamDir]) ->
+main([BeamDir, TargetFile]) ->
Modules = [list_to_atom(filename:basename(F, ".beam")) ||
F <- filelib:wildcard("*.beam", BeamDir)],
{ok, {application, Application, Properties}} = io:read(''),
NewProperties = lists:keyreplace(modules, 1, Properties,
{modules, Modules}),
- io:format("~p.", [{application, Application, NewProperties}]).
+ file:write_file(
+ TargetFile,
+ io_lib:format("~p.~n", [{application, Application, NewProperties}])).
diff --git a/packaging/common/rabbitmq-asroot-script-wrapper b/packaging/common/rabbitmq-asroot-script-wrapper
index 9ef59ad76b..ee5947b66c 100644
--- a/packaging/common/rabbitmq-asroot-script-wrapper
+++ b/packaging/common/rabbitmq-asroot-script-wrapper
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
## The contents of this file are subject to the Mozilla Public License
## Version 1.1 (the "License"); you may not use this file except in
## compliance with the License. You may obtain a copy of the License at
@@ -30,24 +30,16 @@
## Contributor(s): ______________________________________.
##
-# Escape spaces and quotes, because shell is revolting.
-for arg in "$@" ; do
- # Escape quotes in parameters, so that they're passed through cleanly.
- arg=$(sed -e 's/"/\\"/g' <<-END
- $arg
- END
- )
- CMDLINE="${CMDLINE} \"${arg}\""
-done
-
cd /var/lib/rabbitmq
SCRIPT=`basename $0`
if [ `id -u` = 0 ] ; then
- /usr/lib/rabbitmq/bin/${SCRIPT} ${CMDLINE}
+ /usr/lib/rabbitmq/bin/${SCRIPT} "$@"
else
- echo -e "\nOnly root should run ${SCRIPT}\n"
+ echo
+ echo "Only root should run ${SCRIPT}"
+ echo
exit 1
fi
diff --git a/packaging/common/rabbitmq-script-wrapper b/packaging/common/rabbitmq-script-wrapper
index 0c4bd0a8d7..dfb714f16e 100644
--- a/packaging/common/rabbitmq-script-wrapper
+++ b/packaging/common/rabbitmq-script-wrapper
@@ -46,9 +46,13 @@ SCRIPT=`basename $0`
if [ `id -u` = 0 ] ; then
su rabbitmq -s /bin/sh -c "/usr/lib/rabbitmq/bin/${SCRIPT} ${CMDLINE}"
+elif [ `id -u` = `id -u rabbitmq` ] ; then
+ /usr/lib/rabbitmq/bin/${SCRIPT} "$@"
else
/usr/lib/rabbitmq/bin/${SCRIPT}
- echo -e "\nOnly root should run ${SCRIPT}\n"
+ echo
+ echo "Only root or rabbitmq should run ${SCRIPT}"
+ echo
exit 1
fi
diff --git a/packaging/macports/net/rabbitmq-server/Portfile b/packaging/macports/net/rabbitmq-server/Portfile
index 6b51fb2f9b..739f99d0e7 100644
--- a/packaging/macports/net/rabbitmq-server/Portfile
+++ b/packaging/macports/net/rabbitmq-server/Portfile
@@ -3,7 +3,7 @@
PortSystem 1.0
name rabbitmq-server
-version 1.6.0
+version 1.7.0
revision 0
categories net
maintainers tonyg@rabbitmq.com
@@ -19,13 +19,28 @@ homepage http://www.rabbitmq.com/
master_sites http://www.rabbitmq.com/releases/rabbitmq-server/v${version}/
checksums \
- md5 af3b0d868d58e5aefb4f0837b82ca010 \
- sha1 1834c670d076fa9878223aacaa35a5a6528f1d86 \
- rmd160 d6c9de4e1fb48c6ceb1cb5d717ca2afb5e3266fe
+ md5 4505ca0fd8718439bd6f5e2af2379e56 \
+ sha1 84fb86d403057bb808c1b51deee0c1fca3bf7bef \
+ rmd160 092f90946825cc3eb277019805e24db637a559f4
-depends_build port:erlang port:py25-simplejson
+depends_build port:erlang
depends_run port:erlang
+platform darwin 7 {
+ depends_build-append port:py25-simplejson
+ build.args PYTHON=${prefix}/bin/python2.5
+}
+platform darwin 8 {
+ depends_build-append port:py25-simplejson
+ build.args PYTHON=${prefix}/bin/python2.5
+}
+platform darwin 9 {
+ depends_build-append port:py25-simplejson
+ build.args PYTHON=${prefix}/bin/python2.5
+}
+# no need for simplejson on Snow Leopard or higher
+
+
set serveruser rabbitmq
set servergroup rabbitmq
set serverhome ${prefix}/var/lib/rabbitmq
@@ -40,8 +55,6 @@ use_configure no
use_parallel_build yes
-build.args PYTHON=${prefix}/bin/python2.5
-
destroot.destdir \
TARGET_DIR=${destroot}${prefix}/lib/rabbitmq/lib/rabbitmq_server-${version} \
SBIN_DIR=${sbindir} \
diff --git a/packaging/macports/net/rabbitmq-server/files/rabbitmq-script-wrapper b/packaging/macports/net/rabbitmq-server/files/rabbitmq-script-wrapper
index 0d7118c476..80cb7bd53c 100644
--- a/packaging/macports/net/rabbitmq-server/files/rabbitmq-script-wrapper
+++ b/packaging/macports/net/rabbitmq-server/files/rabbitmq-script-wrapper
@@ -5,9 +5,11 @@ SCRIPT=`basename $0`
if [ `id -u` = 0 ] ; then
sudo -u rabbitmq -H /usr/lib/rabbitmq/bin/${SCRIPT} "$@"
+elif [ `id -u` = `id -u rabbitmq` ] ; then
+ /usr/lib/rabbitmq/bin/${SCRIPT} "$@"
else
/usr/lib/rabbitmq/bin/${SCRIPT}
- echo -e "\nOnly root should run ${SCRIPT}\n"
+ echo -e "\nOnly root or rabbitmq should run ${SCRIPT}\n"
exit 1
fi
diff --git a/scripts/rabbitmq-server b/scripts/rabbitmq-server
index 34904850be..310afe9426 100755
--- a/scripts/rabbitmq-server
+++ b/scripts/rabbitmq-server
@@ -109,7 +109,6 @@ exec erl \
-os_mon start_cpu_sup true \
-os_mon start_disksup false \
-os_mon start_memsup false \
- -os_mon vm_memory_high_watermark 0.4 \
-mnesia dir "\"${RABBITMQ_MNESIA_DIR}\"" \
${RABBITMQ_CLUSTER_CONFIG_OPTION} \
${RABBITMQ_SERVER_START_ARGS} \
diff --git a/scripts/rabbitmq-server.bat b/scripts/rabbitmq-server.bat
index 5b82ec1562..211fc78190 100755
--- a/scripts/rabbitmq-server.bat
+++ b/scripts/rabbitmq-server.bat
@@ -140,7 +140,6 @@ if exist "%RABBITMQ_CONFIG_FILE%.config" (
-os_mon start_cpu_sup true ^
-os_mon start_disksup false ^
-os_mon start_memsup false ^
--os_mon vm_memory_high_watermark 0.4 ^
-mnesia dir \""%RABBITMQ_MNESIA_DIR%"\" ^
%CLUSTER_CONFIG% ^
%RABBITMQ_SERVER_START_ARGS% ^
diff --git a/scripts/rabbitmq-service.bat b/scripts/rabbitmq-service.bat
index 0cc7bfa915..d80df9677f 100755
--- a/scripts/rabbitmq-service.bat
+++ b/scripts/rabbitmq-service.bat
@@ -158,11 +158,31 @@ if errorlevel 1 (
echo %RABBITMQ_SERVICENAME% service is already present - only updating service parameters
)
-set RABBIT_EBIN=%~dp0..\ebin
+set RABBITMQ_EBIN_ROOT=%~dp0..\ebin
+if exist "%RABBITMQ_EBIN_ROOT%\rabbit.boot" (
+ echo Using Custom Boot File "%RABBITMQ_EBIN_ROOT%\rabbit.boot"
+ set RABBITMQ_BOOT_FILE=%RABBITMQ_EBIN_ROOT%\rabbit
+ set RABBITMQ_EBIN_PATH=
+) else (
+ set RABBITMQ_BOOT_FILE=start_sasl
+ set RABBITMQ_EBIN_PATH=-pa "%RABBITMQ_EBIN_ROOT%"
+)
+if "%RABBITMQ_CONFIG_FILE%"=="" (
+ set RABBITMQ_CONFIG_FILE=%RABBITMQ_BASE%\rabbitmq
+)
+
+if exist "%RABBITMQ_CONFIG_FILE%.config" (
+ set RABBITMQ_CONFIG_ARG=-config "%RABBITMQ_CONFIG_FILE%"
+) else (
+ set RABBITMQ_CONFIG_ARG=
+)
+
+
set ERLANG_SERVICE_ARGUMENTS= ^
--pa "%RABBIT_EBIN%" ^
--boot start_sasl ^
+%RABBITMQ_EBIN_PATH% ^
+-boot "%RABBITMQ_BOOT_FILE%" ^
+%RABBITMQ_CONFIG_ARG% ^
-s rabbit ^
+W w ^
+A30 ^
@@ -170,12 +190,12 @@ set ERLANG_SERVICE_ARGUMENTS= ^
-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 ^
-os_mon start_disksup false ^
-os_mon start_memsup false ^
--os_mon vm_memory_high_watermark 0.4 ^
-mnesia dir \""%RABBITMQ_MNESIA_DIR%"\" ^
%CLUSTER_CONFIG% ^
%RABBITMQ_SERVER_START_ARGS% ^
diff --git a/src/gen_server2.erl b/src/gen_server2.erl
index a2d9350c4e..53edf8deef 100644
--- a/src/gen_server2.erl
+++ b/src/gen_server2.erl
@@ -180,6 +180,20 @@
-import(error_logger, [format/2]).
%%%=========================================================================
+%%% Specs. These exist only to shut up dialyzer's warnings
+%%%=========================================================================
+
+-ifdef(use_specs).
+
+-spec(handle_common_termination/6 ::
+ (any(), any(), any(), atom(), any(), any()) -> no_return()).
+
+-spec(hibernate/7 ::
+ (pid(), any(), any(), atom(), any(), queue(), any()) -> no_return()).
+
+-endif.
+
+%%%=========================================================================
%%% API
%%%=========================================================================
diff --git a/src/rabbit.erl b/src/rabbit.erl
index 3906f2f76d..b9eede5fc1 100644
--- a/src/rabbit.erl
+++ b/src/rabbit.erl
@@ -141,16 +141,16 @@ start(normal, []) ->
check_empty_content_body_frame_size(),
ok = rabbit_alarm:start(),
- MemoryWatermark =
- application:get_env(os_mon, vm_memory_high_watermark),
- ok = case MemoryWatermark of
- {ok, Float} when Float == 0 -> ok;
- {ok, Float} -> start_child(vm_memory_monitor, [Float]);
- undefined ->
- throw({undefined, os_mon,
- vm_memory_high_watermark, settings})
+
+ {ok, MemoryWatermark} =
+ application:get_env(vm_memory_high_watermark),
+ ok = case MemoryWatermark == 0 of
+ true ->
+ ok;
+ false ->
+ start_child(vm_memory_monitor, [MemoryWatermark])
end,
-
+
ok = rabbit_amqqueue:start(),
ok = start_child(rabbit_router),
@@ -210,6 +210,10 @@ start(normal, []) ->
stop(_State) ->
terminated_ok = error_logger:delete_report_handler(rabbit_error_logger),
ok = rabbit_alarm:stop(),
+ ok = case rabbit_mnesia:is_clustered() of
+ true -> rabbit_amqqueue:on_node_down(node());
+ false -> rabbit_mnesia:empty_ram_only_tables()
+ end,
ok.
%---------------------------------------------------------------------------
diff --git a/src/rabbit_binary_generator.erl b/src/rabbit_binary_generator.erl
index 6cfa9e6d17..01ac4f027f 100644
--- a/src/rabbit_binary_generator.erl
+++ b/src/rabbit_binary_generator.erl
@@ -132,52 +132,66 @@ create_frame(TypeInt, ChannelInt, Payload) ->
%% I, D, T and F, as well as the QPid extensions b, d, f, l, s, t, x,
%% and V.
-table_field_to_binary({FName, longstr, Value}) ->
- [short_string_to_binary(FName), "S", long_string_to_binary(Value)];
+table_field_to_binary({FName, Type, Value}) ->
+ [short_string_to_binary(FName) | field_value_to_binary(Type, Value)].
-table_field_to_binary({FName, signedint, Value}) ->
- [short_string_to_binary(FName), "I", <<Value:32/signed>>];
+field_value_to_binary(longstr, Value) ->
+ ["S", long_string_to_binary(Value)];
-table_field_to_binary({FName, decimal, {Before, After}}) ->
- [short_string_to_binary(FName), "D", Before, <<After:32>>];
+field_value_to_binary(signedint, Value) ->
+ ["I", <<Value:32/signed>>];
-table_field_to_binary({FName, timestamp, Value}) ->
- [short_string_to_binary(FName), "T", <<Value:64>>];
+field_value_to_binary(decimal, {Before, After}) ->
+ ["D", Before, <<After:32>>];
-table_field_to_binary({FName, table, Value}) ->
- [short_string_to_binary(FName), "F", table_to_binary(Value)];
+field_value_to_binary(timestamp, Value) ->
+ ["T", <<Value:64>>];
-table_field_to_binary({FName, byte, Value}) ->
- [short_string_to_binary(FName), "b", <<Value:8/unsigned>>];
+field_value_to_binary(table, Value) ->
+ ["F", table_to_binary(Value)];
-table_field_to_binary({FName, double, Value}) ->
- [short_string_to_binary(FName), "d", <<Value:64/float>>];
+field_value_to_binary(array, Value) ->
+ ["A", array_to_binary(Value)];
-table_field_to_binary({FName, float, Value}) ->
- [short_string_to_binary(FName), "f", <<Value:32/float>>];
+field_value_to_binary(byte, Value) ->
+ ["b", <<Value:8/unsigned>>];
-table_field_to_binary({FName, long, Value}) ->
- [short_string_to_binary(FName), "l", <<Value:64/signed>>];
+field_value_to_binary(double, Value) ->
+ ["d", <<Value:64/float>>];
-table_field_to_binary({FName, short, Value}) ->
- [short_string_to_binary(FName), "s", <<Value:16/signed>>];
+field_value_to_binary(float, Value) ->
+ ["f", <<Value:32/float>>];
-table_field_to_binary({FName, bool, Value}) ->
- [short_string_to_binary(FName), "t", if Value -> 1; true -> 0 end];
+field_value_to_binary(long, Value) ->
+ ["l", <<Value:64/signed>>];
-table_field_to_binary({FName, binary, Value}) ->
- [short_string_to_binary(FName), "x", long_string_to_binary(Value)];
+field_value_to_binary(short, Value) ->
+ ["s", <<Value:16/signed>>];
-table_field_to_binary({FName, void, _Value}) ->
- [short_string_to_binary(FName), "V"].
+field_value_to_binary(bool, Value) ->
+ ["t", if Value -> 1; true -> 0 end];
+
+field_value_to_binary(binary, Value) ->
+ ["x", long_string_to_binary(Value)];
+
+field_value_to_binary(void, _Value) ->
+ ["V"].
table_to_binary(Table) when is_list(Table) ->
BinTable = generate_table(Table),
[<<(size(BinTable)):32>>, BinTable].
+array_to_binary(Array) when is_list(Array) ->
+ BinArray = generate_array(Array),
+ [<<(size(BinArray)):32>>, BinArray].
+
generate_table(Table) when is_list(Table) ->
list_to_binary(lists:map(fun table_field_to_binary/1, Table)).
+generate_array(Array) when is_list(Array) ->
+ list_to_binary(lists:map(
+ fun ({Type, Value}) -> field_value_to_binary(Type, Value) end,
+ Array)).
short_string_to_binary(String) when is_binary(String) and (size(String) < 256) ->
[<<(size(String)):8>>, String];
@@ -186,13 +200,11 @@ short_string_to_binary(String) ->
true = (StringLength < 256), % assertion
[<<StringLength:8>>, String].
-
long_string_to_binary(String) when is_binary(String) ->
[<<(size(String)):32>>, String];
long_string_to_binary(String) ->
[<<(length(String)):32>>, String].
-
encode_properties([], []) ->
<<0, 0>>;
encode_properties(TypeList, ValueList) ->
@@ -238,32 +250,7 @@ encode_property(longlongint, Int) ->
encode_property(timestamp, Int) ->
<<Int:64/unsigned>>;
encode_property(table, Table) ->
- encode_table(Table).
-
-
-encode_table(Table) ->
- TableBin = list_to_binary(lists:map(fun encode_table_entry/1, Table)),
- Len = size(TableBin),
- <<Len:32/unsigned, TableBin:Len/binary>>.
-
-
-encode_table_entry({Name, longstr, Value}) ->
- NLen = size(Name),
- VLen = size(Value),
- <<NLen:8/unsigned, Name:NLen/binary, "S", VLen:32/unsigned, Value:VLen/binary>>;
-encode_table_entry({Name, signedint, Value}) ->
- NLen = size(Name),
- <<NLen:8/unsigned, Name:NLen/binary, "I", Value:32/signed>>;
-encode_table_entry({Name, decimal, {Before, After}}) ->
- NLen = size(Name),
- <<NLen:8/unsigned, Name:NLen/binary, "D", Before:8/unsigned, After:32/unsigned>>;
-encode_table_entry({Name, timestamp, Value}) ->
- NLen = size(Name),
- <<NLen:8/unsigned, Name:NLen/binary, "T", Value:64/unsigned>>;
-encode_table_entry({Name, table, Value}) ->
- NLen = size(Name),
- TableBin = encode_table(Value),
- <<NLen:8/unsigned, Name:NLen/binary, "F", TableBin/binary>>.
+ table_to_binary(Table).
check_empty_content_body_frame_size() ->
%% Intended to ensure that EMPTY_CONTENT_BODY_FRAME_SIZE is
diff --git a/src/rabbit_binary_parser.erl b/src/rabbit_binary_parser.erl
index 4ef382aaf5..506e87ecb1 100644
--- a/src/rabbit_binary_parser.erl
+++ b/src/rabbit_binary_parser.erl
@@ -56,45 +56,57 @@
parse_table(<<>>) ->
[];
+parse_table(<<NLen:8/unsigned, NameString:NLen/binary, ValueAndRest/binary>>) ->
+ {Type, Value, Rest} = parse_field_value(ValueAndRest),
+ [{NameString, Type, Value} | parse_table(Rest)].
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "S", VLen:32/unsigned, ValueString:VLen/binary, Rest/binary>>) ->
- [{NameString, longstr, ValueString} | parse_table(Rest)];
+parse_array(<<>>) ->
+ [];
+parse_array(<<ValueAndRest/binary>>) ->
+ {Type, Value, Rest} = parse_field_value(ValueAndRest),
+ [{Type, Value} | parse_array(Rest)].
+
+parse_field_value(<<"S", VLen:32/unsigned, ValueString:VLen/binary, Rest/binary>>) ->
+ {longstr, ValueString, Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "I", Value:32/signed, Rest/binary>>) ->
- [{NameString, signedint, Value} | parse_table(Rest)];
+parse_field_value(<<"I", Value:32/signed, Rest/binary>>) ->
+ {signedint, Value, Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "D", Before:8/unsigned, After:32/unsigned, Rest/binary>>) ->
- [{NameString, decimal, {Before, After}} | parse_table(Rest)];
+parse_field_value(<<"D", Before:8/unsigned, After:32/unsigned, Rest/binary>>) ->
+ {decimal, {Before, After}, Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "T", Value:64/unsigned, Rest/binary>>) ->
- [{NameString, timestamp, Value} | parse_table(Rest)];
+parse_field_value(<<"T", Value:64/unsigned, Rest/binary>>) ->
+ {timestamp, Value, Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "F", VLen:32/unsigned, Table:VLen/binary, Rest/binary>>) ->
- [{NameString, table, parse_table(Table)} | parse_table(Rest)];
+parse_field_value(<<"F", VLen:32/unsigned, Table:VLen/binary, Rest/binary>>) ->
+ {table, parse_table(Table), Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "b", Value:8/unsigned, Rest/binary>>) ->
- [{NameString, byte, Value} | parse_table(Rest)];
+parse_field_value(<<"A", VLen:32/unsigned, Array:VLen/binary, Rest/binary>>) ->
+ {array, parse_array(Array), Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "d", Value:64/float, Rest/binary>>) ->
- [{NameString, double, Value} | parse_table(Rest)];
+parse_field_value(<<"b", Value:8/unsigned, Rest/binary>>) ->
+ {byte, Value, Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "f", Value:32/float, Rest/binary>>) ->
- [{NameString, float, Value} | parse_table(Rest)];
+parse_field_value(<<"d", Value:64/float, Rest/binary>>) ->
+ {double, Value, Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "l", Value:64/signed, Rest/binary>>) ->
- [{NameString, long, Value} | parse_table(Rest)];
+parse_field_value(<<"f", Value:32/float, Rest/binary>>) ->
+ {float, Value, Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "s", Value:16/signed, Rest/binary>>) ->
- [{NameString, short, Value} | parse_table(Rest)];
+parse_field_value(<<"l", Value:64/signed, Rest/binary>>) ->
+ {long, Value, Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "t", Value:8/unsigned, Rest/binary>>) ->
- [{NameString, bool, (Value /= 0)} | parse_table(Rest)];
+parse_field_value(<<"s", Value:16/signed, Rest/binary>>) ->
+ {short, Value, Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "x", VLen:32/unsigned, ValueString:VLen/binary, Rest/binary>>) ->
- [{NameString, binary, ValueString} | parse_table(Rest)];
+parse_field_value(<<"t", Value:8/unsigned, Rest/binary>>) ->
+ {bool, (Value /= 0), Rest};
-parse_table(<<NLen:8/unsigned, NameString:NLen/binary, "V", Rest/binary>>) ->
- [{NameString, void, undefined} | parse_table(Rest)].
+parse_field_value(<<"x", VLen:32/unsigned, ValueString:VLen/binary, Rest/binary>>) ->
+ {binary, ValueString, Rest};
+
+parse_field_value(<<"V", Rest/binary>>) ->
+ {void, undefined, Rest}.
parse_properties([], _PropBin) ->
@@ -147,7 +159,6 @@ parse_property(bit, Rest) ->
parse_property(table, <<Len:32/unsigned, Table:Len/binary, Rest/binary>>) ->
{parse_table(Table), Rest}.
-
ensure_content_decoded(Content = #content{properties = Props})
when Props =/= 'none' ->
Content;
diff --git a/src/rabbit_mnesia.erl b/src/rabbit_mnesia.erl
index c4d5aac684..749038dbb1 100644
--- a/src/rabbit_mnesia.erl
+++ b/src/rabbit_mnesia.erl
@@ -32,7 +32,8 @@
-module(rabbit_mnesia).
-export([ensure_mnesia_dir/0, dir/0, status/0, init/0, is_db_empty/0,
- cluster/1, reset/0, force_reset/0]).
+ cluster/1, reset/0, force_reset/0, is_clustered/0,
+ empty_ram_only_tables/0]).
-export([table_names/0]).
@@ -54,6 +55,8 @@
-spec(cluster/1 :: ([erlang_node()]) -> 'ok').
-spec(reset/0 :: () -> 'ok').
-spec(force_reset/0 :: () -> 'ok').
+-spec(is_clustered/0 :: () -> boolean()).
+-spec(empty_ram_only_tables/0 :: () -> 'ok').
-spec(create_tables/0 :: () -> 'ok').
-endif.
@@ -98,6 +101,21 @@ cluster(ClusterNodes) ->
reset() -> reset(false).
force_reset() -> reset(true).
+is_clustered() ->
+ RunningNodes = mnesia:system_info(running_db_nodes),
+ [node()] /= RunningNodes andalso [] /= RunningNodes.
+
+empty_ram_only_tables() ->
+ Node = node(),
+ lists:foreach(
+ fun (TabName) ->
+ case lists:member(Node, mnesia:table_info(TabName, ram_copies)) of
+ true -> {atomic, ok} = mnesia:clear_table(TabName);
+ false -> ok
+ end
+ end, table_names()),
+ ok.
+
%%--------------------------------------------------------------------
table_definitions() ->
diff --git a/src/rabbit_plugin_activator.erl b/src/rabbit_plugin_activator.erl
index e22d844fdf..a2ac74ef81 100644
--- a/src/rabbit_plugin_activator.erl
+++ b/src/rabbit_plugin_activator.erl
@@ -39,6 +39,17 @@
-define(BaseApps, [rabbit]).
%%----------------------------------------------------------------------------
+%% Specs
+%%----------------------------------------------------------------------------
+
+-ifdef(use_specs).
+
+-spec(start/0 :: () -> no_return()).
+-spec(stop/0 :: () -> 'ok').
+
+-endif.
+
+%%----------------------------------------------------------------------------
start() ->
%% Ensure Rabbit is loaded so we can access it's environment
diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl
index aff5f29684..416827cb80 100644
--- a/src/rabbit_tests.erl
+++ b/src/rabbit_tests.erl
@@ -194,6 +194,7 @@ test_unfold() ->
test_parsing() ->
passed = test_content_properties(),
+ passed = test_field_values(),
passed.
test_content_properties() ->
@@ -219,9 +220,12 @@ test_content_properties() ->
[{<<"one">>, signedint, 1},
{<<"two">>, signedint, 2}]}]}],
<<
- 16#8000:16, % flags
- % properties:
+ % property-flags
+ 16#8000:16,
+ % property-list:
+
+ % table
117:32, % table length in bytes
11,"a signedint", % name
@@ -250,6 +254,51 @@ test_content_properties() ->
V -> exit({got_success_but_expected_failure, V})
end.
+test_field_values() ->
+ %% FIXME this does not test inexact numbers (double and float) yet,
+ %% because they won't pass the equality assertions
+ test_content_prop_roundtrip(
+ [{table, [{<<"longstr">>, longstr, <<"Here is a long string">>},
+ {<<"signedint">>, signedint, 12345},
+ {<<"decimal">>, decimal, {3, 123456}},
+ {<<"timestamp">>, timestamp, 109876543209876},
+ {<<"table">>, table, [{<<"one">>, signedint, 54321},
+ {<<"two">>, longstr, <<"A long string">>}]},
+ {<<"byte">>, byte, 255},
+ {<<"long">>, long, 1234567890},
+ {<<"short">>, short, 655},
+ {<<"bool">>, bool, true},
+ {<<"binary">>, binary, <<"a binary string">>},
+ {<<"void">>, void, undefined},
+ {<<"array">>, array, [{signedint, 54321},
+ {longstr, <<"A long string">>}]}
+
+ ]}],
+ <<
+ % property-flags
+ 16#8000:16,
+ % table length in bytes
+ 228:32,
+
+ 7,"longstr", "S", 21:32, "Here is a long string", % = 34
+ 9,"signedint", "I", 12345:32/signed, % + 15 = 49
+ 7,"decimal", "D", 3, 123456:32, % + 14 = 63
+ 9,"timestamp", "T", 109876543209876:64, % + 19 = 82
+ 5,"table", "F", 31:32, % length of table % + 11 = 93
+ 3,"one", "I", 54321:32, % + 9 = 102
+ 3,"two", "S", 13:32, "A long string",% + 22 = 124
+ 4,"byte", "b", 255:8, % + 7 = 131
+ 4,"long", "l", 1234567890:64, % + 14 = 145
+ 5,"short", "s", 655:16, % + 9 = 154
+ 4,"bool", "t", 1, % + 7 = 161
+ 6,"binary", "x", 15:32, "a binary string", % + 27 = 188
+ 4,"void", "V", % + 6 = 194
+ 5,"array", "A", 23:32, % + 11 = 205
+ "I", 54321:32, % + 5 = 210
+ "S", 13:32, "A long string" % + 18 = 228
+ >>),
+ passed.
+
%% Test that content frames don't exceed frame-max
test_content_framing(FrameMax, Fragments) ->
[Header | Frames] =