You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2014/08/05 00:18:19 UTC

[17/20] couch commit: updated refs/heads/windsor-merge-102 to 944c542

Allow graceful reloading of OS processes

This patch adds a reload/0 command to couch_proc_manager that will cause
all OS processes to be reclaimed at the next earliest convenience (i.e.,
when the current client is done with the process).  It also adds a
get_stale_proc_count/0 function to report the number of processes that
have yet to be reclaimied.

BugzID: 19529


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/814eadc0
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/814eadc0
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/814eadc0

Branch: refs/heads/windsor-merge-102
Commit: 814eadc09594cff6f1815ade06c4fbb38e65da8d
Parents: 286df6e
Author: Adam Kocoloski <ad...@cloudant.com>
Authored: Mon Jun 3 12:26:35 2013 -0400
Committer: Robert Newson <rn...@apache.org>
Committed: Mon Aug 4 18:39:44 2014 +0100

----------------------------------------------------------------------
 src/couch_proc_manager.erl | 53 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 45 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/814eadc0/src/couch_proc_manager.erl
----------------------------------------------------------------------
diff --git a/src/couch_proc_manager.erl b/src/couch_proc_manager.erl
index 8dd7da4..e0f03e5 100644
--- a/src/couch_proc_manager.erl
+++ b/src/couch_proc_manager.erl
@@ -17,7 +17,13 @@
 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, 
     code_change/3]).
 
--export([start_link/0, get_proc_count/0, new_proc/1]).
+-export([
+    start_link/0,
+    get_proc_count/0,
+    get_stale_proc_count/0,
+    new_proc/1,
+    reload/0
+]).
 
 % config_listener api
 -export([handle_config_change/5]).
@@ -28,7 +34,8 @@
     tab,
     config,
     proc_counts,
-    waiting
+    waiting,
+    threshold_ts
 }).
 
 -record(proc_int, {
@@ -38,7 +45,8 @@
     ddoc_keys = [],
     prompt_fun,
     set_timeout_fun,
-    stop_fun
+    stop_fun,
+    t0
 }).
 
 -record(client, {
@@ -55,6 +63,12 @@ start_link() ->
 get_proc_count() ->
     gen_server:call(?MODULE, get_proc_count).
 
+get_stale_proc_count() ->
+    gen_server:call(?MODULE, get_stale_proc_count).
+
+reload() ->
+    gen_server:call(?MODULE, bump_threshold_ts).
+
 init([]) ->
     process_flag(trap_exit, true),
     ok = config:listen_for_changes(?MODULE, nil),
@@ -63,7 +77,8 @@ init([]) ->
         config = get_proc_config(),
         proc_counts = dict:new(),
         waiting = ets:new(couch_proc_manage_waiting,
-                [ordered_set, {keypos, #client.timestamp}])
+                [ordered_set, {keypos, #client.timestamp}]),
+        threshold_ts = os:timestamp()
     }}.
 
 handle_call(get_table, _From, State) ->
@@ -72,6 +87,11 @@ handle_call(get_table, _From, State) ->
 handle_call(get_proc_count, _From, State) ->
     {reply, ets:info(State#state.tab, size), State};
 
+handle_call(get_stale_proc_count, _From, State) ->
+    #state{tab = Tab, threshold_ts = T0} = State,
+    MatchSpec = [{#proc_int{t0='$1', _='_'}, [{'<', '$1', T0}], [true]}],
+    {reply, ets:select_count(Tab, MatchSpec), State};
+
 handle_call({get_proc, #doc{body={Props}}=DDoc, DDocKey}, From, State) ->
     {ClientPid, _} = From,
     Lang = couch_util:to_binary(
@@ -112,6 +132,16 @@ handle_call({ret_proc, #proc{client=Ref, lang=Lang0} = Proc}, _From, State) ->
     % table before the insert.  Don't know which approach is cheaper.
     {reply, true, return_proc(State, Proc#proc{lang=Lang})};
 
+handle_call(bump_threshold_ts, _From, #state{tab = Tab} = State) ->
+    FoldFun = fun(#proc_int{client = nil, pid = Pid}, _) ->
+        gen_server:cast(Pid, stop),
+        ets:delete(Tab, Pid);
+    (_, _) ->
+        ok
+    end,
+    ets:foldl(FoldFun, nil, Tab),
+    {reply, ok, State#state{threshold_ts = os:timestamp()}};
+
 handle_call(_Call, _From, State) ->
     {reply, ignored, State}.
 
@@ -331,7 +361,8 @@ make_proc(Pid, Lang, Mod) ->
         pid = Pid,
         prompt_fun = {Mod, prompt},
         set_timeout_fun = {Mod, set_timeout},
-        stop_fun = {Mod, stop}
+        stop_fun = {Mod, stop},
+        t0 = os:timestamp()
     },
     unlink(Pid),
     {ok, Proc}.
@@ -345,12 +376,18 @@ assign_proc(Tab, #client{}=Client, #proc{client=nil}=Proc) ->
     assign_proc(Tab, Pid, Proc).
 
 return_proc(State, #proc{pid=Pid, lang=Lang} = Proc) ->
-    #state{tab=Tab, waiting=Waiting} = State,
+    #state{tab=Tab, waiting=Waiting, threshold_ts = T0} = State,
     case is_process_alive(Pid) of true ->
         case get_waiting_client(Waiting, Lang) of
             nil ->
-                gen_server:cast(Pid, garbage_collect),
-                ets:insert(Tab, Proc#proc{client=nil}),
+                [ProcInt] = ets:lookup(Tab, Pid),
+                if ProcInt#proc_int.t0 < T0 ->
+                    gen_server:cast(Pid, stop),
+                    ets:delete(Tab, Pid);
+                true ->
+                    gen_server:cast(Pid, garbage_collect),
+                    ets:insert(Tab, Proc#proc{client=nil})
+                end,
                 State;
             #client{}=Client ->
                 From = Client#client.from,