You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ja...@apache.org on 2019/09/19 10:14:34 UTC

[couchdb] branch feat/intervals created (now 7989b8b)

This is an automated email from the ASF dual-hosted git repository.

jan pushed a change to branch feat/intervals
in repository https://gitbox.apache.org/repos/asf/couchdb.git.


      at 7989b8b  feat: do not run stats aggregations on an interval

This branch includes the following new commits:

     new 7989b8b  feat: do not run stats aggregations on an interval

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[couchdb] 01/01: feat: do not run stats aggregations on an interval

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jan pushed a commit to branch feat/intervals
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 7989b8bb292ebd5ba1c1fa5277b9b9c42e7f08a3
Author: Jan Lehnardt <ja...@apache.org>
AuthorDate: Thu Sep 19 12:01:53 2019 +0200

    feat: do not run stats aggregations on an interval
    
    Similar to 448be7996999a706464d8f7429a56dc9e9c87c3a (hello 0.10.1),
    `timer:{send,apply}_interval()` will apply functions / send messages
    for all intervals that match the time that a machine was in sleep /
    hibernation mode that is common on desktop systems.
    
    In a typical office scneario, a laptop system that sleeps over a
    weekend , when woken up on a monday, issue thousands of function
    calls, that together with other, unrelated wake-up activity, make
    a machine top out its CPU for no good reason.
    
    The change addresses this by instead of relying on an interval to
    start a given task, on startup, start the task once after a timeout,
    and then start a fresh timer after the task is done.
    
    Other than the 0.10-era patch, this one does not account for a system
    waking up before the timeout. I’m happy to add that behaviour, if a
    reviewer insists on it.
    
    As a result, no matter how long the sleep period is, we only run
    the desired function _once_ after we wake up again. In the never-
    sleep scenario, the existing behaviour is retained.
    
    This might impact metrics that have a time component, but I think
    that’s a fair compromise, so I didn’t investigate that further.
---
 src/couch_stats/src/couch_stats_aggregator.erl | 27 +++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/src/couch_stats/src/couch_stats_aggregator.erl b/src/couch_stats/src/couch_stats_aggregator.erl
index 17bd6fc..0bc2bf6 100644
--- a/src/couch_stats/src/couch_stats_aggregator.erl
+++ b/src/couch_stats/src/couch_stats_aggregator.erl
@@ -55,18 +55,19 @@ start_link() ->
 
 init([]) ->
     {ok, Descs} = reload_metrics(),
-    Interval = config:get_integer("stats", "interval", ?DEFAULT_INTERVAL),
-    {ok, CT} = timer:send_interval(Interval * 1000, self(), collect),
-    {ok, RT} = timer:send_interval(?RELOAD_INTERVAL * 1000, self(), reload),
+    {ok, CT} = timer:send_after(get_interval(collect), self(), collect),
+    {ok, RT} = timer:send_after(get_interval(reload), self(), reload),
     {ok, #st{descriptions=Descs, stats=[], collect_timer=CT, reload_timer=RT}}.
 
 handle_call(fetch, _from, #st{stats = Stats}=State) ->
     {reply, {ok, Stats}, State};
 handle_call(flush, _From, State) ->
     {reply, ok, collect(State)};
-handle_call(reload, _from, State) ->
+handle_call(reload, _from, State#st{reload_timer=OldRT}) ->
+    timer:cancel(OldRT),
     {ok, Descriptions} = reload_metrics(),
-    {reply, ok, State#st{descriptions=Descriptions}};
+    {ok, RT} = update_timer(reload),
+    {reply, ok, State#st{descriptions=Descriptions, reload_timer=RT}};
 handle_call(Msg, _From, State) ->
     {stop, {unknown_call, Msg}, error, State}.
 
@@ -140,11 +141,23 @@ load_metrics_for_application(AppName) ->
             end
     end.
 
-collect(State) ->
+collect(State#st{collect_timer=OldCT}) ->
+    timer:cancel(OldCT),
     Stats = lists:map(
         fun({Name, Props}) ->
             {Name, [{value, couch_stats:sample(Name)}|Props]}
         end,
         State#st.descriptions
     ),
-    State#st{stats=Stats}.
+    {ok, CT} = update_timer(collect),
+    State#st{stats=Stats, collect_timer=CT}.
+
+update_timer(collect) ->
+    Interval = get_interval(collect),
+    timer:send_after(Interval, self(), collect);
+update_timer(reload) ->
+    Interval = get_interval(reload),
+    timer:send_after(Interval, self(), reload).
+
+get_interval(reload) -> 1000 * ?RELOAD_INTERVAL;
+get_interval(collect) -> 1000 * config:get_integer("stats", "interval", ?DEFAULT_INTERVAL).