Use index tables to clean up statistics database
This commit is contained in:
parent
dc99947b06
commit
a54cdfe118
|
|
@ -54,8 +54,19 @@
|
|||
{node_node_coarse_stats, set},
|
||||
{queue_msg_rates, set},
|
||||
{vhost_msg_rates, set},
|
||||
{old_aggr_stats, set}
|
||||
]).
|
||||
{old_aggr_stats, set}]).
|
||||
|
||||
-define(INDEX_TABLES, [consumer_stats_queue_index,
|
||||
consumer_stats_channel_index,
|
||||
old_aggr_stats_queue_index,
|
||||
old_aggr_stats_channel_index,
|
||||
channel_exchange_stats_fine_stats_exchange_index,
|
||||
channel_exchange_stats_fine_stats_channel_index,
|
||||
channel_queue_stats_deliver_stats_queue_index,
|
||||
channel_queue_stats_deliver_stats_channel_index,
|
||||
queue_exchange_stats_publish_queue_index,
|
||||
queue_exchange_stats_publish_exchange_index,
|
||||
node_node_coarse_stats_node_index]).
|
||||
|
||||
-define(GC_EVENTS, [connection_closed, channel_closed, consumer_deleted,
|
||||
exchange_deleted, queue_deleted, vhost_deleted,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
-include_lib("rabbit_common/include/rabbit.hrl").
|
||||
-include("rabbit_mgmt_metrics.hrl").
|
||||
|
||||
-behaviour(gen_server2).
|
||||
-behaviour(gen_server).
|
||||
|
||||
-spec start_link(atom()) -> rabbit_types:ok_pid_or_error().
|
||||
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
-export([delete_queue/3]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
-export([index_table/2]).
|
||||
|
||||
-import(rabbit_misc, [pget/3]).
|
||||
-import(rabbit_mgmt_db, [pget/2, lookup_element/3]).
|
||||
|
|
@ -38,16 +39,16 @@ name(Table) ->
|
|||
list_to_atom((atom_to_list(Table) ++ "_metrics_collector")).
|
||||
|
||||
start_link(Table) ->
|
||||
gen_server2:start_link({local, name(Table)}, ?MODULE, [Table], []).
|
||||
gen_server:start_link({local, name(Table)}, ?MODULE, [Table], []).
|
||||
|
||||
override_lookups(Table, Lookups) ->
|
||||
gen_server2:call(name(Table), {override_lookups, Lookups}, infinity).
|
||||
gen_server:call(name(Table), {override_lookups, Lookups}, infinity).
|
||||
|
||||
reset_lookups(Table) ->
|
||||
gen_server2:call(name(Table), reset_lookups, infinity).
|
||||
gen_server:call(name(Table), reset_lookups, infinity).
|
||||
|
||||
delete_queue(Table, Queue, Stats) ->
|
||||
gen_server2:cast(name(Table), {delete_queue, Queue, Stats}).
|
||||
gen_server:cast(name(Table), {delete_queue, Queue, Stats}).
|
||||
|
||||
init([Table]) ->
|
||||
{ok, RatesMode} = application:get_env(rabbitmq_management, rates_mode),
|
||||
|
|
@ -70,6 +71,8 @@ handle_call(reset_lookups, _From, State) ->
|
|||
handle_call({override_lookups, Lookups}, _From, State) ->
|
||||
{reply, ok, State#state{lookup_queue = pget(queue, Lookups),
|
||||
lookup_exchange = pget(exchange, Lookups)}};
|
||||
handle_call({submit, Fun}, _From, State) ->
|
||||
{reply, Fun(), State};
|
||||
handle_call(_Request, _From, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
|
|
@ -164,6 +167,8 @@ aggregate_entry(TS, {{Ch, X} = Id, Metrics}, #state{table = channel_exchange_met
|
|||
pget(return_unroutable, Metrics, 0)),
|
||||
{Publish, _, _} = Diff = get_difference(Id, Stats),
|
||||
ets:insert(old_aggr_stats, ?old_aggr_stats(Id, Stats)),
|
||||
%% Custom insert for channel only to avoid ambiguity with {Channel, Queue} key
|
||||
ets:insert(index_table(old_aggr_stats, channel), {Ch, Id}),
|
||||
[begin
|
||||
insert_entry(channel_stats_fine_stats, Ch, TS, Diff, Size, Interval,
|
||||
true),
|
||||
|
|
@ -197,7 +202,7 @@ aggregate_entry(TS, {{Ch, Q} = Id, Metrics}, #state{table = channel_queue_metric
|
|||
pget(ack, Metrics, 0),
|
||||
Deliver + DeliverNoAck + Get + GetNoAck),
|
||||
Diff = get_difference(Id, Stats),
|
||||
ets:insert(old_aggr_stats, ?old_aggr_stats(Id, Stats)),
|
||||
insert_with_index(old_aggr_stats, Id, ?old_aggr_stats(Id, Stats)),
|
||||
[begin
|
||||
insert_entry(vhost_stats_deliver_stats, vhost(Q), TS, Diff, Size,
|
||||
Interval, true),
|
||||
|
|
@ -259,7 +264,7 @@ aggregate_entry(_TS, {Id, Exclusive, AckRequired, PrefetchCount, Args},
|
|||
{ack_required, AckRequired},
|
||||
{prefetch_count, PrefetchCount},
|
||||
{arguments, Args}], {[], false}),
|
||||
ets:insert(consumer_stats, ?consumer_stats(Id, Fmt)),
|
||||
insert_with_index(consumer_stats, Id, ?consumer_stats(Id, Fmt)),
|
||||
ok;
|
||||
aggregate_entry(TS, {Id, Metrics}, #state{table = queue_metrics,
|
||||
policies = {BPolicies, _, GPolicies},
|
||||
|
|
@ -344,7 +349,7 @@ insert_entry(Table, Id, TS, Entry, Size, Interval, Incremental) ->
|
|||
exometer_slide:new(Size * 1000, [{interval, Interval * 1000},
|
||||
{incremental, Incremental}])
|
||||
end,
|
||||
ets:insert(Table, {Key, exometer_slide:add_element(TS, Entry, Slide)}).
|
||||
insert_with_index(Table, Key, {Key, exometer_slide:add_element(TS, Entry, Slide)}).
|
||||
|
||||
get_difference(Id, Stats) ->
|
||||
case ets:lookup(old_aggr_stats, Id) of
|
||||
|
|
@ -385,3 +390,39 @@ queue_exists(Name) ->
|
|||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
insert_with_index(Table, Key, Tuple) ->
|
||||
Insert = ets:insert(Table, Tuple),
|
||||
insert_index(Table, Key),
|
||||
Insert.
|
||||
|
||||
insert_index(consumer_stats, {Q, Ch, _} = Key) ->
|
||||
ets:insert(index_table(consumer_stats, queue), {Q, Key}),
|
||||
ets:insert(index_table(consumer_stats, channel), {Ch, Key});
|
||||
insert_index(old_aggr_stats, {Ch, Q} = Key) ->
|
||||
ets:insert(index_table(old_aggr_stats, queue), {Q, Key}),
|
||||
ets:insert(index_table(old_aggr_stats, channel), {Ch, Key});
|
||||
insert_index(channel_exchange_stats_fine_stats, {{Ch, Ex}, _} = Key) ->
|
||||
ets:insert(index_table(channel_exchange_stats_fine_stats, exchange), {Ex, Key}),
|
||||
ets:insert(index_table(channel_exchange_stats_fine_stats, channel), {Ch, Key});
|
||||
insert_index(channel_queue_stats_deliver_stats, {{Ch, Q}, _} = Key) ->
|
||||
ets:insert(index_table(channel_queue_stats_deliver_stats, queue), {Q, Key}),
|
||||
ets:insert(index_table(channel_queue_stats_deliver_stats, channel), {Ch, Key});
|
||||
insert_index(queue_exchange_stats_publish, {{Q, Ex}, _} = Key) ->
|
||||
ets:insert(index_table(queue_exchange_stats_publish, queue), {Q, Key}),
|
||||
ets:insert(index_table(queue_exchange_stats_publish, exchange), {Ex, Key});
|
||||
insert_index(node_node_coarse_stats, {{_, Node}, _} = Key) ->
|
||||
ets:insert(index_table(node_node_coarse_stats, node), {Node, Key});
|
||||
insert_index(_, _) -> ok.
|
||||
|
||||
index_table(consumer_stats, queue) -> consumer_stats_queue_index;
|
||||
index_table(consumer_stats, channel) -> consumer_stats_channel_index;
|
||||
index_table(old_aggr_stats, queue) -> old_aggr_stats_queue_index;
|
||||
index_table(old_aggr_stats, channel) -> old_aggr_stats_channel_index;
|
||||
index_table(channel_exchange_stats_fine_stats, exchange) -> channel_exchange_stats_fine_stats_exchange_index;
|
||||
index_table(channel_exchange_stats_fine_stats, channel) -> channel_exchange_stats_fine_stats_channel_index;
|
||||
index_table(channel_queue_stats_deliver_stats, queue) -> channel_queue_stats_deliver_stats_queue_index;
|
||||
index_table(channel_queue_stats_deliver_stats, channel) -> channel_queue_stats_deliver_stats_channel_index;
|
||||
index_table(queue_exchange_stats_publish, queue) -> queue_exchange_stats_publish_queue_index;
|
||||
index_table(queue_exchange_stats_publish, exchange) -> queue_exchange_stats_publish_exchange_index;
|
||||
index_table(node_node_coarse_stats, node) -> node_node_coarse_stats_node_index.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ name(EventType) ->
|
|||
list_to_atom((atom_to_list(EventType) ++ "_metrics_gc")).
|
||||
|
||||
start_link(EventType) ->
|
||||
gen_server2:start_link({local, name(EventType)}, ?MODULE, [], []).
|
||||
gen_server:start_link({local, name(EventType)}, ?MODULE, [], []).
|
||||
|
||||
init(_) ->
|
||||
{ok, Policies} = application:get_env(
|
||||
|
|
@ -64,8 +64,7 @@ handle_cast({event, #event{type = exchange_deleted, props = Props}},
|
|||
remove_exchange(Name, Intervals),
|
||||
{noreply, State};
|
||||
handle_cast({event, #event{type = queue_deleted, props = Props}},
|
||||
State = #state{basic_i = BIntervals,
|
||||
detailed_i = DIntervals}) ->
|
||||
State = #state{basic_i = BIntervals, detailed_i = DIntervals}) ->
|
||||
Name = pget(name, Props),
|
||||
remove_queue(Name, BIntervals, DIntervals),
|
||||
{noreply, State};
|
||||
|
|
@ -102,30 +101,30 @@ remove_channel(Id, Intervals) ->
|
|||
delete_samples(channel_process_stats, Id, Intervals),
|
||||
delete_samples(channel_stats_fine_stats, Id, Intervals),
|
||||
delete_samples(channel_stats_deliver_stats, Id, Intervals),
|
||||
ets:select_delete(consumer_stats, match_consumer_spec(Id)),
|
||||
ets:select_delete(old_aggr_stats, match_spec(Id)),
|
||||
ets:select_delete(channel_exchange_stats_fine_stats, match_interval_spec(Id)),
|
||||
ets:select_delete(channel_queue_stats_deliver_stats, match_interval_spec(Id)),
|
||||
index_delete(consumer_stats, channel, Id),
|
||||
index_delete(old_aggr_stats, channel, Id),
|
||||
index_delete(channel_exchange_stats_fine_stats, channel, Id),
|
||||
index_delete(channel_queue_stats_deliver_stats, channel, Id),
|
||||
ok.
|
||||
|
||||
remove_consumer(Props) ->
|
||||
Id = {pget(queue, Props), pget(channel, Props), pget(consumer_tag, Props)},
|
||||
ets:delete(consumer_stats, Id).
|
||||
ets:delete(consumer_stats, Id),
|
||||
cleanup_index(consumer_stats, Id).
|
||||
|
||||
remove_exchange(Name, Intervals) ->
|
||||
delete_samples(exchange_stats_publish_out, Name, Intervals),
|
||||
delete_samples(exchange_stats_publish_in, Name, Intervals),
|
||||
ets:select_delete(queue_exchange_stats_publish, match_second_interval_spec({Name})),
|
||||
ets:select_delete(channel_exchange_stats_fine_stats, match_second_interval_spec({Name})).
|
||||
index_delete(queue_exchange_stats_publish, exchange, Name),
|
||||
index_delete(channel_exchange_stats_fine_stats, exchange, Name).
|
||||
|
||||
remove_queue(Name, BIntervals, DIntervals) ->
|
||||
ets:delete(queue_stats, Name),
|
||||
delete_samples(queue_stats_publish, Name, DIntervals),
|
||||
delete_samples(queue_stats_deliver_stats, Name, DIntervals),
|
||||
ets:select_delete(channel_queue_stats_deliver_stats, match_second_interval_spec({Name})),
|
||||
ets:select_delete(queue_exchange_stats_publish, match_interval_spec({Name})),
|
||||
delete_samples(queue_process_stats, Name, BIntervals),
|
||||
delete_samples(queue_msg_stats, Name, BIntervals),
|
||||
delete_samples(queue_msg_rates, Name, BIntervals),
|
||||
%% vhost message counts must be updated with the deletion of the messages in this queue
|
||||
case ets:lookup(old_aggr_stats, Name) of
|
||||
[{Name, Stats}] ->
|
||||
|
|
@ -135,8 +134,12 @@ remove_queue(Name, BIntervals, DIntervals) ->
|
|||
end,
|
||||
ets:delete(old_aggr_stats, Name),
|
||||
ets:delete(old_aggr_stats, {Name, rates}),
|
||||
ets:select_delete(old_aggr_stats, match_second_spec({Name})),
|
||||
ets:select_delete(consumer_stats, match_queue_consumer_spec({Name})),
|
||||
|
||||
index_delete(channel_queue_stats_deliver_stats, queue, Name),
|
||||
index_delete(queue_exchange_stats_publish, queue, Name),
|
||||
index_delete(old_aggr_stats, queue, Name),
|
||||
index_delete(consumer_stats, queue, Name),
|
||||
|
||||
ok.
|
||||
|
||||
remove_vhost(Name, BIntervals, DIntervals) ->
|
||||
|
|
@ -145,7 +148,7 @@ remove_vhost(Name, BIntervals, DIntervals) ->
|
|||
delete_samples(vhost_stats_deliver_stats, Name, DIntervals).
|
||||
|
||||
remove_node_node(Name) ->
|
||||
ets:select_delete(node_node_coarse_stats, match_second_interval_spec({Name})).
|
||||
index_delete(node_node_coarse_stats, node, Name).
|
||||
|
||||
intervals(Type, Policies) ->
|
||||
[I || {_, I} <- proplists:get_value(Type, Policies)].
|
||||
|
|
@ -153,20 +156,12 @@ intervals(Type, Policies) ->
|
|||
delete_samples(Table, Id, Intervals) ->
|
||||
[ets:delete(Table, {Id, I}) || I <- Intervals].
|
||||
|
||||
match_spec(Id) ->
|
||||
[{{{'$1', '_'}, '_'}, [{'==', Id, '$1'}], [true]}].
|
||||
index_delete(Table, Type, Id) ->
|
||||
IndexTable = rabbit_mgmt_metrics_collector:index_table(Table, Type),
|
||||
Keys = ets:lookup(IndexTable, Id),
|
||||
[ ets:delete(Table, Key) || Key <- Keys ],
|
||||
ets:delete(IndexTable, Id).
|
||||
|
||||
match_second_spec(Id) ->
|
||||
[{{{'_', '$1'}, '_'}, [{'==', Id, '$1'}], [true]}].
|
||||
|
||||
match_interval_spec(Id) ->
|
||||
[{{{{'$1', '_'}, '_'}, '_'}, [{'==', Id, '$1'}], [true]}].
|
||||
|
||||
match_second_interval_spec(Id) ->
|
||||
[{{{{'_', '$1'}, '_'}, '_'}, [{'==', Id, '$1'}], [true]}].
|
||||
|
||||
match_consumer_spec(Id) ->
|
||||
[{{{'_', '$1', '_'}, '_'}, [{'==', Id, '$1'}], [true]}].
|
||||
|
||||
match_queue_consumer_spec(Id) ->
|
||||
[{{{'$1', '_', '_'}, '_'}, [{'==', Id, '$1'}], [true]}].
|
||||
cleanup_index(consumer_stats, {Q, Ch, _} = Key) ->
|
||||
ets:delete_object(consumer_stats_queue_index, {Q, Key}),
|
||||
ets:delete_object(consumer_stats_channel_index, {Ch, Key}).
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ start_link() ->
|
|||
|
||||
init(_) ->
|
||||
[ets:new(Key, [public, Type, named_table]) || {Key, Type} <- ?TABLES],
|
||||
[ets:new(Key, [public, bag, named_table]) || Key <- ?INDEX_TABLES],
|
||||
{ok, #state{}}.
|
||||
|
||||
handle_call(_Request, _From, State) ->
|
||||
|
|
|
|||
Loading…
Reference in New Issue