diff options
author | kjnilsson <knilsson@pivotal.io> | 2020-03-09 13:09:49 +0000 |
---|---|---|
committer | Gerhard Lazu <gerhard@lazu.co.uk> | 2020-03-12 17:42:00 +0000 |
commit | fa502138b974933d6bbb7b70d1fee76f9cb0debf (patch) | |
tree | 138ef7a97d66b743a851b0486c22fe3c3e433330 | |
parent | c503d57e884dd440aa6b830bb9835be4dd2d8f69 (diff) | |
download | rabbitmq-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.erl | 39 | ||||
-rw-r--r-- | src/rabbit_fifo.hrl | 3 |
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(), |