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/06 13:54:53 UTC
[16/48] couch commit: updated refs/heads/windsor-merge-300 to 2c2f53e
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/1f5673fa
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/1f5673fa
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/1f5673fa
Branch: refs/heads/windsor-merge-300
Commit: 1f5673facc451087edf7622ce337a40a7cb5e996
Parents: 974d85e
Author: Adam Kocoloski <ad...@cloudant.com>
Authored: Mon Jun 3 12:26:35 2013 -0400
Committer: Robert Newson <rn...@apache.org>
Committed: Tue Aug 5 12:03:14 2014 +0100
----------------------------------------------------------------------
src/couch_proc_manager.erl | 62 +++++++++++++++++++++++++++++++++--------
1 file changed, 51 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/1f5673fa/src/couch_proc_manager.erl
----------------------------------------------------------------------
diff --git a/src/couch_proc_manager.erl b/src/couch_proc_manager.erl
index e2a4657..8288b13 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(client, {
@@ -46,7 +53,8 @@
ddoc_keys = [],
prompt_fun,
set_timeout_fun,
- stop_fun
+ stop_fun,
+ t0 = os:timestamp()
}).
start_link() ->
@@ -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),
@@ -72,6 +86,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 +131,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}.
@@ -199,11 +228,17 @@ terminate(_Reason, #state{tab=Tab}) ->
ets:foldl(fun(#proc_int{pid=P}, _) -> couch_util:shutdown_sync(P) end, 0, Tab),
ok.
-code_change(_OldVsn, #state{tab = Tab} = State, _Extra) ->
- NewTab = ets:new(procs, [ordered_set, {keypos, #proc_int.pid}]),
- true = ets:insert(NewTab, ets:tab2list(Tab)),
- true = ets:delete(Tab),
- {ok, State#state{tab = NewTab}}.
+code_change(_OldVsn, {state, Tab}, _Extra) ->
+ State = #state{tab = Tab, threshold_ts = {0,0,0}},
+ ProcInts = lists:map(
+ fun(#proc{} = P) ->
+ setelement(1, erlang:append_element(P, os:timestamp()), proc_int)
+ end,
+ ets:tab2list(Tab)
+ ),
+ ets:delete_all_objects(Tab),
+ ets:insert(Tab, ProcInts),
+ {ok, State}.
handle_config_change("query_server_config", _, _, _, _) ->
gen_server:cast(?MODULE, reload_config),
@@ -353,13 +388,18 @@ return_proc(#state{} = State, #proc{} = Proc) ->
ok
end;
return_proc(#state{} = State, #proc_int{} = ProcInt) ->
- #state{tab = Tab, waiting = Waiting} = State,
+ #state{tab = Tab, waiting = Waiting, threshold_ts = T0} = State,
#proc_int{pid = Pid, lang = Lang} = ProcInt,
case is_process_alive(Pid) of true ->
case get_waiting_client(Waiting, Lang) of
nil ->
- gen_server:cast(Pid, garbage_collect),
- ets:insert(Tab, ProcInt#proc_int{client=nil}),
+ 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, ProcInt#proc_int{client=nil})
+ end,
State;
#client{}=Client ->
From = Client#client.from,