Merged default

This commit is contained in:
Simon MacMullen 2008-12-01 17:02:55 +00:00
commit 5bf65aa0b9
19 changed files with 569 additions and 52 deletions

View File

@ -63,7 +63,7 @@
-include("rabbit_framing_spec.hrl").
-type(maybe(T) :: T | 'none').
-type(node() :: atom()).
-type(erlang_node() :: atom()).
-type(socket() :: port()).
-type(thunk(T) :: fun(() -> T)).
@ -123,7 +123,7 @@
-type(msg_id() :: non_neg_integer()).
-type(msg() :: {queue_name(), pid(), msg_id(), bool(), message()}).
-type(listener() ::
#listener{node :: node(),
#listener{node :: erlang_node(),
protocol :: atom(),
host :: string() | atom(),
port :: non_neg_integer()}).

View File

@ -20,7 +20,8 @@ prepare:
cp rabbitmq-server.logrotate SOURCES/rabbitmq-server.logrotate
server: prepare
rpmbuild -ba SPECS/rabbitmq-server.spec $(DEFINES) --target noarch
rpmbuild -ba SPECS/rabbitmq-server.spec $(DEFINES) --target i386
rpmbuild -ba SPECS/rabbitmq-server.spec $(DEFINES) --target x86_64
clean:
rm -rf SOURCES SPECS RPMS SRPMS BUILD tmp

View File

@ -15,7 +15,7 @@ BuildRequires: erlang, python-json
%endif
Requires: erlang, logrotate
Packager: Hubert Plociniczak <hubert@lshift.net>
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%{_arch}-root
Summary: The RabbitMQ server
Requires(post): chkconfig
Requires(pre): chkconfig initscripts
@ -25,11 +25,14 @@ RabbitMQ is an implementation of AMQP, the emerging standard for high
performance enterprise messaging. The RabbitMQ server is a robust and
scalable implementation of an AMQP broker.
%ifarch x86_64
%define _erllibdir /usr/lib64/erlang/lib
%else
%define _erllibdir /usr/lib/erlang/lib
%endif
%define _erllibdir %(erl -noshell -eval "io:format('~s~n', [code:lib_dir()]), halt().")
%define _maindir %{buildroot}%{_erllibdir}/rabbitmq_server-%{version}
%pre
if [ $1 -gt 1 ]; then
#Upgrade - stop and remove previous instance of rabbitmq-server init.d script
@ -67,6 +70,8 @@ cp %{buildroot}%{_mandir}/man1/rabbitmqctl.1.gz %{buildroot}%{_mandir}/man1/rabb
mkdir -p %{buildroot}/etc/logrotate.d
install %SOURCE3 %{buildroot}/etc/logrotate.d/rabbitmq-server
rm %{_maindir}/LICENSE %{_maindir}/LICENSE-MPL-RabbitMQ %{_maindir}/INSTALL
%post
# create rabbitmq group
if ! getent group rabbitmq >/dev/null; then
@ -110,6 +115,7 @@ fi
/var/log/rabbitmq/
/etc/rc.d/init.d/rabbitmq-server
%config(noreplace) /etc/logrotate.d/rabbitmq-server
%doc LICENSE LICENSE-MPL-RabbitMQ INSTALL
%clean
rm -rf %{buildroot}

View File

