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 2010/06/14 15:37:52 UTC

svn commit: r954458 - in /couchdb/branches/0.11.x: src/couchdb/ test/etap/

Author: jan
Date: Mon Jun 14 13:37:51 2010
New Revision: 954458

URL: http://svn.apache.org/viewvc?rev=954458&view=rev
Log:
Deterministic/synchronous shutdown code.

Modified:
    couchdb/branches/0.11.x/src/couchdb/couch_config.erl
    couchdb/branches/0.11.x/src/couchdb/couch_db.erl
    couchdb/branches/0.11.x/src/couchdb/couch_db_updater.erl
    couchdb/branches/0.11.x/src/couchdb/couch_external_server.erl
    couchdb/branches/0.11.x/src/couchdb/couch_file.erl
    couchdb/branches/0.11.x/src/couchdb/couch_native_process.erl
    couchdb/branches/0.11.x/src/couchdb/couch_os_process.erl
    couchdb/branches/0.11.x/src/couchdb/couch_query_servers.erl
    couchdb/branches/0.11.x/src/couchdb/couch_ref_counter.erl
    couchdb/branches/0.11.x/src/couchdb/couch_server.erl
    couchdb/branches/0.11.x/src/couchdb/couch_server_sup.erl
    couchdb/branches/0.11.x/src/couchdb/couch_stats_collector.erl
    couchdb/branches/0.11.x/src/couchdb/couch_util.erl
    couchdb/branches/0.11.x/src/couchdb/couch_view.erl
    couchdb/branches/0.11.x/src/couchdb/couch_view_group.erl
    couchdb/branches/0.11.x/test/etap/010-file-basics.t
    couchdb/branches/0.11.x/test/etap/040-util.t

Modified: couchdb/branches/0.11.x/src/couchdb/couch_config.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_config.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_config.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_config.erl Mon Jun 14 13:37:51 2010
@@ -111,7 +111,7 @@ terminate(_Reason, _State) ->
 handle_call(all, _From, Config) ->
     Resp = lists:sort((ets:tab2list(?MODULE))),
     {reply, Resp, Config};
