summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkjnilsson <knilsson@pivotal.io>2020-03-09 13:09:49 +0000
committerGerhard Lazu <gerhard@lazu.co.uk>2020-03-12 17:42:00 +0000
commitfa502138b974933d6bbb7b70d1fee76f9cb0debf (patch)
tree138ef7a97d66b743a851b0486c22fe3c3e433330
parentc503d57e884dd440aa6b830bb9835be4dd2d8f69 (diff)
downloadrabbitmq-server-git-fa502138b974933d6bbb7b70d1fee76f9cb0debf.tar.gz
rabbit_fifo: force gc when queue is empty
And it uses more than a fixed limit of ~2Mb of total memory. An empty queue should only need around ~100-200Kb of memory so this should avoid any unnecessary full sweeps. [#171644231]
-rw-r--r--src/rabbit_fifo.erl39
-rw-r--r--src/rabbit_fifo.hrl3
2 files changed, 35 insertions, 7 deletions
diff --git a/src/rabbit_fifo.erl b/src/rabbit_fifo.erl
index 0f7adfb88d..b6686e452b 100644
--- a/src/rabbit_fifo.erl
+++ b/src/rabbit_fifo.erl
@@ -646,26 +646,51 @@ get_checked_out(Cid, From, To, #?MODULE{consumers = Consumers}) ->
[]
end.
+-record(aux_gc, {last_raft_idx = 0 :: ra:index()}).
+-record(aux, {name :: atom(),
+ utilisation :: term(),
+ gc = #aux_gc{} :: #aux_gc{}}).
+
init_aux(Name) when is_atom(Name) ->
%% TODO: catch specific exception throw if table already exists
ok = ra_machine_ets:create_table(rabbit_fifo_usage,
[named_table, set, public,
{write_concurrency, true}]),
Now = erlang:monotonic_time(micro_seconds),
- {Name, {inactive, Now, 1, 1.0}}.
+ #aux{name = Name,
+ utilisation = {inactive, Now, 1, 1.0}}.
-handle_aux(_, cast, Cmd, {Name, Use0}, Log, _) ->
- Use = case Cmd of
+handle_aux(_RaState, cast, Cmd, #aux{name = Name,
+ utilisation = Use0} = State0,
+ Log, MacState) ->
+ State = case Cmd of
_ when Cmd == active orelse Cmd == inactive ->
- update_use(Use0, Cmd);
+ State0#aux{utilisation = update_use(Use0, Cmd)};
tick ->
true = ets:insert(rabbit_fifo_usage,
{Name, utilisation(Use0)}),
- Use0;
+ eval_gc(Log, MacState, State0);
eval ->
- Use0
+ State0
end,
- {no_reply, {Name, Use}, Log}.
+ {no_reply, State, Log}.
+
+eval_gc(Log, #?MODULE{cfg = #cfg{resource = QR}} = MacState,
+ #aux{gc = #aux_gc{last_raft_idx = LastGcIdx} = Gc} = AuxState) ->
+ {Idx, _} = ra_log:last_index_term(Log),
+ {memory, Mem} = erlang:process_info(self(), memory),
+ case messages_total(MacState) of
+ 0 when Idx > LastGcIdx andalso
+ Mem > ?GC_MEM_LIMIT_B ->
+ garbage_collect(),
+ {memory, MemAfter} = erlang:process_info(self(), memory),
+ rabbit_log:info("~s: forcing full sweep GC "
+ "Before ~b After ~b",
+ [rabbit_misc:rs(QR), Mem, MemAfter]),
+ AuxState#aux{gc = Gc#aux_gc{last_raft_idx = Idx}};
+ _ ->
+ AuxState
+ end.
%%% Queries
diff --git a/src/rabbit_fifo.hrl b/src/rabbit_fifo.hrl
index 2a8899d593..291104f1f8 100644
--- a/src/rabbit_fifo.hrl
+++ b/src/rabbit_fifo.hrl
@@ -70,6 +70,9 @@
-define(RELEASE_CURSOR_EVERY, 64000).
-define(RELEASE_CURSOR_EVERY_MAX, 3200000).
-define(USE_AVG_HALF_LIFE, 10000.0).
+%% an average QQ without any message uses about 100KB so setting this limit
+%% to ~10 times that should be relatively safe.
+-define(GC_MEM_LIMIT_B, 2000000).
-record(consumer,
{meta = #{} :: consumer_meta(),