diff options
author | Matthew Sackman <matthew@lshift.net> | 2009-10-28 16:06:03 +0000 |
---|---|---|
committer | Matthew Sackman <matthew@lshift.net> | 2009-10-28 16:06:03 +0000 |
commit | df5a328a797154e5cdec87cfbf409e8320d8a7b3 (patch) | |
tree | f1e53338a5828f667dbeef1f934b6f4ec9ad631a | |
parent | 34ec9525426def320d29757ffd79d681133ed847 (diff) | |
download | rabbitmq-server-df5a328a797154e5cdec87cfbf409e8320d8a7b3.tar.gz |
cosmetics and rearranging only - conformance and consistency
-rw-r--r-- | src/vm_memory_monitor.erl | 216 |
1 files changed, 111 insertions, 105 deletions
diff --git a/src/vm_memory_monitor.erl b/src/vm_memory_monitor.erl index d1bec186..7d291f38 100644 --- a/src/vm_memory_monitor.erl +++ b/src/vm_memory_monitor.erl @@ -30,17 +30,17 @@ %% %% In practice erlang shouldn't be allowed to grow to more than a half -%% of available memory. The pessimistic scenario is when erlang VM has -%% a single erlang process that's consuming all the memory. -%% In such case during garbage collection erlang tries to allocate -%% huge chunk of continuous memory, which can result in a crash -%% (likely on 32-bit machine) or heavy swapping (likely on 64-bit). +%% of available memory. The pessimistic scenario is when erlang VM has +%% a single erlang process that's consuming all the memory. In such +%% case during garbage collection erlang tries to allocate huge chunk +%% of continuous memory, which can result in a crash (likely on 32-bit +%% machine) or heavy swapping (likely on 64-bit). %% -%% This module tries to warn Rabbit before such situations happen, -%% so that it has higher chances to prevent running out of memory. +%% This module tries to warn Rabbit before such situations happen, so +%% that it has higher chances to prevent running out of memory. %% -%% This code depends on Erlang Memsup supervisor. Setting the update interval -%% causes a side effect of setting the interval on Memsup. +%% This code depends on Erlang Memsup supervisor. Setting the update +%% interval causes a side effect of setting the interval on Memsup. %% This should rarely be an issue. -module(vm_memory_monitor). @@ -53,15 +53,16 @@ terminate/2, code_change/3]). -export([update/0, get_total_memory/1, - get_check_interval/0, set_check_interval/1, - get_vm_memory_high_watermark/0, set_vm_memory_high_watermark/1]). + get_check_interval/0, set_check_interval/1, + get_vm_memory_high_watermark/0, set_vm_memory_high_watermark/1]). -define(SERVER, ?MODULE). -define(DEFAULT_MEMORY_CHECK_INTERVAL, 1000). -%% For unknown OS, we assume that we have 512 MB of memory, which is pretty -%% safe value, even for 32 bit systems. It's better to be slow than to crash. +%% For unknown OS, we assume that we have 512 MB of memory, which is +%% pretty safe value, even for 32 bit systems. It's better to be slow +%% than to crash. -define(MEMORY_SIZE_FOR_UNKNOWN_OS, 512*1024*1024). -record(state, {total_memory, @@ -72,17 +73,78 @@ }). %%---------------------------------------------------------------------------- +%% gen_server callbacks +%%---------------------------------------------------------------------------- start_link(Args) -> gen_server2:start_link({local, ?SERVER}, ?MODULE, [Args], []). +init([MemFraction]) -> + TotalMemory = + case get_total_memory(os:type()) of + unknown -> + rabbit_log:info("Unknown total memory size for your OS ~p. " + "Assuming memory size is ~p bytes.~n", + [os:type(), ?MEMORY_SIZE_FOR_UNKNOWN_OS]), + ?MEMORY_SIZE_FOR_UNKNOWN_OS; + M -> M + end, + MemLimit = get_mem_limit(MemFraction, TotalMemory), + rabbit_log:info("Memory limit set to ~pMiB.~n", + [trunc(MemLimit/1048576)]), + TRef = start_timer(?DEFAULT_MEMORY_CHECK_INTERVAL), + State = #state { total_memory = TotalMemory, + memory_limit = MemLimit, + timeout = ?DEFAULT_MEMORY_CHECK_INTERVAL, + timer = TRef, + alarmed = false}, + {ok, internal_update(State)}. + +handle_call(get_vm_memory_high_watermark, _From, State) -> + {reply, State#state.memory_limit / State#state.total_memory, State}; + +handle_call({set_vm_memory_high_watermark, MemFraction}, _From, State) -> + MemLimit = get_mem_limit(MemFraction, State#state.total_memory), + rabbit_log:info("Memory alarm changed to ~p, ~p bytes.~n", + [MemFraction, MemLimit]), + {reply, ok, State#state{memory_limit = MemLimit}}; + +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) -> + {noreply, internal_update(State)}; + +handle_cast(_Request, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------------- +%% Public API +%%---------------------------------------------------------------------------- + update() -> gen_server2:cast(?SERVER, update). -%%---------------------------------------------------------------------------- %% get_total_memory(OS) -> Total %% Windows and Freebsd code based on: memsup:get_memory_usage/1 -%% Original code was part of OTP and released under "Erlang Public License". +%% Original code was part of OTP and released under "Erlang Public +%% License". %% Darwin: Uses vm_stat command. get_total_memory({unix,darwin}) -> @@ -96,16 +158,16 @@ get_total_memory({unix,darwin}) -> MemTotal = PageSize * (Inactive + Active + Free + Wired), MemTotal; -%% FreeBSD: Look in /usr/include/sys/vmmeter.h for the format of struct -%% vmmeter +%% FreeBSD: Look in /usr/include/sys/vmmeter.h for the format of +%% struct vmmeter get_total_memory({unix,freebsd}) -> PageSize = freebsd_sysctl("vm.stats.vm.v_page_size"), PageCount = freebsd_sysctl("vm.stats.vm.v_page_count"), NMemTotal = PageCount * PageSize, NMemTotal; -%% Win32: Find out how much memory is in use by asking -%% the os_mon_sysinfo process. +%% Win32: Find out how much memory is in use by asking the +%% os_mon_sysinfo process. get_total_memory({win32,_OSname}) -> [Result|_] = os_mon_sysinfo:get_mem_info(), {ok, [_MemLoad, TotPhys, _AvailPhys, @@ -127,11 +189,26 @@ get_total_memory({unix, sunos}) -> Dict = dict:from_list(lists:map(fun parse_line_sunos/1, Lines)), MemTotal = dict:fetch('Memory size', Dict), MemTotal; - get_total_memory(_OsType) -> unknown. +get_check_interval() -> + gen_server2:call(?MODULE, get_check_interval). + +set_check_interval(Fraction) -> + gen_server2:call(?MODULE, {set_check_interval, Fraction}). + +get_vm_memory_high_watermark() -> + gen_server2:call(?MODULE, get_vm_memory_high_watermark). + +set_vm_memory_high_watermark(Fraction) -> + gen_server2:call(?MODULE, {set_vm_memory_high_watermark, Fraction}). + +%%---------------------------------------------------------------------------- +%% Internal Helpers +%%---------------------------------------------------------------------------- + %% A line looks like "Foo bar: 123456." parse_line_mach(Line) -> [Name, RHS | _Rest] = string:tokens(Line, ":"), @@ -181,107 +258,37 @@ parse_line_sunos(Line) -> [Name, RHS | _Rest] -> [Value1 | UnitsRest] = string:tokens(RHS, " "), Value2 = case UnitsRest of - ["Gigabytes"] -> list_to_integer(Value1) * 1024 * 1024 * 1024; - ["Megabytes"] -> list_to_integer(Value1) * 1024 * 1024; - ["Kilobytes"] -> list_to_integer(Value1) * 1024; - _ -> Value1 ++ UnitsRest %% no known units - end, + ["Gigabytes"] -> + list_to_integer(Value1) * 1024 * 1024 * 1024; + ["Megabytes"] -> + list_to_integer(Value1) * 1024 * 1024; + ["Kilobytes"] -> + list_to_integer(Value1) * 1024; + _ -> + Value1 ++ UnitsRest %% no known units + end, {list_to_atom(Name), Value2}; [Name] -> {list_to_atom(Name), none} end. - - -%%---------------------------------------------------------------------------- - -%% On a 32-bit machine, if you're using more than 2 gigs of RAM -%% you're in big trouble anyway. +%% On a 32-bit machine, if you're using more than 2 gigs of RAM you're +%% in big trouble anyway. get_vm_limit() -> case erlang:system_info(wordsize) of 4 -> 2*1024*1024*1024; % 2 GiB for 32 bits 8 -> 64*1024*1024*1024*1024 % 64 TiB for 64 bits end. - get_mem_limit(MemFraction, TotalMemory) -> - lists:min([trunc(TotalMemory * MemFraction), - get_vm_limit()]). - -init([MemFraction]) -> - TotalMemory = case get_total_memory(os:type()) of - unknown -> - rabbit_log:info("Unknown total memory size for your OS ~p. " - "Assuming memory size is ~p bytes.~n", - [os:type(), ?MEMORY_SIZE_FOR_UNKNOWN_OS]), - ?MEMORY_SIZE_FOR_UNKNOWN_OS; - M -> M - end, - MemLimit = get_mem_limit(MemFraction, TotalMemory), - rabbit_log:info("Memory limit set to ~pMiB.~n", - [trunc(MemLimit/1048576)]), - TRef = start_timer(?DEFAULT_MEMORY_CHECK_INTERVAL), - State = #state { total_memory = TotalMemory, - memory_limit = MemLimit, - timeout = ?DEFAULT_MEMORY_CHECK_INTERVAL, - timer = TRef, - alarmed = false}, - {ok, internal_update(State)}. + lists:min([trunc(TotalMemory * MemFraction), get_vm_limit()]). start_timer(Timeout) -> {ok, TRef} = timer:apply_interval(Timeout, ?MODULE, update, []), TRef. - -get_check_interval() -> - gen_server2:call(?MODULE, get_check_interval). - -set_check_interval(Fraction) -> - gen_server2:call(?MODULE, {set_check_interval, Fraction}). - -get_vm_memory_high_watermark() -> - gen_server2:call(?MODULE, get_vm_memory_high_watermark). - -set_vm_memory_high_watermark(Fraction) -> - gen_server2:call(?MODULE, {set_vm_memory_high_watermark, Fraction}). - - -handle_call(get_vm_memory_high_watermark, _From, State) -> - {reply, State#state.memory_limit / State#state.total_memory, State}; - -handle_call({set_vm_memory_high_watermark, MemFraction}, _From, State) -> - MemLimit = get_mem_limit(MemFraction, State#state.total_memory), - rabbit_log:info("Memory alarm changed to ~p, ~p bytes.~n", - [MemFraction, MemLimit]), - {reply, ok, State#state{memory_limit = MemLimit}}; - -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) -> - {noreply, internal_update(State)}; - -handle_cast(_Request, State) -> - {noreply, State}. - -handle_info(_Info, State) -> - {noreply, State}. - -terminate(_Reason, _State) -> - ok. - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - emit_update_info(State, MemUsed, MemLimit) -> rabbit_log:info("vm_memory_high_watermark ~p. Memory used:~p allowed:~p~n", - [State, MemUsed, MemLimit]). + [State, MemUsed, MemLimit]). internal_update(State = #state { memory_limit = MemLimit, alarmed = Alarmed}) -> @@ -296,6 +303,5 @@ internal_update(State = #state { memory_limit = MemLimit, alarm_handler:clear_alarm(vm_memory_high_watermark); _ -> ok - end, + end, State #state {alarmed = NewAlarmed}. - |