-handle_call({set, Sec, Key, Val, Persist}, _From, Config) ->
+handle_call({set, Sec, Key, Val, Persist}, From, Config) ->
     true = ets:insert(?MODULE, {{Sec, Key}, Val}),
     case {Persist, Config#config.write_filename} of
         {true, undefined} ->
@@ -121,9 +121,12 @@ handle_call({set, Sec, Key, Val, Persist
         _ ->
             ok
     end,
-    [catch F(Sec, Key, Val, Persist) || {_Pid, F} <- Config#config.notify_funs],
-    {reply, ok, Config};
-handle_call({delete, Sec, Key, Persist}, _From, Config) ->
+    spawn_link(fun() ->
+        [catch F(Sec, Key, Val, Persist) || {_Pid, F} <- Config#config.notify_funs],
+            gen_server:reply(From, ok)
+    end),
+    {noreply, Config};
+handle_call({delete, Sec, Key, Persist}, From, Config) ->
     true = ets:delete(?MODULE, {Sec,Key}),
     case {Persist, Config#config.write_filename} of
         {true, undefined} ->
@@ -133,8 +136,11 @@ handle_call({delete, Sec, Key, Persist},
         _ ->
             ok
     end,
-    [catch F(Sec, Key, deleted, Persist) || {_Pid, F} <- Config#config.notify_funs],
-    {reply, ok, Config};
+    spawn_link(fun() ->
+        [catch F(Sec, Key, deleted, Persist) || {_Pid, F} <- Config#config.notify_funs],
+            gen_server:reply(From, ok)
+    end),
+    {noreply, Config};
 handle_call({register, Fun, Pid}, _From, #config{notify_funs=PidFuns}=Config) ->
     erlang:monitor(process, Pid),
     % convert 1 and 2 arity to 3 arity

Modified: couchdb/branches/0.11.x/src/couchdb/couch_db.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_db.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_db.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_db.erl Mon Jun 14 13:37:51 2010
@@ -905,10 +905,11 @@ init({DbName, Filepath, Fd, Options}) ->
     {ok, #db{fd_ref_counter=RefCntr}=Db} = gen_server:call(UpdaterPid, get_db),
     couch_ref_counter:add(RefCntr),
     couch_stats_collector:track_process_count({couchdb, open_databases}),
+    process_flag(trap_exit, true),
     {ok, Db}.
 
-terminate(Reason, _Db) ->
-    couch_util:terminate_linked(Reason),
+terminate(_Reason, Db) ->
+    couch_util:shutdown_sync(Db#db.update_pid),
     ok.
 
 handle_call({open_ref_count, OpenerPid}, _, #db{fd_ref_counter=RefCntr}=Db) ->
@@ -936,7 +937,11 @@ handle_cast(Msg, Db) ->
 
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
-
+    
+handle_info({'EXIT', _Pid, normal}, Db) ->
+    {noreply, Db};
+handle_info({'EXIT', _Pid, Reason}, Server) ->
+    {stop, Reason, Server};
 handle_info(Msg, Db) ->
     ?LOG_ERROR("Bad message received for db ~s: ~p", [Db#db.name, Msg]),
     exit({error, Msg}).

Modified: couchdb/branches/0.11.x/src/couchdb/couch_db_updater.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_db_updater.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_db_updater.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_db_updater.erl Mon Jun 14 13:37:51 2010
@@ -20,6 +20,7 @@
 
 
 init({MainPid, DbName, Filepath, Fd, Options}) ->
+    process_flag(trap_exit, true),
     case lists:member(create, Options) of
     true ->
         % create a new header and writes it to the file
@@ -37,8 +38,10 @@ init({MainPid, DbName, Filepath, Fd, Opt
     {ok, Db2#db{main_pid=MainPid}}.
 
 
-terminate(Reason, _Srv) ->
-    couch_util:terminate_linked(Reason),
+terminate(_Reason, Db) ->
+    couch_file:close(Db#db.fd),
+    couch_util:shutdown_sync(Db#db.compactor_pid),
+    couch_util:shutdown_sync(Db#db.fd_ref_counter),
     ok.
 
 handle_call(get_db, _From, Db) ->
@@ -218,7 +221,11 @@ handle_info(delayed_commit, Db) ->
         Db2 ->
             ok = gen_server:call(Db2#db.main_pid, {db_updated, Db2}),
             {noreply, Db2}
-    end.
+    end;
+handle_info({'EXIT', _Pid, normal}, Db) ->
+    {noreply, Db};
+handle_info({'EXIT', _Pid, Reason}, Db) ->
+    {stop, Reason, Db}.
 
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.

Modified: couchdb/branches/0.11.x/src/couchdb/couch_external_server.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_external_server.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_external_server.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_external_server.erl Mon Jun 14 13:37:51 2010
@@ -50,9 +50,11 @@ terminate(_Reason, {_Name, _Command, Pid
 handle_call({execute, JsonReq}, _From, {Name, Command, Pid}) ->
     {reply, couch_os_process:prompt(Pid, JsonReq), {Name, Command, Pid}}.
 
+handle_info({'EXIT', _Pid, normal}, State) ->
+    {noreply, State};
 handle_info({'EXIT', Pid, Reason}, {Name, Command, Pid}) ->
     ?LOG_INFO("EXTERNAL: Process for ~s exiting. (reason: ~w)", [Name, Reason]),
-    {stop, normal, {Name, Command, Pid}}.
+    {stop, Reason, {Name, Command, Pid}}.
 
 handle_cast(stop, {Name, Command, Pid}) ->
     ?LOG_INFO("EXTERNAL: Shutting down ~s", [Name]),

Modified: couchdb/branches/0.11.x/src/couchdb/couch_file.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_file.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_file.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_file.erl Mon Jun 14 13:37:51 2010
@@ -176,13 +176,21 @@ sync(Fd) ->
     gen_server:call(Fd, sync, infinity).
 
 %%----------------------------------------------------------------------
-%% Purpose: Close the file. Is performed asynchronously.
+%% Purpose: Close the file.
 %% Returns: ok
 %%----------------------------------------------------------------------
 close(Fd) ->
-    Result = gen_server:cast(Fd, close),
-    catch unlink(Fd),
-    Result.
+    MRef = erlang:monitor(process, Fd),
+    try
+        catch unlink(Fd),
+        catch exit(Fd, shutdown),
+        receive
+        {'DOWN', MRef, _, _, _} ->
+            ok
+        end
+    after
+        erlang:demonitor(MRef, [flush])
+    end.
 
 % 09 UPGRADE CODE
 old_pread(Fd, Pos, Len) ->
@@ -219,6 +227,7 @@ init_status_error(ReturnPid, Ref, Error)
 % server functions
 
 init({Filepath, Options, ReturnPid, Ref}) ->
+    process_flag(trap_exit, true),
     case lists:member(create, Options) of
     true ->
         filelib:ensure_dir(Filepath),
@@ -432,6 +441,8 @@ handle_cast(close, Fd) ->
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
 
+handle_info({'EXIT', _, normal}, Fd) ->
+    {noreply, Fd};
 handle_info({'EXIT', _, Reason}, Fd) ->
     {stop, Reason, Fd}.
 

Modified: couchdb/branches/0.11.x/src/couchdb/couch_native_process.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_native_process.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_native_process.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_native_process.erl Mon Jun 14 13:37:51 2010
@@ -94,8 +94,10 @@ handle_call({prompt, Data}, _From, State
             {reply, Resp, NewState}
     end.
 
-handle_cast(_Msg, State) -> {noreply, State}.
-handle_info(_Msg, State) -> {noreply, State}.
+handle_cast(foo, State) -> {noreply, State}.
+handle_info({'EXIT',_,normal}, State) -> {noreply, State};
+handle_info({'EXIT',_,Reason}, State) ->
+    {stop, Reason, State}.
 terminate(_Reason, _State) -> ok.
 code_change(_OldVersion, State, _Extra) -> {ok, State}.
 

Modified: couchdb/branches/0.11.x/src/couchdb/couch_os_process.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_os_process.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_os_process.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_os_process.erl Mon Jun 14 13:37:51 2010
@@ -104,6 +104,7 @@ readjson(OsProc) when is_record(OsProc, 
 
 % gen_server API
 init([Command, Options, PortOptions]) ->
+    process_flag(trap_exit, true),
     PrivDir = couch_util:priv_dir(),
     Spawnkiller = filename:join(PrivDir, "couchspawnkillable"),
     BaseProc = #os_proc{

Modified: couchdb/branches/0.11.x/src/couchdb/couch_query_servers.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_query_servers.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_query_servers.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_query_servers.erl Mon Jun 14 13:37:51 2010
@@ -15,7 +15,7 @@
 
 -export([start_link/0]).
 
--export([init/1, terminate/2, handle_call/3, handle_cast/2, handle_info/2,code_change/3,stop/0]).
+-export([init/1, terminate/2, handle_call/3, handle_cast/2, handle_info/2,code_change/3]).
 -export([start_doc_map/2, map_docs/2, stop_doc_map/1]).
 -export([reduce/3, rereduce/3,validate_doc_update/5]).
 -export([filter_docs/5]).
@@ -38,9 +38,6 @@
 start_link() ->
     gen_server:start_link({local, couch_query_servers}, couch_query_servers, [], []).
 
-stop() ->
-    exit(whereis(couch_query_servers), normal).
-
 start_doc_map(Lang, Functions) ->
     Proc = get_os_process(Lang),
     lists:foreach(fun(FunctionSource) ->
@@ -218,17 +215,18 @@ init([]) ->
 
     ok = couch_config:register(
         fun("query_servers" ++ _, _) ->
-            ?MODULE:stop()
+            supervisor:terminate_child(couch_secondary_services, query_servers),
+            supervisor:restart_child(couch_secondary_services, query_servers)
         end),
     ok = couch_config:register(
         fun("native_query_servers" ++ _, _) ->
-            ?MODULE:stop()
+            supervisor:terminate_child(couch_secondary_services, query_servers),
+            [supervisor:restart_child(couch_secondary_services, query_servers)]
         end),
 
     Langs = ets:new(couch_query_server_langs, [set, private]),
     PidProcs = ets:new(couch_query_server_pid_langs, [set, private]),
     LangProcs = ets:new(couch_query_server_procs, [set, private]),
-    InUse = ets:new(couch_query_server_used, [set, private]),
     % 'query_servers' specifies an OS command-line to execute.
     lists:foreach(fun({Lang, Command}) ->
         true = ets:insert(Langs, {?l2b(Lang),
@@ -243,75 +241,71 @@ init([]) ->
     process_flag(trap_exit, true),
     {ok, {Langs, % Keyed by language name, value is {Mod,Func,Arg}
           PidProcs, % Keyed by PID, valus is a #proc record.
-          LangProcs, % Keyed by language name, value is a #proc record
-          InUse % Keyed by PID, value is #proc record.
+          LangProcs % Keyed by language name, value is a #proc record
           }}.
 
-terminate(_Reason, _Server) ->
+terminate(_Reason, {_Langs, PidProcs, _LangProcs}) ->
+    [couch_util:shutdown_sync(P) || {P,_} <- ets:tab2list(PidProcs)],
     ok.
 
-handle_call({get_proc, #doc{body={Props}}=DDoc, DDocKey}, _From, {Langs, PidProcs, LangProcs, InUse}=Server) ->
+handle_call({get_proc, #doc{body={Props}}=DDoc, DDocKey}, _From, {Langs, PidProcs, LangProcs}=Server) ->
     % Note to future self. Add max process limit.
     Lang = proplists:get_value(<<"language">>, Props, <<"javascript">>),    
     case ets:lookup(LangProcs, Lang) of
     [{Lang, [P|Rest]}] ->
         % find a proc in the set that has the DDoc
         case proc_with_ddoc(DDoc, DDocKey, [P|Rest]) of
-            {ok, Proc} ->
-                % looks like the proc isn't getting dropped from the list.
-                % we need to change this to take a fun for equality checking
-                % so we can do a comparison on portnum
-                rem_from_list(LangProcs, Lang, Proc),
-                add_to_list(InUse, Lang, Proc),
-                {reply, {ok, Proc, get_query_server_config()}, Server};
-            Error -> 
-                {reply, Error, Server}
-            end;
+        {ok, Proc} ->
+            rem_from_list(LangProcs, Lang, Proc),
+            {reply, {ok, Proc, get_query_server_config()}, Server};
+        Error -> 
+            {reply, Error, Server}
+        end;
     _ ->
         case (catch new_process(Langs, Lang)) of
         {ok, Proc} ->
             add_value(PidProcs, Proc#proc.pid, Proc),
             case proc_with_ddoc(DDoc, DDocKey, [Proc]) of
-                {ok, Proc2} ->
-                    rem_from_list(LangProcs, Lang, Proc),
-                    add_to_list(InUse, Lang, Proc2),
-                    {reply, {ok, Proc2, get_query_server_config()}, Server};
-                Error -> 
-                    {reply, Error, Server}
-                end;
+            {ok, Proc2} ->
+                {reply, {ok, Proc2, get_query_server_config()}, Server};
+            Error -> 
+                {reply, Error, Server}
+            end;
         Error ->
             {reply, Error, Server}
         end
     end;
-handle_call({get_proc, Lang}, _From, {Langs, PidProcs, LangProcs, InUse}=Server) ->
+handle_call({get_proc, Lang}, _From, {Langs, PidProcs, LangProcs}=Server) ->
     % Note to future self. Add max process limit.
     case ets:lookup(LangProcs, Lang) of
     [{Lang, [Proc|_]}] ->
-        add_value(PidProcs, Proc#proc.pid, Proc),
         rem_from_list(LangProcs, Lang, Proc),
-        add_to_list(InUse, Lang, Proc),
         {reply, {ok, Proc, get_query_server_config()}, Server};
     _ ->
         case (catch new_process(Langs, Lang)) of
         {ok, Proc} ->
             add_value(PidProcs, Proc#proc.pid, Proc),
-            add_to_list(InUse, Lang, Proc),
             {reply, {ok, Proc, get_query_server_config()}, Server};
         Error ->
             {reply, Error, Server}
         end
     end;
-handle_call({ret_proc, Proc}, _From, {_, _, LangProcs, InUse}=Server) ->
+handle_call({unlink_proc, Pid}, _From, {_, PidProcs, _}=Server) ->    
+    rem_value(PidProcs, Pid),
+    unlink(Pid),
+    {reply, ok, Server};
+handle_call({ret_proc, Proc}, _From, {_, PidProcs, LangProcs}=Server) ->
     % Along with max process limit, here we should check
     % if we're over the limit and discard when we are.
+    add_value(PidProcs, Proc#proc.pid, Proc),
     add_to_list(LangProcs, Proc#proc.lang, Proc),
-    rem_from_list(InUse, Proc#proc.lang, Proc),
+    link(Proc#proc.pid),
     {reply, true, Server}.
 
 handle_cast(_Whatever, Server) ->
     {noreply, Server}.
 
-handle_info({'EXIT', Pid, Status}, {_, PidProcs, LangProcs, InUse}=Server) ->
+handle_info({'EXIT', Pid, Status}, {_, PidProcs, LangProcs}=Server) ->
     case ets:lookup(PidProcs, Pid) of
     [{Pid, Proc}] ->
         case Status of
@@ -320,11 +314,14 @@ handle_info({'EXIT', Pid, Status}, {_, P
         end,
         rem_value(PidProcs, Pid),
         catch rem_from_list(LangProcs, Proc#proc.lang, Proc),
-        catch rem_from_list(InUse, Proc#proc.lang, Proc),
         {noreply, Server};
     [] ->
-        ?LOG_DEBUG("Unknown linked process died: ~p (reason: ~p)", [Pid, Status]),
-        {stop, Status, Server}
+        case Status of
+        normal ->
+            {noreply, Server};
+        _ ->
+            {stop, Status, Server}
+        end
     end.
 
 code_change(_OldVsn, State, _Extra) ->
@@ -401,6 +398,7 @@ get_ddoc_process(#doc{} = DDoc, DDocKey)
             proc_set_timeout(Proc, list_to_integer(couch_config:get(
                                 "couchdb", "os_process_timeout", "5000"))),
             link(Proc#proc.pid),
+            gen_server:call(couch_query_servers, {unlink_proc, Proc#proc.pid}),
             Proc;
         _ ->
             catch proc_stop(Proc),
@@ -418,6 +416,7 @@ get_os_process(Lang) ->
             proc_set_timeout(Proc, list_to_integer(couch_config:get(
                                 "couchdb", "os_process_timeout", "5000"))),
             link(Proc#proc.pid),
+            gen_server:call(couch_query_servers, {unlink_proc, Proc#proc.pid}),
             Proc;
         _ ->
             catch proc_stop(Proc),

Modified: couchdb/branches/0.11.x/src/couchdb/couch_ref_counter.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_ref_counter.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_ref_counter.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_ref_counter.erl Mon Jun 14 13:37:51 2010
@@ -40,17 +40,18 @@ count(RefCounterPid) ->
 
 -record(srv,
     {
-    referrers=dict:new() % a dict of each ref counting proc.
+    referrers=dict:new(), % a dict of each ref counting proc.
+    child_procs=[]
     }).
 
 init({Pid, ChildProcs}) ->
     [link(ChildProc) || ChildProc <- ChildProcs],
     Referrers = dict:from_list([{Pid, {erlang:monitor(process, Pid), 1}}]),
-    {ok, #srv{referrers=Referrers}}.
+    {ok, #srv{referrers=Referrers, child_procs=ChildProcs}}.
 
 
-terminate(Reason, _Srv) ->
-    couch_util:terminate_linked(Reason),
+terminate(_Reason, #srv{child_procs=ChildProcs}) ->
+    [couch_util:shutdown_sync(Pid) || Pid <- ChildProcs],
     ok.
 
 

Modified: couchdb/branches/0.11.x/src/couchdb/couch_server.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_server.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_server.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_server.erl Mon Jun 14 13:37:51 2010
@@ -147,8 +147,9 @@ init([]) ->
                 max_dbs_open=MaxDbsOpen,
                 start_time=httpd_util:rfc1123_date()}}.
 
-terminate(Reason, _Srv) ->
-    couch_util:terminate_linked(Reason),
+terminate(_Reason, _Srv) ->
+    [couch_util:shutdown_sync(Pid) || {_, {Pid, _LruTime}} <- 
+            ets:tab2list(couch_dbs_by_name)],
     ok.
 
 all_databases() ->
@@ -189,8 +190,7 @@ try_close_lru(StartTime) ->
         [{_, {opened, MainPid, LruTime}}] = ets:lookup(couch_dbs_by_name, DbName),
         case couch_db:is_idle(MainPid) of
         true ->
-            exit(MainPid, kill),
-            receive {'EXIT', MainPid, _Reason} -> ok end,
+            couch_util:shutdown_sync(MainPid),
             true = ets:delete(couch_dbs_by_lru, LruTime),
             true = ets:delete(couch_dbs_by_name, DbName),
             true = ets:delete(couch_dbs_by_pid, MainPid),
@@ -212,7 +212,13 @@ open_async(Server, From, DbName, Filepat
     Opener = spawn_link(fun() ->
             Res = couch_db:start_link(DbName, Filepath, Options),
             gen_server:call(Parent, {open_result, DbName, Res}, infinity),
-            unlink(Parent)
+            unlink(Parent),
+            case Res of
+            {ok, DbReader} ->
+                unlink(DbReader);
+            _ ->
+                ok
+            end
         end),
     true = ets:insert(couch_dbs_by_name, {DbName, {opening, Opener, [From]}}),
     true = ets:insert(couch_dbs_by_pid, {Opener, DbName}),
@@ -299,15 +305,13 @@ handle_call({delete, DbName, _Options}, 
         case ets:lookup(couch_dbs_by_name, DbName) of
         [] -> Server;
         [{_, {opening, Pid, Froms}}] ->
-            exit(Pid, kill),
-            receive {'EXIT', Pid, _Reason} -> ok end,
+            couch_util:shutdown_sync(Pid),
             true = ets:delete(couch_dbs_by_name, DbName),
             true = ets:delete(couch_dbs_by_pid, Pid),
             [gen_server:send_result(F, not_found) || F <- Froms],
             Server#server{dbs_open=Server#server.dbs_open - 1};
         [{_, {opened, Pid, LruTime}}] ->
-            exit(Pid, kill),
-            receive {'EXIT', Pid, _Reason} -> ok end,
+            couch_util:shutdown_sync(Pid),
             true = ets:delete(couch_dbs_by_name, DbName),
             true = ets:delete(couch_dbs_by_pid, Pid),
             true = ets:delete(couch_dbs_by_lru, LruTime),
@@ -336,20 +340,10 @@ handle_cast(Msg, _Server) ->
 
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
-
-handle_info({'EXIT', _Pid, config_change}, _Server) ->
-    exit(kill);
-handle_info({'EXIT', Pid, Reason}, #server{dbs_open=DbsOpen}=Server) ->
-    [{Pid, DbName}] = ets:lookup(couch_dbs_by_pid, Pid),
-    case ets:lookup(couch_dbs_by_name, DbName) of
-    [{DbName, {opened, Pid, LruTime}}] ->
-        true = ets:delete(couch_dbs_by_lru, LruTime);
-    [{DbName, {opening, Pid, Froms}}] ->
-        [gen_server:reply(From, Reason) || From <- Froms]
-    end,
-    true = ets:delete(couch_dbs_by_pid, Pid),
-    true = ets:delete(couch_dbs_by_name, DbName),
-    {noreply, Server#server{dbs_open=DbsOpen - 1}};
-handle_info(Info, _Server) ->
-    exit({unknown_message, Info}).
+    
+handle_info({'EXIT', _Pid, config_change}, Server) ->
+    {noreply, shutdown, Server};
+handle_info(Error, _Server) ->
+    ?LOG_ERROR("Unexpected message, restarting couch_server: ~p", [Error]),
+    exit(kill).
 

Modified: couchdb/branches/0.11.x/src/couchdb/couch_server_sup.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_server_sup.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_server_sup.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_server_sup.erl Mon Jun 14 13:37:51 2010
@@ -174,7 +174,7 @@ start_secondary_services() ->
             {list_to_atom(Name),
                 {Module, Fun, Args},
                 permanent,
-                brutal_kill,
+                1000,
                 worker,
                 [Module]}
         end

Modified: couchdb/branches/0.11.x/src/couchdb/couch_stats_collector.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_stats_collector.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_stats_collector.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_stats_collector.erl Mon Jun 14 13:37:51 2010
@@ -60,7 +60,7 @@ increment(Key) ->
     Key2 = make_key(Key),
     case catch ets:update_counter(?HIT_TABLE, Key2, 1) of
         {'EXIT', {badarg, _}} ->
-            true = ets:insert(?HIT_TABLE, {Key2, 1}),
+            catch ets:insert(?HIT_TABLE, {Key2, 1}),
             ok;
         _ ->
             ok
@@ -70,16 +70,16 @@ decrement(Key) ->
     Key2 = make_key(Key),
     case catch ets:update_counter(?HIT_TABLE, Key2, -1) of
         {'EXIT', {badarg, _}} ->
-            true = ets:insert(?HIT_TABLE, {Key2, -1}),
+            catch ets:insert(?HIT_TABLE, {Key2, -1}),
             ok;
         _ -> ok
     end.
 
 record(Key, Value) ->
-    true = ets:insert(?ABS_TABLE, {make_key(Key), Value}).
+    catch ets:insert(?ABS_TABLE, {make_key(Key), Value}).
 
 clear(Key) ->
-    true = ets:delete(?ABS_TABLE, make_key(Key)).
+    catch ets:delete(?ABS_TABLE, make_key(Key)).
 
 track_process_count(Stat) ->
     track_process_count(self(), Stat).

Modified: couchdb/branches/0.11.x/src/couchdb/couch_util.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_util.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_util.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_util.erl Mon Jun 14 13:37:51 2010
@@ -12,7 +12,7 @@
 
 -module(couch_util).
 
--export([priv_dir/0, start_driver/1, normpath/1, terminate_linked/1]).
+-export([priv_dir/0, start_driver/1, normpath/1]).
 -export([should_flush/0, should_flush/1, to_existing_atom/1]).
 -export([rand32/0, implode/2, collate/2, collate/3]).
 -export([abs_pathname/1,abs_pathname/2, trim/1, ascii_lower/1]).
@@ -21,7 +21,7 @@
 -export([file_read_size/1, get_nested_json_value/2, json_user_ctx/1]).
 -export([to_binary/1, to_integer/1, to_list/1, url_encode/1]).
 -export([json_encode/1, json_decode/1]).
--export([verify/2]).
+-export([verify/2,simple_call/2,shutdown_sync/1]).
 -export([compressible_att_type/1]).
 
 -include("couch_db.hrl").
@@ -72,14 +72,35 @@ to_existing_atom(V) when is_binary(V) ->
 to_existing_atom(V) when is_atom(V) ->
     V.
 
+shutdown_sync(Pid) when not is_pid(Pid)->
+    ok;
+shutdown_sync(Pid) ->
+    MRef = erlang:monitor(process, Pid),
+    try
+        catch unlink(Pid),
+        catch exit(Pid, shutdown),
+        receive
+        {'DOWN', MRef, _, _, _} ->
+            ok
+        end
+    after
+        erlang:demonitor(MRef, [flush])
+    end.
+    
 
-terminate_linked(normal) ->
-    terminate_linked(shutdown);
-terminate_linked(Reason) ->
-    {links, Links} = process_info(self(), links),
-    [catch exit(Pid, Reason) || Pid <- Links],
-    ok.
-
+simple_call(Pid, Message) ->
+    MRef = erlang:monitor(process, Pid),
+    try
+        Pid ! {self(), Message},
+        receive
+        {Pid, Result} ->
+            Result;
+        {'DOWN', MRef, _, _, Reason} ->
+            exit(Reason)
+        end
+    after
+        erlang:demonitor(MRef, [flush])
+    end.
 
 to_hex([]) ->
     [];

Modified: couchdb/branches/0.11.x/src/couchdb/couch_view.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_view.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_view.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_view.erl Mon Jun 14 13:37:51 2010
@@ -269,8 +269,9 @@ init([]) ->
     {ok, #server{root_dir=RootDir}}.
 
 
-terminate(Reason, _Srv) ->
-    couch_util:terminate_linked(Reason),
+terminate(_Reason, _Srv) ->
+    [couch_util:shutdown_sync(Pid) || {Pid, _} <-
+            ets:tab2list(couch_groups_by_updater)],
     ok.
 
 
@@ -311,10 +312,7 @@ do_reset_indexes(DbName, Root) ->
         fun({_DbName, Sig}) ->
             ?LOG_DEBUG("Killing update process for view group ~s. in database ~s.", [Sig, DbName]),
             [{_, Pid}] = ets:lookup(group_servers_by_sig, {DbName, Sig}),
-            exit(Pid, kill),
-            receive {'EXIT', Pid, _} ->
-                delete_from_ets(Pid, DbName, Sig)
-            end
+            couch_util:shutdown_sync(Pid)
         end, Names),
     delete_index_dir(Root, DbName),
     file:delete(Root ++ "/." ++ ?b2l(DbName) ++ "_temp").

Modified: couchdb/branches/0.11.x/src/couchdb/couch_view_group.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/src/couchdb/couch_view_group.erl?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/src/couchdb/couch_view_group.erl (original)
+++ couchdb/branches/0.11.x/src/couchdb/couch_view_group.erl Mon Jun 14 13:37:51 2010
@@ -341,8 +341,8 @@ handle_info({'DOWN',_,_,_,_}, State) ->
 
 terminate(Reason, #group_state{updater_pid=Update, compactor_pid=Compact}=S) ->
     reply_all(S, Reason),
-    catch exit(Update, Reason),
-    catch exit(Compact, Reason),
+    couch_util:shutdown_sync(Update),
+    couch_util:shutdown_sync(Compact),
     ok.
 
 code_change(_OldVsn, State, _Extra) ->

Modified: couchdb/branches/0.11.x/test/etap/010-file-basics.t
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/test/etap/010-file-basics.t?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/test/etap/010-file-basics.t (original)
+++ couchdb/branches/0.11.x/test/etap/010-file-basics.t Mon Jun 14 13:37:51 2010
@@ -16,7 +16,7 @@ filename() -> test_util:build_file("test
 
 main(_) ->
     test_util:init_code_path(),
-    etap:plan(16),
+    etap:plan(19),
     case (catch test()) of
         ok ->
             etap:end_tests();
@@ -67,6 +67,19 @@ test() ->
     {ok, BinPos} = couch_file:append_binary(Fd, <<131,100,0,3,102,111,111>>),
     etap:is({ok, foo}, couch_file:pread_term(Fd, BinPos),
         "Reading a term from a written binary term representation succeeds."),
+        
+    BigBin = list_to_binary(lists:duplicate(100000, 0)),
+    {ok, BigBinPos} = couch_file:append_binary(Fd, BigBin),
+    etap:is({ok, BigBin}, couch_file:pread_binary(Fd, BigBinPos),
+        "Reading a large term from a written representation succeeds."),
+    
+    ok = couch_file:write_header(Fd, hello),
+    etap:is({ok, hello}, couch_file:read_header(Fd),
+        "Reading a header succeeds."),
+        
+    {ok, BigBinPos2} = couch_file:append_binary(Fd, BigBin),
+    etap:is({ok, BigBin}, couch_file:pread_binary(Fd, BigBinPos2),
+        "Reading a large term from a written representation succeeds 2."),
 
     % append_binary == append_iolist?
     % Possible bug in pread_iolist or iolist() -> append_binary

Modified: couchdb/branches/0.11.x/test/etap/040-util.t
URL: http://svn.apache.org/viewvc/couchdb/branches/0.11.x/test/etap/040-util.t?rev=954458&r1=954457&r2=954458&view=diff
==============================================================================
--- couchdb/branches/0.11.x/test/etap/040-util.t (original)
+++ couchdb/branches/0.11.x/test/etap/040-util.t Mon Jun 14 13:37:51 2010
@@ -17,7 +17,7 @@ main(_) ->
     test_util:init_code_path(),
     application:start(crypto),
 
-    etap:plan(16),
+    etap:plan(14),
     case (catch test()) of
         ok ->
             etap:end_tests();
@@ -35,29 +35,6 @@ test() ->
     etap:is(foobarbaz, couch_util:to_existing_atom("foobarbaz"),
         "A list of atoms is one munged atom."),
 
-    % terminate_linked
-    Self = self(),
-    
-    spawn(fun() ->
-        SecondSelf = self(),
-        ChildPid = spawn_link(fun() ->
-            SecondSelf ! {child, started},
-            receive shutdown -> ok end
-        end),
-        PidUp = receive
-            {child, started} -> ok
-        after 1000 ->
-            {error, timeout}
-        end,
-        etap:is(ok, PidUp, "Started a linked process."),
-        couch_util:terminate_linked(normal),
-        Self ! {pid, ChildPid}
-    end),
-    receive
-        {pid, Pid} ->
-            etap:ok(not is_process_alive(Pid), "Linked process was killed.")
-    end,
-
     % implode
     etap:is([1, 38, 2, 38, 3], couch_util:implode([1,2,3],"&"),
         "use & as separator in list."),