diff options
author | Paul Joseph Davis <davisp@apache.org> | 2009-09-17 04:04:46 +0000 |
---|---|---|
committer | Paul Joseph Davis <davisp@apache.org> | 2009-09-17 04:04:46 +0000 |
commit | 4ddb75549c6565b5a2ca9edec0d965bdf53eed11 (patch) | |
tree | 3e4b30f1429857f08a399e14f0cd1848e2d1cd4e /src/couchdb/couch_stats_collector.erl | |
parent | da4f4a1b69f40c8847131f6103d8faca2ef4602c (diff) |
Fixes COUCHDB-396
Makes the stats calculated over a moving window isntead of calculated for non-overlapping timeframes. This should make trend monitoring more robust.
Thanks once again to Bob Dionne for double checking this.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@816043 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/couchdb/couch_stats_collector.erl')
-rw-r--r-- | src/couchdb/couch_stats_collector.erl | 143 |
1 files changed, 66 insertions, 77 deletions
diff --git a/src/couchdb/couch_stats_collector.erl b/src/couchdb/couch_stats_collector.erl index 327a37c1..59d62a6e 100644 --- a/src/couchdb/couch_stats_collector.erl +++ b/src/couchdb/couch_stats_collector.erl @@ -18,23 +18,15 @@ -behaviour(gen_server). --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). +-export([start/0, stop/0]). +-export([all/0, all/1, get/1, increment/1, decrement/1, record/2, clear/1]). +-export([track_process_count/1, track_process_count/2]). +-export([init/1, terminate/2, code_change/3]). +-export([handle_call/3, handle_cast/2, handle_info/2]). --export([start/0, stop/0, get/1, - increment/1, decrement/1, - track_process_count/1, track_process_count/2, - record/2, clear/1, - all/0, all/1]). - --record(state, {}). - --define(ABSOLUTE_VALUE_COUNTER_TABLE, abs_table). --define(HIT_COUNTER_TABLE, hit_table). - - -% PUBLIC API +-define(HIT_TABLE, stats_hit_table). +-define(ABS_TABLE, stats_abs_table). start() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). @@ -42,106 +34,103 @@ start() -> stop() -> gen_server:call(?MODULE, stop). +all() -> + ets:tab2list(?HIT_TABLE) ++ abs_to_list(). + +all(Type) -> + case Type of + incremental -> ets:tab2list(?HIT_TABLE); + absolute -> abs_to_list() + end. + get(Key) -> - case ets:lookup(?HIT_COUNTER_TABLE, Key) of + case ets:lookup(?HIT_TABLE, Key) of [] -> - case ets:lookup(?ABSOLUTE_VALUE_COUNTER_TABLE, Key) of + case ets:lookup(?ABS_TABLE, Key) of [] -> - 0; - Result2 -> extract_value_from_ets_result(Key, Result2) + nil; + AbsVals -> + lists:map(fun({_, Value}) -> Value end, AbsVals) end; - [{_,Result1}] -> Result1 + [{_, Counter}] -> + Counter end. -increment({Module, Key}) when is_integer(Key) -> - increment({Module, list_to_atom(integer_to_list(Key))}); increment(Key) -> - case catch ets:update_counter(?HIT_COUNTER_TABLE, Key, 1) of + Key2 = make_key(Key), + case catch ets:update_counter(?HIT_TABLE, Key2, 1) of {'EXIT', {badarg, _}} -> - true = ets:insert(?HIT_COUNTER_TABLE, {Key, 1}), + true = ets:insert(?HIT_TABLE, {Key2, 1}), ok; - _ -> ok + _ -> + ok end. decrement(Key) -> - case catch ets:update_counter(?HIT_COUNTER_TABLE, Key, -1) of + Key2 = make_key(Key), + case catch ets:update_counter(?HIT_TABLE, Key2, -1) of {'EXIT', {badarg, _}} -> - true = ets:insert(?HIT_COUNTER_TABLE, {Key, -1}), + true = ets:insert(?HIT_TABLE, {Key2, -1}), ok; _ -> ok end. record(Key, Value) -> - ets:insert(?ABSOLUTE_VALUE_COUNTER_TABLE, {Key, Value}). + true = ets:insert(?ABS_TABLE, {make_key(Key), Value}). clear(Key) -> - true = ets:delete(?ABSOLUTE_VALUE_COUNTER_TABLE, Key). - -all() -> - lists:append(ets:tab2list(?HIT_COUNTER_TABLE), - ets:tab2list(?ABSOLUTE_VALUE_COUNTER_TABLE)). - -all(Type) -> - case Type of - incremental -> ets:tab2list(?HIT_COUNTER_TABLE); - absolute -> ets:tab2list(?ABSOLUTE_VALUE_COUNTER_TABLE) - end. + true = ets:delete(?ABS_TABLE, make_key(Key)). track_process_count(Stat) -> track_process_count(self(), Stat). track_process_count(Pid, Stat) -> + MonitorFun = fun() -> + Ref = erlang:monitor(process, Pid), + receive {'DOWN', Ref, _, _, _} -> ok end, + couch_stats_collector:decrement(Stat) + end, case (catch couch_stats_collector:increment(Stat)) of - ok -> - spawn( - fun() -> - erlang:monitor(process, Pid), - receive {'DOWN', _, _, _, _} -> ok end, - couch_stats_collector:decrement(Stat) - end); - _ -> ok + ok -> spawn(MonitorFun); + _ -> ok end. -% GEN_SERVER - - init(_) -> - ets:new(?HIT_COUNTER_TABLE, [named_table, set, public]), - ets:new(?ABSOLUTE_VALUE_COUNTER_TABLE, [named_table, duplicate_bag, public]), - {ok, #state{}}. + ets:new(?HIT_TABLE, [named_table, set, public]), + ets:new(?ABS_TABLE, [named_table, duplicate_bag, public]), + {ok, nil}. +terminate(_Reason, _State) -> + ok. handle_call(stop, _, State) -> {stop, normal, stopped, State}. - -% PRIVATE API - -extract_value_from_ets_result(_Key, Result) -> - lists:map(fun({_, Value}) -> Value end, Result). - - -% Unused gen_server behaviour API functions that we need to declare. - -%% @doc Unused handle_cast(foo, State) -> {noreply, State}. handle_info(_Info, State) -> {noreply, State}. -%% @doc Unused -terminate(_Reason, _State) -> ok. - -%% @doc Unused -code_change(_OldVersion, State, _Extra) -> {ok, State}. - - -%% Tests - --ifdef(TEST). -% Internal API unit tests go here - - --endif. +code_change(_OldVersion, State, _Extra) -> + {ok, State}. + + +make_key({Module, Key}) when is_integer(Key) -> + {Module, list_to_atom(integer_to_list(Key))}; +make_key(Key) -> + Key. + +abs_to_list() -> + SortedKVs = lists:sort(ets:tab2list(?ABS_TABLE)), + lists:foldl(fun({Key, Val}, Acc) -> + case Acc of + [] -> + [{Key, [Val]}]; + [{Key, Prev} | Rest] -> + [{Key, [Val | Prev]} | Rest]; + Others -> + [{Key, [Val]} | Others] + end + end, [], SortedKVs).
\ No newline at end of file |