@ -6,16 +6,13 @@ include /usr/share/cdbs/1/class/makefile.mk
RABBIT_LIB=$(DEB_DESTDIR)usr/lib/erlang/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)/
RABBIT_BIN=$(DEB_DESTDIR)usr/lib/rabbitmq/bin/
DEB_MAKE_INSTALL_TARGET := install TARGET_DIR=$(RABBIT_LIB) SBIN_DIR=$(RABBIT_BIN) MAN_DIR=$(DEB_DESTDIR)usr/share/man
DEB_MAKE_INSTALL_TARGET := install TARGET_DIR=$(RABBIT_LIB) SBIN_DIR=$(RABBIT_BIN) MAN_DIR=$(DEB_DESTDIR)usr/share/man/
DOCDIR=$(DEB_DESTDIR)usr/share/doc/rabbitmq-server/
install/rabbitmq-server::
mkdir -p $(DOCDIR)
rm $(RABBIT_LIB)/LICENSE*
mkdir -p $(RABBIT_BIN)
rm $(DEB_DESTDIR)usr/share/man/man1/rabbitmq-multi.1.gz
rm $(DEB_DESTDIR)usr/share/man/man1/rabbitmq-server.1.gz
rm $(RABBIT_LIB)LICENSE*
cp debian/rabbitmqctl_wrapper $(DEB_DESTDIR)usr/sbin/rabbitmqctl
cp debian/rabbitmq-server.logrotate $(DEB_DESTDIR)etc/logrotate.d/rabbitmq-server
chmod a+x $(DEB_DESTDIR)usr/sbin/rabbitmqctl

View File

@ -10,6 +10,7 @@ dist:
mkdir $(SOURCE_DIR)/sbin
mv $(SOURCE_DIR)/scripts/rabbitmq-server.bat $(SOURCE_DIR)/sbin
mv $(SOURCE_DIR)/scripts/rabbitmq-service.bat $(SOURCE_DIR)/sbin
mv $(SOURCE_DIR)/scripts/rabbitmqctl.bat $(SOURCE_DIR)/sbin
mv $(SOURCE_DIR)/scripts/rabbitmq-multi.bat $(SOURCE_DIR)/sbin
rm -rf $(SOURCE_DIR)/scripts
@ -18,6 +19,8 @@ dist:
rm -rf $(SOURCE_DIR)/docs
mv $(SOURCE_DIR) $(TARGET_DIR)
pod2text --loose rabbitmq-service.pod $(TARGET_DIR)/readme-service.txt
unix2dos $(TARGET_DIR)/readme-service.txt
zip -r $(TARGET_ZIP).zip $(TARGET_DIR)
rm -rf $(TARGET_DIR)

View File

