summaryrefslogtreecommitdiff
path: root/src/couchdb/couch_stats_collector.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/couchdb/couch_stats_collector.erl')
-rw-r--r--src/couchdb/couch_stats_collector.erl127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/couchdb/couch_stats_collector.erl b/src/couchdb/couch_stats_collector.erl
new file mode 100644
index 00000000..8d0234bb
--- /dev/null
+++ b/src/couchdb/couch_stats_collector.erl
@@ -0,0 +1,127 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+% http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+% todo
+% - remove existance check on increment(), decrement() and record(). have
+% modules initialize counters on startup.
+
+-module(couch_stats_collector).
+
+-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, get/1,
+ increment/1, decrement/1,
+ 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
+
+start() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+stop() ->
+ gen_server:call(?MODULE, stop).
+
+get(Key) ->
+ case ets:lookup(?HIT_COUNTER_TABLE, Key) of
+ [] ->
+ case ets:lookup(?ABSOLUTE_VALUE_COUNTER_TABLE, Key) of
+ [] ->
+ 0;
+ Result2 -> extract_value_from_ets_result(Key, Result2)
+ end;
+ [{_,Result1}] -> Result1
+ 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
+ {'EXIT', {badarg, _}} -> ets:insert(?HIT_COUNTER_TABLE, {Key, 1});
+ _ -> ok
+ end.
+
+decrement(Key) ->
+ case catch ets:update_counter(?HIT_COUNTER_TABLE, Key, -1) of
+ {'EXIT', {badarg, _}} -> ets:insert(?HIT_COUNTER_TABLE, {Key, -1});
+ _ -> ok
+ end.
+
+record(Key, Value) ->
+ ets:insert(?ABSOLUTE_VALUE_COUNTER_TABLE, {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.
+
+
+% 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{}}.
+
+
+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. \ No newline at end of file