You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ko...@apache.org on 2009/11/04 17:01:54 UTC

svn commit: r832780 - /couchdb/branches/0.10.x/src/couchdb/couch_stats_aggregator.erl

Author: kocolosk
Date: Wed Nov  4 16:01:54 2009
New Revision: 832780

URL: http://svn.apache.org/viewvc?rev=832780&view=rev
Log:
eliminate new process flood on waking. COUCHDB-539

This patch works towards the same goal as r832477 and r832519, but because
the code bases have diverged the implementation is a bit different.  Still
the same philosophy of using apply_after instead of apply_interval, but we
now have to track a few more timers.

Modified:
    couchdb/branches/0.10.x/src/couchdb/couch_stats_aggregator.erl

Modified: couchdb/branches/0.10.x/src/couchdb/couch_stats_aggregator.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.10.x/src/couchdb/couch_stats_aggregator.erl?rev=832780&r1=832779&r2=832780&view=diff
==============================================================================
--- couchdb/branches/0.10.x/src/couchdb/couch_stats_aggregator.erl (original)
+++ couchdb/branches/0.10.x/src/couchdb/couch_stats_aggregator.erl Wed Nov  4 16:01:54 2009
@@ -24,7 +24,8 @@
 
 -record(state, {
     aggregates = [],
-    descriptions = []
+    descriptions = [],
+    timer_refs = []
 }).
 
 -define(COLLECTOR, couch_stats_collector).
@@ -49,10 +50,10 @@
     gen_server:call(?MODULE, {get_json, Key, Time}).
 
 time_passed() ->
-    gen_server:call(?MODULE, time_passed).
+    gen_server:call(?MODULE, time_passed, infinity).
 
 clear_aggregates(Time) ->
-    gen_server:call(?MODULE, {clear_aggregates, Time}).
+    gen_server:call(?MODULE, {clear_aggregates, Time}, infinity).
 
 all() ->
     gen_server:call(?MODULE, all).
@@ -61,9 +62,9 @@
 
 init(_) ->
     ets:new(?MODULE, [named_table, set, protected]),
-    init_timers(),
+    TimerRefs = init_timers(),
     init_descriptions(),
-    {ok, #state{}}.
+    {ok, #state{timer_refs = TimerRefs}}.
 
 handle_call({get, Key}, _, State) ->
     Value = get_aggregate(Key, State),
@@ -82,7 +83,7 @@
     {reply, Value, State};
 
 handle_call(time_passed, _, OldState) ->
-
+    NewTimerRefs = update_timer(time_passed, OldState#state.timer_refs),
     % the foldls below could probably be refactored into a less code-duping form
 
     % update aggregates on incremental counters
@@ -99,7 +100,7 @@
         update_aggregates_loop(Key, Value, State, absolute)
     end, NextState, ?COLLECTOR:all(absolute)),
 
-    {reply, ok, NewState};
+    {reply, ok, NewState#state{timer_refs = NewTimerRefs}};
 
 handle_call({clear_aggregates, Time}, _, State) ->
     {reply, ok, do_clear_aggregates(Time, State)};
@@ -130,7 +131,8 @@
 % ]
 
 %% clear the aggregats record for a specific Time = 60 | 300 | 900
-do_clear_aggregates(Time, #state{aggregates=Stats}) ->
+do_clear_aggregates(Time, #state{aggregates=Stats, timer_refs=Refs}) ->
+    NewTimerRefs = update_timer(Time, Refs),
     NewStats = lists:map(fun({Key, TimesProplist}) ->
         {Key, case proplists:lookup(Time, TimesProplist) of
             % do have stats for this key, if we don't, return Stat unmodified
@@ -141,7 +143,7 @@
                 [{Time, #aggregates{}} | proplists:delete(Time, TimesProplist)]
         end}
     end, Stats),
-    #state{aggregates=NewStats}.
+    #state{aggregates=NewStats, timer_refs=NewTimerRefs}.
 
 get_aggregate(Key, State) ->
     %% default Time is 0, which is when CouchDB started
@@ -354,11 +356,22 @@
     % too and restarted by the supervision tree, all stats (for the last
     % fifteen minutes) are gone.
 
-    {ok, _} = timer:apply_interval(1000, ?MODULE, time_passed, []),
-    {ok, _} = timer:apply_interval(60000, ?MODULE, clear_aggregates, ['60']),
-    {ok, _} = timer:apply_interval(300000, ?MODULE, clear_aggregates, ['300']),
-    {ok, _} = timer:apply_interval(900000, ?MODULE, clear_aggregates, ['900']).
-
+    {ok, A} = timer:apply_after(1000, ?MODULE, time_passed, []),
+    {ok, B} = timer:apply_after(60000, ?MODULE, clear_aggregates, ['60']),
+    {ok, C} = timer:apply_after(300000, ?MODULE, clear_aggregates, ['300']),
+    {ok, D} = timer:apply_after(900000, ?MODULE, clear_aggregates, ['900']),
+    [{time_passed,A}, {'60',B}, {'300',C}, {'900',D}].
+
+update_timer(Type, Refs) ->
+    timer:cancel(proplists:get_value(Type, Refs)),
+    {ok,NewRef} =
+    if Type == time_passed ->
+        timer:apply_after(1000, ?MODULE, time_passed, []);
+    true ->
+        IntType = list_to_integer(atom_to_list(Type)),
+        timer:apply_after(1000*IntType, ?MODULE, clear_aggregates, [Type])
+    end,
+    [{Type,NewRef} | proplists:delete(Type, Refs)].
 
 % Unused gen_server behaviour API functions that we need to declare.