@ -0,0 +1,138 @@
=head1 NAME
rabbitmq-service - manage RabbitMQ AMQP service
=head1 SYNOPSIS
rabbitmq-service.bat command
=head1 DESCRIPTION
RabbitMQ is an implementation of AMQP, the emerging standard for high
performance enterprise messaging. The RabbitMQ server is a robust and
scalable implementation of an AMQP broker.
Running B<rabbitmq-service> allows the RabbitMQ broker to be run as a
service on NT/2000/2003/XP/Vista® environments. The RabbitMQ broker
service can be started and stopped using the Windows® services
applet.
By default the service will run in the authentication context of the
local system account. It is therefore necessary to synchronise Erlang
cookies between the local system account (typically
C<C:\WINDOWS\.erlang.cookie> and the account that will be used to
run B<rabbitmqctl>.
=head1 COMMANDS
=head2 help
Display usage information.
=head2 install
Install the service. The service will not be started.
Subsequent invocations will update the service parameters if
relevant environment variables were modified.
=head2 remove
Remove the service. If the service is running then it will
automatically be stopped before being removed. No files will be
deleted as a consequence and B<rabbitmq-server> will remain operable.
=head2 start
Start the service. The service must have been correctly installed
beforehand.
=head2 stop
Stop the service. The service must be running for this command to
have any effect.
=head2 disable
Disable the service. This is the equivalent of setting the startup
type to B<Disabled> using the service control panel.
=head2 enable
Enable the service. This is the equivalent of setting the startup
type to B<Automatic> using the service control panel.
=head1 ENVIRONMENT
=head2 SERVICENAME
Defaults to RabbitMQ.
This is the location of log and database directories.
=head2 RABBITMQ_BASE
Defaults to the application data directory of the current user.
This is the location of log and database directories.
=head2 NODENAME
Defaults to "rabbit". This can be useful if you want to run more
than one node per machine - B<NODENAME> should be unique per
erlang-node-and-machine combination. See clustering on a single
machine guide
at L<http://www.rabbitmq.com/clustering.html#single-machine> for
details.
=head2 NODE_IP_ADDRESS
Defaults to "0.0.0.0". This can be changed if you only want to bind
to one network interface.
=head2 NODE_PORT
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.
=head2 CLUSTER_CONFIG_FILE
If this file is present it is used by the server to
auto-configure a RabbitMQ cluster. See the clustering guide
at L<http://www.rabbitmq.com/clustering.html> for details.
=head2 CONSOLE_LOG
Set this varable to B<new> or B<reuse> to have the console
output from the server redirected to a file named B<SERVICENAME>.debug
in the application data directory of the user that installed the service.
Under Vista this will be F<C:\Documents and Settings\User\AppData\username\SERVICENAME>.
Under previous versions of Windows this will be
F<C:\Documents and Settings\username\Application Data\SERVICENAME>.
If B<CONSOLE_LOG> is set to B<new> then a new file will be created
each time the service starts. If B<CONSOLE_LOG> is set to B<reuse>
then the file will be overwritten each time the service starts.
The default behaviour when B<CONSOLE_LOG> is not set or set to a
value other than B<new> or B<reuse> is to discard the server output.
=head1 EXAMPLES
Start a previously-installed RabbitMQ AMQP service:
rabbitmq-service start
=head1 AUTHOR
Originally written by The RabbitMQ Team <info@lshift.net>
=head1 COPYRIGHT
This package, the RabbitMQ server is licensed under the MPL.
If you have any questions regarding licensing, please contact us at
info@rabbitmq.com.
=head1 REFERENCES
RabbitMQ Web Site: http://www.rabbitmq.com

View File

@ -66,7 +66,7 @@ exec erl \
-sasl sasl_error_logger '{file,"'${SASL_LOGS}'"}' \
-os_mon start_cpu_sup true \
-os_mon start_disksup false \
-os_mon start_memsup true \
-os_mon start_memsup false \
-os_mon start_os_sup false \
-os_mon memsup_system_only true \
-os_mon system_memory_high_watermark 0.95 \

2
scripts/rabbitmq-server.bat Normal file → Executable file
View File

@ -107,7 +107,7 @@ set MNESIA_DIR=%MNESIA_BASE%/%NODENAME%-mnesia
-sasl sasl_error_logger {file,\""%LOG_BASE%/%NODENAME%-sasl.log"\"} ^
-os_mon start_cpu_sup true ^
-os_mon start_disksup false ^
-os_mon start_memsup true ^
-os_mon start_memsup false ^
-os_mon start_os_sup false ^
-os_mon memsup_system_only true ^
-os_mon system_memory_high_watermark 0.95 ^

189
scripts/rabbitmq-service.bat Executable file
View File

@ -0,0 +1,189 @@
@echo off
REM The contents of this file are subject to the Mozilla Public License
REM Version 1.1 (the "License"); you may not use this file except in
REM compliance with the License. You may obtain a copy of the License at
REM http://www.mozilla.org/MPL/
REM
REM Software distributed under the License is distributed on an "AS IS"
REM basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
REM License for the specific language governing rights and limitations
REM under the License.
REM
REM The Original Code is RabbitMQ.
REM
REM The Initial Developers of the Original Code are LShift Ltd.,
REM Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
REM
REM Portions created by LShift Ltd., Cohesive Financial Technologies
REM LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007-2008
REM LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit
REM Technologies Ltd.;
REM
REM All Rights Reserved.
REM
REM Contributor(s): ______________________________________.
REM
if "%SERVICENAME%"=="" (
set SERVICENAME=RabbitMQ
)
if "%RABBITMQ_BASE%"=="" (
set RABBITMQ_BASE=%APPDATA%\%SERVICENAME%
)
if "%NODENAME%"=="" (
set NODENAME=rabbit
)
if "%NODE_IP_ADDRESS%"=="" (
set NODE_IP_ADDRESS=0.0.0.0
)
if "%NODE_PORT%"=="" (
set NODE_PORT=5672
)
if "%ERLANG_SERVICE_MANAGER_PATH%"=="" (
set ERLANG_SERVICE_MANAGER_PATH=C:\Program Files\erl5.5.5\erts-5.5.5\bin
)
set CONSOLE_FLAG=
set CONSOLE_LOG_VALID=
for %%i in (new reuse) do if "%%i" == "%CONSOLE_LOG%" set CONSOLE_LOG_VALID=TRUE
if "%CONSOLE_LOG_VALID%" == "TRUE" (
set CONSOLE_FLAG=-debugtype %CONSOLE_LOG%
)
rem *** End of configuration ***
if not exist "%ERLANG_SERVICE_MANAGER_PATH%\erlsrv.exe" (
echo.
echo **********************************************
echo ERLANG_SERVICE_MANAGER_PATH not set correctly.
echo **********************************************
echo.
echo %ERLANG_SERVICE_MANAGER_PATH%\erlsrv.exe not found!
echo Please set ERLANG_SERVICE_MANAGER_PATH to the folder containing "erlsrv.exe".
echo.
exit /B 1
)
rem erlang prefers forwardslash as separator in paths
set RABBITMQ_BASE_UNIX=%RABBITMQ_BASE:\=/%
set MNESIA_BASE=%RABBITMQ_BASE_UNIX%/db
set LOG_BASE=%RABBITMQ_BASE_UNIX%/log
rem We save the previous logs in their respective backup
rem Log management (rotation, filtering based on size...) is left as an exercise for the user.
set BACKUP_EXTENSION=.1
set LOGS="%RABBITMQ_BASE%\log\%NODENAME%.log"
set SASL_LOGS="%RABBITMQ_BASE%\log\%NODENAME%-sasl.log"
set LOGS_BACKUP="%RABBITMQ_BASE%\log\%NODENAME%.log%BACKUP_EXTENSION%"
set SASL_LOGS_BACKUP="%RABBITMQ_BASE%\log\%NODENAME%-sasl.log%BACKUP_EXTENSION%"
if exist %LOGS% (
type %LOGS% >> %LOGS_BACKUP%
)
if exist %SASL_LOGS% (
type %SASL_LOGS% >> %SASL_LOGS_BACKUP%
)
rem End of log management
set CLUSTER_CONFIG_FILE=%RABBITMQ_BASE%\rabbitmq_cluster.config
set CLUSTER_CONFIG=
if not exist "%CLUSTER_CONFIG_FILE%" GOTO L1
set CLUSTER_CONFIG=-rabbit cluster_config \""%CLUSTER_CONFIG_FILE:\=/%"\"
:L1
set MNESIA_DIR=%MNESIA_BASE%/%NODENAME%-mnesia
if "%1" == "install" goto INSTALL_SERVICE
for %%i in (start stop disable enable list remove) do if "%%i" == "%1" goto MODIFY_SERVICE
echo.
echo *********************
echo Service control usage
echo *********************
echo.
echo %~n0 help - Display this help
echo %~n0 install - Install the %SERVICENAME% service
echo %~n0 remove - Remove the %SERVICENAME% service
echo.
echo The following actions can also be accomplished by using
echo Windows Services Management Console (services.msc):
echo.
echo %~n0 start - Start the %SERVICENAME% service
echo %~n0 stop - Stop the %SERVICENAME% service
echo %~n0 disable - Disable the %SERVICENAME% service
echo %~n0 enable - Enable the %SERVICENAME% service
echo.
exit /B
:INSTALL_SERVICE
if not exist "%RABBITMQ_BASE%" (
echo Creating base directory %RABBITMQ_BASE% & md "%RABBITMQ_BASE%"
)
"%ERLANG_SERVICE_MANAGER_PATH%\erlsrv" list %SERVICENAME% 2>NUL 1>NUL
if errorlevel 1 (
"%ERLANG_SERVICE_MANAGER_PATH%\erlsrv" add %SERVICENAME%
) else (
echo %SERVICENAME% service is already present - only updating service parameters
)
set RABBIT_EBIN=%~dp0..\ebin
set ERLANG_SERVICE_ARGUMENTS= ^
-pa "%RABBIT_EBIN%" ^
-boot start_sasl ^
-s rabbit ^
+W w ^
+A30 ^
-kernel inet_default_listen_options "[{nodelay,true},{sndbuf,16384},{recbuf,4096}]" ^
-kernel inet_default_connect_options "[{nodelay,true}]" ^
-rabbit tcp_listeners "[{\"%NODE_IP_ADDRESS%\",%NODE_PORT%}]" ^
-kernel error_logger {file,\""%LOG_BASE%/%NODENAME%.log"\"} ^
-sasl errlog_type error ^
-sasl sasl_error_logger {file,\""%LOG_BASE%/%NODENAME%-sasl.log"\"} ^
-os_mon start_cpu_sup true ^
-os_mon start_disksup false ^
-os_mon start_memsup true ^
-os_mon start_os_sup false ^
-os_mon memsup_system_only true ^
-os_mon system_memory_high_watermark 0.95 ^
-mnesia dir \""%MNESIA_DIR%"\" ^
%CLUSTER_CONFIG% ^
%RABBIT_ARGS% ^
%*
set ERLANG_SERVICE_ARGUMENTS=%ERLANG_SERVICE_ARGUMENTS:\=\\%
set ERLANG_SERVICE_ARGUMENTS=%ERLANG_SERVICE_ARGUMENTS:"=\"%
"%ERLANG_SERVICE_MANAGER_PATH%\erlsrv" set %SERVICENAME% ^
-machine "%ERLANG_SERVICE_MANAGER_PATH%\erl.exe" ^
-env ERL_CRASH_DUMP="%RABBITMQ_BASE_UNIX%/log" ^
-workdir "%RABBITMQ_BASE%" ^
-stopaction "rabbit:stop_and_halt()." ^
-sname %NODENAME% ^
%CONSOLE_FLAG% ^
-args "%ERLANG_SERVICE_ARGUMENTS%" > NUL
goto END
:MODIFY_SERVICE
"%ERLANG_SERVICE_MANAGER_PATH%\erlsrv" %1 %SERVICENAME%
goto END
:END

View File

@ -57,8 +57,8 @@
-spec(rotate_logs/1 :: (file_suffix()) -> 'ok' | {'error', any()}).
-spec(status/0 :: () ->
[{running_applications, [{atom(), string(), string()}]} |
{nodes, [node()]} |
{running_nodes, [node()]}]).
{nodes, [erlang_node()]} |
{running_nodes, [erlang_node()]}]).
-spec(log_location/1 :: ('sasl' | 'kernel') -> log_location()).
-endif.

View File

@ -50,22 +50,57 @@
%%----------------------------------------------------------------------------
start() ->
ok = alarm_handler:add_alarm_handler(?MODULE),
case whereis(memsup) of
undefined ->
Mod = case os:type() of
%% memsup doesn't take account of buffers or
%% cache when considering "free" memory -
%% therefore on Linux we can get memory alarms
%% very easily without any pressure existing on
%% memory at all. Therefore we need to use our
%% own simple memory monitor.
%%
{unix, linux} -> rabbit_memsup_linux;
%% Start memsup programmatically rather than via
%% the rabbitmq-server script. This is not quite
%% the right thing to do as os_mon checks to see
%% if memsup is available before starting it,
%% but as memsup is available everywhere (even
%% on VXWorks) it should be ok.
%%
%% One benefit of the programmatic startup is
%% that we can add our alarm_handler before
%% memsup is running, thus ensuring that we
%% notice memory alarms that go off on startup.
%%
_ -> memsup
end,
%% This is based on os_mon:childspec(memsup, true)
{ok, _} = supervisor:start_child(
os_mon_sup,
{memsup, {Mod, start_link, []},
permanent, 2000, worker, [Mod]}),
ok;
_ ->
ok
end,
%% The default memsup check interval is 1 minute, which is way too
%% long - rabbit can gobble up all memory in a matter of
%% seconds. Unfortunately the memory_check_interval configuration
%% parameter and memsup:set_check_interval/1 function only provide
%% a granularity of minutes. So we have to peel off one layer of
%% the API to get to the underlying layer which operates at the
%% long - rabbit can gobble up all memory in a matter of seconds.
%% Unfortunately the memory_check_interval configuration parameter
%% and memsup:set_check_interval/1 function only provide a
%% granularity of minutes. So we have to peel off one layer of the
%% API to get to the underlying layer which operates at the
%% granularity of milliseconds.
%%
%% Note that the new setting will only take effect after the first
%% check has completed, i.e. after one minute. So if rabbit eats
%% all the memory within the first minute after startup then we
%% are out of luck.
ok = os_mon:call(memsup, {set_check_interval, ?MEMSUP_CHECK_INTERVAL},
infinity),
ok = alarm_handler:add_alarm_handler(?MODULE).
ok = os_mon:call(memsup,
{set_check_interval, ?MEMSUP_CHECK_INTERVAL},
infinity).
stop() ->
ok = alarm_handler:delete_alarm_handler(?MODULE).
@ -77,9 +112,7 @@ register(Pid, HighMemMFA) ->
%%----------------------------------------------------------------------------
init([]) ->
HWM = system_memory_high_watermark(),
{ok, #alarms{alertees = dict:new(),
system_memory_high_watermark = HWM}}.
{ok, #alarms{alertees = dict:new()}}.
handle_call({register, Pid, HighMemMFA},
State = #alarms{alertees = Alertess}) ->
@ -121,19 +154,6 @@ code_change(_OldVsn, State, _Extra) ->
%%----------------------------------------------------------------------------
system_memory_high_watermark() ->
%% When we register our alarm_handler, the
%% system_memory_high_watermark alarm may already have gone
%% off. How do we find out about that? Calling
%% alarm_handler:get_alarms() would deadlock. So instead we ask
%% memsup. Unfortunately that doesn't expose a suitable API, so we
%% have to reach quite deeply into its internals.
{dictionary, D} = process_info(whereis(memsup), dictionary),
case lists:keysearch(system_memory_high_watermark, 1, D) of
{value, {_, set}} -> true;
_Other -> false
end.
alert(Alert, Alertees) ->
dict:fold(fun (Pid, {M, F, A}, Acc) ->
ok = erlang:apply(M, F, A ++ [Pid, Alert]),

View File

@ -89,7 +89,7 @@
-spec(basic_cancel/4 :: (amqqueue(), pid(), ctag(), any()) -> 'ok').
-spec(notify_sent/2 :: (pid(), pid()) -> 'ok').
-spec(internal_delete/1 :: (queue_name()) -> 'ok' | not_found()).
-spec(on_node_down/1 :: (node()) -> 'ok').
-spec(on_node_down/1 :: (erlang_node()) -> 'ok').
-spec(pseudo_queue/2 :: (binary(), pid()) -> amqqueue()).
-endif.

View File

@ -34,11 +34,11 @@
-ifdef(use_specs).
-type(node() :: atom()).
-type(load() :: {{non_neg_integer(), float()}, node()}).
-type(erlang_node() :: atom()).
-type(load() :: {{non_neg_integer(), float()}, erlang_node()}).
-spec(local_load/0 :: () -> load()).
-spec(remote_loads/0 :: () -> [load()]).
-spec(pick/0 :: () -> node()).
-spec(pick/0 :: () -> erlang_node()).
-endif.

View File

@ -32,7 +32,7 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-export([debug/1, debug/2, info/1, info/2,
-export([debug/1, debug/2, message/4, info/1, info/2,
warning/1, warning/2, error/1, error/2]).
-import(io).
@ -67,6 +67,10 @@ debug(Fmt) ->
debug(Fmt, Args) when is_list(Args) ->
gen_server:cast(?SERVER, {debug, Fmt, Args}).
message(Direction, Channel, MethodRecord, Content) ->
gen_server:cast(?SERVER,
{message, Direction, Channel, MethodRecord, Content}).
info(Fmt) ->
gen_server:cast(?SERVER, {info, Fmt}).
@ -100,6 +104,14 @@ handle_cast({debug, Fmt, Args}, State) ->
io:format("debug:: "), io:format(Fmt, Args),
error_logger:info_msg("debug:: " ++ Fmt, Args),
{noreply, State};
handle_cast({message, Direction, Channel, MethodRecord, Content}, State) ->
io:format("~s ch~p ~p~n",
[case Direction of
in -> "-->";
out -> "<--" end,
Channel,
{MethodRecord, Content}]),
{noreply, State};
handle_cast({info, Fmt}, State) ->
error_logger:info_msg(Fmt),
{noreply, State};

150
src/rabbit_memsup_linux.erl Normal file
View File

@ -0,0 +1,150 @@
%% 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
%% http://www.mozilla.org/MPL/
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
%% License for the specific language governing rights and limitations
%% under the License.
%%
%% The Original Code is RabbitMQ.
%%
%% The Initial Developers of the Original Code are LShift Ltd.,
%% Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
%%
%% Portions created by LShift Ltd., Cohesive Financial Technologies
%% LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007-2008
%% LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit
%% Technologies Ltd.;
%%
%% All Rights Reserved.
%%
%% Contributor(s): ______________________________________.
%%
-module(rabbit_memsup_linux).
-behaviour(gen_server).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-export([update/0]).
-define(SERVER, memsup). %% must be the same as the standard memsup
-define(DEFAULT_MEMORY_CHECK_INTERVAL, 1000).
-record(state, {memory_fraction, alarmed, timeout, timer}).
%%----------------------------------------------------------------------------
-ifdef(use_specs).
-spec(start_link/0 :: () -> {'ok', pid()} | 'ignore' | {'error', any()}).
-spec(update/0 :: () -> 'ok').
-endif.
%%----------------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
update() ->
gen_server:cast(?SERVER, update).
%%----------------------------------------------------------------------------
init(_Args) ->
Fraction = os_mon:get_env(memsup, system_memory_high_watermark),
TRef = start_timer(?DEFAULT_MEMORY_CHECK_INTERVAL),
{ok, #state{alarmed = false,
memory_fraction = Fraction,
timeout = ?DEFAULT_MEMORY_CHECK_INTERVAL,
timer = TRef}}.
start_timer(Timeout) ->
{ok, TRef} = timer:apply_interval(Timeout, ?MODULE, update, []),
TRef.
%% Export the same API as the real memsup. Note that
%% get_sysmem_high_watermark gives an int in the range 0 - 100, while
%% set_sysmem_high_watermark takes a float in the range 0.0 - 1.0.
handle_call(get_sysmem_high_watermark, _From, State) ->
{reply, trunc(100 * State#state.memory_fraction), State};
handle_call({set_sysmem_high_watermark, Float}, _From, State) ->
{reply, ok, State#state{memory_fraction = Float}};
handle_call(get_check_interval, _From, State) ->
{reply, State#state.timeout, State};
handle_call({set_check_interval, Timeout}, _From, State) ->
{ok, cancel} = timer:cancel(State#state.timer),
{reply, ok, State#state{timeout = Timeout, timer = start_timer(Timeout)}};
handle_call(_Request, _From, State) ->
{noreply, State}.
handle_cast(update, State = #state{alarmed = Alarmed,
memory_fraction = MemoryFraction}) ->
File = read_proc_file("/proc/meminfo"),
Lines = string:tokens(File, "\n"),
Dict = dict:from_list(lists:map(fun parse_line/1, Lines)),
MemTotal = dict:fetch('MemTotal', Dict),
MemUsed = MemTotal
- dict:fetch('MemFree', Dict)
- dict:fetch('Buffers', Dict)
- dict:fetch('Cached', Dict),
NewAlarmed = MemUsed / MemTotal > MemoryFraction,
case {Alarmed, NewAlarmed} of
{false, true} ->
alarm_handler:set_alarm({system_memory_high_watermark, []});
{true, false} ->
alarm_handler:clear_alarm(system_memory_high_watermark);
_ ->
ok
end,
{noreply, State#state{alarmed = NewAlarmed}};
handle_cast(_Request, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%----------------------------------------------------------------------------
-define(BUFFER_SIZE, 1024).
%% file:read_file does not work on files in /proc as it seems to get
%% the size of the file first and then read that many bytes. But files
%% in /proc always have length 0, we just have to read until we get
%% eof.
read_proc_file(File) ->
{ok, IoDevice} = file:open(File, [read, raw]),
Res = read_proc_file(IoDevice, []),
file:close(IoDevice),
lists:flatten(lists:reverse(Res)).
read_proc_file(IoDevice, Acc) ->
case file:read(IoDevice, ?BUFFER_SIZE) of
{ok, Res} -> read_proc_file(IoDevice, [Res | Acc]);
eof -> Acc
end.
%% A line looks like "FooBar: 123456 kB"
parse_line(Line) ->
[Name, Value | _] = string:tokens(Line, ": "),
{list_to_atom(Name), list_to_integer(Value)}.

View File

@ -85,7 +85,7 @@
-spec(with_user_and_vhost/3 :: (username(), vhost(), thunk(A)) -> A).
-spec(execute_mnesia_transaction/1 :: (thunk(A)) -> A).
-spec(ensure_ok/2 :: ('ok' | {'error', any()}, atom()) -> 'ok').
-spec(localnode/1 :: (atom()) -> node()).
-spec(localnode/1 :: (atom()) -> erlang_node()).
-spec(tcp_name/3 :: (atom(), ip_address(), ip_port()) -> atom()).
-spec(intersperse/2 :: (A, [A]) -> [A]).
-spec(upmap/2 :: (fun ((A) -> B), [A]) -> [B]).

View File

@ -43,11 +43,11 @@
-ifdef(use_specs).
-spec(status/0 :: () -> [{'nodes' | 'running_nodes', [node()]}]).
-spec(status/0 :: () -> [{'nodes' | 'running_nodes', [erlang_node()]}]).
-spec(ensure_mnesia_dir/0 :: () -> 'ok').
-spec(init/0 :: () -> 'ok').
-spec(is_db_empty/0 :: () -> bool()).
-spec(cluster/1 :: ([node()]) -> 'ok').
-spec(cluster/1 :: ([erlang_node()]) -> 'ok').
-spec(reset/0 :: () -> 'ok').
-spec(force_reset/0 :: () -> 'ok').
-spec(create_tables/0 :: () -> 'ok').

View File

@ -45,8 +45,8 @@
-spec(start_tcp_listener/2 :: (host(), ip_port()) -> 'ok').
-spec(stop_tcp_listener/2 :: (host(), ip_port()) -> 'ok').
-spec(active_listeners/0 :: () -> [listener()]).
-spec(node_listeners/1 :: (node()) -> [listener()]).
-spec(on_node_down/1 :: (node()) -> 'ok').
-spec(node_listeners/1 :: (erlang_node()) -> [listener()]).
-spec(on_node_down/1 :: (erlang_node()) -> 'ok').
-spec(check_tcp_listener_address/3 :: (atom(), host(), ip_port()) ->
{ip_address(), atom()}).

View File

@ -71,8 +71,9 @@ handle_call(Event, State) ->
terminate(Reason, State) ->
sasl_report_file_h:terminate(Reason, State).
code_change(OldVsn, State, Extra) ->
sasl_report_file_h:code_change(OldVsn, State, Extra).
code_change(_OldVsn, State, _Extra) ->
%% There is no sasl_report_file_h:code_change/3
{ok, State}.
%%----------------------------------------------------------------------