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,