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 2023/03/22 14:31:22 UTC

[couchdb] 03/03: don't crash if index crashes during open or if event listener crashes

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

rnewson pushed a commit to branch couch_index_fixes
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit c81c5c5a990ff4b3536f82af69cb9f9aa10dd955
Author: Robert Newson <rn...@apache.org>
AuthorDate: Wed Mar 22 14:31:01 2023 +0000

    don't crash if index crashes during open or if event listener crashes
---
 src/couch_index/src/couch_index_server.erl | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/src/couch_index/src/couch_index_server.erl b/src/couch_index/src/couch_index_server.erl
index 2e368bfc2..0a2af85a1 100644
--- a/src/couch_index/src/couch_index_server.erl
+++ b/src/couch_index/src/couch_index_server.erl
@@ -41,7 +41,8 @@
     server_name,
     by_sig,
     by_pid,
-    by_db
+    by_db,
+    event_listener
 }).
 
 start_link(N) ->
@@ -143,8 +144,8 @@ init([N]) ->
         by_db = by_db(N)
     },
     ok = config:listen_for_changes(?MODULE, St),
-    couch_event:link_listener(?MODULE, handle_db_event, St, [all_dbs]),
-    {ok, St}.
+    {ok, Pid} = couch_event:link_listener(?MODULE, handle_db_event, St, [all_dbs]),
+    {ok, St#st{event_listener = Pid}}.
 
 terminate(_Reason, State) ->
     Pids = [Pid || {Pid, _} <- ets:tab2list(State#st.by_pid)],
@@ -154,7 +155,8 @@ terminate(_Reason, State) ->
 handle_call({get_index, {_Mod, _IdxState, DbName, Sig} = Args}, From, State) ->
     case ets:lookup(State#st.by_sig, {DbName, Sig}) of
         [] ->
-            spawn_link(fun() -> new_index(Args) end),
+            Pid = spawn_link(fun() -> new_index(Args) end),
+            ets:insert(State#st.by_pid, {Pid, opening, {DbName, Sig}}),
             ets:insert(State#st.by_sig, {{DbName, Sig}, [From]}),
             {noreply, State};
         [{_, Waiters}] when is_list(Waiters) ->
@@ -169,9 +171,10 @@ handle_call({async_open, {DbName, DDocId, Sig}, {ok, Pid}}, _From, State) ->
     link(Pid),
     add_to_ets(DbName, Sig, DDocId, Pid, State),
     {reply, ok, State};
-handle_call({async_error, {DbName, _DDocId, Sig}, Error}, _From, State) ->
+handle_call({async_error, {DbName, _DDocId, Sig}, Error}, {OpenerPid, _}, State) ->
     [{_, Waiters}] = ets:lookup(State#st.by_sig, {DbName, Sig}),
     [gen_server:reply(From, Error) || From <- Waiters],
+    ets:delete(State#st.by_pid, OpenerPid),
     ets:delete(State#st.by_sig, {DbName, Sig}),
     {reply, ok, State};
 handle_call({reset_indexes, DbName}, _From, State) ->
@@ -194,6 +197,10 @@ handle_cast({rem_from_ets, [DbName, DDocId, Sig]}, State) ->
     ets:delete_object(State#st.by_db, {DbName, {DDocId, Sig}}),
     {noreply, State}.
 
+handle_info({'EXIT', Pid, Reason}, #st{event_listener = Pid} = State) ->
+    couch_log:warning("~p: update notifier died ~p", [?MODULE, Reason]),
+    {ok, Pid1} = start_event_listener(),
+    {noreply, State#st{event_listener = Pid1}};
 handle_info({'EXIT', Pid, Reason}, Server) ->
     case ets:lookup(Server#st.by_pid, Pid) of
         [{Pid, {DbName, Sig}}] ->
@@ -203,6 +210,9 @@ handle_info({'EXIT', Pid, Reason}, Server) ->
                     ets:match_object(Server#st.by_db, {DbName, {'$1', Sig}})
             ],
             rem_from_ets(DbName, Sig, DDocIds, Pid, Server);
+        [{_, opening, {DbName, Sig}}] when Reason /= normal ->
+            Msg = {async_error, {DbName, nil, Sig}, Reason},
+            {reply, ok, _} = handle_call(Msg, {Pid, nil}, Server);
         [] when Reason /= normal ->
             exit(Reason);
         _Else ->
@@ -394,3 +404,6 @@ aggregate_queue_len() ->
      || Name <- Names
     ],
     lists:sum([X || {_, X} <- MQs]).
+
+start_event_listener() ->
+    couch_event:link_listener(?MODULE, handle_db_event, nil, [all_dbs]).