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 2020/12/16 18:05:20 UTC

[couchdb-ioq] 01/01: Use link/unlink for hidden nodes

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

rnewson pushed a commit to branch hidden-node-links
in repository https://gitbox.apache.org/repos/asf/couchdb-ioq.git

commit 6f970cabffda16ddb17440fe0cd13422bcc31e3e
Author: Robert Newson <rn...@apache.org>
AuthorDate: Wed Dec 16 17:53:23 2020 +0000

    Use link/unlink for hidden nodes
    
    link/unlink is supported by JInterface which presents as a hidden
    node, this enhancement to ioq allows us to ditch scalang among other
    effects.
---
 src/ioq_server.erl | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 53 insertions(+), 2 deletions(-)

diff --git a/src/ioq_server.erl b/src/ioq_server.erl
index c9fd79b..9b12986 100644
--- a/src/ioq_server.erl
+++ b/src/ioq_server.erl
@@ -94,6 +94,7 @@ init([]) ->
         histos = ets:new(ioq_histos, [named_table, ordered_set])
     },
     erlang:send_after(get_interval(), self(), dump_table),
+    process_flag(trap_exit, true),
     {ok, update_config(State)}.
 
 handle_call({set_priority, Pri}, _From, State) ->
@@ -146,7 +147,7 @@ handle_info({Ref, Reply}, #state{reqs = Reqs} = State) ->
     case lists:keytake(Ref, #request.ref, Reqs) of
     {value, #request{from=From} = Req, Reqs2} ->
         TResponse = erlang:monotonic_time(),
-        erlang:demonitor(Ref, [flush]),
+        demonitor_(Ref, Req#request.fd),
         reply_to_all(From, Reply),
         update_histograms(ioq_histos, Req, TResponse),
         {noreply, State#state{reqs = Reqs2}, 0};
@@ -163,6 +164,12 @@ handle_info({'DOWN', Ref, _, _, Reason}, #state{reqs = Reqs} = State) ->
         {noreply, State, 0}
     end;
 
+handle_info({'EXIT', Pid, Reason}, #state{reqs = Reqs} = State) ->
+    {L1, L2} = lists:splitwith(fun(R) -> Pid == R#request.fd end, Reqs),
+    lists:foreach(
+        fun(R) -> reply_to_all(R#request.from, {'EXIT', Reason}) end, L1),
+    {noreply, State#state{reqs = L2}, 0};
+
 handle_info(dump_table, State) ->
     erlang:send_after(get_interval(), self(), dump_table),
     {noreply, dump_table(State), 0};
@@ -414,7 +421,7 @@ submit_request(Request, State) ->
     #state{reqs = Reqs, counters = Counters} = State,
 
     % make the request
-    Ref = erlang:monitor(process, Fd),
+    Ref = monitor_(Fd),
     Fd ! {'$gen_call', {self(), Ref}, Call},
 
     % record some stats
@@ -598,6 +605,50 @@ rw({append_bin, _}) ->
 rw(_) ->
     unknown.
 
+
+monitor_(Pid) when is_pid(Pid) ->
+    case is_hidden(Pid) of
+        true ->
+            link(Pid),
+            make_ref();
+        false ->
+            erlang:monitor(process, Pid)
+    end;
+
+monitor_({Name, Node}) when is_atom(Name), is_atom(Node) ->
+    case is_hidden(Node) of
+        true ->
+            make_ref();
+        false ->
+            erlang:monitor(process, {Name, Node})
+    end.
+
+
+demonitor_(Ref, Pid) when is_reference(Ref), is_pid(Pid) ->
+    case is_hidden(Pid) of
+        true ->
+            unlink(Pid);
+        false ->
+            erlang:demonitor(Ref, [flush])
+    end;
+
+demonitor_(Ref, {Name, Node})
+  when is_reference(Ref), is_atom(Name), is_atom(Node) ->
+    case is_hidden(Node) of
+        true ->
+            ok;
+        false ->
+            erlang:demonitor(Ref, [flush])
+    end.
+
+
+is_hidden(Pid) when is_pid(Pid) ->
+    is_hidden(node(Pid));
+
+is_hidden(Node) when is_atom(Node) ->
+    lists:member(Node, nodes(hidden)).
+
+
 -ifdef(TEST).
 -include_lib("eunit/include/eunit.hrl").